r11684: freezing 3.0.21rc1 (current with SAMBA_3_0 r11667)
[Samba.git] / source / smbd / sesssetup.c
blob2c9676016783c611a43082bbca6fe516217df129
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
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "includes.h"
26 uint32 global_client_caps = 0;
29 on a logon error possibly map the error to success if "map to guest"
30 is set approriately
32 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
33 const char *user, const char *domain)
35 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
36 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
37 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
38 DEBUG(3,("No such user %s [%s] - using guest account\n",
39 user, domain));
40 status = make_server_info_guest(server_info);
44 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
45 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
46 DEBUG(3,("Registered username %s for guest access\n",user));
47 status = make_server_info_guest(server_info);
51 return status;
54 /****************************************************************************
55 Add the standard 'Samba' signature to the end of the session setup.
56 ****************************************************************************/
58 static int add_signature(char *outbuf, char *p)
60 char *start = p;
61 fstring lanman;
63 fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
65 p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
66 p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE);
67 p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
69 return PTR_DIFF(p, start);
72 /****************************************************************************
73 Send a security blob via a session setup reply.
74 ****************************************************************************/
76 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
77 DATA_BLOB blob, NTSTATUS nt_status)
79 char *p;
81 set_message(outbuf,4,0,True);
83 nt_status = nt_status_squash(nt_status);
84 SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
85 SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
86 SSVAL(outbuf, smb_vwv3, blob.length);
87 p = smb_buf(outbuf);
89 /* should we cap this? */
90 memcpy(p, blob.data, blob.length);
91 p += blob.length;
93 p += add_signature( outbuf, p );
95 set_message_end(outbuf,p);
97 show_msg(outbuf);
98 return send_smb(smbd_server_fd(),outbuf);
101 /****************************************************************************
102 Do a 'guest' logon, getting back the
103 ****************************************************************************/
105 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
107 struct auth_context *auth_context;
108 auth_usersupplied_info *user_info = NULL;
110 NTSTATUS nt_status;
111 unsigned char chal[8];
113 ZERO_STRUCT(chal);
115 DEBUG(3,("Got anonymous request\n"));
117 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
118 return nt_status;
121 if (!make_user_info_guest(&user_info)) {
122 (auth_context->free)(&auth_context);
123 return NT_STATUS_NO_MEMORY;
126 nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
127 (auth_context->free)(&auth_context);
128 free_user_info(&user_info);
129 return nt_status;
133 #ifdef HAVE_KRB5
134 /****************************************************************************
135 reply to a session setup spnego negotiate packet for kerberos
136 ****************************************************************************/
137 static int reply_spnego_kerberos(connection_struct *conn,
138 char *inbuf, char *outbuf,
139 int length, int bufsize,
140 DATA_BLOB *secblob)
142 TALLOC_CTX *mem_ctx;
143 DATA_BLOB ticket;
144 char *client, *p, *domain;
145 fstring netbios_domain_name;
146 struct passwd *pw;
147 fstring user;
148 int sess_vuid;
149 NTSTATUS ret;
150 PAC_DATA *pac_data;
151 DATA_BLOB ap_rep, ap_rep_wrapped, response;
152 auth_serversupplied_info *server_info = NULL;
153 DATA_BLOB session_key = data_blob(NULL, 0);
154 uint8 tok_id[2];
155 DATA_BLOB nullblob = data_blob(NULL, 0);
156 fstring real_username;
157 BOOL map_domainuser_to_guest = False;
158 PAC_LOGON_INFO *logon_info = NULL;
160 ZERO_STRUCT(ticket);
161 ZERO_STRUCT(pac_data);
162 ZERO_STRUCT(ap_rep);
163 ZERO_STRUCT(ap_rep_wrapped);
164 ZERO_STRUCT(response);
166 mem_ctx = talloc_init("reply_spnego_kerberos");
167 if (mem_ctx == NULL)
168 return ERROR_NT(NT_STATUS_NO_MEMORY);
170 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
171 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
174 ret = ads_verify_ticket(mem_ctx, lp_realm(), &ticket, &client, &pac_data, &ap_rep, &session_key);
176 data_blob_free(&ticket);
178 if (!NT_STATUS_IS_OK(ret)) {
179 DEBUG(1,("Failed to verify incoming ticket!\n"));
180 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
183 DEBUG(3,("Ticket name is [%s]\n", client));
185 p = strchr_m(client, '@');
186 if (!p) {
187 DEBUG(3,("Doesn't look like a valid principal\n"));
188 data_blob_free(&ap_rep);
189 data_blob_free(&session_key);
190 SAFE_FREE(client);
191 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
194 *p = 0;
196 /* save the PAC data if we have it */
198 if (pac_data) {
199 logon_info = get_logon_info_from_pac(pac_data);
200 netsamlogon_cache_store( client, &logon_info->info3 );
203 if (!strequal(p+1, lp_realm())) {
204 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
205 if (!lp_allow_trusted_domains()) {
206 data_blob_free(&ap_rep);
207 data_blob_free(&session_key);
208 SAFE_FREE(client);
209 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
213 /* this gives a fully qualified user name (ie. with full realm).
214 that leads to very long usernames, but what else can we do? */
216 domain = p+1;
218 if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) {
220 unistr2_to_ascii(netbios_domain_name, &logon_info->info3.uni_logon_dom, -1);
221 domain = netbios_domain_name;
222 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
224 } else {
226 /* If we have winbind running, we can (and must) shorten the
227 username by using the short netbios name. Otherwise we will
228 have inconsistent user names. With Kerberos, we get the
229 fully qualified realm, with ntlmssp we get the short
230 name. And even w2k3 does use ntlmssp if you for example
231 connect to an ip address. */
233 struct winbindd_request wb_request;
234 struct winbindd_response wb_response;
235 NSS_STATUS wb_result;
237 ZERO_STRUCT(wb_request);
238 ZERO_STRUCT(wb_response);
240 DEBUG(10, ("Mapping [%s] to short name\n", domain));
242 fstrcpy(wb_request.domain_name, domain);
244 wb_result = winbindd_request_response(WINBINDD_DOMAIN_INFO,
245 &wb_request, &wb_response);
247 if (wb_result == NSS_STATUS_SUCCESS) {
249 fstrcpy(netbios_domain_name,
250 wb_response.data.domain_info.name);
251 domain = netbios_domain_name;
253 DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
254 } else {
255 DEBUG(3, ("Could not find short name -- winbind "
256 "not running?\n"));
260 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
262 /* lookup the passwd struct, create a new user if necessary */
264 map_username( user );
266 pw = smb_getpwnam( user, real_username, True );
267 if (!pw) {
269 /* this was originally the behavior of Samba 2.2, if a user
270 did not have a local uid but has been authenticated, then
271 map them to a guest account */
273 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
274 map_domainuser_to_guest = True;
275 fstrcpy(user,lp_guestaccount());
276 pw = smb_getpwnam( user, real_username, True );
279 /* extra sanity check that the guest account is valid */
281 if ( !pw ) {
282 DEBUG(1,("Username %s is invalid on this system\n", user));
283 SAFE_FREE(client);
284 data_blob_free(&ap_rep);
285 data_blob_free(&session_key);
286 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
290 /* setup the string used by %U */
292 sub_set_smb_name( real_username );
293 reload_services(True);
294 if ( map_domainuser_to_guest ) {
295 make_server_info_guest(&server_info);
296 } else if (logon_info) {
297 ret = make_server_info_pac(&server_info, real_username, pw, logon_info);
299 if ( !NT_STATUS_IS_OK(ret) ) {
300 DEBUG(1,("make_server_info_pac failed!\n"));
301 SAFE_FREE(client);
302 data_blob_free(&ap_rep);
303 data_blob_free(&session_key);
304 passwd_free(&pw);
305 return ERROR_NT(ret);
308 } else {
309 ret = make_server_info_pw(&server_info, real_username, pw);
311 if ( !NT_STATUS_IS_OK(ret) ) {
312 DEBUG(1,("make_server_info_from_pw failed!\n"));
313 SAFE_FREE(client);
314 data_blob_free(&ap_rep);
315 data_blob_free(&session_key);
316 passwd_free(&pw);
317 return ERROR_NT(ret);
320 /* make_server_info_pw does not set the domain. Without this we end up
321 * with the local netbios name in substitutions for %D. */
323 if (server_info->sam_account != NULL) {
324 pdb_set_domain(server_info->sam_account, domain, PDB_SET);
329 passwd_free(&pw);
331 /* register_vuid keeps the server info */
332 /* register_vuid takes ownership of session_key, no need to free after this.
333 A better interface would copy it.... */
334 sess_vuid = register_vuid(server_info, session_key, nullblob, client);
336 SAFE_FREE(client);
338 if (sess_vuid == -1) {
339 ret = NT_STATUS_LOGON_FAILURE;
340 } else {
341 /* current_user_info is changed on new vuid */
342 reload_services( True );
344 set_message(outbuf,4,0,True);
345 SSVAL(outbuf, smb_vwv3, 0);
347 if (server_info->guest) {
348 SSVAL(outbuf,smb_vwv2,1);
351 SSVAL(outbuf, smb_uid, sess_vuid);
353 if (!server_info->guest && !srv_signing_started()) {
354 /* We need to start the signing engine
355 * here but a W2K client sends the old
356 * "BSRSPYL " signature instead of the
357 * correct one. Subsequent packets will
358 * be correct.
360 srv_check_sign_mac(inbuf, False);
364 /* wrap that up in a nice GSS-API wrapping */
365 if (NT_STATUS_IS_OK(ret)) {
366 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
367 } else {
368 ap_rep_wrapped = data_blob(NULL, 0);
370 response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
371 reply_sesssetup_blob(conn, outbuf, response, ret);
373 data_blob_free(&ap_rep);
374 data_blob_free(&ap_rep_wrapped);
375 data_blob_free(&response);
376 talloc_destroy(mem_ctx);
378 return -1; /* already replied */
380 #endif
382 /****************************************************************************
383 Send a session setup reply, wrapped in SPNEGO.
384 Get vuid and check first.
385 End the NTLMSSP exchange context if we are OK/complete fail
386 This should be split into two functions, one to handle each
387 leg of the NTLM auth steps.
388 ***************************************************************************/
390 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
391 uint16 vuid,
392 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
393 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
394 BOOL wrap)
396 BOOL ret;
397 DATA_BLOB response;
398 struct auth_serversupplied_info *server_info = NULL;
400 if (NT_STATUS_IS_OK(nt_status)) {
401 server_info = (*auth_ntlmssp_state)->server_info;
402 } else {
403 nt_status = do_map_to_guest(nt_status,
404 &server_info,
405 (*auth_ntlmssp_state)->ntlmssp_state->user,
406 (*auth_ntlmssp_state)->ntlmssp_state->domain);
409 if (NT_STATUS_IS_OK(nt_status)) {
410 int sess_vuid;
411 DATA_BLOB nullblob = data_blob(NULL, 0);
412 DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
414 /* register_vuid keeps the server info */
415 sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
416 (*auth_ntlmssp_state)->server_info = NULL;
418 if (sess_vuid == -1) {
419 nt_status = NT_STATUS_LOGON_FAILURE;
420 } else {
422 /* current_user_info is changed on new vuid */
423 reload_services( True );
425 set_message(outbuf,4,0,True);
426 SSVAL(outbuf, smb_vwv3, 0);
428 if (server_info->guest) {
429 SSVAL(outbuf,smb_vwv2,1);
432 SSVAL(outbuf,smb_uid,sess_vuid);
434 if (!server_info->guest && !srv_signing_started()) {
435 /* We need to start the signing engine
436 * here but a W2K client sends the old
437 * "BSRSPYL " signature instead of the
438 * correct one. Subsequent packets will
439 * be correct.
442 srv_check_sign_mac(inbuf, False);
447 if (wrap) {
448 response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
449 } else {
450 response = *ntlmssp_blob;
453 ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
454 if (wrap) {
455 data_blob_free(&response);
458 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
459 and the other end, that we are not finished yet. */
461 if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
462 /* NB. This is *NOT* an error case. JRA */
463 auth_ntlmssp_end(auth_ntlmssp_state);
464 /* Kill the intermediate vuid */
465 invalidate_vuid(vuid);
468 return ret;
471 /****************************************************************************
472 Reply to a session setup spnego negotiate packet.
473 ****************************************************************************/
475 static int reply_spnego_negotiate(connection_struct *conn,
476 char *inbuf,
477 char *outbuf,
478 uint16 vuid,
479 int length, int bufsize,
480 DATA_BLOB blob1,
481 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
483 char *OIDs[ASN1_MAX_OIDS];
484 DATA_BLOB secblob;
485 int i;
486 DATA_BLOB chal;
487 #ifdef HAVE_KRB5
488 BOOL got_kerberos_mechanism = False;
489 #endif
490 NTSTATUS nt_status;
492 /* parse out the OIDs and the first sec blob */
493 if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
494 /* Kill the intermediate vuid */
495 invalidate_vuid(vuid);
497 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
500 /* only look at the first OID for determining the mechToken --
501 accoirding to RFC2478, we should choose the one we want
502 and renegotiate, but i smell a client bug here..
504 Problem observed when connecting to a member (samba box)
505 of an AD domain as a user in a Samba domain. Samba member
506 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
507 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
508 NTLMSSP mechtoken. --jerry */
510 #ifdef HAVE_KRB5
511 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
512 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
513 got_kerberos_mechanism = True;
515 #endif
517 for (i=0;OIDs[i];i++) {
518 DEBUG(3,("Got OID %s\n", OIDs[i]));
519 free(OIDs[i]);
521 DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length));
523 #ifdef HAVE_KRB5
524 if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
525 int ret = reply_spnego_kerberos(conn, inbuf, outbuf,
526 length, bufsize, &secblob);
527 data_blob_free(&secblob);
528 /* Kill the intermediate vuid */
529 invalidate_vuid(vuid);
531 return ret;
533 #endif
535 if (*auth_ntlmssp_state) {
536 auth_ntlmssp_end(auth_ntlmssp_state);
539 nt_status = auth_ntlmssp_start(auth_ntlmssp_state);
540 if (!NT_STATUS_IS_OK(nt_status)) {
541 /* Kill the intermediate vuid */
542 invalidate_vuid(vuid);
544 return ERROR_NT(nt_status);
547 nt_status = auth_ntlmssp_update(*auth_ntlmssp_state,
548 secblob, &chal);
550 data_blob_free(&secblob);
552 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state,
553 &chal, nt_status, True);
555 data_blob_free(&chal);
557 /* already replied */
558 return -1;
561 /****************************************************************************
562 Reply to a session setup spnego auth packet.
563 ****************************************************************************/
565 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
566 uint16 vuid,
567 int length, int bufsize,
568 DATA_BLOB blob1,
569 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
571 DATA_BLOB auth, auth_reply;
572 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
574 if (!spnego_parse_auth(blob1, &auth)) {
575 #if 0
576 file_save("auth.dat", blob1.data, blob1.length);
577 #endif
578 /* Kill the intermediate vuid */
579 invalidate_vuid(vuid);
581 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
584 if (!*auth_ntlmssp_state) {
585 /* Kill the intermediate vuid */
586 invalidate_vuid(vuid);
588 /* auth before negotiatiate? */
589 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
592 nt_status = auth_ntlmssp_update(*auth_ntlmssp_state,
593 auth, &auth_reply);
595 data_blob_free(&auth);
597 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid,
598 auth_ntlmssp_state,
599 &auth_reply, nt_status, True);
601 data_blob_free(&auth_reply);
603 /* and tell smbd that we have already replied to this packet */
604 return -1;
607 /****************************************************************************
608 Reply to a session setup command.
609 ****************************************************************************/
611 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
612 char *outbuf,
613 int length,int bufsize)
615 uint8 *p;
616 DATA_BLOB blob1;
617 int ret;
618 size_t bufrem;
619 fstring native_os, native_lanman, primary_domain;
620 char *p2;
621 uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
622 enum remote_arch_types ra_type = get_remote_arch();
623 int vuid = SVAL(inbuf,smb_uid);
624 user_struct *vuser = NULL;
626 DEBUG(3,("Doing spnego session setup\n"));
628 if (global_client_caps == 0) {
629 global_client_caps = IVAL(inbuf,smb_vwv10);
631 if (!(global_client_caps & CAP_STATUS32)) {
632 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
637 p = (uint8 *)smb_buf(inbuf);
639 if (data_blob_len == 0) {
640 /* an invalid request */
641 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
644 bufrem = smb_bufrem(inbuf, p);
645 /* pull the spnego blob */
646 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
648 #if 0
649 file_save("negotiate.dat", blob1.data, blob1.length);
650 #endif
652 p2 = inbuf + smb_vwv13 + data_blob_len;
653 p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
654 p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
655 p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
656 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
657 native_os, native_lanman, primary_domain));
659 if ( ra_type == RA_WIN2K ) {
660 /* Windows 2003 doesn't set the native lanman string,
661 but does set primary domain which is a bug I think */
663 if ( !strlen(native_lanman) )
664 ra_lanman_string( primary_domain );
665 else
666 ra_lanman_string( native_lanman );
669 vuser = get_partial_auth_user_struct(vuid);
670 if (!vuser) {
671 vuid = register_vuid(NULL, data_blob(NULL, 0), data_blob(NULL, 0), NULL);
672 if (vuid == -1) {
673 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
676 vuser = get_partial_auth_user_struct(vuid);
679 if (!vuser) {
680 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
683 SSVAL(outbuf,smb_uid,vuid);
685 if (blob1.data[0] == ASN1_APPLICATION(0)) {
686 /* its a negTokenTarg packet */
687 ret = reply_spnego_negotiate(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
688 &vuser->auth_ntlmssp_state);
689 data_blob_free(&blob1);
690 return ret;
693 if (blob1.data[0] == ASN1_CONTEXT(1)) {
694 /* its a auth packet */
695 ret = reply_spnego_auth(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
696 &vuser->auth_ntlmssp_state);
697 data_blob_free(&blob1);
698 return ret;
701 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
702 DATA_BLOB chal;
703 NTSTATUS nt_status;
704 if (!vuser->auth_ntlmssp_state) {
705 nt_status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
706 if (!NT_STATUS_IS_OK(nt_status)) {
707 /* Kill the intermediate vuid */
708 invalidate_vuid(vuid);
710 return ERROR_NT(nt_status);
714 nt_status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
715 blob1, &chal);
717 data_blob_free(&blob1);
719 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid,
720 &vuser->auth_ntlmssp_state,
721 &chal, nt_status, False);
722 data_blob_free(&chal);
723 return -1;
726 /* what sort of packet is this? */
727 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
729 data_blob_free(&blob1);
731 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
734 /****************************************************************************
735 On new VC == 0, shutdown *all* old connections and users.
736 It seems that only NT4.x does this. At W2K and above (XP etc.).
737 a new session setup with VC==0 is ignored.
738 ****************************************************************************/
740 static void setup_new_vc_session(void)
742 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
743 #if 0
744 conn_close_all();
745 invalidate_all_vuids();
746 #endif
749 /****************************************************************************
750 Reply to a session setup command.
751 ****************************************************************************/
753 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
754 int length,int bufsize)
756 int sess_vuid;
757 int smb_bufsize;
758 DATA_BLOB lm_resp;
759 DATA_BLOB nt_resp;
760 DATA_BLOB plaintext_password;
761 fstring user;
762 fstring sub_user; /* Sainitised username for substituion */
763 fstring domain;
764 fstring native_os;
765 fstring native_lanman;
766 fstring primary_domain;
767 static BOOL done_sesssetup = False;
768 extern BOOL global_encrypted_passwords_negotiated;
769 extern BOOL global_spnego_negotiated;
770 extern enum protocol_types Protocol;
771 extern int max_send;
773 auth_usersupplied_info *user_info = NULL;
774 extern struct auth_context *negprot_global_auth_context;
775 auth_serversupplied_info *server_info = NULL;
777 NTSTATUS nt_status;
779 BOOL doencrypt = global_encrypted_passwords_negotiated;
781 DATA_BLOB session_key;
783 START_PROFILE(SMBsesssetupX);
785 ZERO_STRUCT(lm_resp);
786 ZERO_STRUCT(nt_resp);
787 ZERO_STRUCT(plaintext_password);
789 DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
791 /* a SPNEGO session setup has 12 command words, whereas a normal
792 NT1 session setup has 13. See the cifs spec. */
793 if (CVAL(inbuf, smb_wct) == 12 &&
794 (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
795 if (!global_spnego_negotiated) {
796 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
797 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
800 if (SVAL(inbuf,smb_vwv4) == 0) {
801 setup_new_vc_session();
803 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
806 smb_bufsize = SVAL(inbuf,smb_vwv2);
808 if (Protocol < PROTOCOL_NT1) {
809 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
811 /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
812 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
814 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
815 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
818 if (doencrypt) {
819 lm_resp = data_blob(smb_buf(inbuf), passlen1);
820 } else {
821 plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
822 /* Ensure null termination */
823 plaintext_password.data[passlen1] = 0;
826 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
827 *domain = 0;
829 } else {
830 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
831 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
832 enum remote_arch_types ra_type = get_remote_arch();
833 char *p = smb_buf(inbuf);
834 char *save_p = smb_buf(inbuf);
835 uint16 byte_count;
838 if(global_client_caps == 0) {
839 global_client_caps = IVAL(inbuf,smb_vwv11);
841 if (!(global_client_caps & CAP_STATUS32)) {
842 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
845 /* client_caps is used as final determination if client is NT or Win95.
846 This is needed to return the correct error codes in some
847 circumstances.
850 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
851 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
852 set_remote_arch( RA_WIN95);
857 if (!doencrypt) {
858 /* both Win95 and WinNT stuff up the password lengths for
859 non-encrypting systems. Uggh.
861 if passlen1==24 its a win95 system, and its setting the
862 password length incorrectly. Luckily it still works with the
863 default code because Win95 will null terminate the password
864 anyway
866 if passlen1>0 and passlen2>0 then maybe its a NT box and its
867 setting passlen2 to some random value which really stuffs
868 things up. we need to fix that one. */
870 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
871 passlen2 = 0;
874 /* check for nasty tricks */
875 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
876 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
879 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
880 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
883 /* Save the lanman2 password and the NT md4 password. */
885 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
886 doencrypt = False;
889 if (doencrypt) {
890 lm_resp = data_blob(p, passlen1);
891 nt_resp = data_blob(p+passlen1, passlen2);
892 } else {
893 pstring pass;
894 BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
896 #if 0
897 /* This was the previous fix. Not sure if it's still valid. JRA. */
898 if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
899 /* NT4.0 stuffs up plaintext unicode password lengths... */
900 srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
901 sizeof(pass), passlen1, STR_TERMINATE);
902 #endif
904 if (unic && (passlen2 == 0) && passlen1) {
905 /* Only a ascii plaintext password was sent. */
906 srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass),
907 passlen1, STR_TERMINATE|STR_ASCII);
908 } else {
909 srvstr_pull(inbuf, pass, smb_buf(inbuf),
910 sizeof(pass), unic ? passlen2 : passlen1,
911 STR_TERMINATE);
913 plaintext_password = data_blob(pass, strlen(pass)+1);
916 p += passlen1 + passlen2;
917 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
918 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
919 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
920 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
922 /* not documented or decoded by Ethereal but there is one more string
923 in the extra bytes which is the same as the PrimaryDomain when using
924 extended security. Windows NT 4 and 2003 use this string to store
925 the native lanman string. Windows 9x does not include a string here
926 at all so we have to check if we have any extra bytes left */
928 byte_count = SVAL(inbuf, smb_vwv13);
929 if ( PTR_DIFF(p, save_p) < byte_count)
930 p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
931 else
932 fstrcpy( primary_domain, "null" );
934 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
935 domain, native_os, native_lanman, primary_domain));
937 if ( ra_type == RA_WIN2K ) {
938 if ( strlen(native_lanman) == 0 )
939 ra_lanman_string( primary_domain );
940 else
941 ra_lanman_string( native_lanman );
946 if (SVAL(inbuf,smb_vwv4) == 0) {
947 setup_new_vc_session();
950 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
952 if (*user) {
953 if (global_spnego_negotiated) {
955 /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
957 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
958 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
960 fstrcpy(sub_user, user);
961 } else {
962 fstrcpy(sub_user, lp_guestaccount());
965 sub_set_smb_name(sub_user);
967 reload_services(True);
969 if (lp_security() == SEC_SHARE) {
970 /* in share level we should ignore any passwords */
972 data_blob_free(&lm_resp);
973 data_blob_free(&nt_resp);
974 data_blob_clear_free(&plaintext_password);
976 map_username(sub_user);
977 add_session_user(sub_user);
978 /* Then force it to null for the benfit of the code below */
979 *user = 0;
982 if (!*user) {
984 nt_status = check_guest_password(&server_info);
986 } else if (doencrypt) {
987 if (!negprot_global_auth_context) {
988 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted session setup without negprot denied!\n"));
989 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
991 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
992 lm_resp, nt_resp);
993 if (NT_STATUS_IS_OK(nt_status)) {
994 nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context,
995 user_info,
996 &server_info);
998 } else {
999 struct auth_context *plaintext_auth_context = NULL;
1000 const uint8 *chal;
1001 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
1002 chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
1004 if (!make_user_info_for_reply(&user_info,
1005 user, domain, chal,
1006 plaintext_password)) {
1007 nt_status = NT_STATUS_NO_MEMORY;
1010 if (NT_STATUS_IS_OK(nt_status)) {
1011 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context,
1012 user_info,
1013 &server_info);
1015 (plaintext_auth_context->free)(&plaintext_auth_context);
1020 free_user_info(&user_info);
1022 if (!NT_STATUS_IS_OK(nt_status)) {
1023 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
1026 if (!NT_STATUS_IS_OK(nt_status)) {
1027 data_blob_free(&nt_resp);
1028 data_blob_free(&lm_resp);
1029 data_blob_clear_free(&plaintext_password);
1030 return ERROR_NT(nt_status_squash(nt_status));
1033 if (server_info->user_session_key.data) {
1034 session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
1035 } else {
1036 session_key = data_blob(NULL, 0);
1039 data_blob_clear_free(&plaintext_password);
1041 /* it's ok - setup a reply */
1042 set_message(outbuf,3,0,True);
1043 if (Protocol >= PROTOCOL_NT1) {
1044 char *p = smb_buf( outbuf );
1045 p += add_signature( outbuf, p );
1046 set_message_end( outbuf, p );
1047 /* perhaps grab OS version here?? */
1050 if (server_info->guest) {
1051 SSVAL(outbuf,smb_vwv2,1);
1054 /* register the name and uid as being validated, so further connections
1055 to a uid can get through without a password, on the same VC */
1057 /* register_vuid keeps the server info */
1058 sess_vuid = register_vuid(server_info, session_key, nt_resp.data ? nt_resp : lm_resp, sub_user);
1059 data_blob_free(&nt_resp);
1060 data_blob_free(&lm_resp);
1062 if (sess_vuid == -1) {
1063 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
1066 /* current_user_info is changed on new vuid */
1067 reload_services( True );
1069 if (!server_info->guest && !srv_signing_started() && !srv_check_sign_mac(inbuf, True)) {
1070 exit_server("reply_sesssetup_and_X: bad smb signature");
1073 SSVAL(outbuf,smb_uid,sess_vuid);
1074 SSVAL(inbuf,smb_uid,sess_vuid);
1076 if (!done_sesssetup)
1077 max_send = MIN(max_send,smb_bufsize);
1079 done_sesssetup = True;
1081 END_PROFILE(SMBsesssetupX);
1082 return chain_reply(inbuf,outbuf,length,bufsize);