Restructure the connect function code to always call
[Samba/bb.git] / source3 / smbd / sesssetup.c
blobaddd386fb4fcc1c9288d17dfc5e8f461c60db8b0
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
8 Copyright (C) Volker Lendecke 2007
9 Copyright (C) Jeremy Allison 2007
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "smbd/globals.h"
27 #include "../libcli/auth/spnego.h"
29 /* For split krb5 SPNEGO blobs. */
30 struct pending_auth_data {
31 struct pending_auth_data *prev, *next;
32 uint16 vuid; /* Tag for this entry. */
33 uint16 smbpid; /* Alternate tag for this entry. */
34 size_t needed_len;
35 DATA_BLOB partial_data;
39 on a logon error possibly map the error to success if "map to guest"
40 is set approriately
42 static NTSTATUS do_map_to_guest(NTSTATUS status,
43 auth_serversupplied_info **server_info,
44 const char *user, const char *domain)
46 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
47 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
48 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
49 DEBUG(3,("No such user %s [%s] - using guest account\n",
50 user, domain));
51 status = make_server_info_guest(NULL, server_info);
55 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
56 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
57 DEBUG(3,("Registered username %s for guest access\n",
58 user));
59 status = make_server_info_guest(NULL, server_info);
63 return status;
66 /****************************************************************************
67 Add the standard 'Samba' signature to the end of the session setup.
68 ****************************************************************************/
70 static int push_signature(uint8 **outbuf)
72 char *lanman;
73 int result, tmp;
75 result = 0;
77 tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
79 if (tmp == -1) return -1;
80 result += tmp;
82 if (asprintf(&lanman, "Samba %s", samba_version_string()) != -1) {
83 tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
84 SAFE_FREE(lanman);
86 else {
87 tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
90 if (tmp == -1) return -1;
91 result += tmp;
93 tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
95 if (tmp == -1) return -1;
96 result += tmp;
98 return result;
101 /****************************************************************************
102 Send a security blob via a session setup reply.
103 ****************************************************************************/
105 static void reply_sesssetup_blob(struct smb_request *req,
106 DATA_BLOB blob,
107 NTSTATUS nt_status)
109 if (!NT_STATUS_IS_OK(nt_status) &&
110 !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
111 reply_nterror(req, nt_status_squash(nt_status));
112 return;
115 nt_status = nt_status_squash(nt_status);
116 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
117 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
118 SSVAL(req->outbuf, smb_vwv3, blob.length);
120 if ((message_push_blob(&req->outbuf, blob) == -1)
121 || (push_signature(&req->outbuf) == -1)) {
122 reply_nterror(req, NT_STATUS_NO_MEMORY);
126 /****************************************************************************
127 Do a 'guest' logon, getting back the
128 ****************************************************************************/
130 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
132 struct auth_context *auth_context;
133 auth_usersupplied_info *user_info = NULL;
135 NTSTATUS nt_status;
136 unsigned char chal[8];
138 ZERO_STRUCT(chal);
140 DEBUG(3,("Got anonymous request\n"));
142 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context,
143 chal))) {
144 return nt_status;
147 if (!make_user_info_guest(&user_info)) {
148 (auth_context->free)(&auth_context);
149 return NT_STATUS_NO_MEMORY;
152 nt_status = auth_context->check_ntlm_password(auth_context,
153 user_info,
154 server_info);
155 (auth_context->free)(&auth_context);
156 free_user_info(&user_info);
157 return nt_status;
161 #ifdef HAVE_KRB5
163 #if 0
164 /* Experiment that failed. See "only happens with a KDC" comment below. */
165 /****************************************************************************
166 Cerate a clock skew error blob for a Windows client.
167 ****************************************************************************/
169 static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
171 krb5_context context = NULL;
172 krb5_error_code kerr = 0;
173 krb5_data reply;
174 krb5_principal host_princ = NULL;
175 char *host_princ_s = NULL;
176 bool ret = False;
178 *pblob_out = data_blob_null;
180 initialize_krb5_error_table();
181 kerr = krb5_init_context(&context);
182 if (kerr) {
183 return False;
185 /* Create server principal. */
186 asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
187 if (!host_princ_s) {
188 goto out;
190 strlower_m(host_princ_s);
192 kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
193 if (kerr) {
194 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
195 "for name %s: Error %s\n",
196 host_princ_s, error_message(kerr) ));
197 goto out;
200 kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
201 host_princ, &reply);
202 if (kerr) {
203 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
204 "failed: Error %s\n",
205 error_message(kerr) ));
206 goto out;
209 *pblob_out = data_blob(reply.data, reply.length);
210 kerberos_free_data_contents(context,&reply);
211 ret = True;
213 out:
215 if (host_princ_s) {
216 SAFE_FREE(host_princ_s);
218 if (host_princ) {
219 krb5_free_principal(context, host_princ);
221 krb5_free_context(context);
222 return ret;
224 #endif
226 /****************************************************************************
227 Reply to a session setup spnego negotiate packet for kerberos.
228 ****************************************************************************/
230 static void reply_spnego_kerberos(struct smb_request *req,
231 DATA_BLOB *secblob,
232 const char *mechOID,
233 uint16 vuid,
234 bool *p_invalidate_vuid)
236 TALLOC_CTX *mem_ctx;
237 DATA_BLOB ticket;
238 char *client, *p, *domain;
239 fstring netbios_domain_name;
240 struct passwd *pw;
241 fstring user;
242 int sess_vuid = req->vuid;
243 NTSTATUS ret = NT_STATUS_OK;
244 struct PAC_DATA *pac_data = NULL;
245 DATA_BLOB ap_rep, ap_rep_wrapped, response;
246 auth_serversupplied_info *server_info = NULL;
247 DATA_BLOB session_key = data_blob_null;
248 uint8 tok_id[2];
249 DATA_BLOB nullblob = data_blob_null;
250 fstring real_username;
251 bool map_domainuser_to_guest = False;
252 bool username_was_mapped;
253 struct PAC_LOGON_INFO *logon_info = NULL;
254 struct smbd_server_connection *sconn = smbd_server_conn;
256 ZERO_STRUCT(ticket);
257 ZERO_STRUCT(ap_rep);
258 ZERO_STRUCT(ap_rep_wrapped);
259 ZERO_STRUCT(response);
261 /* Normally we will always invalidate the intermediate vuid. */
262 *p_invalidate_vuid = True;
264 mem_ctx = talloc_init("reply_spnego_kerberos");
265 if (mem_ctx == NULL) {
266 reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
267 return;
270 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
271 talloc_destroy(mem_ctx);
272 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
273 return;
276 ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
277 &client, &pac_data, &ap_rep,
278 &session_key, True);
280 data_blob_free(&ticket);
282 if (!NT_STATUS_IS_OK(ret)) {
283 #if 0
284 /* Experiment that failed.
285 * See "only happens with a KDC" comment below. */
287 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
290 * Windows in this case returns
291 * NT_STATUS_MORE_PROCESSING_REQUIRED
292 * with a negTokenTarg blob containing an krb5_error
293 * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
294 * The client then fixes its clock and continues rather
295 * than giving an error. JRA.
296 * -- Looks like this only happens with a KDC. JRA.
299 bool ok = make_krb5_skew_error(&ap_rep);
300 if (!ok) {
301 talloc_destroy(mem_ctx);
302 return ERROR_NT(nt_status_squash(
303 NT_STATUS_LOGON_FAILURE));
305 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
306 TOK_ID_KRB_ERROR);
307 response = spnego_gen_auth_response(&ap_rep_wrapped,
308 ret, OID_KERBEROS5_OLD);
309 reply_sesssetup_blob(conn, inbuf, outbuf, response,
310 NT_STATUS_MORE_PROCESSING_REQUIRED);
313 * In this one case we don't invalidate the
314 * intermediate vuid as we're expecting the client
315 * to re-use it for the next sessionsetupX packet. JRA.
318 *p_invalidate_vuid = False;
320 data_blob_free(&ap_rep);
321 data_blob_free(&ap_rep_wrapped);
322 data_blob_free(&response);
323 talloc_destroy(mem_ctx);
324 return -1; /* already replied */
326 #else
327 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
328 ret = NT_STATUS_LOGON_FAILURE;
330 #endif
331 DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
332 nt_errstr(ret)));
333 talloc_destroy(mem_ctx);
334 reply_nterror(req, nt_status_squash(ret));
335 return;
338 DEBUG(3,("Ticket name is [%s]\n", client));
340 p = strchr_m(client, '@');
341 if (!p) {
342 DEBUG(3,("Doesn't look like a valid principal\n"));
343 data_blob_free(&ap_rep);
344 data_blob_free(&session_key);
345 talloc_destroy(mem_ctx);
346 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
347 return;
350 *p = 0;
352 /* save the PAC data if we have it */
354 if (pac_data) {
355 logon_info = get_logon_info_from_pac(pac_data);
356 if (logon_info) {
357 netsamlogon_cache_store( client, &logon_info->info3 );
361 if (!strequal(p+1, lp_realm())) {
362 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
363 if (!lp_allow_trusted_domains()) {
364 data_blob_free(&ap_rep);
365 data_blob_free(&session_key);
366 talloc_destroy(mem_ctx);
367 reply_nterror(req, nt_status_squash(
368 NT_STATUS_LOGON_FAILURE));
369 return;
373 /* this gives a fully qualified user name (ie. with full realm).
374 that leads to very long usernames, but what else can we do? */
376 domain = p+1;
378 if (logon_info && logon_info->info3.base.domain.string) {
379 fstrcpy(netbios_domain_name,
380 logon_info->info3.base.domain.string);
381 domain = netbios_domain_name;
382 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
384 } else {
386 /* If we have winbind running, we can (and must) shorten the
387 username by using the short netbios name. Otherwise we will
388 have inconsistent user names. With Kerberos, we get the
389 fully qualified realm, with ntlmssp we get the short
390 name. And even w2k3 does use ntlmssp if you for example
391 connect to an ip address. */
393 wbcErr wbc_status;
394 struct wbcDomainInfo *info = NULL;
396 DEBUG(10, ("Mapping [%s] to short name\n", domain));
398 wbc_status = wbcDomainInfo(domain, &info);
400 if (WBC_ERROR_IS_OK(wbc_status)) {
402 fstrcpy(netbios_domain_name,
403 info->short_name);
405 wbcFreeMemory(info);
406 domain = netbios_domain_name;
407 DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
408 } else {
409 DEBUG(3, ("Could not find short name: %s\n",
410 wbcErrorString(wbc_status)));
414 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
416 /* lookup the passwd struct, create a new user if necessary */
418 username_was_mapped = map_username(sconn, user);
420 pw = smb_getpwnam( mem_ctx, user, real_username, True );
422 if (pw) {
423 /* if a real user check pam account restrictions */
424 /* only really perfomed if "obey pam restriction" is true */
425 /* do this before an eventual mapping to guest occurs */
426 ret = smb_pam_accountcheck(pw->pw_name);
427 if ( !NT_STATUS_IS_OK(ret)) {
428 DEBUG(1,("PAM account restriction "
429 "prevents user login\n"));
430 data_blob_free(&ap_rep);
431 data_blob_free(&session_key);
432 TALLOC_FREE(mem_ctx);
433 reply_nterror(req, nt_status_squash(ret));
434 return;
438 if (!pw) {
440 /* this was originally the behavior of Samba 2.2, if a user
441 did not have a local uid but has been authenticated, then
442 map them to a guest account */
444 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
445 map_domainuser_to_guest = True;
446 fstrcpy(user,lp_guestaccount());
447 pw = smb_getpwnam( mem_ctx, user, real_username, True );
450 /* extra sanity check that the guest account is valid */
452 if ( !pw ) {
453 DEBUG(1,("Username %s is invalid on this system\n",
454 user));
455 data_blob_free(&ap_rep);
456 data_blob_free(&session_key);
457 TALLOC_FREE(mem_ctx);
458 reply_nterror(req, nt_status_squash(
459 NT_STATUS_LOGON_FAILURE));
460 return;
464 /* setup the string used by %U */
466 sub_set_smb_name( real_username );
467 reload_services(True);
469 if ( map_domainuser_to_guest ) {
470 make_server_info_guest(NULL, &server_info);
471 } else if (logon_info) {
472 /* pass the unmapped username here since map_username()
473 will be called again from inside make_server_info_info3() */
475 ret = make_server_info_info3(mem_ctx, client, domain,
476 &server_info, &logon_info->info3);
477 if ( !NT_STATUS_IS_OK(ret) ) {
478 DEBUG(1,("make_server_info_info3 failed: %s!\n",
479 nt_errstr(ret)));
480 data_blob_free(&ap_rep);
481 data_blob_free(&session_key);
482 TALLOC_FREE(mem_ctx);
483 reply_nterror(req, nt_status_squash(ret));
484 return;
487 } else {
488 ret = make_server_info_pw(&server_info, real_username, pw);
490 if ( !NT_STATUS_IS_OK(ret) ) {
491 DEBUG(1,("make_server_info_pw failed: %s!\n",
492 nt_errstr(ret)));
493 data_blob_free(&ap_rep);
494 data_blob_free(&session_key);
495 TALLOC_FREE(mem_ctx);
496 reply_nterror(req, nt_status_squash(ret));
497 return;
500 /* make_server_info_pw does not set the domain. Without this
501 * we end up with the local netbios name in substitutions for
502 * %D. */
504 if (server_info->sam_account != NULL) {
505 pdb_set_domain(server_info->sam_account,
506 domain, PDB_SET);
510 server_info->nss_token |= username_was_mapped;
512 /* we need to build the token for the user. make_server_info_guest()
513 already does this */
515 if ( !server_info->ptok ) {
516 ret = create_local_token( server_info );
517 if ( !NT_STATUS_IS_OK(ret) ) {
518 DEBUG(10,("failed to create local token: %s\n",
519 nt_errstr(ret)));
520 data_blob_free(&ap_rep);
521 data_blob_free(&session_key);
522 TALLOC_FREE( mem_ctx );
523 TALLOC_FREE( server_info );
524 reply_nterror(req, nt_status_squash(ret));
525 return;
529 if (!is_partial_auth_vuid(sconn, sess_vuid)) {
530 sess_vuid = register_initial_vuid(sconn);
533 data_blob_free(&server_info->user_session_key);
534 server_info->user_session_key = session_key;
535 session_key = data_blob_null;
537 /* register_existing_vuid keeps the server info */
538 /* register_existing_vuid takes ownership of session_key on success,
539 * no need to free after this on success. A better interface would copy
540 * it.... */
542 sess_vuid = register_existing_vuid(sconn,
543 sess_vuid,
544 server_info,
545 nullblob,
546 client);
548 reply_outbuf(req, 4, 0);
549 SSVAL(req->outbuf,smb_uid,sess_vuid);
551 if (sess_vuid == UID_FIELD_INVALID ) {
552 ret = NT_STATUS_LOGON_FAILURE;
553 } else {
554 /* current_user_info is changed on new vuid */
555 reload_services( True );
557 SSVAL(req->outbuf, smb_vwv3, 0);
559 if (server_info->guest) {
560 SSVAL(req->outbuf,smb_vwv2,1);
563 SSVAL(req->outbuf, smb_uid, sess_vuid);
565 /* Successful logon. Keep this vuid. */
566 *p_invalidate_vuid = False;
569 /* wrap that up in a nice GSS-API wrapping */
570 if (NT_STATUS_IS_OK(ret)) {
571 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
572 TOK_ID_KRB_AP_REP);
573 } else {
574 ap_rep_wrapped = data_blob_null;
576 response = spnego_gen_auth_response(&ap_rep_wrapped, ret,
577 mechOID);
578 reply_sesssetup_blob(req, response, ret);
580 data_blob_free(&ap_rep);
581 data_blob_free(&ap_rep_wrapped);
582 data_blob_free(&response);
583 TALLOC_FREE(mem_ctx);
586 #endif
588 /****************************************************************************
589 Send a session setup reply, wrapped in SPNEGO.
590 Get vuid and check first.
591 End the NTLMSSP exchange context if we are OK/complete fail
592 This should be split into two functions, one to handle each
593 leg of the NTLM auth steps.
594 ***************************************************************************/
596 static void reply_spnego_ntlmssp(struct smb_request *req,
597 uint16 vuid,
598 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
599 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
600 const char *OID,
601 bool wrap)
603 DATA_BLOB response;
604 struct auth_serversupplied_info *server_info = NULL;
605 struct smbd_server_connection *sconn = smbd_server_conn;
607 if (NT_STATUS_IS_OK(nt_status)) {
608 server_info = (*auth_ntlmssp_state)->server_info;
609 } else {
610 nt_status = do_map_to_guest(nt_status,
611 &server_info,
612 (*auth_ntlmssp_state)->ntlmssp_state->user,
613 (*auth_ntlmssp_state)->ntlmssp_state->domain);
616 reply_outbuf(req, 4, 0);
618 SSVAL(req->outbuf, smb_uid, vuid);
620 if (NT_STATUS_IS_OK(nt_status)) {
621 DATA_BLOB nullblob = data_blob_null;
623 if (!is_partial_auth_vuid(sconn, vuid)) {
624 nt_status = NT_STATUS_LOGON_FAILURE;
625 goto out;
628 data_blob_free(&server_info->user_session_key);
629 server_info->user_session_key =
630 data_blob_talloc(
631 server_info,
632 (*auth_ntlmssp_state)->ntlmssp_state->session_key.data,
633 (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
635 /* register_existing_vuid keeps the server info */
636 if (register_existing_vuid(sconn, vuid,
637 server_info, nullblob,
638 (*auth_ntlmssp_state)->ntlmssp_state->user) !=
639 vuid) {
640 nt_status = NT_STATUS_LOGON_FAILURE;
641 goto out;
644 (*auth_ntlmssp_state)->server_info = NULL;
646 /* current_user_info is changed on new vuid */
647 reload_services( True );
649 SSVAL(req->outbuf, smb_vwv3, 0);
651 if (server_info->guest) {
652 SSVAL(req->outbuf,smb_vwv2,1);
656 out:
658 if (wrap) {
659 response = spnego_gen_auth_response(ntlmssp_blob,
660 nt_status, OID);
661 } else {
662 response = *ntlmssp_blob;
665 reply_sesssetup_blob(req, response, nt_status);
666 if (wrap) {
667 data_blob_free(&response);
670 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
671 and the other end, that we are not finished yet. */
673 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
674 /* NB. This is *NOT* an error case. JRA */
675 auth_ntlmssp_end(auth_ntlmssp_state);
676 if (!NT_STATUS_IS_OK(nt_status)) {
677 /* Kill the intermediate vuid */
678 invalidate_vuid(sconn, vuid);
683 /****************************************************************************
684 Is this a krb5 mechanism ?
685 ****************************************************************************/
687 NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in,
688 DATA_BLOB *pblob_out,
689 char **kerb_mechOID)
691 char *OIDs[ASN1_MAX_OIDS];
692 int i;
693 NTSTATUS ret = NT_STATUS_OK;
695 *kerb_mechOID = NULL;
697 /* parse out the OIDs and the first sec blob */
698 if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
699 return NT_STATUS_LOGON_FAILURE;
702 /* only look at the first OID for determining the mechToken --
703 according to RFC2478, we should choose the one we want
704 and renegotiate, but i smell a client bug here..
706 Problem observed when connecting to a member (samba box)
707 of an AD domain as a user in a Samba domain. Samba member
708 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
709 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
710 NTLMSSP mechtoken. --jerry */
712 #ifdef HAVE_KRB5
713 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
714 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
715 *kerb_mechOID = SMB_STRDUP(OIDs[0]);
716 if (*kerb_mechOID == NULL) {
717 ret = NT_STATUS_NO_MEMORY;
720 #endif
722 for (i=0;OIDs[i];i++) {
723 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
724 talloc_free(OIDs[i]);
726 return ret;
729 /****************************************************************************
730 Fall back from krb5 to NTLMSSP.
731 ****************************************************************************/
733 static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
734 uint16 vuid)
736 DATA_BLOB response;
738 reply_outbuf(req, 4, 0);
739 SSVAL(req->outbuf,smb_uid,vuid);
741 DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
742 "but set to downgrade to NTLMSSP\n"));
744 response = spnego_gen_auth_response(NULL,
745 NT_STATUS_MORE_PROCESSING_REQUIRED,
746 OID_NTLMSSP);
747 reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
748 data_blob_free(&response);
751 /****************************************************************************
752 Reply to a session setup spnego negotiate packet.
753 ****************************************************************************/
755 static void reply_spnego_negotiate(struct smb_request *req,
756 uint16 vuid,
757 DATA_BLOB blob1,
758 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
760 DATA_BLOB secblob;
761 DATA_BLOB chal;
762 char *kerb_mech = NULL;
763 NTSTATUS status;
764 struct smbd_server_connection *sconn = smbd_server_conn;
766 status = parse_spnego_mechanisms(blob1, &secblob, &kerb_mech);
767 if (!NT_STATUS_IS_OK(status)) {
768 /* Kill the intermediate vuid */
769 invalidate_vuid(sconn, vuid);
770 reply_nterror(req, nt_status_squash(status));
771 return;
774 DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
775 (unsigned long)secblob.length));
777 #ifdef HAVE_KRB5
778 if (kerb_mech && ((lp_security()==SEC_ADS) ||
779 USE_KERBEROS_KEYTAB) ) {
780 bool destroy_vuid = True;
781 reply_spnego_kerberos(req, &secblob, kerb_mech,
782 vuid, &destroy_vuid);
783 data_blob_free(&secblob);
784 if (destroy_vuid) {
785 /* Kill the intermediate vuid */
786 invalidate_vuid(sconn, vuid);
788 SAFE_FREE(kerb_mech);
789 return;
791 #endif
793 if (*auth_ntlmssp_state) {
794 auth_ntlmssp_end(auth_ntlmssp_state);
797 if (kerb_mech) {
798 data_blob_free(&secblob);
799 /* The mechtoken is a krb5 ticket, but
800 * we need to fall back to NTLM. */
801 reply_spnego_downgrade_to_ntlmssp(req, vuid);
802 SAFE_FREE(kerb_mech);
803 return;
806 status = auth_ntlmssp_start(auth_ntlmssp_state);
807 if (!NT_STATUS_IS_OK(status)) {
808 /* Kill the intermediate vuid */
809 invalidate_vuid(sconn, vuid);
810 reply_nterror(req, nt_status_squash(status));
811 return;
814 status = auth_ntlmssp_update(*auth_ntlmssp_state,
815 secblob, &chal);
817 data_blob_free(&secblob);
819 reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
820 &chal, status, OID_NTLMSSP, true);
822 data_blob_free(&chal);
824 /* already replied */
825 return;
828 /****************************************************************************
829 Reply to a session setup spnego auth packet.
830 ****************************************************************************/
832 static void reply_spnego_auth(struct smb_request *req,
833 uint16 vuid,
834 DATA_BLOB blob1,
835 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
837 DATA_BLOB auth = data_blob_null;
838 DATA_BLOB auth_reply = data_blob_null;
839 DATA_BLOB secblob = data_blob_null;
840 NTSTATUS status = NT_STATUS_LOGON_FAILURE;
841 struct smbd_server_connection *sconn = smbd_server_conn;
843 if (!spnego_parse_auth(blob1, &auth)) {
844 #if 0
845 file_save("auth.dat", blob1.data, blob1.length);
846 #endif
847 /* Kill the intermediate vuid */
848 invalidate_vuid(sconn, vuid);
850 reply_nterror(req, nt_status_squash(
851 NT_STATUS_LOGON_FAILURE));
852 return;
855 if (auth.data[0] == ASN1_APPLICATION(0)) {
856 /* Might be a second negTokenTarg packet */
857 char *kerb_mech = NULL;
859 status = parse_spnego_mechanisms(auth, &secblob, &kerb_mech);
861 if (!NT_STATUS_IS_OK(status)) {
862 /* Kill the intermediate vuid */
863 invalidate_vuid(sconn, vuid);
864 reply_nterror(req, nt_status_squash(status));
865 return;
868 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
869 (unsigned long)secblob.length));
870 #ifdef HAVE_KRB5
871 if (kerb_mech && ((lp_security()==SEC_ADS) ||
872 USE_KERBEROS_KEYTAB)) {
873 bool destroy_vuid = True;
874 reply_spnego_kerberos(req, &secblob, kerb_mech,
875 vuid, &destroy_vuid);
876 data_blob_free(&secblob);
877 data_blob_free(&auth);
878 if (destroy_vuid) {
879 /* Kill the intermediate vuid */
880 invalidate_vuid(sconn, vuid);
882 SAFE_FREE(kerb_mech);
883 return;
885 #endif
886 /* Can't blunder into NTLMSSP auth if we have
887 * a krb5 ticket. */
889 if (kerb_mech) {
890 /* Kill the intermediate vuid */
891 invalidate_vuid(sconn, vuid);
892 DEBUG(3,("reply_spnego_auth: network "
893 "misconfiguration, client sent us a "
894 "krb5 ticket and kerberos security "
895 "not enabled\n"));
896 reply_nterror(req, nt_status_squash(
897 NT_STATUS_LOGON_FAILURE));
898 SAFE_FREE(kerb_mech);
902 /* If we get here it wasn't a negTokenTarg auth packet. */
903 data_blob_free(&secblob);
905 if (!*auth_ntlmssp_state) {
906 status = auth_ntlmssp_start(auth_ntlmssp_state);
907 if (!NT_STATUS_IS_OK(status)) {
908 /* Kill the intermediate vuid */
909 invalidate_vuid(sconn, vuid);
910 reply_nterror(req, nt_status_squash(status));
911 return;
915 status = auth_ntlmssp_update(*auth_ntlmssp_state,
916 auth, &auth_reply);
918 data_blob_free(&auth);
920 /* Don't send the mechid as we've already sent this (RFC4178). */
922 reply_spnego_ntlmssp(req, vuid,
923 auth_ntlmssp_state,
924 &auth_reply, status, NULL, true);
926 data_blob_free(&auth_reply);
928 /* and tell smbd that we have already replied to this packet */
929 return;
932 /****************************************************************************
933 Delete an entry on the list.
934 ****************************************************************************/
936 static void delete_partial_auth(struct smbd_server_connection *sconn,
937 struct pending_auth_data *pad)
939 if (!pad) {
940 return;
942 DLIST_REMOVE(sconn->smb1.pd_list, pad);
943 data_blob_free(&pad->partial_data);
944 SAFE_FREE(pad);
947 /****************************************************************************
948 Search for a partial SPNEGO auth fragment matching an smbpid.
949 ****************************************************************************/
951 static struct pending_auth_data *get_pending_auth_data(
952 struct smbd_server_connection *sconn,
953 uint16_t smbpid)
955 struct pending_auth_data *pad;
957 * NOTE: using the smbpid here is completely wrong...
958 * see [MS-SMB]
959 * 3.3.5.3 Receiving an SMB_COM_SESSION_SETUP_ANDX Request
961 for (pad = sconn->smb1.pd_list; pad; pad = pad->next) {
962 if (pad->smbpid == smbpid) {
963 break;
966 return pad;
969 /****************************************************************************
970 Check the size of an SPNEGO blob. If we need more return
971 NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
972 the blob to be more than 64k.
973 ****************************************************************************/
975 static NTSTATUS check_spnego_blob_complete(struct smbd_server_connection *sconn,
976 uint16 smbpid, uint16 vuid,
977 DATA_BLOB *pblob)
979 struct pending_auth_data *pad = NULL;
980 ASN1_DATA *data;
981 size_t needed_len = 0;
983 pad = get_pending_auth_data(sconn, smbpid);
985 /* Ensure we have some data. */
986 if (pblob->length == 0) {
987 /* Caller can cope. */
988 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
989 delete_partial_auth(sconn, pad);
990 return NT_STATUS_OK;
993 /* Were we waiting for more data ? */
994 if (pad) {
995 DATA_BLOB tmp_blob;
996 size_t copy_len = MIN(65536, pblob->length);
998 /* Integer wrap paranoia.... */
1000 if (pad->partial_data.length + copy_len <
1001 pad->partial_data.length ||
1002 pad->partial_data.length + copy_len < copy_len) {
1004 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1005 "pad->partial_data.length = %u, "
1006 "copy_len = %u\n",
1007 (unsigned int)pad->partial_data.length,
1008 (unsigned int)copy_len ));
1010 delete_partial_auth(sconn, pad);
1011 return NT_STATUS_INVALID_PARAMETER;
1014 DEBUG(10,("check_spnego_blob_complete: "
1015 "pad->partial_data.length = %u, "
1016 "pad->needed_len = %u, "
1017 "copy_len = %u, "
1018 "pblob->length = %u,\n",
1019 (unsigned int)pad->partial_data.length,
1020 (unsigned int)pad->needed_len,
1021 (unsigned int)copy_len,
1022 (unsigned int)pblob->length ));
1024 tmp_blob = data_blob(NULL,
1025 pad->partial_data.length + copy_len);
1027 /* Concatenate the two (up to copy_len) bytes. */
1028 memcpy(tmp_blob.data,
1029 pad->partial_data.data,
1030 pad->partial_data.length);
1031 memcpy(tmp_blob.data + pad->partial_data.length,
1032 pblob->data,
1033 copy_len);
1035 /* Replace the partial data. */
1036 data_blob_free(&pad->partial_data);
1037 pad->partial_data = tmp_blob;
1038 ZERO_STRUCT(tmp_blob);
1040 /* Are we done ? */
1041 if (pblob->length >= pad->needed_len) {
1042 /* Yes, replace pblob. */
1043 data_blob_free(pblob);
1044 *pblob = pad->partial_data;
1045 ZERO_STRUCT(pad->partial_data);
1046 delete_partial_auth(sconn, pad);
1047 return NT_STATUS_OK;
1050 /* Still need more data. */
1051 pad->needed_len -= copy_len;
1052 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1055 if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
1056 (pblob->data[0] != ASN1_CONTEXT(1))) {
1057 /* Not something we can determine the
1058 * length of.
1060 return NT_STATUS_OK;
1063 /* This is a new SPNEGO sessionsetup - see if
1064 * the data given in this blob is enough.
1067 data = asn1_init(NULL);
1068 if (data == NULL) {
1069 return NT_STATUS_NO_MEMORY;
1072 asn1_load(data, *pblob);
1073 asn1_start_tag(data, pblob->data[0]);
1074 if (data->has_error || data->nesting == NULL) {
1075 asn1_free(data);
1076 /* Let caller catch. */
1077 return NT_STATUS_OK;
1080 /* Integer wrap paranoia.... */
1082 if (data->nesting->taglen + data->nesting->start < data->nesting->taglen ||
1083 data->nesting->taglen + data->nesting->start < data->nesting->start) {
1085 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1086 "data.nesting->taglen = %u, "
1087 "data.nesting->start = %u\n",
1088 (unsigned int)data->nesting->taglen,
1089 (unsigned int)data->nesting->start ));
1091 asn1_free(data);
1092 return NT_STATUS_INVALID_PARAMETER;
1095 /* Total length of the needed asn1 is the tag length
1096 * plus the current offset. */
1098 needed_len = data->nesting->taglen + data->nesting->start;
1099 asn1_free(data);
1101 DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
1102 "pblob->length = %u\n",
1103 (unsigned int)needed_len,
1104 (unsigned int)pblob->length ));
1106 if (needed_len <= pblob->length) {
1107 /* Nothing to do - blob is complete. */
1108 return NT_STATUS_OK;
1111 /* Refuse the blob if it's bigger than 64k. */
1112 if (needed_len > 65536) {
1113 DEBUG(2,("check_spnego_blob_complete: needed_len "
1114 "too large (%u)\n",
1115 (unsigned int)needed_len ));
1116 return NT_STATUS_INVALID_PARAMETER;
1119 /* We must store this blob until complete. */
1120 if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
1121 return NT_STATUS_NO_MEMORY;
1123 pad->needed_len = needed_len - pblob->length;
1124 pad->partial_data = data_blob(pblob->data, pblob->length);
1125 if (pad->partial_data.data == NULL) {
1126 SAFE_FREE(pad);
1127 return NT_STATUS_NO_MEMORY;
1129 pad->smbpid = smbpid;
1130 pad->vuid = vuid;
1131 DLIST_ADD(sconn->smb1.pd_list, pad);
1133 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1136 /****************************************************************************
1137 Reply to a session setup command.
1138 conn POINTER CAN BE NULL HERE !
1139 ****************************************************************************/
1141 static void reply_sesssetup_and_X_spnego(struct smb_request *req)
1143 const uint8 *p;
1144 DATA_BLOB blob1;
1145 size_t bufrem;
1146 char *tmp;
1147 const char *native_os;
1148 const char *native_lanman;
1149 const char *primary_domain;
1150 const char *p2;
1151 uint16 data_blob_len = SVAL(req->vwv+7, 0);
1152 enum remote_arch_types ra_type = get_remote_arch();
1153 int vuid = req->vuid;
1154 user_struct *vuser = NULL;
1155 NTSTATUS status = NT_STATUS_OK;
1156 uint16 smbpid = req->smbpid;
1157 struct smbd_server_connection *sconn = smbd_server_conn;
1159 DEBUG(3,("Doing spnego session setup\n"));
1161 if (global_client_caps == 0) {
1162 global_client_caps = IVAL(req->vwv+10, 0);
1164 if (!(global_client_caps & CAP_STATUS32)) {
1165 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1170 p = req->buf;
1172 if (data_blob_len == 0) {
1173 /* an invalid request */
1174 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1175 return;
1178 bufrem = smbreq_bufrem(req, p);
1179 /* pull the spnego blob */
1180 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1182 #if 0
1183 file_save("negotiate.dat", blob1.data, blob1.length);
1184 #endif
1186 p2 = (char *)req->buf + data_blob_len;
1188 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1189 STR_TERMINATE);
1190 native_os = tmp ? tmp : "";
1192 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1193 STR_TERMINATE);
1194 native_lanman = tmp ? tmp : "";
1196 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1197 STR_TERMINATE);
1198 primary_domain = tmp ? tmp : "";
1200 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1201 native_os, native_lanman, primary_domain));
1203 if ( ra_type == RA_WIN2K ) {
1204 /* Vista sets neither the OS or lanman strings */
1206 if ( !strlen(native_os) && !strlen(native_lanman) )
1207 set_remote_arch(RA_VISTA);
1209 /* Windows 2003 doesn't set the native lanman string,
1210 but does set primary domain which is a bug I think */
1212 if ( !strlen(native_lanman) ) {
1213 ra_lanman_string( primary_domain );
1214 } else {
1215 ra_lanman_string( native_lanman );
1219 /* Did we get a valid vuid ? */
1220 if (!is_partial_auth_vuid(sconn, vuid)) {
1221 /* No, then try and see if this is an intermediate sessionsetup
1222 * for a large SPNEGO packet. */
1223 struct pending_auth_data *pad;
1224 pad = get_pending_auth_data(sconn, smbpid);
1225 if (pad) {
1226 DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1227 "pending vuid %u\n",
1228 (unsigned int)pad->vuid ));
1229 vuid = pad->vuid;
1233 /* Do we have a valid vuid now ? */
1234 if (!is_partial_auth_vuid(sconn, vuid)) {
1235 /* No, start a new authentication setup. */
1236 vuid = register_initial_vuid(sconn);
1237 if (vuid == UID_FIELD_INVALID) {
1238 data_blob_free(&blob1);
1239 reply_nterror(req, nt_status_squash(
1240 NT_STATUS_INVALID_PARAMETER));
1241 return;
1245 vuser = get_partial_auth_user_struct(sconn, vuid);
1246 /* This MUST be valid. */
1247 if (!vuser) {
1248 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1251 /* Large (greater than 4k) SPNEGO blobs are split into multiple
1252 * sessionsetup requests as the Windows limit on the security blob
1253 * field is 4k. Bug #4400. JRA.
1256 status = check_spnego_blob_complete(sconn, smbpid, vuid, &blob1);
1257 if (!NT_STATUS_IS_OK(status)) {
1258 if (!NT_STATUS_EQUAL(status,
1259 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1260 /* Real error - kill the intermediate vuid */
1261 invalidate_vuid(sconn, vuid);
1263 data_blob_free(&blob1);
1264 reply_nterror(req, nt_status_squash(status));
1265 return;
1268 if (blob1.data[0] == ASN1_APPLICATION(0)) {
1270 /* its a negTokenTarg packet */
1272 reply_spnego_negotiate(req, vuid, blob1,
1273 &vuser->auth_ntlmssp_state);
1274 data_blob_free(&blob1);
1275 return;
1278 if (blob1.data[0] == ASN1_CONTEXT(1)) {
1280 /* its a auth packet */
1282 reply_spnego_auth(req, vuid, blob1,
1283 &vuser->auth_ntlmssp_state);
1284 data_blob_free(&blob1);
1285 return;
1288 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1289 DATA_BLOB chal;
1291 if (!vuser->auth_ntlmssp_state) {
1292 status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1293 if (!NT_STATUS_IS_OK(status)) {
1294 /* Kill the intermediate vuid */
1295 invalidate_vuid(sconn, vuid);
1296 data_blob_free(&blob1);
1297 reply_nterror(req, nt_status_squash(status));
1298 return;
1302 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1303 blob1, &chal);
1305 data_blob_free(&blob1);
1307 reply_spnego_ntlmssp(req, vuid,
1308 &vuser->auth_ntlmssp_state,
1309 &chal, status, OID_NTLMSSP, false);
1310 data_blob_free(&chal);
1311 return;
1314 /* what sort of packet is this? */
1315 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1317 data_blob_free(&blob1);
1319 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1322 /****************************************************************************
1323 On new VC == 0, shutdown *all* old connections and users.
1324 It seems that only NT4.x does this. At W2K and above (XP etc.).
1325 a new session setup with VC==0 is ignored.
1326 ****************************************************************************/
1328 static int shutdown_other_smbds(struct db_record *rec,
1329 const struct connections_key *key,
1330 const struct connections_data *crec,
1331 void *private_data)
1333 const char *ip = (const char *)private_data;
1335 if (!process_exists(crec->pid)) {
1336 return 0;
1339 if (procid_is_me(&crec->pid)) {
1340 return 0;
1343 if (strcmp(ip, crec->addr) != 0) {
1344 return 0;
1347 DEBUG(0,("shutdown_other_smbds: shutting down pid %u "
1348 "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid), ip));
1350 messaging_send(smbd_messaging_context(), crec->pid, MSG_SHUTDOWN,
1351 &data_blob_null);
1352 return 0;
1355 static void setup_new_vc_session(void)
1357 char addr[INET6_ADDRSTRLEN];
1359 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1360 "compatible we would close all old resources.\n"));
1361 #if 0
1362 conn_close_all();
1363 invalidate_all_vuids();
1364 #endif
1365 if (lp_reset_on_zero_vc()) {
1366 connections_forall(shutdown_other_smbds,
1367 CONST_DISCARD(void *,
1368 client_addr(get_client_fd(),addr,sizeof(addr))));
1372 /****************************************************************************
1373 Reply to a session setup command.
1374 ****************************************************************************/
1376 void reply_sesssetup_and_X(struct smb_request *req)
1378 int sess_vuid;
1379 int smb_bufsize;
1380 DATA_BLOB lm_resp;
1381 DATA_BLOB nt_resp;
1382 DATA_BLOB plaintext_password;
1383 char *tmp;
1384 const char *user;
1385 fstring sub_user; /* Sainitised username for substituion */
1386 const char *domain;
1387 const char *native_os;
1388 const char *native_lanman;
1389 const char *primary_domain;
1390 auth_usersupplied_info *user_info = NULL;
1391 auth_serversupplied_info *server_info = NULL;
1392 uint16 smb_flag2 = req->flags2;
1394 NTSTATUS nt_status;
1395 struct smbd_server_connection *sconn = smbd_server_conn;
1397 bool doencrypt = sconn->smb1.negprot.encrypted_passwords;
1399 START_PROFILE(SMBsesssetupX);
1401 ZERO_STRUCT(lm_resp);
1402 ZERO_STRUCT(nt_resp);
1403 ZERO_STRUCT(plaintext_password);
1405 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1407 /* a SPNEGO session setup has 12 command words, whereas a normal
1408 NT1 session setup has 13. See the cifs spec. */
1409 if (req->wct == 12 &&
1410 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1412 if (!sconn->smb1.negprot.spnego) {
1413 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1414 "at SPNEGO session setup when it was not "
1415 "negotiated.\n"));
1416 reply_nterror(req, nt_status_squash(
1417 NT_STATUS_LOGON_FAILURE));
1418 END_PROFILE(SMBsesssetupX);
1419 return;
1422 if (SVAL(req->vwv+4, 0) == 0) {
1423 setup_new_vc_session();
1426 reply_sesssetup_and_X_spnego(req);
1427 END_PROFILE(SMBsesssetupX);
1428 return;
1431 smb_bufsize = SVAL(req->vwv+2, 0);
1433 if (get_Protocol() < PROTOCOL_NT1) {
1434 uint16 passlen1 = SVAL(req->vwv+7, 0);
1436 /* Never do NT status codes with protocols before NT1 as we
1437 * don't get client caps. */
1438 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1440 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
1441 reply_nterror(req, nt_status_squash(
1442 NT_STATUS_INVALID_PARAMETER));
1443 END_PROFILE(SMBsesssetupX);
1444 return;
1447 if (doencrypt) {
1448 lm_resp = data_blob(req->buf, passlen1);
1449 } else {
1450 plaintext_password = data_blob(req->buf, passlen1+1);
1451 /* Ensure null termination */
1452 plaintext_password.data[passlen1] = 0;
1455 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
1456 req->buf + passlen1, STR_TERMINATE);
1457 user = tmp ? tmp : "";
1459 domain = "";
1461 } else {
1462 uint16 passlen1 = SVAL(req->vwv+7, 0);
1463 uint16 passlen2 = SVAL(req->vwv+8, 0);
1464 enum remote_arch_types ra_type = get_remote_arch();
1465 const uint8_t *p = req->buf;
1466 const uint8_t *save_p = req->buf;
1467 uint16 byte_count;
1470 if(global_client_caps == 0) {
1471 global_client_caps = IVAL(req->vwv+11, 0);
1473 if (!(global_client_caps & CAP_STATUS32)) {
1474 remove_from_common_flags2(
1475 FLAGS2_32_BIT_ERROR_CODES);
1478 /* client_caps is used as final determination if
1479 * client is NT or Win95. This is needed to return
1480 * the correct error codes in some circumstances.
1483 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1484 ra_type == RA_WIN95) {
1485 if(!(global_client_caps & (CAP_NT_SMBS|
1486 CAP_STATUS32))) {
1487 set_remote_arch( RA_WIN95);
1492 if (!doencrypt) {
1493 /* both Win95 and WinNT stuff up the password
1494 * lengths for non-encrypting systems. Uggh.
1496 if passlen1==24 its a win95 system, and its setting
1497 the password length incorrectly. Luckily it still
1498 works with the default code because Win95 will null
1499 terminate the password anyway
1501 if passlen1>0 and passlen2>0 then maybe its a NT box
1502 and its setting passlen2 to some random value which
1503 really stuffs things up. we need to fix that one. */
1505 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1506 passlen2 != 1) {
1507 passlen2 = 0;
1511 /* check for nasty tricks */
1512 if (passlen1 > MAX_PASS_LEN
1513 || passlen1 > smbreq_bufrem(req, p)) {
1514 reply_nterror(req, nt_status_squash(
1515 NT_STATUS_INVALID_PARAMETER));
1516 END_PROFILE(SMBsesssetupX);
1517 return;
1520 if (passlen2 > MAX_PASS_LEN
1521 || passlen2 > smbreq_bufrem(req, p+passlen1)) {
1522 reply_nterror(req, nt_status_squash(
1523 NT_STATUS_INVALID_PARAMETER));
1524 END_PROFILE(SMBsesssetupX);
1525 return;
1528 /* Save the lanman2 password and the NT md4 password. */
1530 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1531 doencrypt = False;
1534 if (doencrypt) {
1535 lm_resp = data_blob(p, passlen1);
1536 nt_resp = data_blob(p+passlen1, passlen2);
1537 } else if (lp_security() != SEC_SHARE) {
1539 * In share level we should ignore any passwords, so
1540 * only read them if we're not.
1542 char *pass = NULL;
1543 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1545 if (unic && (passlen2 == 0) && passlen1) {
1546 /* Only a ascii plaintext password was sent. */
1547 (void)srvstr_pull_talloc(talloc_tos(),
1548 req->inbuf,
1549 req->flags2,
1550 &pass,
1551 req->buf,
1552 passlen1,
1553 STR_TERMINATE|STR_ASCII);
1554 } else {
1555 (void)srvstr_pull_talloc(talloc_tos(),
1556 req->inbuf,
1557 req->flags2,
1558 &pass,
1559 req->buf,
1560 unic ? passlen2 : passlen1,
1561 STR_TERMINATE);
1563 if (!pass) {
1564 reply_nterror(req, nt_status_squash(
1565 NT_STATUS_INVALID_PARAMETER));
1566 END_PROFILE(SMBsesssetupX);
1567 return;
1569 plaintext_password = data_blob(pass, strlen(pass)+1);
1572 p += passlen1 + passlen2;
1574 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1575 STR_TERMINATE);
1576 user = tmp ? tmp : "";
1578 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1579 STR_TERMINATE);
1580 domain = tmp ? tmp : "";
1582 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1583 STR_TERMINATE);
1584 native_os = tmp ? tmp : "";
1586 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1587 STR_TERMINATE);
1588 native_lanman = tmp ? tmp : "";
1590 /* not documented or decoded by Ethereal but there is one more
1591 * string in the extra bytes which is the same as the
1592 * PrimaryDomain when using extended security. Windows NT 4
1593 * and 2003 use this string to store the native lanman string.
1594 * Windows 9x does not include a string here at all so we have
1595 * to check if we have any extra bytes left */
1597 byte_count = SVAL(req->vwv+13, 0);
1598 if ( PTR_DIFF(p, save_p) < byte_count) {
1599 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1600 STR_TERMINATE);
1601 primary_domain = tmp ? tmp : "";
1602 } else {
1603 primary_domain = talloc_strdup(talloc_tos(), "null");
1606 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
1607 "PrimaryDomain=[%s]\n",
1608 domain, native_os, native_lanman, primary_domain));
1610 if ( ra_type == RA_WIN2K ) {
1611 if ( strlen(native_lanman) == 0 )
1612 ra_lanman_string( primary_domain );
1613 else
1614 ra_lanman_string( native_lanman );
1619 if (SVAL(req->vwv+4, 0) == 0) {
1620 setup_new_vc_session();
1623 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1624 domain, user, get_remote_machine_name()));
1626 if (*user) {
1627 if (sconn->smb1.negprot.spnego) {
1629 /* This has to be here, because this is a perfectly
1630 * valid behaviour for guest logons :-( */
1632 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1633 "at 'normal' session setup after "
1634 "negotiating spnego.\n"));
1635 reply_nterror(req, nt_status_squash(
1636 NT_STATUS_LOGON_FAILURE));
1637 END_PROFILE(SMBsesssetupX);
1638 return;
1640 fstrcpy(sub_user, user);
1641 } else {
1642 fstrcpy(sub_user, lp_guestaccount());
1645 sub_set_smb_name(sub_user);
1647 reload_services(True);
1649 if (lp_security() == SEC_SHARE) {
1650 /* In share level we should ignore any passwords */
1652 data_blob_free(&lm_resp);
1653 data_blob_free(&nt_resp);
1654 data_blob_clear_free(&plaintext_password);
1656 map_username(sconn, sub_user);
1657 add_session_user(sconn, sub_user);
1658 add_session_workgroup(sconn, domain);
1659 /* Then force it to null for the benfit of the code below */
1660 user = "";
1663 if (!*user) {
1665 nt_status = check_guest_password(&server_info);
1667 } else if (doencrypt) {
1668 struct auth_context *negprot_auth_context = NULL;
1669 negprot_auth_context = sconn->smb1.negprot.auth_context;
1670 if (!negprot_auth_context) {
1671 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
1672 "session setup without negprot denied!\n"));
1673 reply_nterror(req, nt_status_squash(
1674 NT_STATUS_LOGON_FAILURE));
1675 END_PROFILE(SMBsesssetupX);
1676 return;
1678 nt_status = make_user_info_for_reply_enc(&user_info, user,
1679 domain,
1680 lm_resp, nt_resp);
1681 if (NT_STATUS_IS_OK(nt_status)) {
1682 nt_status = negprot_auth_context->check_ntlm_password(
1683 negprot_auth_context,
1684 user_info,
1685 &server_info);
1687 } else {
1688 struct auth_context *plaintext_auth_context = NULL;
1690 nt_status = make_auth_context_subsystem(
1691 &plaintext_auth_context);
1693 if (NT_STATUS_IS_OK(nt_status)) {
1694 uint8_t chal[8];
1696 plaintext_auth_context->get_ntlm_challenge(
1697 plaintext_auth_context, chal);
1699 if (!make_user_info_for_reply(&user_info,
1700 user, domain, chal,
1701 plaintext_password)) {
1702 nt_status = NT_STATUS_NO_MEMORY;
1705 if (NT_STATUS_IS_OK(nt_status)) {
1706 nt_status = plaintext_auth_context->check_ntlm_password(
1707 plaintext_auth_context,
1708 user_info,
1709 &server_info);
1711 (plaintext_auth_context->free)(
1712 &plaintext_auth_context);
1717 free_user_info(&user_info);
1719 if (!NT_STATUS_IS_OK(nt_status)) {
1720 nt_status = do_map_to_guest(nt_status, &server_info,
1721 user, domain);
1724 if (!NT_STATUS_IS_OK(nt_status)) {
1725 data_blob_free(&nt_resp);
1726 data_blob_free(&lm_resp);
1727 data_blob_clear_free(&plaintext_password);
1728 reply_nterror(req, nt_status_squash(nt_status));
1729 END_PROFILE(SMBsesssetupX);
1730 return;
1733 /* Ensure we can't possible take a code path leading to a
1734 * null defref. */
1735 if (!server_info) {
1736 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1737 END_PROFILE(SMBsesssetupX);
1738 return;
1741 if (!server_info->ptok) {
1742 nt_status = create_local_token(server_info);
1744 if (!NT_STATUS_IS_OK(nt_status)) {
1745 DEBUG(10, ("create_local_token failed: %s\n",
1746 nt_errstr(nt_status)));
1747 data_blob_free(&nt_resp);
1748 data_blob_free(&lm_resp);
1749 data_blob_clear_free(&plaintext_password);
1750 reply_nterror(req, nt_status_squash(nt_status));
1751 END_PROFILE(SMBsesssetupX);
1752 return;
1756 data_blob_clear_free(&plaintext_password);
1758 /* it's ok - setup a reply */
1759 reply_outbuf(req, 3, 0);
1760 if (get_Protocol() >= PROTOCOL_NT1) {
1761 push_signature(&req->outbuf);
1762 /* perhaps grab OS version here?? */
1765 if (server_info->guest) {
1766 SSVAL(req->outbuf,smb_vwv2,1);
1769 /* register the name and uid as being validated, so further connections
1770 to a uid can get through without a password, on the same VC */
1772 if (lp_security() == SEC_SHARE) {
1773 sess_vuid = UID_FIELD_INVALID;
1774 TALLOC_FREE(server_info);
1775 } else {
1776 /* Ignore the initial vuid. */
1777 sess_vuid = register_initial_vuid(sconn);
1778 if (sess_vuid == UID_FIELD_INVALID) {
1779 data_blob_free(&nt_resp);
1780 data_blob_free(&lm_resp);
1781 reply_nterror(req, nt_status_squash(
1782 NT_STATUS_LOGON_FAILURE));
1783 END_PROFILE(SMBsesssetupX);
1784 return;
1786 /* register_existing_vuid keeps the server info */
1787 sess_vuid = register_existing_vuid(sconn, sess_vuid,
1788 server_info,
1789 nt_resp.data ? nt_resp : lm_resp,
1790 sub_user);
1791 if (sess_vuid == UID_FIELD_INVALID) {
1792 data_blob_free(&nt_resp);
1793 data_blob_free(&lm_resp);
1794 reply_nterror(req, nt_status_squash(
1795 NT_STATUS_LOGON_FAILURE));
1796 END_PROFILE(SMBsesssetupX);
1797 return;
1800 /* current_user_info is changed on new vuid */
1801 reload_services( True );
1804 data_blob_free(&nt_resp);
1805 data_blob_free(&lm_resp);
1807 SSVAL(req->outbuf,smb_uid,sess_vuid);
1808 SSVAL(req->inbuf,smb_uid,sess_vuid);
1809 req->vuid = sess_vuid;
1811 if (!sconn->smb1.sessions.done_sesssetup) {
1812 sconn->smb1.sessions.max_send =
1813 MIN(sconn->smb1.sessions.max_send,smb_bufsize);
1815 sconn->smb1.sessions.done_sesssetup = true;
1817 END_PROFILE(SMBsesssetupX);
1818 chain_reply(req);
1819 return;