source: trunk/server/source3/smbd/sesssetup.c@ 456

Last change on this file since 456 was 454, checked in by Silvan Scherrer, 15 years ago

Samba Server 3.5: merged changes from 3.3

File size: 50.9 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 handle SMBsessionsetup
4 Copyright (C) Andrew Tridgell 1998-2001
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
7 Copyright (C) Luke Howard 2003
8 Copyright (C) Volker Lendecke 2007
9 Copyright (C) Jeremy Allison 2007
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include "includes.h"
26#include "smbd/globals.h"
27#include "../libcli/auth/spnego.h"
28
29/* For split krb5 SPNEGO blobs. */
30struct pending_auth_data {
31 struct pending_auth_data *prev, *next;
32 uint16 vuid; /* Tag for this entry. */
33 uint16 smbpid; /* Alternate tag for this entry. */
34 size_t needed_len;
35 DATA_BLOB partial_data;
36};
37
38/*
39 on a logon error possibly map the error to success if "map to guest"
40 is set approriately
41*/
42static NTSTATUS do_map_to_guest(NTSTATUS status,
43 auth_serversupplied_info **server_info,
44 const char *user, const char *domain)
45{
46 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
47 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
48 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
49 DEBUG(3,("No such user %s [%s] - using guest account\n",
50 user, domain));
51 status = make_server_info_guest(NULL, server_info);
52 }
53 }
54
55 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
56 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
57 DEBUG(3,("Registered username %s for guest access\n",
58 user));
59 status = make_server_info_guest(NULL, server_info);
60 }
61 }
62
63 return status;
64}
65
66/****************************************************************************
67 Add the standard 'Samba' signature to the end of the session setup.
68****************************************************************************/
69
70static int push_signature(uint8 **outbuf)
71{
72 char *lanman;
73 int result, tmp;
74
75 result = 0;
76
77#ifndef __OS2__
78 tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
79#else
80 tmp = message_push_string(outbuf, "eCS (OS/2)", STR_TERMINATE);
81#endif
82
83 if (tmp == -1) return -1;
84 result += tmp;
85
86 if (asprintf(&lanman, "Samba %s", samba_version_string()) != -1) {
87 tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
88 SAFE_FREE(lanman);
89 }
90 else {
91 tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
92 }
93
94 if (tmp == -1) return -1;
95 result += tmp;
96
97 tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
98
99 if (tmp == -1) return -1;
100 result += tmp;
101
102 return result;
103}
104
105/****************************************************************************
106 Send a security blob via a session setup reply.
107****************************************************************************/
108
109static void reply_sesssetup_blob(struct smb_request *req,
110 DATA_BLOB blob,
111 NTSTATUS nt_status)
112{
113 if (!NT_STATUS_IS_OK(nt_status) &&
114 !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
115 reply_nterror(req, nt_status_squash(nt_status));
116 return;
117 }
118
119 nt_status = nt_status_squash(nt_status);
120 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
121 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
122 SSVAL(req->outbuf, smb_vwv3, blob.length);
123
124 if ((message_push_blob(&req->outbuf, blob) == -1)
125 || (push_signature(&req->outbuf) == -1)) {
126 reply_nterror(req, NT_STATUS_NO_MEMORY);
127 }
128}
129
130/****************************************************************************
131 Do a 'guest' logon, getting back the
132****************************************************************************/
133
134static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
135{
136 struct auth_context *auth_context;
137 auth_usersupplied_info *user_info = NULL;
138
139 NTSTATUS nt_status;
140 unsigned char chal[8];
141
142 ZERO_STRUCT(chal);
143
144 DEBUG(3,("Got anonymous request\n"));
145
146 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context,
147 chal))) {
148 return nt_status;
149 }
150
151 if (!make_user_info_guest(&user_info)) {
152 (auth_context->free)(&auth_context);
153 return NT_STATUS_NO_MEMORY;
154 }
155
156 nt_status = auth_context->check_ntlm_password(auth_context,
157 user_info,
158 server_info);
159 (auth_context->free)(&auth_context);
160 free_user_info(&user_info);
161 return nt_status;
162}
163
164
165#ifdef HAVE_KRB5
166
167#if 0
168/* Experiment that failed. See "only happens with a KDC" comment below. */
169/****************************************************************************
170 Cerate a clock skew error blob for a Windows client.
171****************************************************************************/
172
173static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
174{
175 krb5_context context = NULL;
176 krb5_error_code kerr = 0;
177 krb5_data reply;
178 krb5_principal host_princ = NULL;
179 char *host_princ_s = NULL;
180 bool ret = False;
181
182 *pblob_out = data_blob_null;
183
184 initialize_krb5_error_table();
185 kerr = krb5_init_context(&context);
186 if (kerr) {
187 return False;
188 }
189 /* Create server principal. */
190 asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
191 if (!host_princ_s) {
192 goto out;
193 }
194 strlower_m(host_princ_s);
195
196 kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
197 if (kerr) {
198 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
199 "for name %s: Error %s\n",
200 host_princ_s, error_message(kerr) ));
201 goto out;
202 }
203
204 kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
205 host_princ, &reply);
206 if (kerr) {
207 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
208 "failed: Error %s\n",
209 error_message(kerr) ));
210 goto out;
211 }
212
213 *pblob_out = data_blob(reply.data, reply.length);
214 kerberos_free_data_contents(context,&reply);
215 ret = True;
216
217 out:
218
219 if (host_princ_s) {
220 SAFE_FREE(host_princ_s);
221 }
222 if (host_princ) {
223 krb5_free_principal(context, host_princ);
224 }
225 krb5_free_context(context);
226 return ret;
227}
228#endif
229
230/****************************************************************************
231 Reply to a session setup spnego negotiate packet for kerberos.
232****************************************************************************/
233
234static void reply_spnego_kerberos(struct smb_request *req,
235 DATA_BLOB *secblob,
236 const char *mechOID,
237 uint16 vuid,
238 bool *p_invalidate_vuid)
239{
240 TALLOC_CTX *mem_ctx;
241 DATA_BLOB ticket;
242 char *client, *p, *domain;
243 fstring netbios_domain_name;
244 struct passwd *pw;
245 fstring user;
246 int sess_vuid = req->vuid;
247 NTSTATUS ret = NT_STATUS_OK;
248 struct PAC_DATA *pac_data = NULL;
249 DATA_BLOB ap_rep, ap_rep_wrapped, response;
250 auth_serversupplied_info *server_info = NULL;
251 DATA_BLOB session_key = data_blob_null;
252 uint8 tok_id[2];
253 DATA_BLOB nullblob = data_blob_null;
254 fstring real_username;
255 bool map_domainuser_to_guest = False;
256 bool username_was_mapped;
257 struct PAC_LOGON_INFO *logon_info = NULL;
258 struct smbd_server_connection *sconn = smbd_server_conn;
259
260 ZERO_STRUCT(ticket);
261 ZERO_STRUCT(ap_rep);
262 ZERO_STRUCT(ap_rep_wrapped);
263 ZERO_STRUCT(response);
264
265 /* Normally we will always invalidate the intermediate vuid. */
266 *p_invalidate_vuid = True;
267
268 mem_ctx = talloc_init("reply_spnego_kerberos");
269 if (mem_ctx == NULL) {
270 reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
271 return;
272 }
273
274 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
275 talloc_destroy(mem_ctx);
276 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
277 return;
278 }
279
280 ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
281 &client, &pac_data, &ap_rep,
282 &session_key, True);
283
284 data_blob_free(&ticket);
285
286 if (!NT_STATUS_IS_OK(ret)) {
287#if 0
288 /* Experiment that failed.
289 * See "only happens with a KDC" comment below. */
290
291 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
292
293 /*
294 * Windows in this case returns
295 * NT_STATUS_MORE_PROCESSING_REQUIRED
296 * with a negTokenTarg blob containing an krb5_error
297 * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
298 * The client then fixes its clock and continues rather
299 * than giving an error. JRA.
300 * -- Looks like this only happens with a KDC. JRA.
301 */
302
303 bool ok = make_krb5_skew_error(&ap_rep);
304 if (!ok) {
305 talloc_destroy(mem_ctx);
306 return ERROR_NT(nt_status_squash(
307 NT_STATUS_LOGON_FAILURE));
308 }
309 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
310 TOK_ID_KRB_ERROR);
311 response = spnego_gen_auth_response(&ap_rep_wrapped,
312 ret, OID_KERBEROS5_OLD);
313 reply_sesssetup_blob(conn, inbuf, outbuf, response,
314 NT_STATUS_MORE_PROCESSING_REQUIRED);
315
316 /*
317 * In this one case we don't invalidate the
318 * intermediate vuid as we're expecting the client
319 * to re-use it for the next sessionsetupX packet. JRA.
320 */
321
322 *p_invalidate_vuid = False;
323
324 data_blob_free(&ap_rep);
325 data_blob_free(&ap_rep_wrapped);
326 data_blob_free(&response);
327 talloc_destroy(mem_ctx);
328 return -1; /* already replied */
329 }
330#else
331 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
332 ret = NT_STATUS_LOGON_FAILURE;
333 }
334#endif
335 DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
336 nt_errstr(ret)));
337 talloc_destroy(mem_ctx);
338 reply_nterror(req, nt_status_squash(ret));
339 return;
340 }
341
342 DEBUG(3,("Ticket name is [%s]\n", client));
343
344 p = strchr_m(client, '@');
345 if (!p) {
346 DEBUG(3,("Doesn't look like a valid principal\n"));
347 data_blob_free(&ap_rep);
348 data_blob_free(&session_key);
349 talloc_destroy(mem_ctx);
350 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
351 return;
352 }
353
354 *p = 0;
355
356 /* save the PAC data if we have it */
357
358 if (pac_data) {
359 logon_info = get_logon_info_from_pac(pac_data);
360 if (logon_info) {
361 netsamlogon_cache_store( client, &logon_info->info3 );
362 }
363 }
364
365 if (!strequal(p+1, lp_realm())) {
366 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
367 if (!lp_allow_trusted_domains()) {
368 data_blob_free(&ap_rep);
369 data_blob_free(&session_key);
370 talloc_destroy(mem_ctx);
371 reply_nterror(req, nt_status_squash(
372 NT_STATUS_LOGON_FAILURE));
373 return;
374 }
375 }
376
377 /* this gives a fully qualified user name (ie. with full realm).
378 that leads to very long usernames, but what else can we do? */
379
380 domain = p+1;
381
382 if (logon_info && logon_info->info3.base.domain.string) {
383 fstrcpy(netbios_domain_name,
384 logon_info->info3.base.domain.string);
385 domain = netbios_domain_name;
386 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
387
388 } else {
389
390 /* If we have winbind running, we can (and must) shorten the
391 username by using the short netbios name. Otherwise we will
392 have inconsistent user names. With Kerberos, we get the
393 fully qualified realm, with ntlmssp we get the short
394 name. And even w2k3 does use ntlmssp if you for example
395 connect to an ip address. */
396
397 wbcErr wbc_status;
398 struct wbcDomainInfo *info = NULL;
399
400 DEBUG(10, ("Mapping [%s] to short name\n", domain));
401
402 wbc_status = wbcDomainInfo(domain, &info);
403
404 if (WBC_ERROR_IS_OK(wbc_status)) {
405
406 fstrcpy(netbios_domain_name,
407 info->short_name);
408
409 wbcFreeMemory(info);
410 domain = netbios_domain_name;
411 DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
412 } else {
413 DEBUG(3, ("Could not find short name: %s\n",
414 wbcErrorString(wbc_status)));
415 }
416 }
417
418 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
419
420 /* lookup the passwd struct, create a new user if necessary */
421
422 username_was_mapped = map_username(sconn, user);
423
424 pw = smb_getpwnam( mem_ctx, user, real_username, True );
425
426 if (pw) {
427 /* if a real user check pam account restrictions */
428 /* only really perfomed if "obey pam restriction" is true */
429 /* do this before an eventual mapping to guest occurs */
430 ret = smb_pam_accountcheck(pw->pw_name);
431 if ( !NT_STATUS_IS_OK(ret)) {
432 DEBUG(1,("PAM account restriction "
433 "prevents user login\n"));
434 data_blob_free(&ap_rep);
435 data_blob_free(&session_key);
436 TALLOC_FREE(mem_ctx);
437 reply_nterror(req, nt_status_squash(ret));
438 return;
439 }
440 }
441
442 if (!pw) {
443
444 /* this was originally the behavior of Samba 2.2, if a user
445 did not have a local uid but has been authenticated, then
446 map them to a guest account */
447
448 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
449 map_domainuser_to_guest = True;
450 fstrcpy(user,lp_guestaccount());
451 pw = smb_getpwnam( mem_ctx, user, real_username, True );
452 }
453
454 /* extra sanity check that the guest account is valid */
455
456 if ( !pw ) {
457 DEBUG(1,("Username %s is invalid on this system\n",
458 user));
459 data_blob_free(&ap_rep);
460 data_blob_free(&session_key);
461 TALLOC_FREE(mem_ctx);
462 reply_nterror(req, nt_status_squash(
463 NT_STATUS_LOGON_FAILURE));
464 return;
465 }
466 }
467
468 /* setup the string used by %U */
469
470 sub_set_smb_name( real_username );
471 reload_services(True);
472
473 if ( map_domainuser_to_guest ) {
474 make_server_info_guest(NULL, &server_info);
475 } else if (logon_info) {
476 /* pass the unmapped username here since map_username()
477 will be called again from inside make_server_info_info3() */
478
479 ret = make_server_info_info3(mem_ctx, client, domain,
480 &server_info, &logon_info->info3);
481 if ( !NT_STATUS_IS_OK(ret) ) {
482 DEBUG(1,("make_server_info_info3 failed: %s!\n",
483 nt_errstr(ret)));
484 data_blob_free(&ap_rep);
485 data_blob_free(&session_key);
486 TALLOC_FREE(mem_ctx);
487 reply_nterror(req, nt_status_squash(ret));
488 return;
489 }
490
491 } else {
492 /*
493 * We didn't get a PAC, we have to make up the user
494 * ourselves. Try to ask the pdb backend to provide
495 * SID consistency with ntlmssp session setup
496 */
497 struct samu *sampass;
498
499 sampass = samu_new(talloc_tos());
500 if (sampass == NULL) {
501 ret = NT_STATUS_NO_MEMORY;
502 data_blob_free(&ap_rep);
503 data_blob_free(&session_key);
504 TALLOC_FREE(mem_ctx);
505 reply_nterror(req, nt_status_squash(ret));
506 return;
507 }
508
509 if (pdb_getsampwnam(sampass, real_username)) {
510 DEBUG(10, ("found user %s in passdb, calling "
511 "make_server_info_sam\n", real_username));
512 ret = make_server_info_sam(&server_info, sampass);
513 } else {
514 /*
515 * User not in passdb, make it up artificially
516 */
517 TALLOC_FREE(sampass);
518 DEBUG(10, ("didn't find user %s in passdb, calling "
519 "make_server_info_pw\n", real_username));
520 ret = make_server_info_pw(&server_info, real_username,
521 pw);
522 }
523
524 if ( !NT_STATUS_IS_OK(ret) ) {
525 DEBUG(1,("make_server_info_[sam|pw] failed: %s!\n",
526 nt_errstr(ret)));
527 data_blob_free(&ap_rep);
528 data_blob_free(&session_key);
529 TALLOC_FREE(mem_ctx);
530 reply_nterror(req, nt_status_squash(ret));
531 return;
532 }
533
534 /* make_server_info_pw does not set the domain. Without this
535 * we end up with the local netbios name in substitutions for
536 * %D. */
537
538 if (server_info->sam_account != NULL) {
539 pdb_set_domain(server_info->sam_account,
540 domain, PDB_SET);
541 }
542 }
543
544 server_info->nss_token |= username_was_mapped;
545
546 /* we need to build the token for the user. make_server_info_guest()
547 already does this */
548
549 if ( !server_info->ptok ) {
550 ret = create_local_token( server_info );
551 if ( !NT_STATUS_IS_OK(ret) ) {
552 DEBUG(10,("failed to create local token: %s\n",
553 nt_errstr(ret)));
554 data_blob_free(&ap_rep);
555 data_blob_free(&session_key);
556 TALLOC_FREE( mem_ctx );
557 TALLOC_FREE( server_info );
558 reply_nterror(req, nt_status_squash(ret));
559 return;
560 }
561 }
562
563 if (!is_partial_auth_vuid(sconn, sess_vuid)) {
564 sess_vuid = register_initial_vuid(sconn);
565 }
566
567 data_blob_free(&server_info->user_session_key);
568 server_info->user_session_key = session_key;
569 session_key = data_blob_null;
570
571 /* register_existing_vuid keeps the server info */
572 /* register_existing_vuid takes ownership of session_key on success,
573 * no need to free after this on success. A better interface would copy
574 * it.... */
575
576 sess_vuid = register_existing_vuid(sconn,
577 sess_vuid,
578 server_info,
579 nullblob,
580 client);
581
582 reply_outbuf(req, 4, 0);
583 SSVAL(req->outbuf,smb_uid,sess_vuid);
584
585 if (sess_vuid == UID_FIELD_INVALID ) {
586 ret = NT_STATUS_LOGON_FAILURE;
587 } else {
588 /* current_user_info is changed on new vuid */
589 reload_services( True );
590
591 SSVAL(req->outbuf, smb_vwv3, 0);
592
593 if (server_info->guest) {
594 SSVAL(req->outbuf,smb_vwv2,1);
595 }
596
597 SSVAL(req->outbuf, smb_uid, sess_vuid);
598
599 /* Successful logon. Keep this vuid. */
600 *p_invalidate_vuid = False;
601 }
602
603 /* wrap that up in a nice GSS-API wrapping */
604 if (NT_STATUS_IS_OK(ret)) {
605 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
606 TOK_ID_KRB_AP_REP);
607 } else {
608 ap_rep_wrapped = data_blob_null;
609 }
610 response = spnego_gen_auth_response(&ap_rep_wrapped, ret,
611 mechOID);
612 reply_sesssetup_blob(req, response, ret);
613
614 data_blob_free(&ap_rep);
615 data_blob_free(&ap_rep_wrapped);
616 data_blob_free(&response);
617 TALLOC_FREE(mem_ctx);
618}
619
620#endif
621
622/****************************************************************************
623 Send a session setup reply, wrapped in SPNEGO.
624 Get vuid and check first.
625 End the NTLMSSP exchange context if we are OK/complete fail
626 This should be split into two functions, one to handle each
627 leg of the NTLM auth steps.
628***************************************************************************/
629
630static void reply_spnego_ntlmssp(struct smb_request *req,
631 uint16 vuid,
632 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
633 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
634 const char *OID,
635 bool wrap)
636{
637 DATA_BLOB response;
638 struct auth_serversupplied_info *server_info = NULL;
639 struct smbd_server_connection *sconn = smbd_server_conn;
640
641 if (NT_STATUS_IS_OK(nt_status)) {
642 server_info = (*auth_ntlmssp_state)->server_info;
643 } else {
644 nt_status = do_map_to_guest(nt_status,
645 &server_info,
646 (*auth_ntlmssp_state)->ntlmssp_state->user,
647 (*auth_ntlmssp_state)->ntlmssp_state->domain);
648 }
649
650 reply_outbuf(req, 4, 0);
651
652 SSVAL(req->outbuf, smb_uid, vuid);
653
654 if (NT_STATUS_IS_OK(nt_status)) {
655 DATA_BLOB nullblob = data_blob_null;
656
657 if (!is_partial_auth_vuid(sconn, vuid)) {
658 nt_status = NT_STATUS_LOGON_FAILURE;
659 goto out;
660 }
661
662 data_blob_free(&server_info->user_session_key);
663 server_info->user_session_key =
664 data_blob_talloc(
665 server_info,
666 (*auth_ntlmssp_state)->ntlmssp_state->session_key.data,
667 (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
668
669 /* register_existing_vuid keeps the server info */
670 if (register_existing_vuid(sconn, vuid,
671 server_info, nullblob,
672 (*auth_ntlmssp_state)->ntlmssp_state->user) !=
673 vuid) {
674 nt_status = NT_STATUS_LOGON_FAILURE;
675 goto out;
676 }
677
678 (*auth_ntlmssp_state)->server_info = NULL;
679
680 /* current_user_info is changed on new vuid */
681 reload_services( True );
682
683 SSVAL(req->outbuf, smb_vwv3, 0);
684
685 if (server_info->guest) {
686 SSVAL(req->outbuf,smb_vwv2,1);
687 }
688 }
689
690 out:
691
692 if (wrap) {
693 response = spnego_gen_auth_response(ntlmssp_blob,
694 nt_status, OID);
695 } else {
696 response = *ntlmssp_blob;
697 }
698
699 reply_sesssetup_blob(req, response, nt_status);
700 if (wrap) {
701 data_blob_free(&response);
702 }
703
704 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
705 and the other end, that we are not finished yet. */
706
707 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
708 /* NB. This is *NOT* an error case. JRA */
709 auth_ntlmssp_end(auth_ntlmssp_state);
710 if (!NT_STATUS_IS_OK(nt_status)) {
711 /* Kill the intermediate vuid */
712 invalidate_vuid(sconn, vuid);
713 }
714 }
715}
716
717/****************************************************************************
718 Is this a krb5 mechanism ?
719****************************************************************************/
720
721NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in,
722 DATA_BLOB *pblob_out,
723 char **kerb_mechOID)
724{
725 char *OIDs[ASN1_MAX_OIDS];
726 int i;
727 NTSTATUS ret = NT_STATUS_OK;
728
729 *kerb_mechOID = NULL;
730
731 /* parse out the OIDs and the first sec blob */
732 if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
733 return NT_STATUS_LOGON_FAILURE;
734 }
735
736 /* only look at the first OID for determining the mechToken --
737 according to RFC2478, we should choose the one we want
738 and renegotiate, but i smell a client bug here..
739
740 Problem observed when connecting to a member (samba box)
741 of an AD domain as a user in a Samba domain. Samba member
742 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
743 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
744 NTLMSSP mechtoken. --jerry */
745
746#ifdef HAVE_KRB5
747 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
748 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
749 *kerb_mechOID = SMB_STRDUP(OIDs[0]);
750 if (*kerb_mechOID == NULL) {
751 ret = NT_STATUS_NO_MEMORY;
752 }
753 }
754#endif
755
756 for (i=0;OIDs[i];i++) {
757 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
758 talloc_free(OIDs[i]);
759 }
760 return ret;
761}
762
763/****************************************************************************
764 Fall back from krb5 to NTLMSSP.
765****************************************************************************/
766
767static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
768 uint16 vuid)
769{
770 DATA_BLOB response;
771
772 reply_outbuf(req, 4, 0);
773 SSVAL(req->outbuf,smb_uid,vuid);
774
775 DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
776 "but set to downgrade to NTLMSSP\n"));
777
778 response = spnego_gen_auth_response(NULL,
779 NT_STATUS_MORE_PROCESSING_REQUIRED,
780 OID_NTLMSSP);
781 reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
782 data_blob_free(&response);
783}
784
785/****************************************************************************
786 Reply to a session setup spnego negotiate packet.
787****************************************************************************/
788
789static void reply_spnego_negotiate(struct smb_request *req,
790 uint16 vuid,
791 DATA_BLOB blob1,
792 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
793{
794 DATA_BLOB secblob;
795 DATA_BLOB chal;
796 char *kerb_mech = NULL;
797 NTSTATUS status;
798 struct smbd_server_connection *sconn = smbd_server_conn;
799
800 status = parse_spnego_mechanisms(blob1, &secblob, &kerb_mech);
801 if (!NT_STATUS_IS_OK(status)) {
802 /* Kill the intermediate vuid */
803 invalidate_vuid(sconn, vuid);
804 reply_nterror(req, nt_status_squash(status));
805 return;
806 }
807
808 DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
809 (unsigned long)secblob.length));
810
811#ifdef HAVE_KRB5
812 if (kerb_mech && ((lp_security()==SEC_ADS) ||
813 USE_KERBEROS_KEYTAB) ) {
814 bool destroy_vuid = True;
815 reply_spnego_kerberos(req, &secblob, kerb_mech,
816 vuid, &destroy_vuid);
817 data_blob_free(&secblob);
818 if (destroy_vuid) {
819 /* Kill the intermediate vuid */
820 invalidate_vuid(sconn, vuid);
821 }
822 SAFE_FREE(kerb_mech);
823 return;
824 }
825#endif
826
827 if (*auth_ntlmssp_state) {
828 auth_ntlmssp_end(auth_ntlmssp_state);
829 }
830
831 if (kerb_mech) {
832 data_blob_free(&secblob);
833 /* The mechtoken is a krb5 ticket, but
834 * we need to fall back to NTLM. */
835 reply_spnego_downgrade_to_ntlmssp(req, vuid);
836 SAFE_FREE(kerb_mech);
837 return;
838 }
839
840 status = auth_ntlmssp_start(auth_ntlmssp_state);
841 if (!NT_STATUS_IS_OK(status)) {
842 /* Kill the intermediate vuid */
843 invalidate_vuid(sconn, vuid);
844 reply_nterror(req, nt_status_squash(status));
845 return;
846 }
847
848 status = auth_ntlmssp_update(*auth_ntlmssp_state,
849 secblob, &chal);
850
851 data_blob_free(&secblob);
852
853 reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
854 &chal, status, OID_NTLMSSP, true);
855
856 data_blob_free(&chal);
857
858 /* already replied */
859 return;
860}
861
862/****************************************************************************
863 Reply to a session setup spnego auth packet.
864****************************************************************************/
865
866static void reply_spnego_auth(struct smb_request *req,
867 uint16 vuid,
868 DATA_BLOB blob1,
869 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
870{
871 DATA_BLOB auth = data_blob_null;
872 DATA_BLOB auth_reply = data_blob_null;
873 DATA_BLOB secblob = data_blob_null;
874 NTSTATUS status = NT_STATUS_LOGON_FAILURE;
875 struct smbd_server_connection *sconn = smbd_server_conn;
876
877 if (!spnego_parse_auth(blob1, &auth)) {
878#if 0
879 file_save("auth.dat", blob1.data, blob1.length);
880#endif
881 /* Kill the intermediate vuid */
882 invalidate_vuid(sconn, vuid);
883
884 reply_nterror(req, nt_status_squash(
885 NT_STATUS_LOGON_FAILURE));
886 return;
887 }
888
889 if (auth.data[0] == ASN1_APPLICATION(0)) {
890 /* Might be a second negTokenTarg packet */
891 char *kerb_mech = NULL;
892
893 status = parse_spnego_mechanisms(auth, &secblob, &kerb_mech);
894
895 if (!NT_STATUS_IS_OK(status)) {
896 /* Kill the intermediate vuid */
897 invalidate_vuid(sconn, vuid);
898 reply_nterror(req, nt_status_squash(status));
899 return;
900 }
901
902 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
903 (unsigned long)secblob.length));
904#ifdef HAVE_KRB5
905 if (kerb_mech && ((lp_security()==SEC_ADS) ||
906 USE_KERBEROS_KEYTAB)) {
907 bool destroy_vuid = True;
908 reply_spnego_kerberos(req, &secblob, kerb_mech,
909 vuid, &destroy_vuid);
910 data_blob_free(&secblob);
911 data_blob_free(&auth);
912 if (destroy_vuid) {
913 /* Kill the intermediate vuid */
914 invalidate_vuid(sconn, vuid);
915 }
916 SAFE_FREE(kerb_mech);
917 return;
918 }
919#endif
920 /* Can't blunder into NTLMSSP auth if we have
921 * a krb5 ticket. */
922
923 if (kerb_mech) {
924 /* Kill the intermediate vuid */
925 invalidate_vuid(sconn, vuid);
926 DEBUG(3,("reply_spnego_auth: network "
927 "misconfiguration, client sent us a "
928 "krb5 ticket and kerberos security "
929 "not enabled\n"));
930 reply_nterror(req, nt_status_squash(
931 NT_STATUS_LOGON_FAILURE));
932 SAFE_FREE(kerb_mech);
933 }
934 }
935
936 /* If we get here it wasn't a negTokenTarg auth packet. */
937 data_blob_free(&secblob);
938
939 if (!*auth_ntlmssp_state) {
940 status = auth_ntlmssp_start(auth_ntlmssp_state);
941 if (!NT_STATUS_IS_OK(status)) {
942 /* Kill the intermediate vuid */
943 invalidate_vuid(sconn, vuid);
944 reply_nterror(req, nt_status_squash(status));
945 return;
946 }
947 }
948
949 status = auth_ntlmssp_update(*auth_ntlmssp_state,
950 auth, &auth_reply);
951
952 data_blob_free(&auth);
953
954 /* Don't send the mechid as we've already sent this (RFC4178). */
955
956 reply_spnego_ntlmssp(req, vuid,
957 auth_ntlmssp_state,
958 &auth_reply, status, NULL, true);
959
960 data_blob_free(&auth_reply);
961
962 /* and tell smbd that we have already replied to this packet */
963 return;
964}
965
966/****************************************************************************
967 Delete an entry on the list.
968****************************************************************************/
969
970static void delete_partial_auth(struct smbd_server_connection *sconn,
971 struct pending_auth_data *pad)
972{
973 if (!pad) {
974 return;
975 }
976 DLIST_REMOVE(sconn->smb1.pd_list, pad);
977 data_blob_free(&pad->partial_data);
978 SAFE_FREE(pad);
979}
980
981/****************************************************************************
982 Search for a partial SPNEGO auth fragment matching an smbpid.
983****************************************************************************/
984
985static struct pending_auth_data *get_pending_auth_data(
986 struct smbd_server_connection *sconn,
987 uint16_t smbpid)
988{
989 struct pending_auth_data *pad;
990/*
991 * NOTE: using the smbpid here is completely wrong...
992 * see [MS-SMB]
993 * 3.3.5.3 Receiving an SMB_COM_SESSION_SETUP_ANDX Request
994 */
995 for (pad = sconn->smb1.pd_list; pad; pad = pad->next) {
996 if (pad->smbpid == smbpid) {
997 break;
998 }
999 }
1000 return pad;
1001}
1002
1003/****************************************************************************
1004 Check the size of an SPNEGO blob. If we need more return
1005 NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
1006 the blob to be more than 64k.
1007****************************************************************************/
1008
1009static NTSTATUS check_spnego_blob_complete(struct smbd_server_connection *sconn,
1010 uint16 smbpid, uint16 vuid,
1011 DATA_BLOB *pblob)
1012{
1013 struct pending_auth_data *pad = NULL;
1014 ASN1_DATA *data;
1015 size_t needed_len = 0;
1016
1017 pad = get_pending_auth_data(sconn, smbpid);
1018
1019 /* Ensure we have some data. */
1020 if (pblob->length == 0) {
1021 /* Caller can cope. */
1022 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
1023 delete_partial_auth(sconn, pad);
1024 return NT_STATUS_OK;
1025 }
1026
1027 /* Were we waiting for more data ? */
1028 if (pad) {
1029 DATA_BLOB tmp_blob;
1030 size_t copy_len = MIN(65536, pblob->length);
1031
1032 /* Integer wrap paranoia.... */
1033
1034 if (pad->partial_data.length + copy_len <
1035 pad->partial_data.length ||
1036 pad->partial_data.length + copy_len < copy_len) {
1037
1038 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1039 "pad->partial_data.length = %u, "
1040 "copy_len = %u\n",
1041 (unsigned int)pad->partial_data.length,
1042 (unsigned int)copy_len ));
1043
1044 delete_partial_auth(sconn, pad);
1045 return NT_STATUS_INVALID_PARAMETER;
1046 }
1047
1048 DEBUG(10,("check_spnego_blob_complete: "
1049 "pad->partial_data.length = %u, "
1050 "pad->needed_len = %u, "
1051 "copy_len = %u, "
1052 "pblob->length = %u,\n",
1053 (unsigned int)pad->partial_data.length,
1054 (unsigned int)pad->needed_len,
1055 (unsigned int)copy_len,
1056 (unsigned int)pblob->length ));
1057
1058 tmp_blob = data_blob(NULL,
1059 pad->partial_data.length + copy_len);
1060
1061 /* Concatenate the two (up to copy_len) bytes. */
1062 memcpy(tmp_blob.data,
1063 pad->partial_data.data,
1064 pad->partial_data.length);
1065 memcpy(tmp_blob.data + pad->partial_data.length,
1066 pblob->data,
1067 copy_len);
1068
1069 /* Replace the partial data. */
1070 data_blob_free(&pad->partial_data);
1071 pad->partial_data = tmp_blob;
1072 ZERO_STRUCT(tmp_blob);
1073
1074 /* Are we done ? */
1075 if (pblob->length >= pad->needed_len) {
1076 /* Yes, replace pblob. */
1077 data_blob_free(pblob);
1078 *pblob = pad->partial_data;
1079 ZERO_STRUCT(pad->partial_data);
1080 delete_partial_auth(sconn, pad);
1081 return NT_STATUS_OK;
1082 }
1083
1084 /* Still need more data. */
1085 pad->needed_len -= copy_len;
1086 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1087 }
1088
1089 if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
1090 (pblob->data[0] != ASN1_CONTEXT(1))) {
1091 /* Not something we can determine the
1092 * length of.
1093 */
1094 return NT_STATUS_OK;
1095 }
1096
1097 /* This is a new SPNEGO sessionsetup - see if
1098 * the data given in this blob is enough.
1099 */
1100
1101 data = asn1_init(NULL);
1102 if (data == NULL) {
1103 return NT_STATUS_NO_MEMORY;
1104 }
1105
1106 asn1_load(data, *pblob);
1107 asn1_start_tag(data, pblob->data[0]);
1108 if (data->has_error || data->nesting == NULL) {
1109 asn1_free(data);
1110 /* Let caller catch. */
1111 return NT_STATUS_OK;
1112 }
1113
1114 /* Integer wrap paranoia.... */
1115
1116 if (data->nesting->taglen + data->nesting->start < data->nesting->taglen ||
1117 data->nesting->taglen + data->nesting->start < data->nesting->start) {
1118
1119 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1120 "data.nesting->taglen = %u, "
1121 "data.nesting->start = %u\n",
1122 (unsigned int)data->nesting->taglen,
1123 (unsigned int)data->nesting->start ));
1124
1125 asn1_free(data);
1126 return NT_STATUS_INVALID_PARAMETER;
1127 }
1128
1129 /* Total length of the needed asn1 is the tag length
1130 * plus the current offset. */
1131
1132 needed_len = data->nesting->taglen + data->nesting->start;
1133 asn1_free(data);
1134
1135 DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
1136 "pblob->length = %u\n",
1137 (unsigned int)needed_len,
1138 (unsigned int)pblob->length ));
1139
1140 if (needed_len <= pblob->length) {
1141 /* Nothing to do - blob is complete. */
1142 return NT_STATUS_OK;
1143 }
1144
1145 /* Refuse the blob if it's bigger than 64k. */
1146 if (needed_len > 65536) {
1147 DEBUG(2,("check_spnego_blob_complete: needed_len "
1148 "too large (%u)\n",
1149 (unsigned int)needed_len ));
1150 return NT_STATUS_INVALID_PARAMETER;
1151 }
1152
1153 /* We must store this blob until complete. */
1154 if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
1155 return NT_STATUS_NO_MEMORY;
1156 }
1157 pad->needed_len = needed_len - pblob->length;
1158 pad->partial_data = data_blob(pblob->data, pblob->length);
1159 if (pad->partial_data.data == NULL) {
1160 SAFE_FREE(pad);
1161 return NT_STATUS_NO_MEMORY;
1162 }
1163 pad->smbpid = smbpid;
1164 pad->vuid = vuid;
1165 DLIST_ADD(sconn->smb1.pd_list, pad);
1166
1167 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1168}
1169
1170/****************************************************************************
1171 Reply to a session setup command.
1172 conn POINTER CAN BE NULL HERE !
1173****************************************************************************/
1174
1175static void reply_sesssetup_and_X_spnego(struct smb_request *req)
1176{
1177 const uint8 *p;
1178 DATA_BLOB blob1;
1179 size_t bufrem;
1180 char *tmp;
1181 const char *native_os;
1182 const char *native_lanman;
1183 const char *primary_domain;
1184 const char *p2;
1185 uint16 data_blob_len = SVAL(req->vwv+7, 0);
1186 enum remote_arch_types ra_type = get_remote_arch();
1187 int vuid = req->vuid;
1188 user_struct *vuser = NULL;
1189 NTSTATUS status = NT_STATUS_OK;
1190 uint16 smbpid = req->smbpid;
1191 struct smbd_server_connection *sconn = smbd_server_conn;
1192
1193 DEBUG(3,("Doing spnego session setup\n"));
1194
1195 if (global_client_caps == 0) {
1196 global_client_caps = IVAL(req->vwv+10, 0);
1197
1198 if (!(global_client_caps & CAP_STATUS32)) {
1199 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1200 }
1201
1202 }
1203
1204 p = req->buf;
1205
1206 if (data_blob_len == 0) {
1207 /* an invalid request */
1208 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1209 return;
1210 }
1211
1212 bufrem = smbreq_bufrem(req, p);
1213 /* pull the spnego blob */
1214 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1215
1216#if 0
1217 file_save("negotiate.dat", blob1.data, blob1.length);
1218#endif
1219
1220 p2 = (char *)req->buf + blob1.length;
1221
1222 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1223 STR_TERMINATE);
1224 native_os = tmp ? tmp : "";
1225
1226 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1227 STR_TERMINATE);
1228 native_lanman = tmp ? tmp : "";
1229
1230 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1231 STR_TERMINATE);
1232 primary_domain = tmp ? tmp : "";
1233
1234 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1235 native_os, native_lanman, primary_domain));
1236
1237 if ( ra_type == RA_WIN2K ) {
1238 /* Vista sets neither the OS or lanman strings */
1239
1240 if ( !strlen(native_os) && !strlen(native_lanman) )
1241 set_remote_arch(RA_VISTA);
1242
1243 /* Windows 2003 doesn't set the native lanman string,
1244 but does set primary domain which is a bug I think */
1245
1246 if ( !strlen(native_lanman) ) {
1247 ra_lanman_string( primary_domain );
1248 } else {
1249 ra_lanman_string( native_lanman );
1250 }
1251 }
1252
1253 /* Did we get a valid vuid ? */
1254 if (!is_partial_auth_vuid(sconn, vuid)) {
1255 /* No, then try and see if this is an intermediate sessionsetup
1256 * for a large SPNEGO packet. */
1257 struct pending_auth_data *pad;
1258 pad = get_pending_auth_data(sconn, smbpid);
1259 if (pad) {
1260 DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1261 "pending vuid %u\n",
1262 (unsigned int)pad->vuid ));
1263 vuid = pad->vuid;
1264 }
1265 }
1266
1267 /* Do we have a valid vuid now ? */
1268 if (!is_partial_auth_vuid(sconn, vuid)) {
1269 /* No, start a new authentication setup. */
1270 vuid = register_initial_vuid(sconn);
1271 if (vuid == UID_FIELD_INVALID) {
1272 data_blob_free(&blob1);
1273 reply_nterror(req, nt_status_squash(
1274 NT_STATUS_INVALID_PARAMETER));
1275 return;
1276 }
1277 }
1278
1279 vuser = get_partial_auth_user_struct(sconn, vuid);
1280 /* This MUST be valid. */
1281 if (!vuser) {
1282 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1283 }
1284
1285 /* Large (greater than 4k) SPNEGO blobs are split into multiple
1286 * sessionsetup requests as the Windows limit on the security blob
1287 * field is 4k. Bug #4400. JRA.
1288 */
1289
1290 status = check_spnego_blob_complete(sconn, smbpid, vuid, &blob1);
1291 if (!NT_STATUS_IS_OK(status)) {
1292 if (!NT_STATUS_EQUAL(status,
1293 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1294 /* Real error - kill the intermediate vuid */
1295 invalidate_vuid(sconn, vuid);
1296 }
1297 data_blob_free(&blob1);
1298 reply_nterror(req, nt_status_squash(status));
1299 return;
1300 }
1301
1302 if (blob1.data[0] == ASN1_APPLICATION(0)) {
1303
1304 /* its a negTokenTarg packet */
1305
1306 reply_spnego_negotiate(req, vuid, blob1,
1307 &vuser->auth_ntlmssp_state);
1308 data_blob_free(&blob1);
1309 return;
1310 }
1311
1312 if (blob1.data[0] == ASN1_CONTEXT(1)) {
1313
1314 /* its a auth packet */
1315
1316 reply_spnego_auth(req, vuid, blob1,
1317 &vuser->auth_ntlmssp_state);
1318 data_blob_free(&blob1);
1319 return;
1320 }
1321
1322 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1323 DATA_BLOB chal;
1324
1325 if (!vuser->auth_ntlmssp_state) {
1326 status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1327 if (!NT_STATUS_IS_OK(status)) {
1328 /* Kill the intermediate vuid */
1329 invalidate_vuid(sconn, vuid);
1330 data_blob_free(&blob1);
1331 reply_nterror(req, nt_status_squash(status));
1332 return;
1333 }
1334 }
1335
1336 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1337 blob1, &chal);
1338
1339 data_blob_free(&blob1);
1340
1341 reply_spnego_ntlmssp(req, vuid,
1342 &vuser->auth_ntlmssp_state,
1343 &chal, status, OID_NTLMSSP, false);
1344 data_blob_free(&chal);
1345 return;
1346 }
1347
1348 /* what sort of packet is this? */
1349 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1350
1351 data_blob_free(&blob1);
1352
1353 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1354}
1355
1356/****************************************************************************
1357 On new VC == 0, shutdown *all* old connections and users.
1358 It seems that only NT4.x does this. At W2K and above (XP etc.).
1359 a new session setup with VC==0 is ignored.
1360****************************************************************************/
1361
1362static int shutdown_other_smbds(struct db_record *rec,
1363 const struct connections_key *key,
1364 const struct connections_data *crec,
1365 void *private_data)
1366{
1367 const char *ip = (const char *)private_data;
1368
1369 if (!process_exists(crec->pid)) {
1370 return 0;
1371 }
1372
1373 if (procid_is_me(&crec->pid)) {
1374 return 0;
1375 }
1376
1377 if (strcmp(ip, crec->addr) != 0) {
1378 return 0;
1379 }
1380
1381 DEBUG(0,("shutdown_other_smbds: shutting down pid %u "
1382 "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid), ip));
1383
1384 messaging_send(smbd_messaging_context(), crec->pid, MSG_SHUTDOWN,
1385 &data_blob_null);
1386 return 0;
1387}
1388
1389static void setup_new_vc_session(void)
1390{
1391 char addr[INET6_ADDRSTRLEN];
1392
1393 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1394 "compatible we would close all old resources.\n"));
1395#if 0
1396 conn_close_all();
1397 invalidate_all_vuids();
1398#endif
1399 if (lp_reset_on_zero_vc()) {
1400 connections_forall(shutdown_other_smbds,
1401 CONST_DISCARD(void *,
1402 client_addr(get_client_fd(),addr,sizeof(addr))));
1403 }
1404}
1405
1406/****************************************************************************
1407 Reply to a session setup command.
1408****************************************************************************/
1409
1410void reply_sesssetup_and_X(struct smb_request *req)
1411{
1412 int sess_vuid;
1413 int smb_bufsize;
1414 DATA_BLOB lm_resp;
1415 DATA_BLOB nt_resp;
1416 DATA_BLOB plaintext_password;
1417 char *tmp;
1418 const char *user;
1419 fstring sub_user; /* Sainitised username for substituion */
1420 const char *domain;
1421 const char *native_os;
1422 const char *native_lanman;
1423 const char *primary_domain;
1424 auth_usersupplied_info *user_info = NULL;
1425 auth_serversupplied_info *server_info = NULL;
1426 uint16 smb_flag2 = req->flags2;
1427
1428 NTSTATUS nt_status;
1429 struct smbd_server_connection *sconn = smbd_server_conn;
1430
1431 bool doencrypt = sconn->smb1.negprot.encrypted_passwords;
1432
1433 START_PROFILE(SMBsesssetupX);
1434
1435 ZERO_STRUCT(lm_resp);
1436 ZERO_STRUCT(nt_resp);
1437 ZERO_STRUCT(plaintext_password);
1438
1439 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1440
1441 /* a SPNEGO session setup has 12 command words, whereas a normal
1442 NT1 session setup has 13. See the cifs spec. */
1443 if (req->wct == 12 &&
1444 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1445
1446 if (!sconn->smb1.negprot.spnego) {
1447 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1448 "at SPNEGO session setup when it was not "
1449 "negotiated.\n"));
1450 reply_nterror(req, nt_status_squash(
1451 NT_STATUS_LOGON_FAILURE));
1452 END_PROFILE(SMBsesssetupX);
1453 return;
1454 }
1455
1456 if (SVAL(req->vwv+4, 0) == 0) {
1457 setup_new_vc_session();
1458 }
1459
1460 reply_sesssetup_and_X_spnego(req);
1461 END_PROFILE(SMBsesssetupX);
1462 return;
1463 }
1464
1465 smb_bufsize = SVAL(req->vwv+2, 0);
1466
1467 if (get_Protocol() < PROTOCOL_NT1) {
1468 uint16 passlen1 = SVAL(req->vwv+7, 0);
1469
1470 /* Never do NT status codes with protocols before NT1 as we
1471 * don't get client caps. */
1472 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1473
1474 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
1475 reply_nterror(req, nt_status_squash(
1476 NT_STATUS_INVALID_PARAMETER));
1477 END_PROFILE(SMBsesssetupX);
1478 return;
1479 }
1480
1481 if (doencrypt) {
1482 lm_resp = data_blob(req->buf, passlen1);
1483 } else {
1484 plaintext_password = data_blob(req->buf, passlen1+1);
1485 /* Ensure null termination */
1486 plaintext_password.data[passlen1] = 0;
1487 }
1488
1489 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
1490 req->buf + passlen1, STR_TERMINATE);
1491 user = tmp ? tmp : "";
1492
1493 domain = "";
1494
1495 } else {
1496 uint16 passlen1 = SVAL(req->vwv+7, 0);
1497 uint16 passlen2 = SVAL(req->vwv+8, 0);
1498 enum remote_arch_types ra_type = get_remote_arch();
1499 const uint8_t *p = req->buf;
1500 const uint8_t *save_p = req->buf;
1501 uint16 byte_count;
1502
1503
1504 if(global_client_caps == 0) {
1505 global_client_caps = IVAL(req->vwv+11, 0);
1506
1507 if (!(global_client_caps & CAP_STATUS32)) {
1508 remove_from_common_flags2(
1509 FLAGS2_32_BIT_ERROR_CODES);
1510 }
1511
1512 /* client_caps is used as final determination if
1513 * client is NT or Win95. This is needed to return
1514 * the correct error codes in some circumstances.
1515 */
1516
1517 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1518 ra_type == RA_WIN95) {
1519 if(!(global_client_caps & (CAP_NT_SMBS|
1520 CAP_STATUS32))) {
1521 set_remote_arch( RA_WIN95);
1522 }
1523 }
1524 }
1525
1526 if (!doencrypt) {
1527 /* both Win95 and WinNT stuff up the password
1528 * lengths for non-encrypting systems. Uggh.
1529
1530 if passlen1==24 its a win95 system, and its setting
1531 the password length incorrectly. Luckily it still
1532 works with the default code because Win95 will null
1533 terminate the password anyway
1534
1535 if passlen1>0 and passlen2>0 then maybe its a NT box
1536 and its setting passlen2 to some random value which
1537 really stuffs things up. we need to fix that one. */
1538
1539 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1540 passlen2 != 1) {
1541 passlen2 = 0;
1542 }
1543 }
1544
1545 /* check for nasty tricks */
1546 if (passlen1 > MAX_PASS_LEN
1547 || passlen1 > smbreq_bufrem(req, p)) {
1548 reply_nterror(req, nt_status_squash(
1549 NT_STATUS_INVALID_PARAMETER));
1550 END_PROFILE(SMBsesssetupX);
1551 return;
1552 }
1553
1554 if (passlen2 > MAX_PASS_LEN
1555 || passlen2 > smbreq_bufrem(req, p+passlen1)) {
1556 reply_nterror(req, nt_status_squash(
1557 NT_STATUS_INVALID_PARAMETER));
1558 END_PROFILE(SMBsesssetupX);
1559 return;
1560 }
1561
1562 /* Save the lanman2 password and the NT md4 password. */
1563
1564 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1565 doencrypt = False;
1566 }
1567
1568 if (doencrypt) {
1569 lm_resp = data_blob(p, passlen1);
1570 nt_resp = data_blob(p+passlen1, passlen2);
1571 } else if (lp_security() != SEC_SHARE) {
1572 /*
1573 * In share level we should ignore any passwords, so
1574 * only read them if we're not.
1575 */
1576 char *pass = NULL;
1577 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1578
1579 if (unic && (passlen2 == 0) && passlen1) {
1580 /* Only a ascii plaintext password was sent. */
1581 (void)srvstr_pull_talloc(talloc_tos(),
1582 req->inbuf,
1583 req->flags2,
1584 &pass,
1585 req->buf,
1586 passlen1,
1587 STR_TERMINATE|STR_ASCII);
1588 } else {
1589 (void)srvstr_pull_talloc(talloc_tos(),
1590 req->inbuf,
1591 req->flags2,
1592 &pass,
1593 req->buf,
1594 unic ? passlen2 : passlen1,
1595 STR_TERMINATE);
1596 }
1597 if (!pass) {
1598 reply_nterror(req, nt_status_squash(
1599 NT_STATUS_INVALID_PARAMETER));
1600 END_PROFILE(SMBsesssetupX);
1601 return;
1602 }
1603 plaintext_password = data_blob(pass, strlen(pass)+1);
1604 }
1605
1606 p += passlen1 + passlen2;
1607
1608 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1609 STR_TERMINATE);
1610 user = tmp ? tmp : "";
1611
1612 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1613 STR_TERMINATE);
1614 domain = tmp ? tmp : "";
1615
1616 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1617 STR_TERMINATE);
1618 native_os = tmp ? tmp : "";
1619
1620 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1621 STR_TERMINATE);
1622 native_lanman = tmp ? tmp : "";
1623
1624 /* not documented or decoded by Ethereal but there is one more
1625 * string in the extra bytes which is the same as the
1626 * PrimaryDomain when using extended security. Windows NT 4
1627 * and 2003 use this string to store the native lanman string.
1628 * Windows 9x does not include a string here at all so we have
1629 * to check if we have any extra bytes left */
1630
1631 byte_count = SVAL(req->vwv+13, 0);
1632 if ( PTR_DIFF(p, save_p) < byte_count) {
1633 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1634 STR_TERMINATE);
1635 primary_domain = tmp ? tmp : "";
1636 } else {
1637 primary_domain = talloc_strdup(talloc_tos(), "null");
1638 }
1639
1640 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
1641 "PrimaryDomain=[%s]\n",
1642 domain, native_os, native_lanman, primary_domain));
1643
1644 if ( ra_type == RA_WIN2K ) {
1645 if ( strlen(native_lanman) == 0 )
1646 ra_lanman_string( primary_domain );
1647 else
1648 ra_lanman_string( native_lanman );
1649 }
1650
1651 }
1652
1653 if (SVAL(req->vwv+4, 0) == 0) {
1654 setup_new_vc_session();
1655 }
1656
1657 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1658 domain, user, get_remote_machine_name()));
1659
1660 if (*user) {
1661 if (sconn->smb1.negprot.spnego) {
1662
1663 /* This has to be here, because this is a perfectly
1664 * valid behaviour for guest logons :-( */
1665
1666 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1667 "at 'normal' session setup after "
1668 "negotiating spnego.\n"));
1669 reply_nterror(req, nt_status_squash(
1670 NT_STATUS_LOGON_FAILURE));
1671 END_PROFILE(SMBsesssetupX);
1672 return;
1673 }
1674 fstrcpy(sub_user, user);
1675 } else {
1676 fstrcpy(sub_user, lp_guestaccount());
1677 }
1678
1679 sub_set_smb_name(sub_user);
1680
1681 reload_services(True);
1682
1683 if (lp_security() == SEC_SHARE) {
1684 /* In share level we should ignore any passwords */
1685
1686 data_blob_free(&lm_resp);
1687 data_blob_free(&nt_resp);
1688 data_blob_clear_free(&plaintext_password);
1689
1690 map_username(sconn, sub_user);
1691 add_session_user(sconn, sub_user);
1692 add_session_workgroup(sconn, domain);
1693 /* Then force it to null for the benfit of the code below */
1694 user = "";
1695 }
1696
1697 if (!*user) {
1698
1699 nt_status = check_guest_password(&server_info);
1700
1701 } else if (doencrypt) {
1702 struct auth_context *negprot_auth_context = NULL;
1703 negprot_auth_context = sconn->smb1.negprot.auth_context;
1704 if (!negprot_auth_context) {
1705 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
1706 "session setup without negprot denied!\n"));
1707 reply_nterror(req, nt_status_squash(
1708 NT_STATUS_LOGON_FAILURE));
1709 END_PROFILE(SMBsesssetupX);
1710 return;
1711 }
1712 nt_status = make_user_info_for_reply_enc(&user_info, user,
1713 domain,
1714 lm_resp, nt_resp);
1715 if (NT_STATUS_IS_OK(nt_status)) {
1716 nt_status = negprot_auth_context->check_ntlm_password(
1717 negprot_auth_context,
1718 user_info,
1719 &server_info);
1720 }
1721 } else {
1722 struct auth_context *plaintext_auth_context = NULL;
1723
1724 nt_status = make_auth_context_subsystem(
1725 &plaintext_auth_context);
1726
1727 if (NT_STATUS_IS_OK(nt_status)) {
1728 uint8_t chal[8];
1729
1730 plaintext_auth_context->get_ntlm_challenge(
1731 plaintext_auth_context, chal);
1732
1733 if (!make_user_info_for_reply(&user_info,
1734 user, domain, chal,
1735 plaintext_password)) {
1736 nt_status = NT_STATUS_NO_MEMORY;
1737 }
1738
1739 if (NT_STATUS_IS_OK(nt_status)) {
1740 nt_status = plaintext_auth_context->check_ntlm_password(
1741 plaintext_auth_context,
1742 user_info,
1743 &server_info);
1744
1745 (plaintext_auth_context->free)(
1746 &plaintext_auth_context);
1747 }
1748 }
1749 }
1750
1751 free_user_info(&user_info);
1752
1753 if (!NT_STATUS_IS_OK(nt_status)) {
1754 nt_status = do_map_to_guest(nt_status, &server_info,
1755 user, domain);
1756 }
1757
1758 if (!NT_STATUS_IS_OK(nt_status)) {
1759 data_blob_free(&nt_resp);
1760 data_blob_free(&lm_resp);
1761 data_blob_clear_free(&plaintext_password);
1762 reply_nterror(req, nt_status_squash(nt_status));
1763 END_PROFILE(SMBsesssetupX);
1764 return;
1765 }
1766
1767 /* Ensure we can't possible take a code path leading to a
1768 * null defref. */
1769 if (!server_info) {
1770 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1771 END_PROFILE(SMBsesssetupX);
1772 return;
1773 }
1774
1775 if (!server_info->ptok) {
1776 nt_status = create_local_token(server_info);
1777
1778 if (!NT_STATUS_IS_OK(nt_status)) {
1779 DEBUG(10, ("create_local_token failed: %s\n",
1780 nt_errstr(nt_status)));
1781 data_blob_free(&nt_resp);
1782 data_blob_free(&lm_resp);
1783 data_blob_clear_free(&plaintext_password);
1784 reply_nterror(req, nt_status_squash(nt_status));
1785 END_PROFILE(SMBsesssetupX);
1786 return;
1787 }
1788 }
1789
1790 data_blob_clear_free(&plaintext_password);
1791
1792 /* it's ok - setup a reply */
1793 reply_outbuf(req, 3, 0);
1794 if (get_Protocol() >= PROTOCOL_NT1) {
1795 push_signature(&req->outbuf);
1796 /* perhaps grab OS version here?? */
1797 }
1798
1799 if (server_info->guest) {
1800 SSVAL(req->outbuf,smb_vwv2,1);
1801 }
1802
1803 /* register the name and uid as being validated, so further connections
1804 to a uid can get through without a password, on the same VC */
1805
1806 if (lp_security() == SEC_SHARE) {
1807 sess_vuid = UID_FIELD_INVALID;
1808 TALLOC_FREE(server_info);
1809 } else {
1810 /* Ignore the initial vuid. */
1811 sess_vuid = register_initial_vuid(sconn);
1812 if (sess_vuid == UID_FIELD_INVALID) {
1813 data_blob_free(&nt_resp);
1814 data_blob_free(&lm_resp);
1815 reply_nterror(req, nt_status_squash(
1816 NT_STATUS_LOGON_FAILURE));
1817 END_PROFILE(SMBsesssetupX);
1818 return;
1819 }
1820 /* register_existing_vuid keeps the server info */
1821 sess_vuid = register_existing_vuid(sconn, sess_vuid,
1822 server_info,
1823 nt_resp.data ? nt_resp : lm_resp,
1824 sub_user);
1825 if (sess_vuid == UID_FIELD_INVALID) {
1826 data_blob_free(&nt_resp);
1827 data_blob_free(&lm_resp);
1828 reply_nterror(req, nt_status_squash(
1829 NT_STATUS_LOGON_FAILURE));
1830 END_PROFILE(SMBsesssetupX);
1831 return;
1832 }
1833
1834 /* current_user_info is changed on new vuid */
1835 reload_services( True );
1836 }
1837
1838 data_blob_free(&nt_resp);
1839 data_blob_free(&lm_resp);
1840
1841 SSVAL(req->outbuf,smb_uid,sess_vuid);
1842 SSVAL(req->inbuf,smb_uid,sess_vuid);
1843 req->vuid = sess_vuid;
1844
1845 if (!sconn->smb1.sessions.done_sesssetup) {
1846 sconn->smb1.sessions.max_send =
1847 MIN(sconn->smb1.sessions.max_send,smb_bufsize);
1848 }
1849 sconn->smb1.sessions.done_sesssetup = true;
1850
1851 END_PROFILE(SMBsesssetupX);
1852 chain_reply(req);
1853 return;
1854}
Note: See TracBrowser for help on using the repository browser.