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
,
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
;
157 BOOL map_domainuser_to_guest
= False
;
158 PAC_LOGON_INFO
*logon_info
= NULL
;
161 ZERO_STRUCT(pac_data
);
163 ZERO_STRUCT(ap_rep_wrapped
);
164 ZERO_STRUCT(response
);
166 mem_ctx
= talloc_init("reply_spnego_kerberos");
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
, '@');
187 DEBUG(3,("Doesn't look like a valid principal\n"));
188 data_blob_free(&ap_rep
);
189 data_blob_free(&session_key
);
191 return ERROR_NT(NT_STATUS_LOGON_FAILURE
);
196 /* save the PAC data if we have it */
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
);
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? */
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
));
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
));
255 DEBUG(3, ("Could not find short name -- winbind "
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
);
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 */
282 DEBUG(1,("Username %s is invalid on this system\n", user
));
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"));
302 data_blob_free(&ap_rep
);
303 data_blob_free(&session_key
);
305 return ERROR_NT(ret
);
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"));
314 data_blob_free(&ap_rep
);
315 data_blob_free(&session_key
);
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
);
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
);
338 if (sess_vuid
== -1) {
339 ret
= NT_STATUS_LOGON_FAILURE
;
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
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
);
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 */
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
,
392 AUTH_NTLMSSP_STATE
**auth_ntlmssp_state
,
393 DATA_BLOB
*ntlmssp_blob
, NTSTATUS nt_status
,
398 struct auth_serversupplied_info
*server_info
= NULL
;
400 if (NT_STATUS_IS_OK(nt_status
)) {
401 server_info
= (*auth_ntlmssp_state
)->server_info
;
403 nt_status
= do_map_to_guest(nt_status
,
405 (*auth_ntlmssp_state
)->ntlmssp_state
->user
,
406 (*auth_ntlmssp_state
)->ntlmssp_state
->domain
);
409 if (NT_STATUS_IS_OK(nt_status
)) {
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
;
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
442 srv_check_sign_mac(inbuf
, False
);
448 response
= spnego_gen_auth_response(ntlmssp_blob
, nt_status
, OID_NTLMSSP
);
450 response
= *ntlmssp_blob
;
453 ret
= reply_sesssetup_blob(conn
, outbuf
, response
, nt_status
);
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
);
471 /****************************************************************************
472 Reply to a session setup spnego negotiate packet.
473 ****************************************************************************/
475 static int reply_spnego_negotiate(connection_struct
*conn
,
479 int length
, int bufsize
,
481 AUTH_NTLMSSP_STATE
**auth_ntlmssp_state
)
483 char *OIDs
[ASN1_MAX_OIDS
];
488 BOOL got_kerberos_mechanism
= False
;
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 */
511 if (strcmp(OID_KERBEROS5
, OIDs
[0]) == 0 ||
512 strcmp(OID_KERBEROS5_OLD
, OIDs
[0]) == 0) {
513 got_kerberos_mechanism
= True
;
517 for (i
=0;OIDs
[i
];i
++) {
518 DEBUG(3,("Got OID %s\n", OIDs
[i
]));
521 DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob
.length
));
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
);
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
,
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 */
561 /****************************************************************************
562 Reply to a session setup spnego auth packet.
563 ****************************************************************************/
565 static int reply_spnego_auth(connection_struct
*conn
, char *inbuf
, char *outbuf
,
567 int length
, int bufsize
,
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
)) {
576 file_save("auth.dat", blob1
.data
, blob1
.length
);
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
,
595 data_blob_free(&auth
);
597 reply_spnego_ntlmssp(conn
, inbuf
, outbuf
, vuid
,
599 &auth_reply
, nt_status
, True
);
601 data_blob_free(&auth_reply
);
603 /* and tell smbd that we have already replied to this packet */
607 /****************************************************************************
608 Reply to a session setup command.
609 ****************************************************************************/
611 static int reply_sesssetup_and_X_spnego(connection_struct
*conn
, char *inbuf
,
613 int length
,int bufsize
)
619 fstring native_os
, native_lanman
, primary_domain
;
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
));
649 file_save("negotiate.dat", blob1
.data
, blob1
.length
);
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
);
666 ra_lanman_string( native_lanman
);
669 vuser
= get_partial_auth_user_struct(vuid
);
671 vuid
= register_vuid(NULL
, data_blob(NULL
, 0), data_blob(NULL
, 0), NULL
);
673 return ERROR_NT(NT_STATUS_INVALID_PARAMETER
);
676 vuser
= get_partial_auth_user_struct(vuid
);
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
);
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
);
701 if (strncmp((char *)(blob1
.data
), "NTLMSSP", 7) == 0) {
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
,
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
);
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"));
745 invalidate_all_vuids();
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
)
760 DATA_BLOB plaintext_password
;
762 fstring sub_user
; /* Sainitised username for substituion */
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
;
773 auth_usersupplied_info
*user_info
= NULL
;
774 extern struct auth_context
*negprot_global_auth_context
;
775 auth_serversupplied_info
*server_info
= NULL
;
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
);
819 lm_resp
= data_blob(smb_buf(inbuf
), passlen1
);
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
);
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
);
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
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
);
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
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)
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)) {
890 lm_resp
= data_blob(p
, passlen1
);
891 nt_resp
= data_blob(p
+passlen1
, passlen2
);
894 BOOL unic
=SVAL(inbuf
, smb_flg2
) & FLAGS2_UNICODE_STRINGS
;
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
);
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
);
909 srvstr_pull(inbuf
, pass
, smb_buf(inbuf
),
910 sizeof(pass
), unic
? passlen2
: passlen1
,
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
);
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
);
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()));
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
);
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 */
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
,
993 if (NT_STATUS_IS_OK(nt_status
)) {
994 nt_status
= negprot_global_auth_context
->check_ntlm_password(negprot_global_auth_context
,
999 struct auth_context
*plaintext_auth_context
= NULL
;
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
,
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
,
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
);
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
);