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
;
155 BOOL foreign
= False
;
156 DATA_BLOB nullblob
= data_blob(NULL
, 0);
157 fstring real_username
;
160 ZERO_STRUCT(auth_data
);
162 ZERO_STRUCT(ap_rep_wrapped
);
163 ZERO_STRUCT(response
);
165 if (!spnego_parse_krb5_wrap(*secblob
, &ticket
, tok_id
)) {
166 return ERROR_NT(NT_STATUS_LOGON_FAILURE
);
169 ret
= ads_verify_ticket(lp_realm(), &ticket
, &client
, &auth_data
, &ap_rep
, &session_key
);
171 data_blob_free(&ticket
);
173 if (!NT_STATUS_IS_OK(ret
)) {
174 DEBUG(1,("Failed to verify incoming ticket!\n"));
175 return ERROR_NT(NT_STATUS_LOGON_FAILURE
);
178 data_blob_free(&auth_data
);
180 DEBUG(3,("Ticket name is [%s]\n", client
));
182 p
= strchr_m(client
, '@');
184 DEBUG(3,("Doesn't look like a valid principal\n"));
185 data_blob_free(&ap_rep
);
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
);
196 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 pw
= smb_getpwnam( user
, real_username
, True
);
248 DEBUG(1,("Username %s is invalid on this system\n",user
));
251 data_blob_free(&ap_rep
);
252 return ERROR_NT(NT_STATUS_LOGON_FAILURE
);
255 /* setup the string used by %U */
257 sub_set_smb_name( real_username
);
258 reload_services(True
);
260 if (!NT_STATUS_IS_OK(ret
= make_server_info_pw(&server_info
, real_username
, pw
)))
262 DEBUG(1,("make_server_info_from_pw failed!\n"));
265 data_blob_free(&ap_rep
);
266 return ERROR_NT(ret
);
269 /* make_server_info_pw does not set the domain. Without this we end up
270 * with the local netbios name in substitutions for %D. */
272 if (server_info
->sam_account
!= NULL
) {
273 pdb_set_domain(server_info
->sam_account
, domain
, PDB_SET
);
276 /* register_vuid keeps the server info */
277 sess_vuid
= register_vuid(server_info
, session_key
, nullblob
, client
);
282 if (sess_vuid
== -1) {
283 ret
= NT_STATUS_LOGON_FAILURE
;
285 /* current_user_info is changed on new vuid */
286 reload_services( True
);
288 set_message(outbuf
,4,0,True
);
289 SSVAL(outbuf
, smb_vwv3
, 0);
291 if (server_info
->guest
) {
292 SSVAL(outbuf
,smb_vwv2
,1);
295 SSVAL(outbuf
, smb_uid
, sess_vuid
);
297 if (!server_info
->guest
) {
298 /* We need to start the signing engine
299 * here but a W2K client sends the old
300 * "BSRSPYL " signature instead of the
301 * correct one. Subsequent packets will
304 srv_check_sign_mac(inbuf
);
308 /* wrap that up in a nice GSS-API wrapping */
309 if (NT_STATUS_IS_OK(ret
)) {
310 ap_rep_wrapped
= spnego_gen_krb5_wrap(ap_rep
, TOK_ID_KRB_AP_REP
);
312 ap_rep_wrapped
= data_blob(NULL
, 0);
314 response
= spnego_gen_auth_response(&ap_rep_wrapped
, ret
, OID_KERBEROS5_OLD
);
315 reply_sesssetup_blob(conn
, outbuf
, response
, ret
);
317 data_blob_free(&ap_rep
);
318 data_blob_free(&ap_rep_wrapped
);
319 data_blob_free(&response
);
321 return -1; /* already replied */
325 /****************************************************************************
326 Send a session setup reply, wrapped in SPNEGO.
327 Get vuid and check first.
328 End the NTLMSSP exchange context if we are OK/complete fail
329 ***************************************************************************/
331 static BOOL
reply_spnego_ntlmssp(connection_struct
*conn
, char *inbuf
, char *outbuf
,
332 AUTH_NTLMSSP_STATE
**auth_ntlmssp_state
,
333 DATA_BLOB
*ntlmssp_blob
, NTSTATUS nt_status
)
337 struct auth_serversupplied_info
*server_info
= NULL
;
339 if (NT_STATUS_IS_OK(nt_status
)) {
340 server_info
= (*auth_ntlmssp_state
)->server_info
;
342 nt_status
= do_map_to_guest(nt_status
,
344 (*auth_ntlmssp_state
)->ntlmssp_state
->user
,
345 (*auth_ntlmssp_state
)->ntlmssp_state
->domain
);
348 if (NT_STATUS_IS_OK(nt_status
)) {
350 DATA_BLOB nullblob
= data_blob(NULL
, 0);
351 DATA_BLOB session_key
= data_blob((*auth_ntlmssp_state
)->ntlmssp_state
->session_key
.data
, (*auth_ntlmssp_state
)->ntlmssp_state
->session_key
.length
);
353 /* register_vuid keeps the server info */
354 sess_vuid
= register_vuid(server_info
, session_key
, nullblob
, (*auth_ntlmssp_state
)->ntlmssp_state
->user
);
355 (*auth_ntlmssp_state
)->server_info
= NULL
;
357 if (sess_vuid
== -1) {
358 nt_status
= NT_STATUS_LOGON_FAILURE
;
361 /* current_user_info is changed on new vuid */
362 reload_services( True
);
364 set_message(outbuf
,4,0,True
);
365 SSVAL(outbuf
, smb_vwv3
, 0);
367 if (server_info
->guest
) {
368 SSVAL(outbuf
,smb_vwv2
,1);
371 SSVAL(outbuf
,smb_uid
,sess_vuid
);
373 if (!server_info
->guest
) {
374 /* We need to start the signing engine
375 * here but a W2K client sends the old
376 * "BSRSPYL " signature instead of the
377 * correct one. Subsequent packets will
380 srv_check_sign_mac(inbuf
);
385 response
= spnego_gen_auth_response(ntlmssp_blob
, nt_status
, OID_NTLMSSP
);
386 ret
= reply_sesssetup_blob(conn
, outbuf
, response
, nt_status
);
387 data_blob_free(&response
);
389 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
390 and the other end, that we are not finished yet. */
392 if (!ret
|| !NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
393 auth_ntlmssp_end(auth_ntlmssp_state
);
399 /****************************************************************************
400 Reply to a session setup spnego negotiate packet.
401 ****************************************************************************/
403 static int reply_spnego_negotiate(connection_struct
*conn
,
406 int length
, int bufsize
,
409 char *OIDs
[ASN1_MAX_OIDS
];
413 BOOL got_kerberos
= False
;
416 /* parse out the OIDs and the first sec blob */
417 if (!parse_negTokenTarg(blob1
, OIDs
, &secblob
)) {
418 return ERROR_NT(NT_STATUS_LOGON_FAILURE
);
421 /* only look at the first OID for determining the mechToken --
422 accoirding to RFC2478, we should choose the one we want
423 and renegotiate, but i smell a client bug here..
425 Problem observed when connecting to a member (samba box)
426 of an AD domain as a user in a Samba domain. Samba member
427 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
428 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
429 NTLMSSP mechtoken. --jerry */
431 if (strcmp(OID_KERBEROS5
, OIDs
[0]) == 0 ||
432 strcmp(OID_KERBEROS5_OLD
, OIDs
[0]) == 0) {
436 for (i
=0;OIDs
[i
];i
++) {
437 DEBUG(3,("Got OID %s\n", OIDs
[i
]));
440 DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob
.length
));
443 if (got_kerberos
&& (SEC_ADS
== lp_security())) {
444 int ret
= reply_spnego_kerberos(conn
, inbuf
, outbuf
,
445 length
, bufsize
, &secblob
);
446 data_blob_free(&secblob
);
451 if (global_ntlmssp_state
) {
452 auth_ntlmssp_end(&global_ntlmssp_state
);
455 nt_status
= auth_ntlmssp_start(&global_ntlmssp_state
);
456 if (!NT_STATUS_IS_OK(nt_status
)) {
457 return ERROR_NT(nt_status
);
460 nt_status
= auth_ntlmssp_update(global_ntlmssp_state
,
463 data_blob_free(&secblob
);
465 reply_spnego_ntlmssp(conn
, inbuf
, outbuf
, &global_ntlmssp_state
,
468 data_blob_free(&chal
);
470 /* already replied */
474 /****************************************************************************
475 Reply to a session setup spnego auth packet.
476 ****************************************************************************/
478 static int reply_spnego_auth(connection_struct
*conn
, char *inbuf
, char *outbuf
,
479 int length
, int bufsize
,
482 DATA_BLOB auth
, auth_reply
;
483 NTSTATUS nt_status
= NT_STATUS_INVALID_PARAMETER
;
485 if (!spnego_parse_auth(blob1
, &auth
)) {
487 file_save("auth.dat", blob1
.data
, blob1
.length
);
489 return ERROR_NT(NT_STATUS_INVALID_PARAMETER
);
492 if (!global_ntlmssp_state
) {
493 /* auth before negotiatiate? */
494 return ERROR_NT(NT_STATUS_INVALID_PARAMETER
);
497 nt_status
= auth_ntlmssp_update(global_ntlmssp_state
,
500 data_blob_free(&auth
);
502 reply_spnego_ntlmssp(conn
, inbuf
, outbuf
, &global_ntlmssp_state
,
503 &auth_reply
, nt_status
);
505 data_blob_free(&auth_reply
);
507 /* and tell smbd that we have already replied to this packet */
511 /****************************************************************************
512 Reply to a session setup command.
513 ****************************************************************************/
515 static int reply_sesssetup_and_X_spnego(connection_struct
*conn
, char *inbuf
,
517 int length
,int bufsize
)
523 fstring native_os
, native_lanman
, primary_domain
;
525 uint16 data_blob_len
= SVAL(inbuf
, smb_vwv7
);
526 enum remote_arch_types ra_type
= get_remote_arch();
528 DEBUG(3,("Doing spnego session setup\n"));
530 if (global_client_caps
== 0) {
531 global_client_caps
= IVAL(inbuf
,smb_vwv10
);
533 if (!(global_client_caps
& CAP_STATUS32
)) {
534 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES
);
539 p
= (uint8
*)smb_buf(inbuf
);
541 if (data_blob_len
== 0) {
542 /* an invalid request */
543 return ERROR_NT(NT_STATUS_LOGON_FAILURE
);
546 bufrem
= smb_bufrem(inbuf
, p
);
547 /* pull the spnego blob */
548 blob1
= data_blob(p
, MIN(bufrem
, data_blob_len
));
551 file_save("negotiate.dat", blob1
.data
, blob1
.length
);
554 p2
= inbuf
+ smb_vwv13
+ data_blob_len
;
555 p2
+= srvstr_pull_buf(inbuf
, native_os
, p2
, sizeof(native_os
), STR_TERMINATE
);
556 p2
+= srvstr_pull_buf(inbuf
, native_lanman
, p2
, sizeof(native_lanman
), STR_TERMINATE
);
557 p2
+= srvstr_pull_buf(inbuf
, primary_domain
, p2
, sizeof(primary_domain
), STR_TERMINATE
);
558 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
559 native_os
, native_lanman
, primary_domain
));
561 if ( ra_type
== RA_WIN2K
) {
562 /* Windows 2003 doesn't set the native lanman string,
563 but does set primary domain which is a bug I think */
565 if ( !strlen(native_lanman
) )
566 ra_lanman_string( primary_domain
);
568 ra_lanman_string( native_lanman
);
571 if (blob1
.data
[0] == ASN1_APPLICATION(0)) {
572 /* its a negTokenTarg packet */
573 ret
= reply_spnego_negotiate(conn
, inbuf
, outbuf
, length
, bufsize
, blob1
);
574 data_blob_free(&blob1
);
578 if (blob1
.data
[0] == ASN1_CONTEXT(1)) {
579 /* its a auth packet */
580 ret
= reply_spnego_auth(conn
, inbuf
, outbuf
, length
, bufsize
, blob1
);
581 data_blob_free(&blob1
);
585 /* what sort of packet is this? */
586 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
588 data_blob_free(&blob1
);
590 return ERROR_NT(NT_STATUS_LOGON_FAILURE
);
593 /****************************************************************************
594 On new VC == 0, shutdown *all* old connections and users.
595 It seems that only NT4.x does this. At W2K and above (XP etc.).
596 a new session setup with VC==0 is ignored.
597 ****************************************************************************/
599 static void setup_new_vc_session(void)
601 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
604 invalidate_all_vuids();
608 /****************************************************************************
609 Reply to a session setup command.
610 ****************************************************************************/
612 int reply_sesssetup_and_X(connection_struct
*conn
, char *inbuf
,char *outbuf
,
613 int length
,int bufsize
)
619 DATA_BLOB plaintext_password
;
621 fstring sub_user
; /* Sainitised username for substituion */
624 fstring native_lanman
;
625 fstring primary_domain
;
626 static BOOL done_sesssetup
= False
;
627 extern BOOL global_encrypted_passwords_negotiated
;
628 extern BOOL global_spnego_negotiated
;
632 auth_usersupplied_info
*user_info
= NULL
;
633 extern struct auth_context
*negprot_global_auth_context
;
634 auth_serversupplied_info
*server_info
= NULL
;
638 BOOL doencrypt
= global_encrypted_passwords_negotiated
;
640 DATA_BLOB session_key
;
642 START_PROFILE(SMBsesssetupX
);
644 ZERO_STRUCT(lm_resp
);
645 ZERO_STRUCT(nt_resp
);
646 ZERO_STRUCT(plaintext_password
);
648 DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf
, smb_wct
), SVAL(inbuf
, smb_flg2
)));
650 /* a SPNEGO session setup has 12 command words, whereas a normal
651 NT1 session setup has 13. See the cifs spec. */
652 if (CVAL(inbuf
, smb_wct
) == 12 &&
653 (SVAL(inbuf
, smb_flg2
) & FLAGS2_EXTENDED_SECURITY
)) {
654 if (!global_spnego_negotiated
) {
655 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
656 return ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
659 if (SVAL(inbuf
,smb_vwv4
) == 0) {
660 setup_new_vc_session();
662 return reply_sesssetup_and_X_spnego(conn
, inbuf
, outbuf
, length
, bufsize
);
665 smb_bufsize
= SVAL(inbuf
,smb_vwv2
);
667 if (Protocol
< PROTOCOL_NT1
) {
668 uint16 passlen1
= SVAL(inbuf
,smb_vwv7
);
669 if ((passlen1
> MAX_PASS_LEN
) || (passlen1
> smb_bufrem(inbuf
, smb_buf(inbuf
)))) {
670 return ERROR_NT(NT_STATUS_INVALID_PARAMETER
);
674 lm_resp
= data_blob(smb_buf(inbuf
), passlen1
);
676 plaintext_password
= data_blob(smb_buf(inbuf
), passlen1
+1);
677 /* Ensure null termination */
678 plaintext_password
.data
[passlen1
] = 0;
681 srvstr_pull_buf(inbuf
, user
, smb_buf(inbuf
)+passlen1
, sizeof(user
), STR_TERMINATE
);
685 uint16 passlen1
= SVAL(inbuf
,smb_vwv7
);
686 uint16 passlen2
= SVAL(inbuf
,smb_vwv8
);
687 enum remote_arch_types ra_type
= get_remote_arch();
688 char *p
= smb_buf(inbuf
);
689 char *save_p
= smb_buf(inbuf
);
693 if(global_client_caps
== 0) {
694 global_client_caps
= IVAL(inbuf
,smb_vwv11
);
696 if (!(global_client_caps
& CAP_STATUS32
)) {
697 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES
);
700 /* client_caps is used as final determination if client is NT or Win95.
701 This is needed to return the correct error codes in some
705 if(ra_type
== RA_WINNT
|| ra_type
== RA_WIN2K
|| ra_type
== RA_WIN95
) {
706 if(!(global_client_caps
& (CAP_NT_SMBS
| CAP_STATUS32
))) {
707 set_remote_arch( RA_WIN95
);
713 /* both Win95 and WinNT stuff up the password lengths for
714 non-encrypting systems. Uggh.
716 if passlen1==24 its a win95 system, and its setting the
717 password length incorrectly. Luckily it still works with the
718 default code because Win95 will null terminate the password
721 if passlen1>0 and passlen2>0 then maybe its a NT box and its
722 setting passlen2 to some random value which really stuffs
723 things up. we need to fix that one. */
725 if (passlen1
> 0 && passlen2
> 0 && passlen2
!= 24 && passlen2
!= 1)
729 /* check for nasty tricks */
730 if (passlen1
> MAX_PASS_LEN
|| passlen1
> smb_bufrem(inbuf
, p
)) {
731 return ERROR_NT(NT_STATUS_INVALID_PARAMETER
);
734 if (passlen2
> MAX_PASS_LEN
|| passlen2
> smb_bufrem(inbuf
, p
+passlen1
)) {
735 return ERROR_NT(NT_STATUS_INVALID_PARAMETER
);
738 /* Save the lanman2 password and the NT md4 password. */
740 if ((doencrypt
) && (passlen1
!= 0) && (passlen1
!= 24)) {
745 lm_resp
= data_blob(p
, passlen1
);
746 nt_resp
= data_blob(p
+passlen1
, passlen2
);
749 BOOL unic
=SVAL(inbuf
, smb_flg2
) & FLAGS2_UNICODE_STRINGS
;
751 if ((ra_type
== RA_WINNT
) && (passlen2
== 0) && unic
&& passlen1
) {
752 /* NT4.0 stuffs up plaintext unicode password lengths... */
753 srvstr_pull(inbuf
, pass
, smb_buf(inbuf
) + 1,
754 sizeof(pass
), passlen1
, STR_TERMINATE
);
756 srvstr_pull(inbuf
, pass
, smb_buf(inbuf
),
757 sizeof(pass
), unic
? passlen2
: passlen1
,
760 plaintext_password
= data_blob(pass
, strlen(pass
)+1);
763 p
+= passlen1
+ passlen2
;
764 p
+= srvstr_pull_buf(inbuf
, user
, p
, sizeof(user
), STR_TERMINATE
);
765 p
+= srvstr_pull_buf(inbuf
, domain
, p
, sizeof(domain
), STR_TERMINATE
);
766 p
+= srvstr_pull_buf(inbuf
, native_os
, p
, sizeof(native_os
), STR_TERMINATE
);
767 p
+= srvstr_pull_buf(inbuf
, native_lanman
, p
, sizeof(native_lanman
), STR_TERMINATE
);
769 /* not documented or decoded by Ethereal but there is one more string
770 in the extra bytes which is the same as the PrimaryDomain when using
771 extended security. Windows NT 4 and 2003 use this string to store
772 the native lanman string. Windows 9x does not include a string here
773 at all so we have to check if we have any extra bytes left */
775 byte_count
= SVAL(inbuf
, smb_vwv13
);
776 if ( PTR_DIFF(p
, save_p
) < byte_count
)
777 p
+= srvstr_pull_buf(inbuf
, primary_domain
, p
, sizeof(primary_domain
), STR_TERMINATE
);
779 fstrcpy( primary_domain
, "null" );
781 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
782 domain
, native_os
, native_lanman
, primary_domain
));
784 if ( ra_type
== RA_WIN2K
) {
785 if ( strlen(native_lanman
) == 0 )
786 ra_lanman_string( primary_domain
);
788 ra_lanman_string( native_lanman
);
793 if (SVAL(inbuf
,smb_vwv4
) == 0) {
794 setup_new_vc_session();
797 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain
, user
, get_remote_machine_name()));
800 if (global_spnego_negotiated
) {
802 /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
804 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
805 return ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
807 fstrcpy(sub_user
, user
);
809 /* setup the string used by %U */
810 sub_set_smb_name(user
);
812 fstrcpy(sub_user
, lp_guestaccount());
815 sub_set_smb_name(sub_user
);
817 reload_services(True
);
819 if (lp_security() == SEC_SHARE
) {
820 /* in share level we should ignore any passwords */
822 data_blob_free(&lm_resp
);
823 data_blob_free(&nt_resp
);
824 data_blob_clear_free(&plaintext_password
);
826 map_username(sub_user
);
827 add_session_user(sub_user
);
828 /* Then force it to null for the benfit of the code below */
834 nt_status
= check_guest_password(&server_info
);
836 } else if (doencrypt
) {
837 if (!negprot_global_auth_context
) {
838 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted session setup without negprot denied!\n"));
839 return ERROR_NT(NT_STATUS_LOGON_FAILURE
);
841 nt_status
= make_user_info_for_reply_enc(&user_info
, user
, domain
,
843 if (NT_STATUS_IS_OK(nt_status
)) {
844 nt_status
= negprot_global_auth_context
->check_ntlm_password(negprot_global_auth_context
,
849 struct auth_context
*plaintext_auth_context
= NULL
;
851 if (NT_STATUS_IS_OK(nt_status
= make_auth_context_subsystem(&plaintext_auth_context
))) {
852 chal
= plaintext_auth_context
->get_ntlm_challenge(plaintext_auth_context
);
854 if (!make_user_info_for_reply(&user_info
,
856 plaintext_password
)) {
857 nt_status
= NT_STATUS_NO_MEMORY
;
860 if (NT_STATUS_IS_OK(nt_status
)) {
861 nt_status
= plaintext_auth_context
->check_ntlm_password(plaintext_auth_context
,
865 (plaintext_auth_context
->free
)(&plaintext_auth_context
);
870 free_user_info(&user_info
);
872 if (!NT_STATUS_IS_OK(nt_status
)) {
873 nt_status
= do_map_to_guest(nt_status
, &server_info
, user
, domain
);
876 if (!NT_STATUS_IS_OK(nt_status
)) {
877 data_blob_free(&nt_resp
);
878 data_blob_free(&lm_resp
);
879 data_blob_clear_free(&plaintext_password
);
880 return ERROR_NT(nt_status_squash(nt_status
));
883 if (server_info
->nt_session_key
.data
) {
884 session_key
= data_blob(server_info
->nt_session_key
.data
, server_info
->nt_session_key
.length
);
885 } else if (server_info
->lm_session_key
.length
>= 8 && lm_resp
.length
== 24) {
886 session_key
= data_blob(NULL
, 16);
887 SMBsesskeygen_lmv1(server_info
->lm_session_key
.data
, lm_resp
.data
,
890 session_key
= data_blob(NULL
, 0);
893 data_blob_free(&lm_resp
);
894 data_blob_clear_free(&plaintext_password
);
896 /* it's ok - setup a reply */
897 set_message(outbuf
,3,0,True
);
898 if (Protocol
>= PROTOCOL_NT1
) {
899 char *p
= smb_buf( outbuf
);
900 p
+= add_signature( outbuf
, p
);
901 set_message_end( outbuf
, p
);
902 /* perhaps grab OS version here?? */
905 if (server_info
->guest
) {
906 SSVAL(outbuf
,smb_vwv2
,1);
909 /* register the name and uid as being validated, so further connections
910 to a uid can get through without a password, on the same VC */
912 /* register_vuid keeps the server info */
913 sess_vuid
= register_vuid(server_info
, session_key
, nt_resp
, sub_user
);
914 data_blob_free(&nt_resp
);
916 if (sess_vuid
== -1) {
917 return ERROR_NT(NT_STATUS_LOGON_FAILURE
);
920 /* current_user_info is changed on new vuid */
921 reload_services( True
);
923 if (!server_info
->guest
&& !srv_check_sign_mac(inbuf
)) {
924 exit_server("reply_sesssetup_and_X: bad smb signature");
927 SSVAL(outbuf
,smb_uid
,sess_vuid
);
928 SSVAL(inbuf
,smb_uid
,sess_vuid
);
931 max_send
= MIN(max_send
,smb_bufsize
);
933 done_sesssetup
= True
;
935 END_PROFILE(SMBsesssetupX
);
936 return chain_reply(inbuf
,outbuf
,length
,bufsize
);