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;
29 on a logon error possibly map the error to success if "map to guest"
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",
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);
54 /****************************************************************************
55 Add the standard 'Samba' signature to the end of the session setup.
56 ****************************************************************************/
58 static int add_signature(char *outbuf, char *p)
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)
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);
89 /* should we cap this? */
90 memcpy(p, blob.data, blob.length);
93 p += add_signature( outbuf, p );
95 set_message_end(outbuf,p);
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;
111 unsigned char chal[8];
115 DEBUG(3,("Got anonymous request\n"));
117 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
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);
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,
143 char *client, *p, *domain;
144 fstring netbios_domain_name;
150 DATA_BLOB ap_rep, ap_rep_wrapped, response;
151 auth_serversupplied_info *server_info = NULL;
152 DATA_BLOB session_key = data_blob(NULL, 0);
154 DATA_BLOB nullblob = data_blob(NULL, 0);
155 fstring real_username;
156 BOOL map_domainuser_to_guest = False;
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_response(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 fstr_sprintf(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 /* this was originally the behavior of Samba 2.2, if a user
251 did not have a local uid but has been authenticated, then
252 map them to a guest account */
254 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
255 map_domainuser_to_guest = True;
256 fstrcpy(user,lp_guestaccount());
257 pw = smb_getpwnam( user, real_username, True );
260 /* extra sanity check that the guest account is valid */
263 DEBUG(1,("Username %s is invalid on this system\n", user));
265 data_blob_free(&ap_rep);
266 data_blob_free(&session_key);
267 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
271 /* setup the string used by %U */
273 sub_set_smb_name( real_username );
274 reload_services(True);
275 if ( map_domainuser_to_guest ) {
276 make_server_info_guest(&server_info);
278 ret = make_server_info_pw(&server_info, real_username, pw);
279 if ( !NT_STATUS_IS_OK(ret) ) {
280 DEBUG(1,("make_server_info_from_pw failed!\n"));
282 data_blob_free(&ap_rep);
283 data_blob_free(&session_key);
285 return ERROR_NT(ret);
290 /* make_server_info_pw does not set the domain. Without this we end up
291 * with the local netbios name in substitutions for %D. */
293 if (server_info->sam_account != NULL) {
294 pdb_set_domain(server_info->sam_account, domain, PDB_SET);
297 /* register_vuid keeps the server info */
298 /* register_vuid takes ownership of session_key, no need to free after this.
299 A better interface would copy it.... */
300 sess_vuid = register_vuid(server_info, session_key, nullblob, client);
304 if (sess_vuid == -1) {
305 ret = NT_STATUS_LOGON_FAILURE;
307 /* current_user_info is changed on new vuid */
308 reload_services( True );
310 set_message(outbuf,4,0,True);
311 SSVAL(outbuf, smb_vwv3, 0);
313 if (server_info->guest) {
314 SSVAL(outbuf,smb_vwv2,1);
317 SSVAL(outbuf, smb_uid, sess_vuid);
319 if (!server_info->guest && !srv_signing_started()) {
320 /* We need to start the signing engine
321 * here but a W2K client sends the old
322 * "BSRSPYL " signature instead of the
323 * correct one. Subsequent packets will
326 srv_check_sign_mac(inbuf, False);
330 /* wrap that up in a nice GSS-API wrapping */
331 if (NT_STATUS_IS_OK(ret)) {
332 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
334 ap_rep_wrapped = data_blob(NULL, 0);
336 response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
337 reply_sesssetup_blob(conn, outbuf, response, ret);
339 data_blob_free(&ap_rep);
340 data_blob_free(&ap_rep_wrapped);
341 data_blob_free(&response);
343 return -1; /* already replied */
347 /****************************************************************************
348 Send a session setup reply, wrapped in SPNEGO.
349 Get vuid and check first.
350 End the NTLMSSP exchange context if we are OK/complete fail
351 ***************************************************************************/
353 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
355 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
356 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
361 struct auth_serversupplied_info *server_info = NULL;
363 if (NT_STATUS_IS_OK(nt_status)) {
364 server_info = (*auth_ntlmssp_state)->server_info;
366 nt_status = do_map_to_guest(nt_status,
368 (*auth_ntlmssp_state)->ntlmssp_state->user,
369 (*auth_ntlmssp_state)->ntlmssp_state->domain);
372 if (NT_STATUS_IS_OK(nt_status)) {
374 DATA_BLOB nullblob = data_blob(NULL, 0);
375 DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
377 /* register_vuid keeps the server info */
378 sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
379 (*auth_ntlmssp_state)->server_info = NULL;
381 if (sess_vuid == -1) {
382 nt_status = NT_STATUS_LOGON_FAILURE;
385 /* current_user_info is changed on new vuid */
386 reload_services( True );
388 set_message(outbuf,4,0,True);
389 SSVAL(outbuf, smb_vwv3, 0);
391 if (server_info->guest) {
392 SSVAL(outbuf,smb_vwv2,1);
395 SSVAL(outbuf,smb_uid,sess_vuid);
397 if (!server_info->guest && !srv_signing_started()) {
398 /* We need to start the signing engine
399 * here but a W2K client sends the old
400 * "BSRSPYL " signature instead of the
401 * correct one. Subsequent packets will
405 srv_check_sign_mac(inbuf, False);
411 response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
413 response = *ntlmssp_blob;
416 ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
418 data_blob_free(&response);
421 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
422 and the other end, that we are not finished yet. */
424 if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
425 auth_ntlmssp_end(auth_ntlmssp_state);
426 /* Kill the intermediate vuid */
427 invalidate_vuid(vuid);
433 /****************************************************************************
434 Reply to a session setup spnego negotiate packet.
435 ****************************************************************************/
437 static int reply_spnego_negotiate(connection_struct *conn,
441 int length, int bufsize,
443 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
445 char *OIDs[ASN1_MAX_OIDS];
450 BOOL got_kerberos_mechanism = False;
454 /* parse out the OIDs and the first sec blob */
455 if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
456 /* Kill the intermediate vuid */
457 invalidate_vuid(vuid);
459 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
462 /* only look at the first OID for determining the mechToken --
463 accoirding to RFC2478, we should choose the one we want
464 and renegotiate, but i smell a client bug here..
466 Problem observed when connecting to a member (samba box)
467 of an AD domain as a user in a Samba domain. Samba member
468 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
469 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
470 NTLMSSP mechtoken. --jerry */
473 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
474 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
475 got_kerberos_mechanism = True;
479 for (i=0;OIDs[i];i++) {
480 DEBUG(3,("Got OID %s\n", OIDs[i]));
483 DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length));
486 if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
487 int ret = reply_spnego_kerberos(conn, inbuf, outbuf,
488 length, bufsize, &secblob);
489 data_blob_free(&secblob);
490 /* Kill the intermediate vuid */
491 invalidate_vuid(vuid);
497 if (*auth_ntlmssp_state) {
498 auth_ntlmssp_end(auth_ntlmssp_state);
501 nt_status = auth_ntlmssp_start(auth_ntlmssp_state);
502 if (!NT_STATUS_IS_OK(nt_status)) {
503 /* Kill the intermediate vuid */
504 invalidate_vuid(vuid);
506 return ERROR_NT(nt_status);
509 nt_status = auth_ntlmssp_update(*auth_ntlmssp_state,
512 data_blob_free(&secblob);
514 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state,
515 &chal, nt_status, True);
517 data_blob_free(&chal);
519 /* already replied */
523 /****************************************************************************
524 Reply to a session setup spnego auth packet.
525 ****************************************************************************/
527 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
529 int length, int bufsize,
531 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
533 DATA_BLOB auth, auth_reply;
534 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
536 if (!spnego_parse_auth(blob1, &auth)) {
538 file_save("auth.dat", blob1.data, blob1.length);
540 /* Kill the intermediate vuid */
541 invalidate_vuid(vuid);
543 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
546 if (!*auth_ntlmssp_state) {
547 /* Kill the intermediate vuid */
548 invalidate_vuid(vuid);
550 /* auth before negotiatiate? */
551 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
554 nt_status = auth_ntlmssp_update(*auth_ntlmssp_state,
557 data_blob_free(&auth);
559 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid,
561 &auth_reply, nt_status, True);
563 data_blob_free(&auth_reply);
565 /* and tell smbd that we have already replied to this packet */
569 /****************************************************************************
570 Reply to a session setup command.
571 ****************************************************************************/
573 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
575 int length,int bufsize)
581 fstring native_os, native_lanman, primary_domain;
583 uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
584 enum remote_arch_types ra_type = get_remote_arch();
585 int vuid = SVAL(inbuf,smb_uid);
586 user_struct *vuser = NULL;
588 DEBUG(3,("Doing spnego session setup\n"));
590 if (global_client_caps == 0) {
591 global_client_caps = IVAL(inbuf,smb_vwv10);
593 if (!(global_client_caps & CAP_STATUS32)) {
594 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
599 p = (uint8 *)smb_buf(inbuf);
601 if (data_blob_len == 0) {
602 /* an invalid request */
603 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
606 bufrem = smb_bufrem(inbuf, p);
607 /* pull the spnego blob */
608 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
611 file_save("negotiate.dat", blob1.data, blob1.length);
614 p2 = inbuf + smb_vwv13 + data_blob_len;
615 p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
616 p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
617 p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
618 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
619 native_os, native_lanman, primary_domain));
621 if ( ra_type == RA_WIN2K ) {
622 /* Windows 2003 doesn't set the native lanman string,
623 but does set primary domain which is a bug I think */
625 if ( !strlen(native_lanman) )
626 ra_lanman_string( primary_domain );
628 ra_lanman_string( native_lanman );
631 vuser = get_partial_auth_user_struct(vuid);
633 vuid = register_vuid(NULL, data_blob(NULL, 0), data_blob(NULL, 0), NULL);
635 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
638 vuser = get_partial_auth_user_struct(vuid);
642 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
645 SSVAL(outbuf,smb_uid,vuid);
647 if (blob1.data[0] == ASN1_APPLICATION(0)) {
648 /* its a negTokenTarg packet */
649 ret = reply_spnego_negotiate(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
650 &vuser->auth_ntlmssp_state);
651 data_blob_free(&blob1);
655 if (blob1.data[0] == ASN1_CONTEXT(1)) {
656 /* its a auth packet */
657 ret = reply_spnego_auth(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
658 &vuser->auth_ntlmssp_state);
659 data_blob_free(&blob1);
663 if (strncmp(blob1.data, "NTLMSSP", 7) == 0) {
666 if (!vuser->auth_ntlmssp_state) {
667 nt_status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
668 if (!NT_STATUS_IS_OK(nt_status)) {
669 /* Kill the intermediate vuid */
670 invalidate_vuid(vuid);
672 return ERROR_NT(nt_status);
676 nt_status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
679 data_blob_free(&blob1);
681 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid,
682 &vuser->auth_ntlmssp_state,
683 &chal, nt_status, False);
684 data_blob_free(&blob1);
688 /* what sort of packet is this? */
689 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
691 data_blob_free(&blob1);
693 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
696 /****************************************************************************
697 On new VC == 0, shutdown *all* old connections and users.
698 It seems that only NT4.x does this. At W2K and above (XP etc.).
699 a new session setup with VC==0 is ignored.
700 ****************************************************************************/
702 static void setup_new_vc_session(void)
704 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
707 invalidate_all_vuids();
711 /****************************************************************************
712 Reply to a session setup command.
713 ****************************************************************************/
715 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
716 int length,int bufsize)
722 DATA_BLOB plaintext_password;
724 fstring sub_user; /* Sainitised username for substituion */
727 fstring native_lanman;
728 fstring primary_domain;
729 static BOOL done_sesssetup = False;
730 extern BOOL global_encrypted_passwords_negotiated;
731 extern BOOL global_spnego_negotiated;
732 extern enum protocol_types Protocol;
735 auth_usersupplied_info *user_info = NULL;
736 extern struct auth_context *negprot_global_auth_context;
737 auth_serversupplied_info *server_info = NULL;
741 BOOL doencrypt = global_encrypted_passwords_negotiated;
743 DATA_BLOB session_key;
745 START_PROFILE(SMBsesssetupX);
747 ZERO_STRUCT(lm_resp);
748 ZERO_STRUCT(nt_resp);
749 ZERO_STRUCT(plaintext_password);
751 DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
753 /* a SPNEGO session setup has 12 command words, whereas a normal
754 NT1 session setup has 13. See the cifs spec. */
755 if (CVAL(inbuf, smb_wct) == 12 &&
756 (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
757 if (!global_spnego_negotiated) {
758 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
759 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
762 if (SVAL(inbuf,smb_vwv4) == 0) {
763 setup_new_vc_session();
765 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
768 smb_bufsize = SVAL(inbuf,smb_vwv2);
770 if (Protocol < PROTOCOL_NT1) {
771 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
773 /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
774 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
776 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
777 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
781 lm_resp = data_blob(smb_buf(inbuf), passlen1);
783 plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
784 /* Ensure null termination */
785 plaintext_password.data[passlen1] = 0;
788 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
792 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
793 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
794 enum remote_arch_types ra_type = get_remote_arch();
795 char *p = smb_buf(inbuf);
796 char *save_p = smb_buf(inbuf);
800 if(global_client_caps == 0) {
801 global_client_caps = IVAL(inbuf,smb_vwv11);
803 if (!(global_client_caps & CAP_STATUS32)) {
804 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
807 /* client_caps is used as final determination if client is NT or Win95.
808 This is needed to return the correct error codes in some
812 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
813 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
814 set_remote_arch( RA_WIN95);
820 /* both Win95 and WinNT stuff up the password lengths for
821 non-encrypting systems. Uggh.
823 if passlen1==24 its a win95 system, and its setting the
824 password length incorrectly. Luckily it still works with the
825 default code because Win95 will null terminate the password
828 if passlen1>0 and passlen2>0 then maybe its a NT box and its
829 setting passlen2 to some random value which really stuffs
830 things up. we need to fix that one. */
832 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
836 /* check for nasty tricks */
837 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
838 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
841 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
842 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
845 /* Save the lanman2 password and the NT md4 password. */
847 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
852 lm_resp = data_blob(p, passlen1);
853 nt_resp = data_blob(p+passlen1, passlen2);
856 BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
859 /* This was the previous fix. Not sure if it's still valid. JRA. */
860 if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
861 /* NT4.0 stuffs up plaintext unicode password lengths... */
862 srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
863 sizeof(pass), passlen1, STR_TERMINATE);
866 if (unic && (passlen2 == 0) && passlen1) {
867 /* Only a ascii plaintext password was sent. */
868 srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass),
869 passlen1, STR_TERMINATE|STR_ASCII);
871 srvstr_pull(inbuf, pass, smb_buf(inbuf),
872 sizeof(pass), unic ? passlen2 : passlen1,
875 plaintext_password = data_blob(pass, strlen(pass)+1);
878 p += passlen1 + passlen2;
879 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
880 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
881 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
882 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
884 /* not documented or decoded by Ethereal but there is one more string
885 in the extra bytes which is the same as the PrimaryDomain when using
886 extended security. Windows NT 4 and 2003 use this string to store
887 the native lanman string. Windows 9x does not include a string here
888 at all so we have to check if we have any extra bytes left */
890 byte_count = SVAL(inbuf, smb_vwv13);
891 if ( PTR_DIFF(p, save_p) < byte_count)
892 p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
894 fstrcpy( primary_domain, "null" );
896 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
897 domain, native_os, native_lanman, primary_domain));
899 if ( ra_type == RA_WIN2K ) {
900 if ( strlen(native_lanman) == 0 )
901 ra_lanman_string( primary_domain );
903 ra_lanman_string( native_lanman );
908 if (SVAL(inbuf,smb_vwv4) == 0) {
909 setup_new_vc_session();
912 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
915 if (global_spnego_negotiated) {
917 /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
919 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
920 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
922 fstrcpy(sub_user, user);
924 /* setup the string used by %U */
925 sub_set_smb_name(user);
927 fstrcpy(sub_user, lp_guestaccount());
930 sub_set_smb_name(sub_user);
932 reload_services(True);
934 if (lp_security() == SEC_SHARE) {
935 /* in share level we should ignore any passwords */
937 data_blob_free(&lm_resp);
938 data_blob_free(&nt_resp);
939 data_blob_clear_free(&plaintext_password);
941 map_username(sub_user);
942 add_session_user(sub_user);
943 /* Then force it to null for the benfit of the code below */
949 nt_status = check_guest_password(&server_info);
951 } else if (doencrypt) {
952 if (!negprot_global_auth_context) {
953 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted session setup without negprot denied!\n"));
954 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
956 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
958 if (NT_STATUS_IS_OK(nt_status)) {
959 nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context,
964 struct auth_context *plaintext_auth_context = NULL;
966 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
967 chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
969 if (!make_user_info_for_reply(&user_info,
971 plaintext_password)) {
972 nt_status = NT_STATUS_NO_MEMORY;
975 if (NT_STATUS_IS_OK(nt_status)) {
976 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context,
980 (plaintext_auth_context->free)(&plaintext_auth_context);
985 free_user_info(&user_info);
987 if (!NT_STATUS_IS_OK(nt_status)) {
988 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
991 if (!NT_STATUS_IS_OK(nt_status)) {
992 data_blob_free(&nt_resp);
993 data_blob_free(&lm_resp);
994 data_blob_clear_free(&plaintext_password);
995 return ERROR_NT(nt_status_squash(nt_status));
998 if (server_info->user_session_key.data) {
999 session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
1001 session_key = data_blob(NULL, 0);
1004 data_blob_clear_free(&plaintext_password);
1006 /* it's ok - setup a reply */
1007 set_message(outbuf,3,0,True);
1008 if (Protocol >= PROTOCOL_NT1) {
1009 char *p = smb_buf( outbuf );
1010 p += add_signature( outbuf, p );
1011 set_message_end( outbuf, p );
1012 /* perhaps grab OS version here?? */
1015 if (server_info->guest) {
1016 SSVAL(outbuf,smb_vwv2,1);
1019 /* register the name and uid as being validated, so further connections
1020 to a uid can get through without a password, on the same VC */
1022 /* register_vuid keeps the server info */
1023 sess_vuid = register_vuid(server_info, session_key, nt_resp.data ? nt_resp : lm_resp, sub_user);
1024 data_blob_free(&nt_resp);
1025 data_blob_free(&lm_resp);
1027 if (sess_vuid == -1) {
1028 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
1031 /* current_user_info is changed on new vuid */
1032 reload_services( True );
1034 if (!server_info->guest && !srv_signing_started() && !srv_check_sign_mac(inbuf, True)) {
1035 exit_server("reply_sesssetup_and_X: bad smb signature");
1038 SSVAL(outbuf,smb_uid,sess_vuid);
1039 SSVAL(inbuf,smb_uid,sess_vuid);
1041 if (!done_sesssetup)
1042 max_send = MIN(max_send,smb_bufsize);
1044 done_sesssetup = True;
1046 END_PROFILE(SMBsesssetupX);
1047 return chain_reply(inbuf,outbuf,length,bufsize);