r13316: Let the carnage begin....
[Samba/gbeck.git] / source / smbd / sesssetup.c
blob38e16126e2135d62f89be88f46a8d42ca75f3a03
1 /*
2 Unix SMB/CIFS implementation.
3 handle SMBsessionsetup
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.
24 #include "includes.h"
26 uint32 global_client_caps = 0;
29 on a logon error possibly map the error to success if "map to guest"
30 is set approriately
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",
39 user, domain));
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);
51 return status;
54 /****************************************************************************
55 Add the standard 'Samba' signature to the end of the session setup.
56 ****************************************************************************/
58 static int add_signature(char *outbuf, char *p)
60 char *start = p;
61 fstring lanman;
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)
79 char *p;
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);
87 p = smb_buf(outbuf);
89 /* should we cap this? */
90 memcpy(p, blob.data, blob.length);
91 p += blob.length;
93 p += add_signature( outbuf, p );
95 set_message_end(outbuf,p);
97 show_msg(outbuf);
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;
110 NTSTATUS nt_status;
111 unsigned char chal[8];
113 ZERO_STRUCT(chal);
115 DEBUG(3,("Got anonymous request\n"));
117 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
118 return nt_status;
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);
129 return nt_status;
133 #ifdef HAVE_KRB5
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,
140 DATA_BLOB *secblob)
142 TALLOC_CTX *mem_ctx;
143 DATA_BLOB ticket;
144 char *client, *p, *domain;
145 fstring netbios_domain_name;
146 struct passwd *pw;
147 fstring user;
148 int sess_vuid;
149 NTSTATUS ret;
150 PAC_DATA *pac_data;
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);
154 uint8 tok_id[2];
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;
160 ZERO_STRUCT(ticket);
161 ZERO_STRUCT(pac_data);
162 ZERO_STRUCT(ap_rep);
163 ZERO_STRUCT(ap_rep_wrapped);
164 ZERO_STRUCT(response);
166 mem_ctx = talloc_init("reply_spnego_kerberos");
167 if (mem_ctx == NULL)
168 return ERROR_NT(NT_STATUS_NO_MEMORY);
170 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
171 talloc_destroy(mem_ctx);
172 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
175 ret = ads_verify_ticket(mem_ctx, lp_realm(), &ticket, &client, &pac_data, &ap_rep, &session_key);
177 data_blob_free(&ticket);
179 if (!NT_STATUS_IS_OK(ret)) {
180 DEBUG(1,("Failed to verify incoming ticket!\n"));
181 talloc_destroy(mem_ctx);
182 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
185 DEBUG(3,("Ticket name is [%s]\n", client));
187 p = strchr_m(client, '@');
188 if (!p) {
189 DEBUG(3,("Doesn't look like a valid principal\n"));
190 data_blob_free(&ap_rep);
191 data_blob_free(&session_key);
192 SAFE_FREE(client);
193 talloc_destroy(mem_ctx);
194 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
197 *p = 0;
199 /* save the PAC data if we have it */
201 if (pac_data) {
202 logon_info = get_logon_info_from_pac(pac_data);
203 netsamlogon_cache_store( client, &logon_info->info3 );
206 if (!strequal(p+1, lp_realm())) {
207 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
208 if (!lp_allow_trusted_domains()) {
209 data_blob_free(&ap_rep);
210 data_blob_free(&session_key);
211 SAFE_FREE(client);
212 talloc_destroy(mem_ctx);
213 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
217 /* this gives a fully qualified user name (ie. with full realm).
218 that leads to very long usernames, but what else can we do? */
220 domain = p+1;
222 if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) {
224 unistr2_to_ascii(netbios_domain_name, &logon_info->info3.uni_logon_dom, -1);
225 domain = netbios_domain_name;
226 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
228 } else {
230 /* If we have winbind running, we can (and must) shorten the
231 username by using the short netbios name. Otherwise we will
232 have inconsistent user names. With Kerberos, we get the
233 fully qualified realm, with ntlmssp we get the short
234 name. And even w2k3 does use ntlmssp if you for example
235 connect to an ip address. */
237 struct winbindd_request wb_request;
238 struct winbindd_response wb_response;
239 NSS_STATUS wb_result;
241 ZERO_STRUCT(wb_request);
242 ZERO_STRUCT(wb_response);
244 DEBUG(10, ("Mapping [%s] to short name\n", domain));
246 fstrcpy(wb_request.domain_name, domain);
248 wb_result = winbindd_request_response(WINBINDD_DOMAIN_INFO,
249 &wb_request, &wb_response);
251 if (wb_result == NSS_STATUS_SUCCESS) {
253 fstrcpy(netbios_domain_name,
254 wb_response.data.domain_info.name);
255 domain = netbios_domain_name;
257 DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
258 } else {
259 DEBUG(3, ("Could not find short name -- winbind "
260 "not running?\n"));
264 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
266 /* lookup the passwd struct, create a new user if necessary */
268 map_username( user );
270 pw = smb_getpwnam( mem_ctx, user, real_username, True );
271 if (!pw) {
273 /* this was originally the behavior of Samba 2.2, if a user
274 did not have a local uid but has been authenticated, then
275 map them to a guest account */
277 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
278 map_domainuser_to_guest = True;
279 fstrcpy(user,lp_guestaccount());
280 pw = smb_getpwnam( mem_ctx, user, real_username, True );
283 /* extra sanity check that the guest account is valid */
285 if ( !pw ) {
286 DEBUG(1,("Username %s is invalid on this system\n", user));
287 SAFE_FREE(client);
288 data_blob_free(&ap_rep);
289 data_blob_free(&session_key);
290 talloc_destroy(mem_ctx);
291 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
295 /* setup the string used by %U */
297 sub_set_smb_name( real_username );
298 reload_services(True);
299 if ( map_domainuser_to_guest ) {
300 make_server_info_guest(&server_info);
301 } else if (logon_info) {
302 ret = make_server_info_pac(&server_info, real_username, pw, logon_info);
304 if ( !NT_STATUS_IS_OK(ret) ) {
305 DEBUG(1,("make_server_info_pac failed: %s!\n",
306 nt_errstr(ret)));
307 SAFE_FREE(client);
308 data_blob_free(&ap_rep);
309 data_blob_free(&session_key);
310 talloc_destroy(mem_ctx);
311 return ERROR_NT(ret);
314 } else {
315 ret = make_server_info_pw(&server_info, real_username, pw);
317 if ( !NT_STATUS_IS_OK(ret) ) {
318 DEBUG(1,("make_server_info_pw failed: %s!\n",
319 nt_errstr(ret)));
320 SAFE_FREE(client);
321 data_blob_free(&ap_rep);
322 data_blob_free(&session_key);
323 talloc_destroy(mem_ctx);
324 return ERROR_NT(ret);
327 /* make_server_info_pw does not set the domain. Without this
328 * we end up with the local netbios name in substitutions for
329 * %D. */
331 if (server_info->sam_account != NULL) {
332 pdb_set_domain(server_info->sam_account, domain, PDB_SET);
336 /* register_vuid keeps the server info */
337 /* register_vuid takes ownership of session_key, no need to free after this.
338 A better interface would copy it.... */
339 sess_vuid = register_vuid(server_info, session_key, nullblob, client);
341 SAFE_FREE(client);
343 if (sess_vuid == -1) {
344 ret = NT_STATUS_LOGON_FAILURE;
345 } else {
346 /* current_user_info is changed on new vuid */
347 reload_services( True );
349 set_message(outbuf,4,0,True);
350 SSVAL(outbuf, smb_vwv3, 0);
352 if (server_info->guest) {
353 SSVAL(outbuf,smb_vwv2,1);
356 SSVAL(outbuf, smb_uid, sess_vuid);
358 if (!server_info->guest && !srv_signing_started()) {
359 /* We need to start the signing engine
360 * here but a W2K client sends the old
361 * "BSRSPYL " signature instead of the
362 * correct one. Subsequent packets will
363 * be correct.
365 srv_check_sign_mac(inbuf, False);
369 /* wrap that up in a nice GSS-API wrapping */
370 if (NT_STATUS_IS_OK(ret)) {
371 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
372 } else {
373 ap_rep_wrapped = data_blob(NULL, 0);
375 response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
376 reply_sesssetup_blob(conn, outbuf, response, ret);
378 data_blob_free(&ap_rep);
379 data_blob_free(&ap_rep_wrapped);
380 data_blob_free(&response);
381 talloc_destroy(mem_ctx);
383 return -1; /* already replied */
385 #endif
387 /****************************************************************************
388 Send a session setup reply, wrapped in SPNEGO.
389 Get vuid and check first.
390 End the NTLMSSP exchange context if we are OK/complete fail
391 This should be split into two functions, one to handle each
392 leg of the NTLM auth steps.
393 ***************************************************************************/
395 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
396 uint16 vuid,
397 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
398 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
399 BOOL wrap)
401 BOOL ret;
402 DATA_BLOB response;
403 struct auth_serversupplied_info *server_info = NULL;
405 if (NT_STATUS_IS_OK(nt_status)) {
406 server_info = (*auth_ntlmssp_state)->server_info;
407 } else {
408 nt_status = do_map_to_guest(nt_status,
409 &server_info,
410 (*auth_ntlmssp_state)->ntlmssp_state->user,
411 (*auth_ntlmssp_state)->ntlmssp_state->domain);
414 if (NT_STATUS_IS_OK(nt_status)) {
415 int sess_vuid;
416 DATA_BLOB nullblob = data_blob(NULL, 0);
417 DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
419 /* register_vuid keeps the server info */
420 sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
421 (*auth_ntlmssp_state)->server_info = NULL;
423 if (sess_vuid == -1) {
424 nt_status = NT_STATUS_LOGON_FAILURE;
425 } else {
427 /* current_user_info is changed on new vuid */
428 reload_services( True );
430 set_message(outbuf,4,0,True);
431 SSVAL(outbuf, smb_vwv3, 0);
433 if (server_info->guest) {
434 SSVAL(outbuf,smb_vwv2,1);
437 SSVAL(outbuf,smb_uid,sess_vuid);
439 if (!server_info->guest && !srv_signing_started()) {
440 /* We need to start the signing engine
441 * here but a W2K client sends the old
442 * "BSRSPYL " signature instead of the
443 * correct one. Subsequent packets will
444 * be correct.
447 srv_check_sign_mac(inbuf, False);
452 if (wrap) {
453 response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
454 } else {
455 response = *ntlmssp_blob;
458 ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
459 if (wrap) {
460 data_blob_free(&response);
463 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
464 and the other end, that we are not finished yet. */
466 if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
467 /* NB. This is *NOT* an error case. JRA */
468 auth_ntlmssp_end(auth_ntlmssp_state);
469 /* Kill the intermediate vuid */
470 invalidate_vuid(vuid);
473 return ret;
476 /****************************************************************************
477 Reply to a session setup spnego negotiate packet.
478 ****************************************************************************/
480 static int reply_spnego_negotiate(connection_struct *conn,
481 char *inbuf,
482 char *outbuf,
483 uint16 vuid,
484 int length, int bufsize,
485 DATA_BLOB blob1,
486 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
488 char *OIDs[ASN1_MAX_OIDS];
489 DATA_BLOB secblob;
490 int i;
491 DATA_BLOB chal;
492 #ifdef HAVE_KRB5
493 BOOL got_kerberos_mechanism = False;
494 #endif
495 NTSTATUS nt_status;
497 /* parse out the OIDs and the first sec blob */
498 if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
499 /* Kill the intermediate vuid */
500 invalidate_vuid(vuid);
502 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
505 /* only look at the first OID for determining the mechToken --
506 accoirding to RFC2478, we should choose the one we want
507 and renegotiate, but i smell a client bug here..
509 Problem observed when connecting to a member (samba box)
510 of an AD domain as a user in a Samba domain. Samba member
511 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
512 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
513 NTLMSSP mechtoken. --jerry */
515 #ifdef HAVE_KRB5
516 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
517 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
518 got_kerberos_mechanism = True;
520 #endif
522 for (i=0;OIDs[i];i++) {
523 DEBUG(3,("Got OID %s\n", OIDs[i]));
524 free(OIDs[i]);
526 DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length));
528 #ifdef HAVE_KRB5
529 if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
530 int ret = reply_spnego_kerberos(conn, inbuf, outbuf,
531 length, bufsize, &secblob);
532 data_blob_free(&secblob);
533 /* Kill the intermediate vuid */
534 invalidate_vuid(vuid);
536 return ret;
538 #endif
540 if (*auth_ntlmssp_state) {
541 auth_ntlmssp_end(auth_ntlmssp_state);
544 nt_status = auth_ntlmssp_start(auth_ntlmssp_state);
545 if (!NT_STATUS_IS_OK(nt_status)) {
546 /* Kill the intermediate vuid */
547 invalidate_vuid(vuid);
549 return ERROR_NT(nt_status);
552 nt_status = auth_ntlmssp_update(*auth_ntlmssp_state,
553 secblob, &chal);
555 data_blob_free(&secblob);
557 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state,
558 &chal, nt_status, True);
560 data_blob_free(&chal);
562 /* already replied */
563 return -1;
566 /****************************************************************************
567 Reply to a session setup spnego auth packet.
568 ****************************************************************************/
570 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
571 uint16 vuid,
572 int length, int bufsize,
573 DATA_BLOB blob1,
574 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
576 DATA_BLOB auth, auth_reply;
577 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
579 if (!spnego_parse_auth(blob1, &auth)) {
580 #if 0
581 file_save("auth.dat", blob1.data, blob1.length);
582 #endif
583 /* Kill the intermediate vuid */
584 invalidate_vuid(vuid);
586 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
589 if (!*auth_ntlmssp_state) {
590 /* Kill the intermediate vuid */
591 invalidate_vuid(vuid);
593 /* auth before negotiatiate? */
594 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
597 nt_status = auth_ntlmssp_update(*auth_ntlmssp_state,
598 auth, &auth_reply);
600 data_blob_free(&auth);
602 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid,
603 auth_ntlmssp_state,
604 &auth_reply, nt_status, True);
606 data_blob_free(&auth_reply);
608 /* and tell smbd that we have already replied to this packet */
609 return -1;
612 /****************************************************************************
613 Reply to a session setup command.
614 ****************************************************************************/
616 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
617 char *outbuf,
618 int length,int bufsize)
620 uint8 *p;
621 DATA_BLOB blob1;
622 int ret;
623 size_t bufrem;
624 fstring native_os, native_lanman, primary_domain;
625 char *p2;
626 uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
627 enum remote_arch_types ra_type = get_remote_arch();
628 int vuid = SVAL(inbuf,smb_uid);
629 user_struct *vuser = NULL;
631 DEBUG(3,("Doing spnego session setup\n"));
633 if (global_client_caps == 0) {
634 global_client_caps = IVAL(inbuf,smb_vwv10);
636 if (!(global_client_caps & CAP_STATUS32)) {
637 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
642 p = (uint8 *)smb_buf(inbuf);
644 if (data_blob_len == 0) {
645 /* an invalid request */
646 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
649 bufrem = smb_bufrem(inbuf, p);
650 /* pull the spnego blob */
651 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
653 #if 0
654 file_save("negotiate.dat", blob1.data, blob1.length);
655 #endif
657 p2 = inbuf + smb_vwv13 + data_blob_len;
658 p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
659 p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
660 p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
661 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
662 native_os, native_lanman, primary_domain));
664 if ( ra_type == RA_WIN2K ) {
665 /* Windows 2003 doesn't set the native lanman string,
666 but does set primary domain which is a bug I think */
668 if ( !strlen(native_lanman) )
669 ra_lanman_string( primary_domain );
670 else
671 ra_lanman_string( native_lanman );
674 vuser = get_partial_auth_user_struct(vuid);
675 if (!vuser) {
676 vuid = register_vuid(NULL, data_blob(NULL, 0), data_blob(NULL, 0), NULL);
677 if (vuid == -1) {
678 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
681 vuser = get_partial_auth_user_struct(vuid);
684 if (!vuser) {
685 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
688 SSVAL(outbuf,smb_uid,vuid);
690 if (blob1.data[0] == ASN1_APPLICATION(0)) {
691 /* its a negTokenTarg packet */
692 ret = reply_spnego_negotiate(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
693 &vuser->auth_ntlmssp_state);
694 data_blob_free(&blob1);
695 return ret;
698 if (blob1.data[0] == ASN1_CONTEXT(1)) {
699 /* its a auth packet */
700 ret = reply_spnego_auth(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
701 &vuser->auth_ntlmssp_state);
702 data_blob_free(&blob1);
703 return ret;
706 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
707 DATA_BLOB chal;
708 NTSTATUS nt_status;
709 if (!vuser->auth_ntlmssp_state) {
710 nt_status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
711 if (!NT_STATUS_IS_OK(nt_status)) {
712 /* Kill the intermediate vuid */
713 invalidate_vuid(vuid);
715 return ERROR_NT(nt_status);
719 nt_status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
720 blob1, &chal);
722 data_blob_free(&blob1);
724 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid,
725 &vuser->auth_ntlmssp_state,
726 &chal, nt_status, False);
727 data_blob_free(&chal);
728 return -1;
731 /* what sort of packet is this? */
732 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
734 data_blob_free(&blob1);
736 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
739 /****************************************************************************
740 On new VC == 0, shutdown *all* old connections and users.
741 It seems that only NT4.x does this. At W2K and above (XP etc.).
742 a new session setup with VC==0 is ignored.
743 ****************************************************************************/
745 static int shutdown_other_smbds(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
746 void *p)
748 struct sessionid *sessionid = (struct sessionid *)dbuf.dptr;
749 const char *ip = (const char *)p;
751 if (!process_exists(pid_to_procid(sessionid->pid))) {
752 return 0;
755 if (sessionid->pid == sys_getpid()) {
756 return 0;
759 if (strcmp(ip, sessionid->ip_addr) != 0) {
760 return 0;
763 message_send_pid(pid_to_procid(sessionid->pid), MSG_SHUTDOWN,
764 NULL, 0, True);
765 return 0;
768 static void setup_new_vc_session(void)
770 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
771 #if 0
772 conn_close_all();
773 invalidate_all_vuids();
774 #endif
775 if (lp_reset_on_zero_vc()) {
776 session_traverse(shutdown_other_smbds, client_addr());
780 /****************************************************************************
781 Reply to a session setup command.
782 ****************************************************************************/
784 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
785 int length,int bufsize)
787 int sess_vuid;
788 int smb_bufsize;
789 DATA_BLOB lm_resp;
790 DATA_BLOB nt_resp;
791 DATA_BLOB plaintext_password;
792 fstring user;
793 fstring sub_user; /* Sainitised username for substituion */
794 fstring domain;
795 fstring native_os;
796 fstring native_lanman;
797 fstring primary_domain;
798 static BOOL done_sesssetup = False;
799 extern BOOL global_encrypted_passwords_negotiated;
800 extern BOOL global_spnego_negotiated;
801 extern enum protocol_types Protocol;
802 extern int max_send;
804 auth_usersupplied_info *user_info = NULL;
805 extern struct auth_context *negprot_global_auth_context;
806 auth_serversupplied_info *server_info = NULL;
808 NTSTATUS nt_status;
810 BOOL doencrypt = global_encrypted_passwords_negotiated;
812 DATA_BLOB session_key;
814 START_PROFILE(SMBsesssetupX);
816 ZERO_STRUCT(lm_resp);
817 ZERO_STRUCT(nt_resp);
818 ZERO_STRUCT(plaintext_password);
820 DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
822 /* a SPNEGO session setup has 12 command words, whereas a normal
823 NT1 session setup has 13. See the cifs spec. */
824 if (CVAL(inbuf, smb_wct) == 12 &&
825 (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
826 if (!global_spnego_negotiated) {
827 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
828 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
831 if (SVAL(inbuf,smb_vwv4) == 0) {
832 setup_new_vc_session();
834 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
837 smb_bufsize = SVAL(inbuf,smb_vwv2);
839 if (Protocol < PROTOCOL_NT1) {
840 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
842 /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
843 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
845 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
846 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
849 if (doencrypt) {
850 lm_resp = data_blob(smb_buf(inbuf), passlen1);
851 } else {
852 plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
853 /* Ensure null termination */
854 plaintext_password.data[passlen1] = 0;
857 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
858 *domain = 0;
860 } else {
861 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
862 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
863 enum remote_arch_types ra_type = get_remote_arch();
864 char *p = smb_buf(inbuf);
865 char *save_p = smb_buf(inbuf);
866 uint16 byte_count;
869 if(global_client_caps == 0) {
870 global_client_caps = IVAL(inbuf,smb_vwv11);
872 if (!(global_client_caps & CAP_STATUS32)) {
873 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
876 /* client_caps is used as final determination if client is NT or Win95.
877 This is needed to return the correct error codes in some
878 circumstances.
881 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
882 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
883 set_remote_arch( RA_WIN95);
888 if (!doencrypt) {
889 /* both Win95 and WinNT stuff up the password lengths for
890 non-encrypting systems. Uggh.
892 if passlen1==24 its a win95 system, and its setting the
893 password length incorrectly. Luckily it still works with the
894 default code because Win95 will null terminate the password
895 anyway
897 if passlen1>0 and passlen2>0 then maybe its a NT box and its
898 setting passlen2 to some random value which really stuffs
899 things up. we need to fix that one. */
901 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
902 passlen2 = 0;
905 /* check for nasty tricks */
906 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
907 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
910 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
911 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
914 /* Save the lanman2 password and the NT md4 password. */
916 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
917 doencrypt = False;
920 if (doencrypt) {
921 lm_resp = data_blob(p, passlen1);
922 nt_resp = data_blob(p+passlen1, passlen2);
923 } else {
924 pstring pass;
925 BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
927 #if 0
928 /* This was the previous fix. Not sure if it's still valid. JRA. */
929 if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
930 /* NT4.0 stuffs up plaintext unicode password lengths... */
931 srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
932 sizeof(pass), passlen1, STR_TERMINATE);
933 #endif
935 if (unic && (passlen2 == 0) && passlen1) {
936 /* Only a ascii plaintext password was sent. */
937 srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass),
938 passlen1, STR_TERMINATE|STR_ASCII);
939 } else {
940 srvstr_pull(inbuf, pass, smb_buf(inbuf),
941 sizeof(pass), unic ? passlen2 : passlen1,
942 STR_TERMINATE);
944 plaintext_password = data_blob(pass, strlen(pass)+1);
947 p += passlen1 + passlen2;
948 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
949 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
950 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
951 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
953 /* not documented or decoded by Ethereal but there is one more string
954 in the extra bytes which is the same as the PrimaryDomain when using
955 extended security. Windows NT 4 and 2003 use this string to store
956 the native lanman string. Windows 9x does not include a string here
957 at all so we have to check if we have any extra bytes left */
959 byte_count = SVAL(inbuf, smb_vwv13);
960 if ( PTR_DIFF(p, save_p) < byte_count)
961 p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
962 else
963 fstrcpy( primary_domain, "null" );
965 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
966 domain, native_os, native_lanman, primary_domain));
968 if ( ra_type == RA_WIN2K ) {
969 if ( strlen(native_lanman) == 0 )
970 ra_lanman_string( primary_domain );
971 else
972 ra_lanman_string( native_lanman );
977 if (SVAL(inbuf,smb_vwv4) == 0) {
978 setup_new_vc_session();
981 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
983 if (*user) {
984 if (global_spnego_negotiated) {
986 /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
988 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
989 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
991 fstrcpy(sub_user, user);
992 } else {
993 fstrcpy(sub_user, lp_guestaccount());
996 sub_set_smb_name(sub_user);
998 reload_services(True);
1000 if (lp_security() == SEC_SHARE) {
1001 /* in share level we should ignore any passwords */
1003 data_blob_free(&lm_resp);
1004 data_blob_free(&nt_resp);
1005 data_blob_clear_free(&plaintext_password);
1007 map_username(sub_user);
1008 add_session_user(sub_user);
1009 /* Then force it to null for the benfit of the code below */
1010 *user = 0;
1013 if (!*user) {
1015 nt_status = check_guest_password(&server_info);
1017 } else if (doencrypt) {
1018 if (!negprot_global_auth_context) {
1019 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted session setup without negprot denied!\n"));
1020 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
1022 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
1023 lm_resp, nt_resp);
1024 if (NT_STATUS_IS_OK(nt_status)) {
1025 nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context,
1026 user_info,
1027 &server_info);
1029 } else {
1030 struct auth_context *plaintext_auth_context = NULL;
1031 const uint8 *chal;
1032 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
1033 chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
1035 if (!make_user_info_for_reply(&user_info,
1036 user, domain, chal,
1037 plaintext_password)) {
1038 nt_status = NT_STATUS_NO_MEMORY;
1041 if (NT_STATUS_IS_OK(nt_status)) {
1042 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context,
1043 user_info,
1044 &server_info);
1046 (plaintext_auth_context->free)(&plaintext_auth_context);
1051 free_user_info(&user_info);
1053 if (!NT_STATUS_IS_OK(nt_status)) {
1054 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
1057 if (!NT_STATUS_IS_OK(nt_status)) {
1058 data_blob_free(&nt_resp);
1059 data_blob_free(&lm_resp);
1060 data_blob_clear_free(&plaintext_password);
1061 return ERROR_NT(nt_status_squash(nt_status));
1064 nt_status = create_local_token(server_info);
1065 if (!NT_STATUS_IS_OK(nt_status)) {
1066 DEBUG(10, ("create_local_token failed: %s\n",
1067 nt_errstr(nt_status)));
1068 data_blob_free(&nt_resp);
1069 data_blob_free(&lm_resp);
1070 data_blob_clear_free(&plaintext_password);
1071 return ERROR_NT(nt_status_squash(nt_status));
1074 if (server_info->user_session_key.data) {
1075 session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
1076 } else {
1077 session_key = data_blob(NULL, 0);
1080 data_blob_clear_free(&plaintext_password);
1082 /* it's ok - setup a reply */
1083 set_message(outbuf,3,0,True);
1084 if (Protocol >= PROTOCOL_NT1) {
1085 char *p = smb_buf( outbuf );
1086 p += add_signature( outbuf, p );
1087 set_message_end( outbuf, p );
1088 /* perhaps grab OS version here?? */
1091 if (server_info->guest) {
1092 SSVAL(outbuf,smb_vwv2,1);
1095 /* register the name and uid as being validated, so further connections
1096 to a uid can get through without a password, on the same VC */
1098 /* register_vuid keeps the server info */
1099 sess_vuid = register_vuid(server_info, session_key, nt_resp.data ? nt_resp : lm_resp, sub_user);
1100 data_blob_free(&nt_resp);
1101 data_blob_free(&lm_resp);
1103 if (sess_vuid == -1) {
1104 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
1107 /* current_user_info is changed on new vuid */
1108 reload_services( True );
1110 if (!server_info->guest && !srv_signing_started() && !srv_check_sign_mac(inbuf, True)) {
1111 exit_server("reply_sesssetup_and_X: bad smb signature");
1114 SSVAL(outbuf,smb_uid,sess_vuid);
1115 SSVAL(inbuf,smb_uid,sess_vuid);
1117 if (!done_sesssetup)
1118 max_send = MIN(max_send,smb_bufsize);
1120 done_sesssetup = True;
1122 END_PROFILE(SMBsesssetupX);
1123 return chain_reply(inbuf,outbuf,length,bufsize);