Correctly use SPNEGO to negotiate down from krb5 to NTLMSSP.
[Samba.git] / source3 / smbd / sesssetup.c
blob3e04da35df7139d0ccbc426db20a4bf7b8d6dc3b
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"
27 extern struct auth_context *negprot_global_auth_context;
28 extern bool global_encrypted_passwords_negotiated;
29 extern bool global_spnego_negotiated;
30 extern enum protocol_types Protocol;
31 extern int max_send;
33 uint32 global_client_caps = 0;
36 on a logon error possibly map the error to success if "map to guest"
37 is set approriately
39 static NTSTATUS do_map_to_guest(NTSTATUS status,
40 auth_serversupplied_info **server_info,
41 const char *user, const char *domain)
43 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
44 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
45 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
46 DEBUG(3,("No such user %s [%s] - using guest account\n",
47 user, domain));
48 status = make_server_info_guest(server_info);
52 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
53 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
54 DEBUG(3,("Registered username %s for guest access\n",
55 user));
56 status = make_server_info_guest(server_info);
60 return status;
63 /****************************************************************************
64 Add the standard 'Samba' signature to the end of the session setup.
65 ****************************************************************************/
67 static int push_signature(uint8 **outbuf)
69 char *lanman;
70 int result, tmp;
72 result = 0;
74 tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
76 if (tmp == -1) return -1;
77 result += tmp;
79 if (asprintf(&lanman, "Samba %s", SAMBA_VERSION_STRING) != -1) {
80 tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
81 SAFE_FREE(lanman);
83 else {
84 tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
87 if (tmp == -1) return -1;
88 result += tmp;
90 tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
92 if (tmp == -1) return -1;
93 result += tmp;
95 return result;
98 /****************************************************************************
99 Start the signing engine if needed. Don't fail signing here.
100 ****************************************************************************/
102 static void sessionsetup_start_signing_engine(
103 const auth_serversupplied_info *server_info,
104 const uint8 *inbuf)
106 if (!server_info->guest && !srv_signing_started()) {
107 /* We need to start the signing engine
108 * here but a W2K client sends the old
109 * "BSRSPYL " signature instead of the
110 * correct one. Subsequent packets will
111 * be correct.
113 srv_check_sign_mac((char *)inbuf, False);
117 /****************************************************************************
118 Send a security blob via a session setup reply.
119 ****************************************************************************/
121 static void reply_sesssetup_blob(struct smb_request *req,
122 DATA_BLOB blob,
123 NTSTATUS nt_status)
125 if (!NT_STATUS_IS_OK(nt_status) &&
126 !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
127 reply_nterror(req, nt_status_squash(nt_status));
128 } else {
129 nt_status = nt_status_squash(nt_status);
130 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
131 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
132 SSVAL(req->outbuf, smb_vwv3, blob.length);
134 if ((message_push_blob(&req->outbuf, blob) == -1)
135 || (push_signature(&req->outbuf) == -1)) {
136 reply_nterror(req, NT_STATUS_NO_MEMORY);
140 show_msg((char *)req->outbuf);
141 srv_send_smb(smbd_server_fd(),(char *)req->outbuf,req->encrypted);
142 TALLOC_FREE(req->outbuf);
145 /****************************************************************************
146 Do a 'guest' logon, getting back the
147 ****************************************************************************/
149 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
151 struct auth_context *auth_context;
152 auth_usersupplied_info *user_info = NULL;
154 NTSTATUS nt_status;
155 unsigned char chal[8];
157 ZERO_STRUCT(chal);
159 DEBUG(3,("Got anonymous request\n"));
161 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context,
162 chal))) {
163 return nt_status;
166 if (!make_user_info_guest(&user_info)) {
167 (auth_context->free)(&auth_context);
168 return NT_STATUS_NO_MEMORY;
171 nt_status = auth_context->check_ntlm_password(auth_context,
172 user_info,
173 server_info);
174 (auth_context->free)(&auth_context);
175 free_user_info(&user_info);
176 return nt_status;
180 #ifdef HAVE_KRB5
182 #if 0
183 /* Experiment that failed. See "only happens with a KDC" comment below. */
184 /****************************************************************************
185 Cerate a clock skew error blob for a Windows client.
186 ****************************************************************************/
188 static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
190 krb5_context context = NULL;
191 krb5_error_code kerr = 0;
192 krb5_data reply;
193 krb5_principal host_princ = NULL;
194 char *host_princ_s = NULL;
195 bool ret = False;
197 *pblob_out = data_blob_null;
199 initialize_krb5_error_table();
200 kerr = krb5_init_context(&context);
201 if (kerr) {
202 return False;
204 /* Create server principal. */
205 asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
206 if (!host_princ_s) {
207 goto out;
209 strlower_m(host_princ_s);
211 kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
212 if (kerr) {
213 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
214 "for name %s: Error %s\n",
215 host_princ_s, error_message(kerr) ));
216 goto out;
219 kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
220 host_princ, &reply);
221 if (kerr) {
222 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
223 "failed: Error %s\n",
224 error_message(kerr) ));
225 goto out;
228 *pblob_out = data_blob(reply.data, reply.length);
229 kerberos_free_data_contents(context,&reply);
230 ret = True;
232 out:
234 if (host_princ_s) {
235 SAFE_FREE(host_princ_s);
237 if (host_princ) {
238 krb5_free_principal(context, host_princ);
240 krb5_free_context(context);
241 return ret;
243 #endif
245 /****************************************************************************
246 Reply to a session setup spnego negotiate packet for kerberos.
247 ****************************************************************************/
249 static void reply_spnego_kerberos(struct smb_request *req,
250 DATA_BLOB *secblob,
251 uint16 vuid,
252 bool *p_invalidate_vuid)
254 TALLOC_CTX *mem_ctx;
255 DATA_BLOB ticket;
256 char *client, *p, *domain;
257 fstring netbios_domain_name;
258 struct passwd *pw;
259 fstring user;
260 int sess_vuid = req->vuid;
261 NTSTATUS ret = NT_STATUS_OK;
262 PAC_DATA *pac_data = NULL;
263 DATA_BLOB ap_rep, ap_rep_wrapped, response;
264 auth_serversupplied_info *server_info = NULL;
265 DATA_BLOB session_key = data_blob_null;
266 uint8 tok_id[2];
267 DATA_BLOB nullblob = data_blob_null;
268 fstring real_username;
269 bool map_domainuser_to_guest = False;
270 bool username_was_mapped;
271 PAC_LOGON_INFO *logon_info = NULL;
273 ZERO_STRUCT(ticket);
274 ZERO_STRUCT(ap_rep);
275 ZERO_STRUCT(ap_rep_wrapped);
276 ZERO_STRUCT(response);
278 /* Normally we will always invalidate the intermediate vuid. */
279 *p_invalidate_vuid = True;
281 mem_ctx = talloc_init("reply_spnego_kerberos");
282 if (mem_ctx == NULL) {
283 reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
284 return;
287 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
288 talloc_destroy(mem_ctx);
289 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
290 return;
293 ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
294 &client, &pac_data, &ap_rep,
295 &session_key, True);
297 data_blob_free(&ticket);
299 if (!NT_STATUS_IS_OK(ret)) {
300 #if 0
301 /* Experiment that failed.
302 * See "only happens with a KDC" comment below. */
304 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
307 * Windows in this case returns
308 * NT_STATUS_MORE_PROCESSING_REQUIRED
309 * with a negTokenTarg blob containing an krb5_error
310 * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
311 * The client then fixes its clock and continues rather
312 * than giving an error. JRA.
313 * -- Looks like this only happens with a KDC. JRA.
316 bool ok = make_krb5_skew_error(&ap_rep);
317 if (!ok) {
318 talloc_destroy(mem_ctx);
319 return ERROR_NT(nt_status_squash(
320 NT_STATUS_LOGON_FAILURE));
322 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
323 TOK_ID_KRB_ERROR);
324 response = spnego_gen_auth_response(&ap_rep_wrapped,
325 ret, OID_KERBEROS5_OLD);
326 reply_sesssetup_blob(conn, inbuf, outbuf, response,
327 NT_STATUS_MORE_PROCESSING_REQUIRED);
330 * In this one case we don't invalidate the
331 * intermediate vuid as we're expecting the client
332 * to re-use it for the next sessionsetupX packet. JRA.
335 *p_invalidate_vuid = False;
337 data_blob_free(&ap_rep);
338 data_blob_free(&ap_rep_wrapped);
339 data_blob_free(&response);
340 talloc_destroy(mem_ctx);
341 return -1; /* already replied */
343 #else
344 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
345 ret = NT_STATUS_LOGON_FAILURE;
347 #endif
348 DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
349 nt_errstr(ret)));
350 talloc_destroy(mem_ctx);
351 reply_nterror(req, nt_status_squash(ret));
352 return;
355 DEBUG(3,("Ticket name is [%s]\n", client));
357 p = strchr_m(client, '@');
358 if (!p) {
359 DEBUG(3,("Doesn't look like a valid principal\n"));
360 data_blob_free(&ap_rep);
361 data_blob_free(&session_key);
362 SAFE_FREE(client);
363 talloc_destroy(mem_ctx);
364 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
365 return;
368 *p = 0;
370 /* save the PAC data if we have it */
372 if (pac_data) {
373 logon_info = get_logon_info_from_pac(pac_data);
374 if (logon_info) {
375 netsamlogon_cache_store( client, &logon_info->info3 );
379 if (!strequal(p+1, lp_realm())) {
380 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
381 if (!lp_allow_trusted_domains()) {
382 data_blob_free(&ap_rep);
383 data_blob_free(&session_key);
384 SAFE_FREE(client);
385 talloc_destroy(mem_ctx);
386 reply_nterror(req, nt_status_squash(
387 NT_STATUS_LOGON_FAILURE));
388 return;
392 /* this gives a fully qualified user name (ie. with full realm).
393 that leads to very long usernames, but what else can we do? */
395 domain = p+1;
397 if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) {
398 unistr2_to_ascii(netbios_domain_name,
399 &logon_info->info3.uni_logon_dom,
400 sizeof(netbios_domain_name));
401 domain = netbios_domain_name;
402 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
404 } else {
406 /* If we have winbind running, we can (and must) shorten the
407 username by using the short netbios name. Otherwise we will
408 have inconsistent user names. With Kerberos, we get the
409 fully qualified realm, with ntlmssp we get the short
410 name. And even w2k3 does use ntlmssp if you for example
411 connect to an ip address. */
413 wbcErr wbc_status;
414 struct wbcDomainInfo *info = NULL;
416 DEBUG(10, ("Mapping [%s] to short name\n", domain));
418 wbc_status = wbcDomainInfo(domain, &info);
420 if (WBC_ERROR_IS_OK(wbc_status)) {
422 fstrcpy(netbios_domain_name,
423 info->short_name);
425 wbcFreeMemory(info);
426 domain = netbios_domain_name;
427 DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
428 } else {
429 DEBUG(3, ("Could not find short name: %s\n",
430 wbcErrorString(wbc_status)));
434 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
436 /* lookup the passwd struct, create a new user if necessary */
438 username_was_mapped = map_username( user );
440 pw = smb_getpwnam( mem_ctx, user, real_username, True );
442 if (pw) {
443 /* if a real user check pam account restrictions */
444 /* only really perfomed if "obey pam restriction" is true */
445 /* do this before an eventual mappign to guest occurs */
446 ret = smb_pam_accountcheck(pw->pw_name);
447 if ( !NT_STATUS_IS_OK(ret)) {
448 DEBUG(1,("PAM account restriction "
449 "prevents user login\n"));
450 data_blob_free(&ap_rep);
451 data_blob_free(&session_key);
452 TALLOC_FREE(mem_ctx);
453 reply_nterror(req, nt_status_squash(ret));
454 return;
458 if (!pw) {
460 /* this was originally the behavior of Samba 2.2, if a user
461 did not have a local uid but has been authenticated, then
462 map them to a guest account */
464 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
465 map_domainuser_to_guest = True;
466 fstrcpy(user,lp_guestaccount());
467 pw = smb_getpwnam( mem_ctx, user, real_username, True );
470 /* extra sanity check that the guest account is valid */
472 if ( !pw ) {
473 DEBUG(1,("Username %s is invalid on this system\n",
474 user));
475 SAFE_FREE(client);
476 data_blob_free(&ap_rep);
477 data_blob_free(&session_key);
478 TALLOC_FREE(mem_ctx);
479 reply_nterror(req, nt_status_squash(
480 NT_STATUS_LOGON_FAILURE));
481 return;
485 /* setup the string used by %U */
487 sub_set_smb_name( real_username );
488 reload_services(True);
490 if ( map_domainuser_to_guest ) {
491 make_server_info_guest(&server_info);
492 } else if (logon_info) {
493 /* pass the unmapped username here since map_username()
494 will be called again from inside make_server_info_info3() */
496 ret = make_server_info_info3(mem_ctx, client, domain,
497 &server_info, &logon_info->info3);
498 if ( !NT_STATUS_IS_OK(ret) ) {
499 DEBUG(1,("make_server_info_info3 failed: %s!\n",
500 nt_errstr(ret)));
501 SAFE_FREE(client);
502 data_blob_free(&ap_rep);
503 data_blob_free(&session_key);
504 TALLOC_FREE(mem_ctx);
505 reply_nterror(req, nt_status_squash(ret));
506 return;
509 } else {
510 ret = make_server_info_pw(&server_info, real_username, pw);
512 if ( !NT_STATUS_IS_OK(ret) ) {
513 DEBUG(1,("make_server_info_pw failed: %s!\n",
514 nt_errstr(ret)));
515 SAFE_FREE(client);
516 data_blob_free(&ap_rep);
517 data_blob_free(&session_key);
518 TALLOC_FREE(mem_ctx);
519 reply_nterror(req, nt_status_squash(ret));
520 return;
523 /* make_server_info_pw does not set the domain. Without this
524 * we end up with the local netbios name in substitutions for
525 * %D. */
527 if (server_info->sam_account != NULL) {
528 pdb_set_domain(server_info->sam_account,
529 domain, PDB_SET);
533 if (username_was_mapped) {
534 server_info->was_mapped = username_was_mapped;
537 /* we need to build the token for the user. make_server_info_guest()
538 already does this */
540 if ( !server_info->ptok ) {
541 ret = create_local_token( server_info );
542 if ( !NT_STATUS_IS_OK(ret) ) {
543 SAFE_FREE(client);
544 data_blob_free(&ap_rep);
545 data_blob_free(&session_key);
546 TALLOC_FREE( mem_ctx );
547 TALLOC_FREE( server_info );
548 reply_nterror(req, nt_status_squash(ret));
549 return;
553 /* register_existing_vuid keeps the server info */
554 /* register_existing_vuid takes ownership of session_key on success,
555 * no need to free after this on success. A better interface would copy
556 * it.... */
558 if (!is_partial_auth_vuid(sess_vuid)) {
559 sess_vuid = register_initial_vuid();
561 sess_vuid = register_existing_vuid(sess_vuid,
562 server_info,
563 session_key,
564 nullblob,
565 client);
567 SAFE_FREE(client);
569 reply_outbuf(req, 4, 0);
570 SSVAL(req->outbuf,smb_uid,sess_vuid);
572 if (sess_vuid == UID_FIELD_INVALID ) {
573 ret = NT_STATUS_LOGON_FAILURE;
574 data_blob_free(&session_key);
575 } else {
576 /* current_user_info is changed on new vuid */
577 reload_services( True );
579 SSVAL(req->outbuf, smb_vwv3, 0);
581 if (server_info->guest) {
582 SSVAL(req->outbuf,smb_vwv2,1);
585 SSVAL(req->outbuf, smb_uid, sess_vuid);
587 sessionsetup_start_signing_engine(server_info, req->inbuf);
588 /* Successful logon. Keep this vuid. */
589 *p_invalidate_vuid = False;
592 /* wrap that up in a nice GSS-API wrapping */
593 if (NT_STATUS_IS_OK(ret)) {
594 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
595 TOK_ID_KRB_AP_REP);
596 } else {
597 ap_rep_wrapped = data_blob_null;
599 response = spnego_gen_auth_response(&ap_rep_wrapped, ret,
600 OID_KERBEROS5_OLD);
601 reply_sesssetup_blob(req, response, ret);
603 data_blob_free(&ap_rep);
604 data_blob_free(&ap_rep_wrapped);
605 data_blob_free(&response);
606 TALLOC_FREE(mem_ctx);
609 #endif
611 /****************************************************************************
612 Send a session setup reply, wrapped in SPNEGO.
613 Get vuid and check first.
614 End the NTLMSSP exchange context if we are OK/complete fail
615 This should be split into two functions, one to handle each
616 leg of the NTLM auth steps.
617 ***************************************************************************/
619 static void reply_spnego_ntlmssp(struct smb_request *req,
620 uint16 vuid,
621 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
622 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
623 const char *OID,
624 bool wrap)
626 DATA_BLOB response;
627 struct auth_serversupplied_info *server_info = NULL;
629 if (NT_STATUS_IS_OK(nt_status)) {
630 server_info = (*auth_ntlmssp_state)->server_info;
631 } else {
632 nt_status = do_map_to_guest(nt_status,
633 &server_info,
634 (*auth_ntlmssp_state)->ntlmssp_state->user,
635 (*auth_ntlmssp_state)->ntlmssp_state->domain);
638 reply_outbuf(req, 4, 0);
640 SSVAL(req->outbuf, smb_uid, vuid);
642 if (NT_STATUS_IS_OK(nt_status)) {
643 DATA_BLOB nullblob = data_blob_null;
644 DATA_BLOB session_key =
645 data_blob(
646 (*auth_ntlmssp_state)->ntlmssp_state->session_key.data,
647 (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
649 if (!is_partial_auth_vuid(vuid)) {
650 data_blob_free(&session_key);
651 nt_status = NT_STATUS_LOGON_FAILURE;
652 goto out;
654 /* register_existing_vuid keeps the server info */
655 if (register_existing_vuid(vuid,
656 server_info,
657 session_key, nullblob,
658 (*auth_ntlmssp_state)->ntlmssp_state->user) !=
659 vuid) {
660 data_blob_free(&session_key);
661 nt_status = NT_STATUS_LOGON_FAILURE;
662 goto out;
665 (*auth_ntlmssp_state)->server_info = NULL;
667 /* current_user_info is changed on new vuid */
668 reload_services( True );
670 SSVAL(req->outbuf, smb_vwv3, 0);
672 if (server_info->guest) {
673 SSVAL(req->outbuf,smb_vwv2,1);
676 sessionsetup_start_signing_engine(server_info,
677 (uint8 *)req->inbuf);
680 out:
682 if (wrap) {
683 response = spnego_gen_auth_response(ntlmssp_blob,
684 nt_status, OID);
685 } else {
686 response = *ntlmssp_blob;
689 reply_sesssetup_blob(req, response, nt_status);
690 if (wrap) {
691 data_blob_free(&response);
694 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
695 and the other end, that we are not finished yet. */
697 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
698 /* NB. This is *NOT* an error case. JRA */
699 auth_ntlmssp_end(auth_ntlmssp_state);
700 if (!NT_STATUS_IS_OK(nt_status)) {
701 /* Kill the intermediate vuid */
702 invalidate_vuid(vuid);
707 /****************************************************************************
708 Is this a krb5 mechanism ?
709 ****************************************************************************/
711 NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out,
712 bool *p_is_krb5)
714 char *OIDs[ASN1_MAX_OIDS];
715 int i;
717 *p_is_krb5 = False;
719 /* parse out the OIDs and the first sec blob */
720 if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
721 return NT_STATUS_LOGON_FAILURE;
724 /* only look at the first OID for determining the mechToken --
725 according to RFC2478, we should choose the one we want
726 and renegotiate, but i smell a client bug here..
728 Problem observed when connecting to a member (samba box)
729 of an AD domain as a user in a Samba domain. Samba member
730 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
731 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
732 NTLMSSP mechtoken. --jerry */
734 #ifdef HAVE_KRB5
735 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
736 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
737 *p_is_krb5 = True;
739 #endif
741 for (i=0;OIDs[i];i++) {
742 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
743 free(OIDs[i]);
745 return NT_STATUS_OK;
748 /****************************************************************************
749 Fall back from krb5 to NTLMSSP.
750 ****************************************************************************/
752 static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
753 uint16 vuid)
755 DATA_BLOB response;
757 reply_outbuf(req, 4, 0);
758 SSVAL(req->outbuf,smb_uid,vuid);
760 DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
761 "but set to downgrade to NTLMSSP\n"));
763 response = spnego_gen_auth_response(NULL,
764 NT_STATUS_MORE_PROCESSING_REQUIRED,
765 OID_NTLMSSP);
766 reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
767 data_blob_free(&response);
770 /****************************************************************************
771 Reply to a session setup spnego negotiate packet.
772 ****************************************************************************/
774 static void reply_spnego_negotiate(struct smb_request *req,
775 uint16 vuid,
776 DATA_BLOB blob1,
777 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
779 DATA_BLOB secblob;
780 DATA_BLOB chal;
781 bool got_kerberos_mechanism = False;
782 NTSTATUS status;
784 status = parse_spnego_mechanisms(blob1, &secblob,
785 &got_kerberos_mechanism);
786 if (!NT_STATUS_IS_OK(status)) {
787 /* Kill the intermediate vuid */
788 invalidate_vuid(vuid);
789 reply_nterror(req, nt_status_squash(status));
790 return;
793 DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
794 (unsigned long)secblob.length));
796 #ifdef HAVE_KRB5
797 if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) ||
798 lp_use_kerberos_keytab()) ) {
799 bool destroy_vuid = True;
800 reply_spnego_kerberos(req, &secblob, vuid,
801 &destroy_vuid);
802 data_blob_free(&secblob);
803 if (destroy_vuid) {
804 /* Kill the intermediate vuid */
805 invalidate_vuid(vuid);
807 return;
809 #endif
811 if (*auth_ntlmssp_state) {
812 auth_ntlmssp_end(auth_ntlmssp_state);
815 if (got_kerberos_mechanism) {
816 data_blob_free(&secblob);
817 /* The mechtoken is a krb5 ticket, but
818 * we need to fall back to NTLM. */
819 reply_spnego_downgrade_to_ntlmssp(req,
820 vuid);
821 return;
824 status = auth_ntlmssp_start(auth_ntlmssp_state);
825 if (!NT_STATUS_IS_OK(status)) {
826 /* Kill the intermediate vuid */
827 invalidate_vuid(vuid);
828 reply_nterror(req, nt_status_squash(status));
829 return;
832 status = auth_ntlmssp_update(*auth_ntlmssp_state,
833 secblob, &chal);
835 data_blob_free(&secblob);
837 reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
838 &chal, status, OID_NTLMSSP, true);
840 data_blob_free(&chal);
842 /* already replied */
843 return;
846 /****************************************************************************
847 Reply to a session setup spnego auth packet.
848 ****************************************************************************/
850 static void reply_spnego_auth(struct smb_request *req,
851 uint16 vuid,
852 DATA_BLOB blob1,
853 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
855 DATA_BLOB auth = data_blob_null;
856 DATA_BLOB auth_reply = data_blob_null;
857 DATA_BLOB secblob = data_blob_null;
858 NTSTATUS status = NT_STATUS_LOGON_FAILURE;
860 if (!spnego_parse_auth(blob1, &auth)) {
861 #if 0
862 file_save("auth.dat", blob1.data, blob1.length);
863 #endif
864 /* Kill the intermediate vuid */
865 invalidate_vuid(vuid);
867 reply_nterror(req, nt_status_squash(
868 NT_STATUS_LOGON_FAILURE));
869 return;
872 if (auth.data[0] == ASN1_APPLICATION(0)) {
873 /* Might be a second negTokenTarg packet */
875 bool got_krb5_mechanism = False;
876 status = parse_spnego_mechanisms(auth, &secblob,
877 &got_krb5_mechanism);
879 if (!NT_STATUS_IS_OK(status)) {
880 /* Kill the intermediate vuid */
881 invalidate_vuid(vuid);
882 reply_nterror(req, nt_status_squash(status));
883 return;
886 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
887 (unsigned long)secblob.length));
888 #ifdef HAVE_KRB5
889 if ( got_krb5_mechanism && ((lp_security()==SEC_ADS) ||
890 lp_use_kerberos_keytab()) ) {
891 bool destroy_vuid = True;
892 reply_spnego_kerberos(req, &secblob,
893 vuid, &destroy_vuid);
894 data_blob_free(&secblob);
895 data_blob_free(&auth);
896 if (destroy_vuid) {
897 /* Kill the intermediate vuid */
898 invalidate_vuid(vuid);
900 return;
902 #endif
903 /* Can't blunder into NTLMSSP auth if we have
904 * a krb5 ticket. */
906 if (got_krb5_mechanism) {
907 /* Kill the intermediate vuid */
908 invalidate_vuid(vuid);
909 DEBUG(3,("reply_spnego_auth: network "
910 "misconfiguration, client sent us a "
911 "krb5 ticket and kerberos security "
912 "not enabled"));
913 reply_nterror(req, nt_status_squash(
914 NT_STATUS_LOGON_FAILURE));
918 /* If we get here it wasn't a negTokenTarg auth packet. */
919 data_blob_free(&secblob);
921 if (!*auth_ntlmssp_state) {
922 status = auth_ntlmssp_start(auth_ntlmssp_state);
923 if (!NT_STATUS_IS_OK(status)) {
924 /* Kill the intermediate vuid */
925 invalidate_vuid(vuid);
926 reply_nterror(req, nt_status_squash(status));
927 return;
931 status = auth_ntlmssp_update(*auth_ntlmssp_state,
932 auth, &auth_reply);
934 data_blob_free(&auth);
936 /* Don't send the mechid as we've already sent this (RFC4178). */
938 reply_spnego_ntlmssp(req, vuid,
939 auth_ntlmssp_state,
940 &auth_reply, status, NULL, true);
942 data_blob_free(&auth_reply);
944 /* and tell smbd that we have already replied to this packet */
945 return;
948 /****************************************************************************
949 List to store partial SPNEGO auth fragments.
950 ****************************************************************************/
952 static struct pending_auth_data *pd_list;
954 /****************************************************************************
955 Delete an entry on the list.
956 ****************************************************************************/
958 static void delete_partial_auth(struct pending_auth_data *pad)
960 if (!pad) {
961 return;
963 DLIST_REMOVE(pd_list, pad);
964 data_blob_free(&pad->partial_data);
965 SAFE_FREE(pad);
968 /****************************************************************************
969 Search for a partial SPNEGO auth fragment matching an smbpid.
970 ****************************************************************************/
972 static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
974 struct pending_auth_data *pad;
976 for (pad = pd_list; pad; pad = pad->next) {
977 if (pad->smbpid == smbpid) {
978 break;
981 return pad;
984 /****************************************************************************
985 Check the size of an SPNEGO blob. If we need more return
986 NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
987 the blob to be more than 64k.
988 ****************************************************************************/
990 static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid,
991 DATA_BLOB *pblob)
993 struct pending_auth_data *pad = NULL;
994 ASN1_DATA data;
995 size_t needed_len = 0;
997 pad = get_pending_auth_data(smbpid);
999 /* Ensure we have some data. */
1000 if (pblob->length == 0) {
1001 /* Caller can cope. */
1002 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
1003 delete_partial_auth(pad);
1004 return NT_STATUS_OK;
1007 /* Were we waiting for more data ? */
1008 if (pad) {
1009 DATA_BLOB tmp_blob;
1010 size_t copy_len = MIN(65536, pblob->length);
1012 /* Integer wrap paranoia.... */
1014 if (pad->partial_data.length + copy_len <
1015 pad->partial_data.length ||
1016 pad->partial_data.length + copy_len < copy_len) {
1018 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1019 "pad->partial_data.length = %u, "
1020 "copy_len = %u\n",
1021 (unsigned int)pad->partial_data.length,
1022 (unsigned int)copy_len ));
1024 delete_partial_auth(pad);
1025 return NT_STATUS_INVALID_PARAMETER;
1028 DEBUG(10,("check_spnego_blob_complete: "
1029 "pad->partial_data.length = %u, "
1030 "pad->needed_len = %u, "
1031 "copy_len = %u, "
1032 "pblob->length = %u,\n",
1033 (unsigned int)pad->partial_data.length,
1034 (unsigned int)pad->needed_len,
1035 (unsigned int)copy_len,
1036 (unsigned int)pblob->length ));
1038 tmp_blob = data_blob(NULL,
1039 pad->partial_data.length + copy_len);
1041 /* Concatenate the two (up to copy_len) bytes. */
1042 memcpy(tmp_blob.data,
1043 pad->partial_data.data,
1044 pad->partial_data.length);
1045 memcpy(tmp_blob.data + pad->partial_data.length,
1046 pblob->data,
1047 copy_len);
1049 /* Replace the partial data. */
1050 data_blob_free(&pad->partial_data);
1051 pad->partial_data = tmp_blob;
1052 ZERO_STRUCT(tmp_blob);
1054 /* Are we done ? */
1055 if (pblob->length >= pad->needed_len) {
1056 /* Yes, replace pblob. */
1057 data_blob_free(pblob);
1058 *pblob = pad->partial_data;
1059 ZERO_STRUCT(pad->partial_data);
1060 delete_partial_auth(pad);
1061 return NT_STATUS_OK;
1064 /* Still need more data. */
1065 pad->needed_len -= copy_len;
1066 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1069 if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
1070 (pblob->data[0] != ASN1_CONTEXT(1))) {
1071 /* Not something we can determine the
1072 * length of.
1074 return NT_STATUS_OK;
1077 /* This is a new SPNEGO sessionsetup - see if
1078 * the data given in this blob is enough.
1081 asn1_load(&data, *pblob);
1082 asn1_start_tag(&data, pblob->data[0]);
1083 if (data.has_error || data.nesting == NULL) {
1084 asn1_free(&data);
1085 /* Let caller catch. */
1086 return NT_STATUS_OK;
1089 /* Integer wrap paranoia.... */
1091 if (data.nesting->taglen + data.nesting->start < data.nesting->taglen ||
1092 data.nesting->taglen + data.nesting->start < data.nesting->start) {
1094 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1095 "data.nesting->taglen = %u, "
1096 "data.nesting->start = %u\n",
1097 (unsigned int)data.nesting->taglen,
1098 (unsigned int)data.nesting->start ));
1100 asn1_free(&data);
1101 return NT_STATUS_INVALID_PARAMETER;
1104 /* Total length of the needed asn1 is the tag length
1105 * plus the current offset. */
1107 needed_len = data.nesting->taglen + data.nesting->start;
1108 asn1_free(&data);
1110 DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
1111 "pblob->length = %u\n",
1112 (unsigned int)needed_len,
1113 (unsigned int)pblob->length ));
1115 if (needed_len <= pblob->length) {
1116 /* Nothing to do - blob is complete. */
1117 return NT_STATUS_OK;
1120 /* Refuse the blob if it's bigger than 64k. */
1121 if (needed_len > 65536) {
1122 DEBUG(2,("check_spnego_blob_complete: needed_len "
1123 "too large (%u)\n",
1124 (unsigned int)needed_len ));
1125 return NT_STATUS_INVALID_PARAMETER;
1128 /* We must store this blob until complete. */
1129 if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
1130 return NT_STATUS_NO_MEMORY;
1132 pad->needed_len = needed_len - pblob->length;
1133 pad->partial_data = data_blob(pblob->data, pblob->length);
1134 if (pad->partial_data.data == NULL) {
1135 SAFE_FREE(pad);
1136 return NT_STATUS_NO_MEMORY;
1138 pad->smbpid = smbpid;
1139 pad->vuid = vuid;
1140 DLIST_ADD(pd_list, pad);
1142 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1145 /****************************************************************************
1146 Reply to a session setup command.
1147 conn POINTER CAN BE NULL HERE !
1148 ****************************************************************************/
1150 static void reply_sesssetup_and_X_spnego(struct smb_request *req)
1152 uint8 *p;
1153 DATA_BLOB blob1;
1154 size_t bufrem;
1155 fstring native_os, native_lanman, primary_domain;
1156 const char *p2;
1157 uint16 data_blob_len = SVAL(req->inbuf, smb_vwv7);
1158 enum remote_arch_types ra_type = get_remote_arch();
1159 int vuid = SVAL(req->inbuf,smb_uid);
1160 user_struct *vuser = NULL;
1161 NTSTATUS status = NT_STATUS_OK;
1162 uint16 smbpid = req->smbpid;
1163 uint16 smb_flag2 = req->flags2;
1165 DEBUG(3,("Doing spnego session setup\n"));
1167 if (global_client_caps == 0) {
1168 global_client_caps = IVAL(req->inbuf,smb_vwv10);
1170 if (!(global_client_caps & CAP_STATUS32)) {
1171 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1176 p = (uint8 *)smb_buf(req->inbuf);
1178 if (data_blob_len == 0) {
1179 /* an invalid request */
1180 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1181 return;
1184 bufrem = smb_bufrem(req->inbuf, p);
1185 /* pull the spnego blob */
1186 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1188 #if 0
1189 file_save("negotiate.dat", blob1.data, blob1.length);
1190 #endif
1192 p2 = (char *)req->inbuf + smb_vwv13 + data_blob_len;
1193 p2 += srvstr_pull_buf(req->inbuf, smb_flag2, native_os, p2,
1194 sizeof(native_os), STR_TERMINATE);
1195 p2 += srvstr_pull_buf(req->inbuf, smb_flag2, native_lanman, p2,
1196 sizeof(native_lanman), STR_TERMINATE);
1197 p2 += srvstr_pull_buf(req->inbuf, smb_flag2, primary_domain, p2,
1198 sizeof(primary_domain), STR_TERMINATE);
1199 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1200 native_os, native_lanman, primary_domain));
1202 if ( ra_type == RA_WIN2K ) {
1203 /* Vista sets neither the OS or lanman strings */
1205 if ( !strlen(native_os) && !strlen(native_lanman) )
1206 set_remote_arch(RA_VISTA);
1208 /* Windows 2003 doesn't set the native lanman string,
1209 but does set primary domain which is a bug I think */
1211 if ( !strlen(native_lanman) ) {
1212 ra_lanman_string( primary_domain );
1213 } else {
1214 ra_lanman_string( native_lanman );
1218 /* Did we get a valid vuid ? */
1219 if (!is_partial_auth_vuid(vuid)) {
1220 /* No, then try and see if this is an intermediate sessionsetup
1221 * for a large SPNEGO packet. */
1222 struct pending_auth_data *pad = get_pending_auth_data(smbpid);
1223 if (pad) {
1224 DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1225 "pending vuid %u\n",
1226 (unsigned int)pad->vuid ));
1227 vuid = pad->vuid;
1231 /* Do we have a valid vuid now ? */
1232 if (!is_partial_auth_vuid(vuid)) {
1233 /* No, start a new authentication setup. */
1234 vuid = register_initial_vuid();
1235 if (vuid == UID_FIELD_INVALID) {
1236 data_blob_free(&blob1);
1237 reply_nterror(req, nt_status_squash(
1238 NT_STATUS_INVALID_PARAMETER));
1239 return;
1243 vuser = get_partial_auth_user_struct(vuid);
1244 /* This MUST be valid. */
1245 if (!vuser) {
1246 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1249 /* Large (greater than 4k) SPNEGO blobs are split into multiple
1250 * sessionsetup requests as the Windows limit on the security blob
1251 * field is 4k. Bug #4400. JRA.
1254 status = check_spnego_blob_complete(smbpid, vuid, &blob1);
1255 if (!NT_STATUS_IS_OK(status)) {
1256 if (!NT_STATUS_EQUAL(status,
1257 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1258 /* Real error - kill the intermediate vuid */
1259 invalidate_vuid(vuid);
1261 data_blob_free(&blob1);
1262 reply_nterror(req, nt_status_squash(status));
1263 return;
1266 if (blob1.data[0] == ASN1_APPLICATION(0)) {
1268 /* its a negTokenTarg packet */
1270 reply_spnego_negotiate(req, vuid, blob1,
1271 &vuser->auth_ntlmssp_state);
1272 data_blob_free(&blob1);
1273 return;
1276 if (blob1.data[0] == ASN1_CONTEXT(1)) {
1278 /* its a auth packet */
1280 reply_spnego_auth(req, vuid, blob1,
1281 &vuser->auth_ntlmssp_state);
1282 data_blob_free(&blob1);
1283 return;
1286 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1287 DATA_BLOB chal;
1289 if (!vuser->auth_ntlmssp_state) {
1290 status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1291 if (!NT_STATUS_IS_OK(status)) {
1292 /* Kill the intermediate vuid */
1293 invalidate_vuid(vuid);
1294 data_blob_free(&blob1);
1295 reply_nterror(req, nt_status_squash(status));
1296 return;
1300 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1301 blob1, &chal);
1303 data_blob_free(&blob1);
1305 reply_spnego_ntlmssp(req, vuid,
1306 &vuser->auth_ntlmssp_state,
1307 &chal, status, OID_NTLMSSP, false);
1308 data_blob_free(&chal);
1309 return;
1312 /* what sort of packet is this? */
1313 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1315 data_blob_free(&blob1);
1317 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1320 /****************************************************************************
1321 On new VC == 0, shutdown *all* old connections and users.
1322 It seems that only NT4.x does this. At W2K and above (XP etc.).
1323 a new session setup with VC==0 is ignored.
1324 ****************************************************************************/
1326 static int shutdown_other_smbds(struct db_record *rec,
1327 const struct connections_key *key,
1328 const struct connections_data *crec,
1329 void *private_data)
1331 const char *ip = (const char *)private_data;
1333 if (!process_exists(crec->pid)) {
1334 return 0;
1337 if (procid_is_me(&crec->pid)) {
1338 return 0;
1341 if (strcmp(ip, crec->addr) != 0) {
1342 return 0;
1345 messaging_send(smbd_messaging_context(), crec->pid, MSG_SHUTDOWN,
1346 &data_blob_null);
1347 return 0;
1350 static void setup_new_vc_session(void)
1352 char addr[INET6_ADDRSTRLEN];
1354 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1355 "compatible we would close all old resources.\n"));
1356 #if 0
1357 conn_close_all();
1358 invalidate_all_vuids();
1359 #endif
1360 if (lp_reset_on_zero_vc()) {
1361 connections_forall(shutdown_other_smbds,
1362 CONST_DISCARD(void *,
1363 client_addr(get_client_fd(),addr,sizeof(addr))));
1367 /****************************************************************************
1368 Reply to a session setup command.
1369 ****************************************************************************/
1371 void reply_sesssetup_and_X(struct smb_request *req)
1373 int sess_vuid;
1374 int smb_bufsize;
1375 DATA_BLOB lm_resp;
1376 DATA_BLOB nt_resp;
1377 DATA_BLOB plaintext_password;
1378 fstring user;
1379 fstring sub_user; /* Sainitised username for substituion */
1380 fstring domain;
1381 fstring native_os;
1382 fstring native_lanman;
1383 fstring primary_domain;
1384 static bool done_sesssetup = False;
1385 auth_usersupplied_info *user_info = NULL;
1386 auth_serversupplied_info *server_info = NULL;
1387 uint16 smb_flag2 = req->flags2;
1389 NTSTATUS nt_status;
1391 bool doencrypt = global_encrypted_passwords_negotiated;
1393 DATA_BLOB session_key;
1395 START_PROFILE(SMBsesssetupX);
1397 ZERO_STRUCT(lm_resp);
1398 ZERO_STRUCT(nt_resp);
1399 ZERO_STRUCT(plaintext_password);
1401 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1403 /* a SPNEGO session setup has 12 command words, whereas a normal
1404 NT1 session setup has 13. See the cifs spec. */
1405 if (req->wct == 12 &&
1406 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1408 if (!global_spnego_negotiated) {
1409 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1410 "at SPNEGO session setup when it was not "
1411 "negotiated.\n"));
1412 reply_nterror(req, nt_status_squash(
1413 NT_STATUS_LOGON_FAILURE));
1414 END_PROFILE(SMBsesssetupX);
1415 return;
1418 if (SVAL(req->inbuf,smb_vwv4) == 0) {
1419 setup_new_vc_session();
1422 reply_sesssetup_and_X_spnego(req);
1423 END_PROFILE(SMBsesssetupX);
1424 return;
1427 smb_bufsize = SVAL(req->inbuf,smb_vwv2);
1429 if (Protocol < PROTOCOL_NT1) {
1430 uint16 passlen1 = SVAL(req->inbuf,smb_vwv7);
1432 /* Never do NT status codes with protocols before NT1 as we
1433 * don't get client caps. */
1434 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1436 if ((passlen1 > MAX_PASS_LEN)
1437 || (passlen1 > smb_bufrem(req->inbuf,
1438 smb_buf(req->inbuf)))) {
1439 reply_nterror(req, nt_status_squash(
1440 NT_STATUS_INVALID_PARAMETER));
1441 END_PROFILE(SMBsesssetupX);
1442 return;
1445 if (doencrypt) {
1446 lm_resp = data_blob(smb_buf(req->inbuf), passlen1);
1447 } else {
1448 plaintext_password = data_blob(smb_buf(req->inbuf),
1449 passlen1+1);
1450 /* Ensure null termination */
1451 plaintext_password.data[passlen1] = 0;
1454 srvstr_pull_buf(req->inbuf, req->flags2, user,
1455 smb_buf(req->inbuf)+passlen1, sizeof(user),
1456 STR_TERMINATE);
1457 *domain = 0;
1459 } else {
1460 uint16 passlen1 = SVAL(req->inbuf,smb_vwv7);
1461 uint16 passlen2 = SVAL(req->inbuf,smb_vwv8);
1462 enum remote_arch_types ra_type = get_remote_arch();
1463 char *p = smb_buf(req->inbuf);
1464 char *save_p = smb_buf(req->inbuf);
1465 uint16 byte_count;
1468 if(global_client_caps == 0) {
1469 global_client_caps = IVAL(req->inbuf,smb_vwv11);
1471 if (!(global_client_caps & CAP_STATUS32)) {
1472 remove_from_common_flags2(
1473 FLAGS2_32_BIT_ERROR_CODES);
1476 /* client_caps is used as final determination if
1477 * client is NT or Win95. This is needed to return
1478 * the correct error codes in some circumstances.
1481 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1482 ra_type == RA_WIN95) {
1483 if(!(global_client_caps & (CAP_NT_SMBS|
1484 CAP_STATUS32))) {
1485 set_remote_arch( RA_WIN95);
1490 if (!doencrypt) {
1491 /* both Win95 and WinNT stuff up the password
1492 * lengths for non-encrypting systems. Uggh.
1494 if passlen1==24 its a win95 system, and its setting
1495 the password length incorrectly. Luckily it still
1496 works with the default code because Win95 will null
1497 terminate the password anyway
1499 if passlen1>0 and passlen2>0 then maybe its a NT box
1500 and its setting passlen2 to some random value which
1501 really stuffs things up. we need to fix that one. */
1503 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1504 passlen2 != 1) {
1505 passlen2 = 0;
1509 /* check for nasty tricks */
1510 if (passlen1 > MAX_PASS_LEN
1511 || passlen1 > smb_bufrem(req->inbuf, p)) {
1512 reply_nterror(req, nt_status_squash(
1513 NT_STATUS_INVALID_PARAMETER));
1514 END_PROFILE(SMBsesssetupX);
1515 return;
1518 if (passlen2 > MAX_PASS_LEN
1519 || passlen2 > smb_bufrem(req->inbuf, p+passlen1)) {
1520 reply_nterror(req, nt_status_squash(
1521 NT_STATUS_INVALID_PARAMETER));
1522 END_PROFILE(SMBsesssetupX);
1523 return;
1526 /* Save the lanman2 password and the NT md4 password. */
1528 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1529 doencrypt = False;
1532 if (doencrypt) {
1533 lm_resp = data_blob(p, passlen1);
1534 nt_resp = data_blob(p+passlen1, passlen2);
1535 } else {
1536 char *pass = NULL;
1537 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1539 if (unic && (passlen2 == 0) && passlen1) {
1540 /* Only a ascii plaintext password was sent. */
1541 (void)srvstr_pull_talloc(talloc_tos(),
1542 req->inbuf,
1543 req->flags2,
1544 &pass,
1545 smb_buf(req->inbuf),
1546 passlen1,
1547 STR_TERMINATE|STR_ASCII);
1548 } else {
1549 (void)srvstr_pull_talloc(talloc_tos(),
1550 req->inbuf,
1551 req->flags2,
1552 &pass,
1553 smb_buf(req->inbuf),
1554 unic ? passlen2 : passlen1,
1555 STR_TERMINATE);
1557 if (!pass) {
1558 reply_nterror(req, nt_status_squash(
1559 NT_STATUS_INVALID_PARAMETER));
1560 END_PROFILE(SMBsesssetupX);
1561 return;
1563 plaintext_password = data_blob(pass, strlen(pass)+1);
1566 p += passlen1 + passlen2;
1567 p += srvstr_pull_buf(req->inbuf, req->flags2, user, p,
1568 sizeof(user), STR_TERMINATE);
1569 p += srvstr_pull_buf(req->inbuf, req->flags2, domain, p,
1570 sizeof(domain), STR_TERMINATE);
1571 p += srvstr_pull_buf(req->inbuf, req->flags2, native_os,
1572 p, sizeof(native_os), STR_TERMINATE);
1573 p += srvstr_pull_buf(req->inbuf, req->flags2,
1574 native_lanman, p, sizeof(native_lanman),
1575 STR_TERMINATE);
1577 /* not documented or decoded by Ethereal but there is one more
1578 * string in the extra bytes which is the same as the
1579 * PrimaryDomain when using extended security. Windows NT 4
1580 * and 2003 use this string to store the native lanman string.
1581 * Windows 9x does not include a string here at all so we have
1582 * to check if we have any extra bytes left */
1584 byte_count = SVAL(req->inbuf, smb_vwv13);
1585 if ( PTR_DIFF(p, save_p) < byte_count) {
1586 p += srvstr_pull_buf(req->inbuf, req->flags2,
1587 primary_domain, p,
1588 sizeof(primary_domain),
1589 STR_TERMINATE);
1590 } else {
1591 fstrcpy( primary_domain, "null" );
1594 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
1595 "PrimaryDomain=[%s]\n",
1596 domain, native_os, native_lanman, primary_domain));
1598 if ( ra_type == RA_WIN2K ) {
1599 if ( strlen(native_lanman) == 0 )
1600 ra_lanman_string( primary_domain );
1601 else
1602 ra_lanman_string( native_lanman );
1607 if (SVAL(req->inbuf,smb_vwv4) == 0) {
1608 setup_new_vc_session();
1611 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1612 domain, user, get_remote_machine_name()));
1614 if (*user) {
1615 if (global_spnego_negotiated) {
1617 /* This has to be here, because this is a perfectly
1618 * valid behaviour for guest logons :-( */
1620 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1621 "at 'normal' session setup after "
1622 "negotiating spnego.\n"));
1623 reply_nterror(req, nt_status_squash(
1624 NT_STATUS_LOGON_FAILURE));
1625 END_PROFILE(SMBsesssetupX);
1626 return;
1628 fstrcpy(sub_user, user);
1629 } else {
1630 fstrcpy(sub_user, lp_guestaccount());
1633 sub_set_smb_name(sub_user);
1635 reload_services(True);
1637 if (lp_security() == SEC_SHARE) {
1638 /* in share level we should ignore any passwords */
1640 data_blob_free(&lm_resp);
1641 data_blob_free(&nt_resp);
1642 data_blob_clear_free(&plaintext_password);
1644 map_username(sub_user);
1645 add_session_user(sub_user);
1646 add_session_workgroup(domain);
1647 /* Then force it to null for the benfit of the code below */
1648 *user = 0;
1651 if (!*user) {
1653 nt_status = check_guest_password(&server_info);
1655 } else if (doencrypt) {
1656 if (!negprot_global_auth_context) {
1657 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
1658 "session setup without negprot denied!\n"));
1659 reply_nterror(req, nt_status_squash(
1660 NT_STATUS_LOGON_FAILURE));
1661 END_PROFILE(SMBsesssetupX);
1662 return;
1664 nt_status = make_user_info_for_reply_enc(&user_info, user,
1665 domain,
1666 lm_resp, nt_resp);
1667 if (NT_STATUS_IS_OK(nt_status)) {
1668 nt_status = negprot_global_auth_context->check_ntlm_password(
1669 negprot_global_auth_context,
1670 user_info,
1671 &server_info);
1673 } else {
1674 struct auth_context *plaintext_auth_context = NULL;
1675 const uint8 *chal;
1677 nt_status = make_auth_context_subsystem(
1678 &plaintext_auth_context);
1680 if (NT_STATUS_IS_OK(nt_status)) {
1681 chal = plaintext_auth_context->get_ntlm_challenge(
1682 plaintext_auth_context);
1684 if (!make_user_info_for_reply(&user_info,
1685 user, domain, chal,
1686 plaintext_password)) {
1687 nt_status = NT_STATUS_NO_MEMORY;
1690 if (NT_STATUS_IS_OK(nt_status)) {
1691 nt_status = plaintext_auth_context->check_ntlm_password(
1692 plaintext_auth_context,
1693 user_info,
1694 &server_info);
1696 (plaintext_auth_context->free)(
1697 &plaintext_auth_context);
1702 free_user_info(&user_info);
1704 if (!NT_STATUS_IS_OK(nt_status)) {
1705 nt_status = do_map_to_guest(nt_status, &server_info,
1706 user, domain);
1709 if (!NT_STATUS_IS_OK(nt_status)) {
1710 data_blob_free(&nt_resp);
1711 data_blob_free(&lm_resp);
1712 data_blob_clear_free(&plaintext_password);
1713 reply_nterror(req, nt_status_squash(nt_status));
1714 END_PROFILE(SMBsesssetupX);
1715 return;
1718 /* Ensure we can't possible take a code path leading to a
1719 * null defref. */
1720 if (!server_info) {
1721 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1722 END_PROFILE(SMBsesssetupX);
1723 return;
1726 nt_status = create_local_token(server_info);
1727 if (!NT_STATUS_IS_OK(nt_status)) {
1728 DEBUG(10, ("create_local_token failed: %s\n",
1729 nt_errstr(nt_status)));
1730 data_blob_free(&nt_resp);
1731 data_blob_free(&lm_resp);
1732 data_blob_clear_free(&plaintext_password);
1733 reply_nterror(req, nt_status_squash(nt_status));
1734 END_PROFILE(SMBsesssetupX);
1735 return;
1738 if (server_info->user_session_key.data) {
1739 session_key = data_blob(server_info->user_session_key.data,
1740 server_info->user_session_key.length);
1741 } else {
1742 session_key = data_blob_null;
1745 data_blob_clear_free(&plaintext_password);
1747 /* it's ok - setup a reply */
1748 reply_outbuf(req, 3, 0);
1749 if (Protocol >= PROTOCOL_NT1) {
1750 push_signature(&req->outbuf);
1751 /* perhaps grab OS version here?? */
1754 if (server_info->guest) {
1755 SSVAL(req->outbuf,smb_vwv2,1);
1758 /* register the name and uid as being validated, so further connections
1759 to a uid can get through without a password, on the same VC */
1761 if (lp_security() == SEC_SHARE) {
1762 sess_vuid = UID_FIELD_INVALID;
1763 data_blob_free(&session_key);
1764 TALLOC_FREE(server_info);
1765 } else {
1766 /* Ignore the initial vuid. */
1767 sess_vuid = register_initial_vuid();
1768 if (sess_vuid == UID_FIELD_INVALID) {
1769 data_blob_free(&nt_resp);
1770 data_blob_free(&lm_resp);
1771 data_blob_free(&session_key);
1772 reply_nterror(req, nt_status_squash(
1773 NT_STATUS_LOGON_FAILURE));
1774 END_PROFILE(SMBsesssetupX);
1775 return;
1777 /* register_existing_vuid keeps the server info */
1778 sess_vuid = register_existing_vuid(sess_vuid,
1779 server_info,
1780 session_key,
1781 nt_resp.data ? nt_resp : lm_resp,
1782 sub_user);
1783 if (sess_vuid == UID_FIELD_INVALID) {
1784 data_blob_free(&nt_resp);
1785 data_blob_free(&lm_resp);
1786 data_blob_free(&session_key);
1787 reply_nterror(req, nt_status_squash(
1788 NT_STATUS_LOGON_FAILURE));
1789 END_PROFILE(SMBsesssetupX);
1790 return;
1793 /* current_user_info is changed on new vuid */
1794 reload_services( True );
1796 sessionsetup_start_signing_engine(server_info, req->inbuf);
1799 data_blob_free(&nt_resp);
1800 data_blob_free(&lm_resp);
1802 SSVAL(req->outbuf,smb_uid,sess_vuid);
1803 SSVAL(req->inbuf,smb_uid,sess_vuid);
1805 if (!done_sesssetup)
1806 max_send = MIN(max_send,smb_bufsize);
1808 done_sesssetup = True;
1810 END_PROFILE(SMBsesssetupX);
1811 chain_reply(req);
1812 return;