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 Start the signing engine if needed. Don't fail signing here.
74 ****************************************************************************/
76 static void sessionsetup_start_signing_engine(const auth_serversupplied_info
*server_info
, char *inbuf
)
78 if (!server_info
->guest
&& !srv_signing_started()) {
79 /* We need to start the signing engine
80 * here but a W2K client sends the old
81 * "BSRSPYL " signature instead of the
82 * correct one. Subsequent packets will
85 srv_check_sign_mac(inbuf
, False
);
89 /****************************************************************************
90 Send a security blob via a session setup reply.
91 ****************************************************************************/
93 static BOOL
reply_sesssetup_blob(connection_struct
*conn
, char *outbuf
,
94 DATA_BLOB blob
, NTSTATUS nt_status
)
98 if (!NT_STATUS_IS_OK(nt_status
) && !NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
99 ERROR_NT(nt_status_squash(nt_status
));
101 set_message(outbuf
,4,0,True
);
103 nt_status
= nt_status_squash(nt_status
);
104 SIVAL(outbuf
, smb_rcls
, NT_STATUS_V(nt_status
));
105 SSVAL(outbuf
, smb_vwv0
, 0xFF); /* no chaining possible */
106 SSVAL(outbuf
, smb_vwv3
, blob
.length
);
109 /* should we cap this? */
110 memcpy(p
, blob
.data
, blob
.length
);
113 p
+= add_signature( outbuf
, p
);
115 set_message_end(outbuf
,p
);
119 return send_smb(smbd_server_fd(),outbuf
);
122 /****************************************************************************
123 Do a 'guest' logon, getting back the
124 ****************************************************************************/
126 static NTSTATUS
check_guest_password(auth_serversupplied_info
**server_info
)
128 struct auth_context
*auth_context
;
129 auth_usersupplied_info
*user_info
= NULL
;
132 unsigned char chal
[8];
136 DEBUG(3,("Got anonymous request\n"));
138 if (!NT_STATUS_IS_OK(nt_status
= make_auth_context_fixed(&auth_context
, chal
))) {
142 if (!make_user_info_guest(&user_info
)) {
143 (auth_context
->free
)(&auth_context
);
144 return NT_STATUS_NO_MEMORY
;
147 nt_status
= auth_context
->check_ntlm_password(auth_context
, user_info
, server_info
);
148 (auth_context
->free
)(&auth_context
);
149 free_user_info(&user_info
);
155 /****************************************************************************
156 reply to a session setup spnego negotiate packet for kerberos
157 ****************************************************************************/
158 static int reply_spnego_kerberos(connection_struct
*conn
,
159 char *inbuf
, char *outbuf
,
160 int length
, int bufsize
,
165 char *client
, *p
, *domain
;
166 fstring netbios_domain_name
;
172 DATA_BLOB ap_rep
, ap_rep_wrapped
, response
;
173 auth_serversupplied_info
*server_info
= NULL
;
174 DATA_BLOB session_key
= data_blob(NULL
, 0);
176 DATA_BLOB nullblob
= data_blob(NULL
, 0);
177 fstring real_username
;
178 BOOL map_domainuser_to_guest
= False
;
179 BOOL username_was_mapped
;
180 PAC_LOGON_INFO
*logon_info
= NULL
;
183 ZERO_STRUCT(pac_data
);
185 ZERO_STRUCT(ap_rep_wrapped
);
186 ZERO_STRUCT(response
);
188 mem_ctx
= talloc_init("reply_spnego_kerberos");
190 return ERROR_NT(nt_status_squash(NT_STATUS_NO_MEMORY
));
192 if (!spnego_parse_krb5_wrap(*secblob
, &ticket
, tok_id
)) {
193 talloc_destroy(mem_ctx
);
194 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE
));
197 ret
= ads_verify_ticket(mem_ctx
, lp_realm(), 0, &ticket
, &client
, &pac_data
, &ap_rep
, &session_key
);
199 data_blob_free(&ticket
);
201 if (!NT_STATUS_IS_OK(ret
)) {
202 DEBUG(1,("Failed to verify incoming ticket!\n"));
203 talloc_destroy(mem_ctx
);
204 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE
));
207 DEBUG(3,("Ticket name is [%s]\n", client
));
209 p
= strchr_m(client
, '@');
211 DEBUG(3,("Doesn't look like a valid principal\n"));
212 data_blob_free(&ap_rep
);
213 data_blob_free(&session_key
);
215 talloc_destroy(mem_ctx
);
216 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE
));
221 /* save the PAC data if we have it */
224 logon_info
= get_logon_info_from_pac(pac_data
);
226 netsamlogon_cache_store( client
, &logon_info
->info3
);
230 if (!strequal(p
+1, lp_realm())) {
231 DEBUG(3,("Ticket for foreign realm %s@%s\n", client
, p
+1));
232 if (!lp_allow_trusted_domains()) {
233 data_blob_free(&ap_rep
);
234 data_blob_free(&session_key
);
236 talloc_destroy(mem_ctx
);
237 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE
));
241 /* this gives a fully qualified user name (ie. with full realm).
242 that leads to very long usernames, but what else can we do? */
246 if (logon_info
&& logon_info
->info3
.hdr_logon_dom
.uni_str_len
) {
248 unistr2_to_ascii(netbios_domain_name
, &logon_info
->info3
.uni_logon_dom
, -1);
249 domain
= netbios_domain_name
;
250 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain
));
254 /* If we have winbind running, we can (and must) shorten the
255 username by using the short netbios name. Otherwise we will
256 have inconsistent user names. With Kerberos, we get the
257 fully qualified realm, with ntlmssp we get the short
258 name. And even w2k3 does use ntlmssp if you for example
259 connect to an ip address. */
261 struct winbindd_request wb_request
;
262 struct winbindd_response wb_response
;
263 NSS_STATUS wb_result
;
265 ZERO_STRUCT(wb_request
);
266 ZERO_STRUCT(wb_response
);
268 DEBUG(10, ("Mapping [%s] to short name\n", domain
));
270 fstrcpy(wb_request
.domain_name
, domain
);
272 wb_result
= winbindd_request_response(WINBINDD_DOMAIN_INFO
,
273 &wb_request
, &wb_response
);
275 if (wb_result
== NSS_STATUS_SUCCESS
) {
277 fstrcpy(netbios_domain_name
,
278 wb_response
.data
.domain_info
.name
);
279 domain
= netbios_domain_name
;
281 DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain
));
283 DEBUG(3, ("Could not find short name -- winbind "
288 fstr_sprintf(user
, "%s%c%s", domain
, *lp_winbind_separator(), client
);
290 /* lookup the passwd struct, create a new user if necessary */
292 username_was_mapped
= map_username( user
);
294 pw
= smb_getpwnam( mem_ctx
, user
, real_username
, True
);
297 /* this was originally the behavior of Samba 2.2, if a user
298 did not have a local uid but has been authenticated, then
299 map them to a guest account */
301 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID
){
302 map_domainuser_to_guest
= True
;
303 fstrcpy(user
,lp_guestaccount());
304 pw
= smb_getpwnam( mem_ctx
, user
, real_username
, True
);
307 /* extra sanity check that the guest account is valid */
310 DEBUG(1,("Username %s is invalid on this system\n", user
));
312 data_blob_free(&ap_rep
);
313 data_blob_free(&session_key
);
314 talloc_destroy(mem_ctx
);
315 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE
));
319 /* setup the string used by %U */
321 sub_set_smb_name( real_username
);
322 reload_services(True
);
324 if ( map_domainuser_to_guest
) {
325 make_server_info_guest(&server_info
);
326 } else if (logon_info
) {
327 /* pass the unmapped username here since map_username()
328 will be called again from inside make_server_info_info3() */
330 ret
= make_server_info_info3(mem_ctx
, user
, domain
,
331 &server_info
, &logon_info
->info3
);
332 if ( !NT_STATUS_IS_OK(ret
) ) {
333 DEBUG(1,("make_server_info_info3 failed: %s!\n",
336 data_blob_free(&ap_rep
);
337 data_blob_free(&session_key
);
338 talloc_destroy(mem_ctx
);
339 return ERROR_NT(nt_status_squash(ret
));
343 ret
= make_server_info_pw(&server_info
, real_username
, pw
);
345 if ( !NT_STATUS_IS_OK(ret
) ) {
346 DEBUG(1,("make_server_info_pw failed: %s!\n",
349 data_blob_free(&ap_rep
);
350 data_blob_free(&session_key
);
351 talloc_destroy(mem_ctx
);
352 return ERROR_NT(nt_status_squash(ret
));
355 /* make_server_info_pw does not set the domain. Without this
356 * we end up with the local netbios name in substitutions for
359 if (server_info
->sam_account
!= NULL
) {
360 pdb_set_domain(server_info
->sam_account
, domain
, PDB_SET
);
364 server_info
->was_mapped
|= username_was_mapped
;
366 /* we need to build the token for the user. make_server_info_guest()
369 if ( !server_info
->ptok
) {
370 ret
= create_local_token( server_info
);
371 if ( !NT_STATUS_IS_OK(ret
) ) {
373 data_blob_free(&ap_rep
);
374 data_blob_free(&session_key
);
375 TALLOC_FREE( mem_ctx
);
376 TALLOC_FREE( server_info
);
377 return ERROR_NT(nt_status_squash(ret
));
381 /* register_vuid keeps the server info */
382 /* register_vuid takes ownership of session_key, no need to free after this.
383 A better interface would copy it.... */
384 sess_vuid
= register_vuid(server_info
, session_key
, nullblob
, client
);
388 if (sess_vuid
== UID_FIELD_INVALID
) {
389 ret
= NT_STATUS_LOGON_FAILURE
;
391 /* current_user_info is changed on new vuid */
392 reload_services( True
);
394 set_message(outbuf
,4,0,True
);
395 SSVAL(outbuf
, smb_vwv3
, 0);
397 if (server_info
->guest
) {
398 SSVAL(outbuf
,smb_vwv2
,1);
401 SSVAL(outbuf
, smb_uid
, sess_vuid
);
403 sessionsetup_start_signing_engine(server_info
, inbuf
);
406 /* wrap that up in a nice GSS-API wrapping */
407 if (NT_STATUS_IS_OK(ret
)) {
408 ap_rep_wrapped
= spnego_gen_krb5_wrap(ap_rep
, TOK_ID_KRB_AP_REP
);
410 ap_rep_wrapped
= data_blob(NULL
, 0);
412 response
= spnego_gen_auth_response(&ap_rep_wrapped
, ret
, OID_KERBEROS5_OLD
);
413 reply_sesssetup_blob(conn
, outbuf
, response
, ret
);
415 data_blob_free(&ap_rep
);
416 data_blob_free(&ap_rep_wrapped
);
417 data_blob_free(&response
);
418 talloc_destroy(mem_ctx
);
420 return -1; /* already replied */
424 /****************************************************************************
425 Send a session setup reply, wrapped in SPNEGO.
426 Get vuid and check first.
427 End the NTLMSSP exchange context if we are OK/complete fail
428 This should be split into two functions, one to handle each
429 leg of the NTLM auth steps.
430 ***************************************************************************/
432 static BOOL
reply_spnego_ntlmssp(connection_struct
*conn
, char *inbuf
, char *outbuf
,
434 AUTH_NTLMSSP_STATE
**auth_ntlmssp_state
,
435 DATA_BLOB
*ntlmssp_blob
, NTSTATUS nt_status
,
440 struct auth_serversupplied_info
*server_info
= NULL
;
442 if (NT_STATUS_IS_OK(nt_status
)) {
443 server_info
= (*auth_ntlmssp_state
)->server_info
;
445 nt_status
= do_map_to_guest(nt_status
,
447 (*auth_ntlmssp_state
)->ntlmssp_state
->user
,
448 (*auth_ntlmssp_state
)->ntlmssp_state
->domain
);
451 if (NT_STATUS_IS_OK(nt_status
)) {
453 DATA_BLOB nullblob
= data_blob(NULL
, 0);
454 DATA_BLOB session_key
= data_blob((*auth_ntlmssp_state
)->ntlmssp_state
->session_key
.data
, (*auth_ntlmssp_state
)->ntlmssp_state
->session_key
.length
);
456 /* register_vuid keeps the server info */
457 sess_vuid
= register_vuid(server_info
, session_key
, nullblob
, (*auth_ntlmssp_state
)->ntlmssp_state
->user
);
458 (*auth_ntlmssp_state
)->server_info
= NULL
;
460 if (sess_vuid
== UID_FIELD_INVALID
) {
461 nt_status
= NT_STATUS_LOGON_FAILURE
;
464 /* current_user_info is changed on new vuid */
465 reload_services( True
);
467 set_message(outbuf
,4,0,True
);
468 SSVAL(outbuf
, smb_vwv3
, 0);
470 if (server_info
->guest
) {
471 SSVAL(outbuf
,smb_vwv2
,1);
474 SSVAL(outbuf
,smb_uid
,sess_vuid
);
476 sessionsetup_start_signing_engine(server_info
, inbuf
);
481 response
= spnego_gen_auth_response(ntlmssp_blob
, nt_status
, OID_NTLMSSP
);
483 response
= *ntlmssp_blob
;
486 ret
= reply_sesssetup_blob(conn
, outbuf
, response
, nt_status
);
488 data_blob_free(&response
);
491 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
492 and the other end, that we are not finished yet. */
494 if (!ret
|| !NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
495 /* NB. This is *NOT* an error case. JRA */
496 auth_ntlmssp_end(auth_ntlmssp_state
);
497 /* Kill the intermediate vuid */
498 invalidate_vuid(vuid
);
504 /****************************************************************************
505 Reply to a session setup spnego negotiate packet.
506 ****************************************************************************/
508 static int reply_spnego_negotiate(connection_struct
*conn
,
512 int length
, int bufsize
,
514 AUTH_NTLMSSP_STATE
**auth_ntlmssp_state
)
516 char *OIDs
[ASN1_MAX_OIDS
];
521 BOOL got_kerberos_mechanism
= False
;
525 /* parse out the OIDs and the first sec blob */
526 if (!parse_negTokenTarg(blob1
, OIDs
, &secblob
)) {
527 /* Kill the intermediate vuid */
528 invalidate_vuid(vuid
);
530 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE
));
533 /* only look at the first OID for determining the mechToken --
534 accoirding to RFC2478, we should choose the one we want
535 and renegotiate, but i smell a client bug here..
537 Problem observed when connecting to a member (samba box)
538 of an AD domain as a user in a Samba domain. Samba member
539 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
540 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
541 NTLMSSP mechtoken. --jerry */
544 if (strcmp(OID_KERBEROS5
, OIDs
[0]) == 0 ||
545 strcmp(OID_KERBEROS5_OLD
, OIDs
[0]) == 0) {
546 got_kerberos_mechanism
= True
;
550 for (i
=0;OIDs
[i
];i
++) {
551 DEBUG(3,("Got OID %s\n", OIDs
[i
]));
554 DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob
.length
));
557 if ( got_kerberos_mechanism
&& ((lp_security()==SEC_ADS
) || lp_use_kerberos_keytab()) ) {
558 int ret
= reply_spnego_kerberos(conn
, inbuf
, outbuf
,
559 length
, bufsize
, &secblob
);
560 data_blob_free(&secblob
);
561 /* Kill the intermediate vuid */
562 invalidate_vuid(vuid
);
568 if (*auth_ntlmssp_state
) {
569 auth_ntlmssp_end(auth_ntlmssp_state
);
572 nt_status
= auth_ntlmssp_start(auth_ntlmssp_state
);
573 if (!NT_STATUS_IS_OK(nt_status
)) {
574 /* Kill the intermediate vuid */
575 invalidate_vuid(vuid
);
577 return ERROR_NT(nt_status_squash(nt_status
));
580 nt_status
= auth_ntlmssp_update(*auth_ntlmssp_state
,
583 data_blob_free(&secblob
);
585 reply_spnego_ntlmssp(conn
, inbuf
, outbuf
, vuid
, auth_ntlmssp_state
,
586 &chal
, nt_status
, True
);
588 data_blob_free(&chal
);
590 /* already replied */
594 /****************************************************************************
595 Reply to a session setup spnego auth packet.
596 ****************************************************************************/
598 static int reply_spnego_auth(connection_struct
*conn
, char *inbuf
, char *outbuf
,
600 int length
, int bufsize
,
602 AUTH_NTLMSSP_STATE
**auth_ntlmssp_state
)
604 DATA_BLOB auth
, auth_reply
;
605 NTSTATUS nt_status
= NT_STATUS_INVALID_PARAMETER
;
607 if (!spnego_parse_auth(blob1
, &auth
)) {
609 file_save("auth.dat", blob1
.data
, blob1
.length
);
611 /* Kill the intermediate vuid */
612 invalidate_vuid(vuid
);
614 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER
));
617 if (!*auth_ntlmssp_state
) {
618 /* Kill the intermediate vuid */
619 invalidate_vuid(vuid
);
621 /* auth before negotiatiate? */
622 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER
));
625 nt_status
= auth_ntlmssp_update(*auth_ntlmssp_state
,
628 data_blob_free(&auth
);
630 reply_spnego_ntlmssp(conn
, inbuf
, outbuf
, vuid
,
632 &auth_reply
, nt_status
, True
);
634 data_blob_free(&auth_reply
);
636 /* and tell smbd that we have already replied to this packet */
640 /****************************************************************************
641 Reply to a session setup command.
642 conn POINTER CAN BE NULL HERE !
643 ****************************************************************************/
645 static int reply_sesssetup_and_X_spnego(connection_struct
*conn
, char *inbuf
,
647 int length
,int bufsize
)
653 fstring native_os
, native_lanman
, primary_domain
;
655 uint16 data_blob_len
= SVAL(inbuf
, smb_vwv7
);
656 enum remote_arch_types ra_type
= get_remote_arch();
657 int vuid
= SVAL(inbuf
,smb_uid
);
658 user_struct
*vuser
= NULL
;
660 DEBUG(3,("Doing spnego session setup\n"));
662 if (global_client_caps
== 0) {
663 global_client_caps
= IVAL(inbuf
,smb_vwv10
);
665 if (!(global_client_caps
& CAP_STATUS32
)) {
666 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES
);
671 p
= (uint8
*)smb_buf(inbuf
);
673 if (data_blob_len
== 0) {
674 /* an invalid request */
675 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE
));
678 bufrem
= smb_bufrem(inbuf
, p
);
679 /* pull the spnego blob */
680 blob1
= data_blob(p
, MIN(bufrem
, data_blob_len
));
683 file_save("negotiate.dat", blob1
.data
, blob1
.length
);
686 p2
= inbuf
+ smb_vwv13
+ data_blob_len
;
687 p2
+= srvstr_pull_buf(inbuf
, native_os
, p2
, sizeof(native_os
), STR_TERMINATE
);
688 p2
+= srvstr_pull_buf(inbuf
, native_lanman
, p2
, sizeof(native_lanman
), STR_TERMINATE
);
689 p2
+= srvstr_pull_buf(inbuf
, primary_domain
, p2
, sizeof(primary_domain
), STR_TERMINATE
);
690 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
691 native_os
, native_lanman
, primary_domain
));
693 if ( ra_type
== RA_WIN2K
) {
694 /* Windows 2003 doesn't set the native lanman string,
695 but does set primary domain which is a bug I think */
697 if ( !strlen(native_lanman
) )
698 ra_lanman_string( primary_domain
);
700 ra_lanman_string( native_lanman
);
703 vuser
= get_partial_auth_user_struct(vuid
);
705 vuid
= register_vuid(NULL
, data_blob(NULL
, 0), data_blob(NULL
, 0), NULL
);
706 if (vuid
== UID_FIELD_INVALID
) {
707 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER
));
710 vuser
= get_partial_auth_user_struct(vuid
);
714 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER
));
717 SSVAL(outbuf
,smb_uid
,vuid
);
719 if (blob1
.data
[0] == ASN1_APPLICATION(0)) {
720 /* its a negTokenTarg packet */
721 ret
= reply_spnego_negotiate(conn
, inbuf
, outbuf
, vuid
, length
, bufsize
, blob1
,
722 &vuser
->auth_ntlmssp_state
);
723 data_blob_free(&blob1
);
727 if (blob1
.data
[0] == ASN1_CONTEXT(1)) {
728 /* its a auth packet */
729 ret
= reply_spnego_auth(conn
, inbuf
, outbuf
, vuid
, length
, bufsize
, blob1
,
730 &vuser
->auth_ntlmssp_state
);
731 data_blob_free(&blob1
);
735 if (strncmp((char *)(blob1
.data
), "NTLMSSP", 7) == 0) {
738 if (!vuser
->auth_ntlmssp_state
) {
739 nt_status
= auth_ntlmssp_start(&vuser
->auth_ntlmssp_state
);
740 if (!NT_STATUS_IS_OK(nt_status
)) {
741 /* Kill the intermediate vuid */
742 invalidate_vuid(vuid
);
744 return ERROR_NT(nt_status_squash(nt_status
));
748 nt_status
= auth_ntlmssp_update(vuser
->auth_ntlmssp_state
,
751 data_blob_free(&blob1
);
753 reply_spnego_ntlmssp(conn
, inbuf
, outbuf
, vuid
,
754 &vuser
->auth_ntlmssp_state
,
755 &chal
, nt_status
, False
);
756 data_blob_free(&chal
);
760 /* what sort of packet is this? */
761 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
763 data_blob_free(&blob1
);
765 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE
));
768 /****************************************************************************
769 On new VC == 0, shutdown *all* old connections and users.
770 It seems that only NT4.x does this. At W2K and above (XP etc.).
771 a new session setup with VC==0 is ignored.
772 ****************************************************************************/
774 static int shutdown_other_smbds(TDB_CONTEXT
*tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
777 struct sessionid
*sessionid
= (struct sessionid
*)dbuf
.dptr
;
778 const char *ip
= (const char *)p
;
780 if (!process_exists(pid_to_procid(sessionid
->pid
))) {
784 if (sessionid
->pid
== sys_getpid()) {
788 if (strcmp(ip
, sessionid
->ip_addr
) != 0) {
792 message_send_pid(pid_to_procid(sessionid
->pid
), MSG_SHUTDOWN
,
797 static void setup_new_vc_session(void)
799 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
802 invalidate_all_vuids();
804 if (lp_reset_on_zero_vc()) {
805 session_traverse(shutdown_other_smbds
, client_addr());
809 /****************************************************************************
810 Reply to a session setup command.
811 ****************************************************************************/
813 int reply_sesssetup_and_X(connection_struct
*conn
, char *inbuf
,char *outbuf
,
814 int length
,int bufsize
)
820 DATA_BLOB plaintext_password
;
822 fstring sub_user
; /* Sainitised username for substituion */
825 fstring native_lanman
;
826 fstring primary_domain
;
827 static BOOL done_sesssetup
= False
;
828 extern BOOL global_encrypted_passwords_negotiated
;
829 extern BOOL global_spnego_negotiated
;
830 extern enum protocol_types Protocol
;
833 auth_usersupplied_info
*user_info
= NULL
;
834 extern struct auth_context
*negprot_global_auth_context
;
835 auth_serversupplied_info
*server_info
= NULL
;
839 BOOL doencrypt
= global_encrypted_passwords_negotiated
;
841 DATA_BLOB session_key
;
843 START_PROFILE(SMBsesssetupX
);
845 ZERO_STRUCT(lm_resp
);
846 ZERO_STRUCT(nt_resp
);
847 ZERO_STRUCT(plaintext_password
);
849 DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf
, smb_wct
), SVAL(inbuf
, smb_flg2
)));
851 /* a SPNEGO session setup has 12 command words, whereas a normal
852 NT1 session setup has 13. See the cifs spec. */
853 if (CVAL(inbuf
, smb_wct
) == 12 &&
854 (SVAL(inbuf
, smb_flg2
) & FLAGS2_EXTENDED_SECURITY
)) {
855 if (!global_spnego_negotiated
) {
856 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
857 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE
));
860 if (SVAL(inbuf
,smb_vwv4
) == 0) {
861 setup_new_vc_session();
863 return reply_sesssetup_and_X_spnego(conn
, inbuf
, outbuf
, length
, bufsize
);
866 smb_bufsize
= SVAL(inbuf
,smb_vwv2
);
868 if (Protocol
< PROTOCOL_NT1
) {
869 uint16 passlen1
= SVAL(inbuf
,smb_vwv7
);
871 /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
872 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES
);
874 if ((passlen1
> MAX_PASS_LEN
) || (passlen1
> smb_bufrem(inbuf
, smb_buf(inbuf
)))) {
875 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER
));
879 lm_resp
= data_blob(smb_buf(inbuf
), passlen1
);
881 plaintext_password
= data_blob(smb_buf(inbuf
), passlen1
+1);
882 /* Ensure null termination */
883 plaintext_password
.data
[passlen1
] = 0;
886 srvstr_pull_buf(inbuf
, user
, smb_buf(inbuf
)+passlen1
, sizeof(user
), STR_TERMINATE
);
890 uint16 passlen1
= SVAL(inbuf
,smb_vwv7
);
891 uint16 passlen2
= SVAL(inbuf
,smb_vwv8
);
892 enum remote_arch_types ra_type
= get_remote_arch();
893 char *p
= smb_buf(inbuf
);
894 char *save_p
= smb_buf(inbuf
);
898 if(global_client_caps
== 0) {
899 global_client_caps
= IVAL(inbuf
,smb_vwv11
);
901 if (!(global_client_caps
& CAP_STATUS32
)) {
902 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES
);
905 /* client_caps is used as final determination if client is NT or Win95.
906 This is needed to return the correct error codes in some
910 if(ra_type
== RA_WINNT
|| ra_type
== RA_WIN2K
|| ra_type
== RA_WIN95
) {
911 if(!(global_client_caps
& (CAP_NT_SMBS
| CAP_STATUS32
))) {
912 set_remote_arch( RA_WIN95
);
918 /* both Win95 and WinNT stuff up the password lengths for
919 non-encrypting systems. Uggh.
921 if passlen1==24 its a win95 system, and its setting the
922 password length incorrectly. Luckily it still works with the
923 default code because Win95 will null terminate the password
926 if passlen1>0 and passlen2>0 then maybe its a NT box and its
927 setting passlen2 to some random value which really stuffs
928 things up. we need to fix that one. */
930 if (passlen1
> 0 && passlen2
> 0 && passlen2
!= 24 && passlen2
!= 1)
934 /* check for nasty tricks */
935 if (passlen1
> MAX_PASS_LEN
|| passlen1
> smb_bufrem(inbuf
, p
)) {
936 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER
));
939 if (passlen2
> MAX_PASS_LEN
|| passlen2
> smb_bufrem(inbuf
, p
+passlen1
)) {
940 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER
));
943 /* Save the lanman2 password and the NT md4 password. */
945 if ((doencrypt
) && (passlen1
!= 0) && (passlen1
!= 24)) {
950 lm_resp
= data_blob(p
, passlen1
);
951 nt_resp
= data_blob(p
+passlen1
, passlen2
);
954 BOOL unic
=SVAL(inbuf
, smb_flg2
) & FLAGS2_UNICODE_STRINGS
;
957 /* This was the previous fix. Not sure if it's still valid. JRA. */
958 if ((ra_type
== RA_WINNT
) && (passlen2
== 0) && unic
&& passlen1
) {
959 /* NT4.0 stuffs up plaintext unicode password lengths... */
960 srvstr_pull(inbuf
, pass
, smb_buf(inbuf
) + 1,
961 sizeof(pass
), passlen1
, STR_TERMINATE
);
964 if (unic
&& (passlen2
== 0) && passlen1
) {
965 /* Only a ascii plaintext password was sent. */
966 srvstr_pull(inbuf
, pass
, smb_buf(inbuf
), sizeof(pass
),
967 passlen1
, STR_TERMINATE
|STR_ASCII
);
969 srvstr_pull(inbuf
, pass
, smb_buf(inbuf
),
970 sizeof(pass
), unic
? passlen2
: passlen1
,
973 plaintext_password
= data_blob(pass
, strlen(pass
)+1);
976 p
+= passlen1
+ passlen2
;
977 p
+= srvstr_pull_buf(inbuf
, user
, p
, sizeof(user
), STR_TERMINATE
);
978 p
+= srvstr_pull_buf(inbuf
, domain
, p
, sizeof(domain
), STR_TERMINATE
);
979 p
+= srvstr_pull_buf(inbuf
, native_os
, p
, sizeof(native_os
), STR_TERMINATE
);
980 p
+= srvstr_pull_buf(inbuf
, native_lanman
, p
, sizeof(native_lanman
), STR_TERMINATE
);
982 /* not documented or decoded by Ethereal but there is one more string
983 in the extra bytes which is the same as the PrimaryDomain when using
984 extended security. Windows NT 4 and 2003 use this string to store
985 the native lanman string. Windows 9x does not include a string here
986 at all so we have to check if we have any extra bytes left */
988 byte_count
= SVAL(inbuf
, smb_vwv13
);
989 if ( PTR_DIFF(p
, save_p
) < byte_count
)
990 p
+= srvstr_pull_buf(inbuf
, primary_domain
, p
, sizeof(primary_domain
), STR_TERMINATE
);
992 fstrcpy( primary_domain
, "null" );
994 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
995 domain
, native_os
, native_lanman
, primary_domain
));
997 if ( ra_type
== RA_WIN2K
) {
998 if ( strlen(native_lanman
) == 0 )
999 ra_lanman_string( primary_domain
);
1001 ra_lanman_string( native_lanman
);
1006 if (SVAL(inbuf
,smb_vwv4
) == 0) {
1007 setup_new_vc_session();
1010 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain
, user
, get_remote_machine_name()));
1013 if (global_spnego_negotiated
) {
1015 /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
1017 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
1018 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE
));
1020 fstrcpy(sub_user
, user
);
1022 fstrcpy(sub_user
, lp_guestaccount());
1025 sub_set_smb_name(sub_user
);
1027 reload_services(True
);
1029 if (lp_security() == SEC_SHARE
) {
1030 /* in share level we should ignore any passwords */
1032 data_blob_free(&lm_resp
);
1033 data_blob_free(&nt_resp
);
1034 data_blob_clear_free(&plaintext_password
);
1036 map_username(sub_user
);
1037 add_session_user(sub_user
);
1038 /* Then force it to null for the benfit of the code below */
1044 nt_status
= check_guest_password(&server_info
);
1046 } else if (doencrypt
) {
1047 if (!negprot_global_auth_context
) {
1048 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted session setup without negprot denied!\n"));
1049 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE
));
1051 nt_status
= make_user_info_for_reply_enc(&user_info
, user
, domain
,
1053 if (NT_STATUS_IS_OK(nt_status
)) {
1054 nt_status
= negprot_global_auth_context
->check_ntlm_password(negprot_global_auth_context
,
1059 struct auth_context
*plaintext_auth_context
= NULL
;
1062 nt_status
= make_auth_context_subsystem(&plaintext_auth_context
);
1064 if (NT_STATUS_IS_OK(nt_status
)) {
1065 chal
= plaintext_auth_context
->get_ntlm_challenge(plaintext_auth_context
);
1067 if (!make_user_info_for_reply(&user_info
,
1069 plaintext_password
)) {
1070 nt_status
= NT_STATUS_NO_MEMORY
;
1073 if (NT_STATUS_IS_OK(nt_status
)) {
1074 nt_status
= plaintext_auth_context
->check_ntlm_password(plaintext_auth_context
,
1078 (plaintext_auth_context
->free
)(&plaintext_auth_context
);
1083 free_user_info(&user_info
);
1085 if (!NT_STATUS_IS_OK(nt_status
)) {
1086 nt_status
= do_map_to_guest(nt_status
, &server_info
, user
, domain
);
1089 if (!NT_STATUS_IS_OK(nt_status
)) {
1090 data_blob_free(&nt_resp
);
1091 data_blob_free(&lm_resp
);
1092 data_blob_clear_free(&plaintext_password
);
1093 return ERROR_NT(nt_status_squash(nt_status
));
1096 /* Ensure we can't possible take a code path leading to a null defref. */
1098 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE
));
1101 nt_status
= create_local_token(server_info
);
1102 if (!NT_STATUS_IS_OK(nt_status
)) {
1103 DEBUG(10, ("create_local_token failed: %s\n",
1104 nt_errstr(nt_status
)));
1105 data_blob_free(&nt_resp
);
1106 data_blob_free(&lm_resp
);
1107 data_blob_clear_free(&plaintext_password
);
1108 return ERROR_NT(nt_status_squash(nt_status
));
1111 if (server_info
->user_session_key
.data
) {
1112 session_key
= data_blob(server_info
->user_session_key
.data
, server_info
->user_session_key
.length
);
1114 session_key
= data_blob(NULL
, 0);
1117 data_blob_clear_free(&plaintext_password
);
1119 /* it's ok - setup a reply */
1120 set_message(outbuf
,3,0,True
);
1121 if (Protocol
>= PROTOCOL_NT1
) {
1122 char *p
= smb_buf( outbuf
);
1123 p
+= add_signature( outbuf
, p
);
1124 set_message_end( outbuf
, p
);
1125 /* perhaps grab OS version here?? */
1128 if (server_info
->guest
) {
1129 SSVAL(outbuf
,smb_vwv2
,1);
1132 /* register the name and uid as being validated, so further connections
1133 to a uid can get through without a password, on the same VC */
1135 if (lp_security() == SEC_SHARE
) {
1136 sess_vuid
= UID_FIELD_INVALID
;
1137 data_blob_free(&session_key
);
1138 TALLOC_FREE(server_info
);
1140 /* register_vuid keeps the server info */
1141 sess_vuid
= register_vuid(server_info
, session_key
,
1142 nt_resp
.data
? nt_resp
: lm_resp
,
1144 if (sess_vuid
== UID_FIELD_INVALID
) {
1145 data_blob_free(&nt_resp
);
1146 data_blob_free(&lm_resp
);
1147 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE
));
1150 /* current_user_info is changed on new vuid */
1151 reload_services( True
);
1153 sessionsetup_start_signing_engine(server_info
, inbuf
);
1156 data_blob_free(&nt_resp
);
1157 data_blob_free(&lm_resp
);
1159 SSVAL(outbuf
,smb_uid
,sess_vuid
);
1160 SSVAL(inbuf
,smb_uid
,sess_vuid
);
1162 if (!done_sesssetup
)
1163 max_send
= MIN(max_send
,smb_bufsize
);
1165 done_sesssetup
= True
;
1167 END_PROFILE(SMBsesssetupX
);
1168 return chain_reply(inbuf
,outbuf
,length
,bufsize
);