2 Unix SMB/CIFS implementation.
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.
26 uint32 global_client_caps = 0;
28 static struct auth_ntlmssp_state *global_ntlmssp_state;
31 on a logon error possibly map the error to success if "map to guest"
34 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
35 const char *user, const char *domain)
37 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
38 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
39 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
40 DEBUG(3,("No such user %s [%s] - using guest account\n",
42 status = make_server_info_guest(server_info);
46 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
47 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
48 DEBUG(3,("Registered username %s for guest access\n",user));
49 status = make_server_info_guest(server_info);
56 /****************************************************************************
57 Add the standard 'Samba' signature to the end of the session setup.
58 ****************************************************************************/
60 static int add_signature(char *outbuf, char *p)
65 fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
67 p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
68 p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE);
69 p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
71 return PTR_DIFF(p, start);
74 /****************************************************************************
75 Send a security blob via a session setup reply.
76 ****************************************************************************/
78 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
79 DATA_BLOB blob, NTSTATUS nt_status)
83 set_message(outbuf,4,0,True);
85 nt_status = nt_status_squash(nt_status);
86 SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
87 SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
88 SSVAL(outbuf, smb_vwv3, blob.length);
91 /* should we cap this? */
92 memcpy(p, blob.data, blob.length);
95 p += add_signature( outbuf, p );
97 set_message_end(outbuf,p);
99 return send_smb(smbd_server_fd(),outbuf);
102 /****************************************************************************
103 Do a 'guest' logon, getting back the
104 ****************************************************************************/
106 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
108 struct auth_context *auth_context;
109 auth_usersupplied_info *user_info = NULL;
112 unsigned char chal[8];
116 DEBUG(3,("Got anonymous request\n"));
118 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
122 if (!make_user_info_guest(&user_info)) {
123 (auth_context->free)(&auth_context);
124 return NT_STATUS_NO_MEMORY;
127 nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
128 (auth_context->free)(&auth_context);
129 free_user_info(&user_info);
135 /****************************************************************************
136 reply to a session setup spnego negotiate packet for kerberos
137 ****************************************************************************/
138 static int reply_spnego_kerberos(connection_struct *conn,
139 char *inbuf, char *outbuf,
140 int length, int bufsize,
144 char *client, *p, *domain;
145 fstring netbios_domain_name;
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);
155 DATA_BLOB nullblob = data_blob(NULL, 0);
156 fstring real_username;
159 ZERO_STRUCT(auth_data);
161 ZERO_STRUCT(ap_rep_wrapped);
162 ZERO_STRUCT(response);
164 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
165 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
168 ret = ads_verify_ticket(lp_realm(), &ticket, &client, &auth_data, &ap_rep, &session_key);
170 data_blob_free(&ticket);
172 if (!NT_STATUS_IS_OK(ret)) {
173 DEBUG(1,("Failed to verify incoming ticket!\n"));
174 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
177 data_blob_free(&auth_data);
179 DEBUG(3,("Ticket name is [%s]\n", client));
181 p = strchr_m(client, '@');
183 DEBUG(3,("Doesn't look like a valid principal\n"));
184 data_blob_free(&ap_rep);
185 data_blob_free(&session_key);
187 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
191 if (!strequal(p+1, lp_realm())) {
192 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
193 if (!lp_allow_trusted_domains()) {
194 data_blob_free(&ap_rep);
195 data_blob_free(&session_key);
197 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
201 /* this gives a fully qualified user name (ie. with full realm).
202 that leads to very long usernames, but what else can we do? */
207 /* If we have winbind running, we can (and must) shorten the
208 username by using the short netbios name. Otherwise we will
209 have inconsistent user names. With Kerberos, we get the
210 fully qualified realm, with ntlmssp we get the short
211 name. And even w2k3 does use ntlmssp if you for example
212 connect to an ip address. */
214 struct winbindd_request wb_request;
215 struct winbindd_response wb_response;
216 NSS_STATUS wb_result;
218 ZERO_STRUCT(wb_request);
219 ZERO_STRUCT(wb_response);
221 DEBUG(10, ("Mapping [%s] to short name\n", domain));
223 fstrcpy(wb_request.domain_name, domain);
225 wb_result = winbindd_request(WINBINDD_DOMAIN_INFO,
226 &wb_request, &wb_response);
228 if (wb_result == NSS_STATUS_SUCCESS) {
230 fstrcpy(netbios_domain_name,
231 wb_response.data.domain_info.name);
232 domain = netbios_domain_name;
234 DEBUG(10, ("Mapped to [%s]\n", domain));
236 DEBUG(3, ("Could not find short name -- winbind "
241 asprintf(&user, "%s%c%s", domain, *lp_winbind_separator(), client);
243 /* lookup the passwd struct, create a new user if necessary */
245 map_username( user );
247 pw = smb_getpwnam( user, real_username, True );
250 DEBUG(1,("Username %s is invalid on this system\n",user));
253 data_blob_free(&ap_rep);
254 data_blob_free(&session_key);
255 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
258 /* setup the string used by %U */
260 sub_set_smb_name( real_username );
261 reload_services(True);
263 if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info, real_username, pw)))
265 DEBUG(1,("make_server_info_from_pw failed!\n"));
268 data_blob_free(&ap_rep);
269 data_blob_free(&session_key);
270 return ERROR_NT(ret);
273 /* make_server_info_pw does not set the domain. Without this we end up
274 * with the local netbios name in substitutions for %D. */
276 if (server_info->sam_account != NULL) {
277 pdb_set_domain(server_info->sam_account, domain, PDB_SET);
280 /* register_vuid keeps the server info */
281 /* register_vuid takes ownership of session_key, no need to free after this.
282 A better interface would copy it.... */
283 sess_vuid = register_vuid(server_info, session_key, nullblob, client);
288 if (sess_vuid == -1) {
289 ret = NT_STATUS_LOGON_FAILURE;
291 /* current_user_info is changed on new vuid */
292 reload_services( True );
294 set_message(outbuf,4,0,True);
295 SSVAL(outbuf, smb_vwv3, 0);
297 if (server_info->guest) {
298 SSVAL(outbuf,smb_vwv2,1);
301 SSVAL(outbuf, smb_uid, sess_vuid);
303 if (!server_info->guest && !srv_signing_started()) {
304 /* We need to start the signing engine
305 * here but a W2K client sends the old
306 * "BSRSPYL " signature instead of the
307 * correct one. Subsequent packets will
310 srv_check_sign_mac(inbuf, False);
314 /* wrap that up in a nice GSS-API wrapping */
315 if (NT_STATUS_IS_OK(ret)) {
316 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
318 ap_rep_wrapped = data_blob(NULL, 0);
320 response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
321 reply_sesssetup_blob(conn, outbuf, response, ret);
323 data_blob_free(&ap_rep);
324 data_blob_free(&ap_rep_wrapped);
325 data_blob_free(&response);
327 return -1; /* already replied */
331 /****************************************************************************
332 Send a session setup reply, wrapped in SPNEGO.
333 Get vuid and check first.
334 End the NTLMSSP exchange context if we are OK/complete fail
335 ***************************************************************************/
337 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
338 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
339 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status)
343 struct auth_serversupplied_info *server_info = NULL;
345 if (NT_STATUS_IS_OK(nt_status)) {
346 server_info = (*auth_ntlmssp_state)->server_info;
348 nt_status = do_map_to_guest(nt_status,
350 (*auth_ntlmssp_state)->ntlmssp_state->user,
351 (*auth_ntlmssp_state)->ntlmssp_state->domain);
354 if (NT_STATUS_IS_OK(nt_status)) {
356 DATA_BLOB nullblob = data_blob(NULL, 0);
357 DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
359 /* register_vuid keeps the server info */
360 sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
361 (*auth_ntlmssp_state)->server_info = NULL;
363 if (sess_vuid == -1) {
364 nt_status = NT_STATUS_LOGON_FAILURE;
367 /* current_user_info is changed on new vuid */
368 reload_services( True );
370 set_message(outbuf,4,0,True);
371 SSVAL(outbuf, smb_vwv3, 0);
373 if (server_info->guest) {
374 SSVAL(outbuf,smb_vwv2,1);
377 SSVAL(outbuf,smb_uid,sess_vuid);
379 if (!server_info->guest && !srv_signing_started()) {
380 /* We need to start the signing engine
381 * here but a W2K client sends the old
382 * "BSRSPYL " signature instead of the
383 * correct one. Subsequent packets will
387 srv_check_sign_mac(inbuf, False);
392 response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
393 ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
394 data_blob_free(&response);
396 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
397 and the other end, that we are not finished yet. */
399 if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
400 auth_ntlmssp_end(auth_ntlmssp_state);
406 /****************************************************************************
407 Reply to a session setup spnego negotiate packet.
408 ****************************************************************************/
410 static int reply_spnego_negotiate(connection_struct *conn,
413 int length, int bufsize,
416 char *OIDs[ASN1_MAX_OIDS];
421 BOOL got_kerberos_mechanism = False;
425 /* parse out the OIDs and the first sec blob */
426 if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
427 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
430 /* only look at the first OID for determining the mechToken --
431 accoirding to RFC2478, we should choose the one we want
432 and renegotiate, but i smell a client bug here..
434 Problem observed when connecting to a member (samba box)
435 of an AD domain as a user in a Samba domain. Samba member
436 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
437 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
438 NTLMSSP mechtoken. --jerry */
441 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
442 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
443 got_kerberos_mechanism = True;
447 for (i=0;OIDs[i];i++) {
448 DEBUG(3,("Got OID %s\n", OIDs[i]));
451 DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length));
454 if (got_kerberos_mechanism && (SEC_ADS == lp_security())) {
455 int ret = reply_spnego_kerberos(conn, inbuf, outbuf,
456 length, bufsize, &secblob);
457 data_blob_free(&secblob);
462 if (global_ntlmssp_state) {
463 auth_ntlmssp_end(&global_ntlmssp_state);
466 nt_status = auth_ntlmssp_start(&global_ntlmssp_state);
467 if (!NT_STATUS_IS_OK(nt_status)) {
468 return ERROR_NT(nt_status);
471 nt_status = auth_ntlmssp_update(global_ntlmssp_state,
474 data_blob_free(&secblob);
476 reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state,
479 data_blob_free(&chal);
481 /* already replied */
485 /****************************************************************************
486 Reply to a session setup spnego auth packet.
487 ****************************************************************************/
489 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
490 int length, int bufsize,
493 DATA_BLOB auth, auth_reply;
494 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
496 if (!spnego_parse_auth(blob1, &auth)) {
498 file_save("auth.dat", blob1.data, blob1.length);
500 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
503 if (!global_ntlmssp_state) {
504 /* auth before negotiatiate? */
505 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
508 nt_status = auth_ntlmssp_update(global_ntlmssp_state,
511 data_blob_free(&auth);
513 reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state,
514 &auth_reply, nt_status);
516 data_blob_free(&auth_reply);
518 /* and tell smbd that we have already replied to this packet */
522 /****************************************************************************
523 Reply to a session setup command.
524 ****************************************************************************/
526 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
528 int length,int bufsize)
534 fstring native_os, native_lanman, primary_domain;
536 uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
537 enum remote_arch_types ra_type = get_remote_arch();
539 DEBUG(3,("Doing spnego session setup\n"));
541 if (global_client_caps == 0) {
542 global_client_caps = IVAL(inbuf,smb_vwv10);
544 if (!(global_client_caps & CAP_STATUS32)) {
545 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
550 p = (uint8 *)smb_buf(inbuf);
552 if (data_blob_len == 0) {
553 /* an invalid request */
554 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
557 bufrem = smb_bufrem(inbuf, p);
558 /* pull the spnego blob */
559 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
562 file_save("negotiate.dat", blob1.data, blob1.length);
565 p2 = inbuf + smb_vwv13 + data_blob_len;
566 p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
567 p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
568 p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
569 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
570 native_os, native_lanman, primary_domain));
572 if ( ra_type == RA_WIN2K ) {
573 /* Windows 2003 doesn't set the native lanman string,
574 but does set primary domain which is a bug I think */
576 if ( !strlen(native_lanman) )
577 ra_lanman_string( primary_domain );
579 ra_lanman_string( native_lanman );
582 if (blob1.data[0] == ASN1_APPLICATION(0)) {
583 /* its a negTokenTarg packet */
584 ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
585 data_blob_free(&blob1);
589 if (blob1.data[0] == ASN1_CONTEXT(1)) {
590 /* its a auth packet */
591 ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
592 data_blob_free(&blob1);
596 /* what sort of packet is this? */
597 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
599 data_blob_free(&blob1);
601 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
604 /****************************************************************************
605 On new VC == 0, shutdown *all* old connections and users.
606 It seems that only NT4.x does this. At W2K and above (XP etc.).
607 a new session setup with VC==0 is ignored.
608 ****************************************************************************/
610 static void setup_new_vc_session(void)
612 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
615 invalidate_all_vuids();
619 /****************************************************************************
620 Reply to a session setup command.
621 ****************************************************************************/
623 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
624 int length,int bufsize)
630 DATA_BLOB plaintext_password;
632 fstring sub_user; /* Sainitised username for substituion */
635 fstring native_lanman;
636 fstring primary_domain;
637 static BOOL done_sesssetup = False;
638 extern BOOL global_encrypted_passwords_negotiated;
639 extern BOOL global_spnego_negotiated;
640 extern enum protocol_types Protocol;
643 auth_usersupplied_info *user_info = NULL;
644 extern struct auth_context *negprot_global_auth_context;
645 auth_serversupplied_info *server_info = NULL;
649 BOOL doencrypt = global_encrypted_passwords_negotiated;
651 DATA_BLOB session_key;
653 START_PROFILE(SMBsesssetupX);
655 ZERO_STRUCT(lm_resp);
656 ZERO_STRUCT(nt_resp);
657 ZERO_STRUCT(plaintext_password);
659 DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
661 /* a SPNEGO session setup has 12 command words, whereas a normal
662 NT1 session setup has 13. See the cifs spec. */
663 if (CVAL(inbuf, smb_wct) == 12 &&
664 (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
665 if (!global_spnego_negotiated) {
666 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
667 return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
670 if (SVAL(inbuf,smb_vwv4) == 0) {
671 setup_new_vc_session();
673 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
676 smb_bufsize = SVAL(inbuf,smb_vwv2);
678 if (Protocol < PROTOCOL_NT1) {
679 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
681 /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
682 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
684 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
685 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
689 lm_resp = data_blob(smb_buf(inbuf), passlen1);
691 plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
692 /* Ensure null termination */
693 plaintext_password.data[passlen1] = 0;
696 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
700 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
701 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
702 enum remote_arch_types ra_type = get_remote_arch();
703 char *p = smb_buf(inbuf);
704 char *save_p = smb_buf(inbuf);
708 if(global_client_caps == 0) {
709 global_client_caps = IVAL(inbuf,smb_vwv11);
711 if (!(global_client_caps & CAP_STATUS32)) {
712 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
715 /* client_caps is used as final determination if client is NT or Win95.
716 This is needed to return the correct error codes in some
720 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
721 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
722 set_remote_arch( RA_WIN95);
728 /* both Win95 and WinNT stuff up the password lengths for
729 non-encrypting systems. Uggh.
731 if passlen1==24 its a win95 system, and its setting the
732 password length incorrectly. Luckily it still works with the
733 default code because Win95 will null terminate the password
736 if passlen1>0 and passlen2>0 then maybe its a NT box and its
737 setting passlen2 to some random value which really stuffs
738 things up. we need to fix that one. */
740 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
744 /* check for nasty tricks */
745 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
746 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
749 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
750 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
753 /* Save the lanman2 password and the NT md4 password. */
755 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
760 lm_resp = data_blob(p, passlen1);
761 nt_resp = data_blob(p+passlen1, passlen2);
764 BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
767 /* This was the previous fix. Not sure if it's still valid. JRA. */
768 if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
769 /* NT4.0 stuffs up plaintext unicode password lengths... */
770 srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
771 sizeof(pass), passlen1, STR_TERMINATE);
774 if (unic && (passlen2 == 0) && passlen1) {
775 /* Only a ascii plaintext password was sent. */
776 srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass),
777 passlen1, STR_TERMINATE|STR_ASCII);
779 srvstr_pull(inbuf, pass, smb_buf(inbuf),
780 sizeof(pass), unic ? passlen2 : passlen1,
783 plaintext_password = data_blob(pass, strlen(pass)+1);
786 p += passlen1 + passlen2;
787 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
788 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
789 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
790 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
792 /* not documented or decoded by Ethereal but there is one more string
793 in the extra bytes which is the same as the PrimaryDomain when using
794 extended security. Windows NT 4 and 2003 use this string to store
795 the native lanman string. Windows 9x does not include a string here
796 at all so we have to check if we have any extra bytes left */
798 byte_count = SVAL(inbuf, smb_vwv13);
799 if ( PTR_DIFF(p, save_p) < byte_count)
800 p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
802 fstrcpy( primary_domain, "null" );
804 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
805 domain, native_os, native_lanman, primary_domain));
807 if ( ra_type == RA_WIN2K ) {
808 if ( strlen(native_lanman) == 0 )
809 ra_lanman_string( primary_domain );
811 ra_lanman_string( native_lanman );
816 if (SVAL(inbuf,smb_vwv4) == 0) {
817 setup_new_vc_session();
820 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
823 if (global_spnego_negotiated) {
825 /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
827 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
828 return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
830 fstrcpy(sub_user, user);
832 /* setup the string used by %U */
833 sub_set_smb_name(user);
835 fstrcpy(sub_user, lp_guestaccount());
838 sub_set_smb_name(sub_user);
840 reload_services(True);
842 if (lp_security() == SEC_SHARE) {
843 /* in share level we should ignore any passwords */
845 data_blob_free(&lm_resp);
846 data_blob_free(&nt_resp);
847 data_blob_clear_free(&plaintext_password);
849 map_username(sub_user);
850 add_session_user(sub_user);
851 /* Then force it to null for the benfit of the code below */
857 nt_status = check_guest_password(&server_info);
859 } else if (doencrypt) {
860 if (!negprot_global_auth_context) {
861 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted session setup without negprot denied!\n"));
862 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
864 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
866 if (NT_STATUS_IS_OK(nt_status)) {
867 nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context,
872 struct auth_context *plaintext_auth_context = NULL;
874 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
875 chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
877 if (!make_user_info_for_reply(&user_info,
879 plaintext_password)) {
880 nt_status = NT_STATUS_NO_MEMORY;
883 if (NT_STATUS_IS_OK(nt_status)) {
884 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context,
888 (plaintext_auth_context->free)(&plaintext_auth_context);
893 free_user_info(&user_info);
895 if (!NT_STATUS_IS_OK(nt_status)) {
896 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
899 if (!NT_STATUS_IS_OK(nt_status)) {
900 data_blob_free(&nt_resp);
901 data_blob_free(&lm_resp);
902 data_blob_clear_free(&plaintext_password);
903 return ERROR_NT(nt_status_squash(nt_status));
906 if (server_info->user_session_key.data) {
907 session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
909 session_key = data_blob(NULL, 0);
912 data_blob_clear_free(&plaintext_password);
914 /* it's ok - setup a reply */
915 set_message(outbuf,3,0,True);
916 if (Protocol >= PROTOCOL_NT1) {
917 char *p = smb_buf( outbuf );
918 p += add_signature( outbuf, p );
919 set_message_end( outbuf, p );
920 /* perhaps grab OS version here?? */
923 if (server_info->guest) {
924 SSVAL(outbuf,smb_vwv2,1);
927 /* register the name and uid as being validated, so further connections
928 to a uid can get through without a password, on the same VC */
930 /* register_vuid keeps the server info */
931 sess_vuid = register_vuid(server_info, session_key, nt_resp.data ? nt_resp : lm_resp, sub_user);
932 data_blob_free(&nt_resp);
933 data_blob_free(&lm_resp);
935 if (sess_vuid == -1) {
936 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
939 /* current_user_info is changed on new vuid */
940 reload_services( True );
942 if (!server_info->guest && !srv_signing_started() && !srv_check_sign_mac(inbuf, True)) {
943 exit_server("reply_sesssetup_and_X: bad smb signature");
946 SSVAL(outbuf,smb_uid,sess_vuid);
947 SSVAL(inbuf,smb_uid,sess_vuid);
950 max_send = MIN(max_send,smb_bufsize);
952 done_sesssetup = True;
954 END_PROFILE(SMBsesssetupX);
955 return chain_reply(inbuf,outbuf,length,bufsize);