s3-build: really fix build of winbind_krb5_locator.
[Samba.git] / source / smbd / sesssetup.c
blob6d7eb6fae2a701795510208ae4c683dea2243849
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(NULL, 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(NULL, 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 const char *mechOID,
252 uint16 vuid,
253 bool *p_invalidate_vuid)
255 TALLOC_CTX *mem_ctx;
256 DATA_BLOB ticket;
257 char *client, *p, *domain;
258 fstring netbios_domain_name;
259 struct passwd *pw;
260 fstring user;
261 int sess_vuid = req->vuid;
262 NTSTATUS ret = NT_STATUS_OK;
263 struct PAC_DATA *pac_data = NULL;
264 DATA_BLOB ap_rep, ap_rep_wrapped, response;
265 auth_serversupplied_info *server_info = NULL;
266 DATA_BLOB session_key = data_blob_null;
267 uint8 tok_id[2];
268 DATA_BLOB nullblob = data_blob_null;
269 fstring real_username;
270 bool map_domainuser_to_guest = False;
271 bool username_was_mapped;
272 struct PAC_LOGON_INFO *logon_info = NULL;
274 ZERO_STRUCT(ticket);
275 ZERO_STRUCT(ap_rep);
276 ZERO_STRUCT(ap_rep_wrapped);
277 ZERO_STRUCT(response);
279 /* Normally we will always invalidate the intermediate vuid. */
280 *p_invalidate_vuid = True;
282 mem_ctx = talloc_init("reply_spnego_kerberos");
283 if (mem_ctx == NULL) {
284 reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
285 return;
288 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
289 talloc_destroy(mem_ctx);
290 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
291 return;
294 ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
295 &client, &pac_data, &ap_rep,
296 &session_key, True);
298 data_blob_free(&ticket);
300 if (!NT_STATUS_IS_OK(ret)) {
301 #if 0
302 /* Experiment that failed.
303 * See "only happens with a KDC" comment below. */
305 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
308 * Windows in this case returns
309 * NT_STATUS_MORE_PROCESSING_REQUIRED
310 * with a negTokenTarg blob containing an krb5_error
311 * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
312 * The client then fixes its clock and continues rather
313 * than giving an error. JRA.
314 * -- Looks like this only happens with a KDC. JRA.
317 bool ok = make_krb5_skew_error(&ap_rep);
318 if (!ok) {
319 talloc_destroy(mem_ctx);
320 return ERROR_NT(nt_status_squash(
321 NT_STATUS_LOGON_FAILURE));
323 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
324 TOK_ID_KRB_ERROR);
325 response = spnego_gen_auth_response(&ap_rep_wrapped,
326 ret, OID_KERBEROS5_OLD);
327 reply_sesssetup_blob(conn, inbuf, outbuf, response,
328 NT_STATUS_MORE_PROCESSING_REQUIRED);
331 * In this one case we don't invalidate the
332 * intermediate vuid as we're expecting the client
333 * to re-use it for the next sessionsetupX packet. JRA.
336 *p_invalidate_vuid = False;
338 data_blob_free(&ap_rep);
339 data_blob_free(&ap_rep_wrapped);
340 data_blob_free(&response);
341 talloc_destroy(mem_ctx);
342 return -1; /* already replied */
344 #else
345 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
346 ret = NT_STATUS_LOGON_FAILURE;
348 #endif
349 DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
350 nt_errstr(ret)));
351 talloc_destroy(mem_ctx);
352 reply_nterror(req, nt_status_squash(ret));
353 return;
356 DEBUG(3,("Ticket name is [%s]\n", client));
358 p = strchr_m(client, '@');
359 if (!p) {
360 DEBUG(3,("Doesn't look like a valid principal\n"));
361 data_blob_free(&ap_rep);
362 data_blob_free(&session_key);
363 SAFE_FREE(client);
364 talloc_destroy(mem_ctx);
365 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
366 return;
369 *p = 0;
371 /* save the PAC data if we have it */
373 if (pac_data) {
374 logon_info = get_logon_info_from_pac(pac_data);
375 if (logon_info) {
376 netsamlogon_cache_store( client, &logon_info->info3 );
380 if (!strequal(p+1, lp_realm())) {
381 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
382 if (!lp_allow_trusted_domains()) {
383 data_blob_free(&ap_rep);
384 data_blob_free(&session_key);
385 SAFE_FREE(client);
386 talloc_destroy(mem_ctx);
387 reply_nterror(req, nt_status_squash(
388 NT_STATUS_LOGON_FAILURE));
389 return;
393 /* this gives a fully qualified user name (ie. with full realm).
394 that leads to very long usernames, but what else can we do? */
396 domain = p+1;
398 if (logon_info && logon_info->info3.base.domain.string) {
399 fstrcpy(netbios_domain_name,
400 logon_info->info3.base.domain.string);
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 mapping 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(NULL, &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 server_info->nss_token |= username_was_mapped;
535 /* we need to build the token for the user. make_server_info_guest()
536 already does this */
538 if ( !server_info->ptok ) {
539 ret = create_local_token( server_info );
540 if ( !NT_STATUS_IS_OK(ret) ) {
541 DEBUG(10,("failed to create local token: %s\n",
542 nt_errstr(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();
562 data_blob_free(&server_info->user_session_key);
563 server_info->user_session_key = session_key;
564 session_key = data_blob_null;
566 sess_vuid = register_existing_vuid(sess_vuid,
567 server_info,
568 nullblob,
569 client);
571 SAFE_FREE(client);
573 reply_outbuf(req, 4, 0);
574 SSVAL(req->outbuf,smb_uid,sess_vuid);
576 if (sess_vuid == UID_FIELD_INVALID ) {
577 ret = NT_STATUS_LOGON_FAILURE;
578 } else {
579 /* current_user_info is changed on new vuid */
580 reload_services( True );
582 SSVAL(req->outbuf, smb_vwv3, 0);
584 if (server_info->guest) {
585 SSVAL(req->outbuf,smb_vwv2,1);
588 SSVAL(req->outbuf, smb_uid, sess_vuid);
590 sessionsetup_start_signing_engine(server_info, req->inbuf);
591 /* Successful logon. Keep this vuid. */
592 *p_invalidate_vuid = False;
595 /* wrap that up in a nice GSS-API wrapping */
596 if (NT_STATUS_IS_OK(ret)) {
597 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
598 TOK_ID_KRB_AP_REP);
599 } else {
600 ap_rep_wrapped = data_blob_null;
602 response = spnego_gen_auth_response(&ap_rep_wrapped, ret,
603 mechOID);
604 reply_sesssetup_blob(req, response, ret);
606 data_blob_free(&ap_rep);
607 data_blob_free(&ap_rep_wrapped);
608 data_blob_free(&response);
609 TALLOC_FREE(mem_ctx);
612 #endif
614 /****************************************************************************
615 Send a session setup reply, wrapped in SPNEGO.
616 Get vuid and check first.
617 End the NTLMSSP exchange context if we are OK/complete fail
618 This should be split into two functions, one to handle each
619 leg of the NTLM auth steps.
620 ***************************************************************************/
622 static void reply_spnego_ntlmssp(struct smb_request *req,
623 uint16 vuid,
624 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
625 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
626 const char *OID,
627 bool wrap)
629 DATA_BLOB response;
630 struct auth_serversupplied_info *server_info = NULL;
632 if (NT_STATUS_IS_OK(nt_status)) {
633 server_info = (*auth_ntlmssp_state)->server_info;
634 } else {
635 nt_status = do_map_to_guest(nt_status,
636 &server_info,
637 (*auth_ntlmssp_state)->ntlmssp_state->user,
638 (*auth_ntlmssp_state)->ntlmssp_state->domain);
641 reply_outbuf(req, 4, 0);
643 SSVAL(req->outbuf, smb_uid, vuid);
645 if (NT_STATUS_IS_OK(nt_status)) {
646 DATA_BLOB nullblob = data_blob_null;
648 if (!is_partial_auth_vuid(vuid)) {
649 nt_status = NT_STATUS_LOGON_FAILURE;
650 goto out;
653 data_blob_free(&server_info->user_session_key);
654 server_info->user_session_key =
655 data_blob_talloc(
656 server_info,
657 (*auth_ntlmssp_state)->ntlmssp_state->session_key.data,
658 (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
660 /* register_existing_vuid keeps the server info */
661 if (register_existing_vuid(vuid,
662 server_info, nullblob,
663 (*auth_ntlmssp_state)->ntlmssp_state->user) !=
664 vuid) {
665 nt_status = NT_STATUS_LOGON_FAILURE;
666 goto out;
669 (*auth_ntlmssp_state)->server_info = NULL;
671 /* current_user_info is changed on new vuid */
672 reload_services( True );
674 SSVAL(req->outbuf, smb_vwv3, 0);
676 if (server_info->guest) {
677 SSVAL(req->outbuf,smb_vwv2,1);
680 sessionsetup_start_signing_engine(server_info,
681 (uint8 *)req->inbuf);
684 out:
686 if (wrap) {
687 response = spnego_gen_auth_response(ntlmssp_blob,
688 nt_status, OID);
689 } else {
690 response = *ntlmssp_blob;
693 reply_sesssetup_blob(req, response, nt_status);
694 if (wrap) {
695 data_blob_free(&response);
698 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
699 and the other end, that we are not finished yet. */
701 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
702 /* NB. This is *NOT* an error case. JRA */
703 auth_ntlmssp_end(auth_ntlmssp_state);
704 if (!NT_STATUS_IS_OK(nt_status)) {
705 /* Kill the intermediate vuid */
706 invalidate_vuid(vuid);
711 /****************************************************************************
712 Is this a krb5 mechanism ?
713 ****************************************************************************/
715 NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in,
716 DATA_BLOB *pblob_out,
717 char **kerb_mechOID)
719 char *OIDs[ASN1_MAX_OIDS];
720 int i;
721 NTSTATUS ret = NT_STATUS_OK;
723 *kerb_mechOID = NULL;
725 /* parse out the OIDs and the first sec blob */
726 if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
727 return NT_STATUS_LOGON_FAILURE;
730 /* only look at the first OID for determining the mechToken --
731 according to RFC2478, we should choose the one we want
732 and renegotiate, but i smell a client bug here..
734 Problem observed when connecting to a member (samba box)
735 of an AD domain as a user in a Samba domain. Samba member
736 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
737 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
738 NTLMSSP mechtoken. --jerry */
740 #ifdef HAVE_KRB5
741 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
742 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
743 *kerb_mechOID = SMB_STRDUP(OIDs[0]);
744 if (*kerb_mechOID == NULL) {
745 ret = NT_STATUS_NO_MEMORY;
748 #endif
750 for (i=0;OIDs[i];i++) {
751 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
752 free(OIDs[i]);
754 return ret;
757 /****************************************************************************
758 Fall back from krb5 to NTLMSSP.
759 ****************************************************************************/
761 static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
762 uint16 vuid)
764 DATA_BLOB response;
766 reply_outbuf(req, 4, 0);
767 SSVAL(req->outbuf,smb_uid,vuid);
769 DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
770 "but set to downgrade to NTLMSSP\n"));
772 response = spnego_gen_auth_response(NULL,
773 NT_STATUS_MORE_PROCESSING_REQUIRED,
774 OID_NTLMSSP);
775 reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
776 data_blob_free(&response);
779 /****************************************************************************
780 Reply to a session setup spnego negotiate packet.
781 ****************************************************************************/
783 static void reply_spnego_negotiate(struct smb_request *req,
784 uint16 vuid,
785 DATA_BLOB blob1,
786 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
788 DATA_BLOB secblob;
789 DATA_BLOB chal;
790 char *kerb_mech = NULL;
791 NTSTATUS status;
793 status = parse_spnego_mechanisms(blob1, &secblob, &kerb_mech);
794 if (!NT_STATUS_IS_OK(status)) {
795 /* Kill the intermediate vuid */
796 invalidate_vuid(vuid);
797 reply_nterror(req, nt_status_squash(status));
798 return;
801 DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
802 (unsigned long)secblob.length));
804 #ifdef HAVE_KRB5
805 if (kerb_mech && ((lp_security()==SEC_ADS) ||
806 lp_use_kerberos_keytab()) ) {
807 bool destroy_vuid = True;
808 reply_spnego_kerberos(req, &secblob, kerb_mech,
809 vuid, &destroy_vuid);
810 data_blob_free(&secblob);
811 if (destroy_vuid) {
812 /* Kill the intermediate vuid */
813 invalidate_vuid(vuid);
815 SAFE_FREE(kerb_mech);
816 return;
818 #endif
820 if (*auth_ntlmssp_state) {
821 auth_ntlmssp_end(auth_ntlmssp_state);
824 if (kerb_mech) {
825 data_blob_free(&secblob);
826 /* The mechtoken is a krb5 ticket, but
827 * we need to fall back to NTLM. */
828 reply_spnego_downgrade_to_ntlmssp(req, vuid);
829 SAFE_FREE(kerb_mech);
830 return;
833 status = auth_ntlmssp_start(auth_ntlmssp_state);
834 if (!NT_STATUS_IS_OK(status)) {
835 /* Kill the intermediate vuid */
836 invalidate_vuid(vuid);
837 reply_nterror(req, nt_status_squash(status));
838 return;
841 status = auth_ntlmssp_update(*auth_ntlmssp_state,
842 secblob, &chal);
844 data_blob_free(&secblob);
846 reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
847 &chal, status, OID_NTLMSSP, true);
849 data_blob_free(&chal);
851 /* already replied */
852 return;
855 /****************************************************************************
856 Reply to a session setup spnego auth packet.
857 ****************************************************************************/
859 static void reply_spnego_auth(struct smb_request *req,
860 uint16 vuid,
861 DATA_BLOB blob1,
862 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
864 DATA_BLOB auth = data_blob_null;
865 DATA_BLOB auth_reply = data_blob_null;
866 DATA_BLOB secblob = data_blob_null;
867 NTSTATUS status = NT_STATUS_LOGON_FAILURE;
869 if (!spnego_parse_auth(blob1, &auth)) {
870 #if 0
871 file_save("auth.dat", blob1.data, blob1.length);
872 #endif
873 /* Kill the intermediate vuid */
874 invalidate_vuid(vuid);
876 reply_nterror(req, nt_status_squash(
877 NT_STATUS_LOGON_FAILURE));
878 return;
881 if (auth.data[0] == ASN1_APPLICATION(0)) {
882 /* Might be a second negTokenTarg packet */
883 char *kerb_mech = NULL;
885 status = parse_spnego_mechanisms(auth, &secblob, &kerb_mech);
887 if (!NT_STATUS_IS_OK(status)) {
888 /* Kill the intermediate vuid */
889 invalidate_vuid(vuid);
890 reply_nterror(req, nt_status_squash(status));
891 return;
894 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
895 (unsigned long)secblob.length));
896 #ifdef HAVE_KRB5
897 if (kerb_mech && ((lp_security()==SEC_ADS) ||
898 lp_use_kerberos_keytab()) ) {
899 bool destroy_vuid = True;
900 reply_spnego_kerberos(req, &secblob, kerb_mech,
901 vuid, &destroy_vuid);
902 data_blob_free(&secblob);
903 data_blob_free(&auth);
904 if (destroy_vuid) {
905 /* Kill the intermediate vuid */
906 invalidate_vuid(vuid);
908 SAFE_FREE(kerb_mech);
909 return;
911 #endif
912 /* Can't blunder into NTLMSSP auth if we have
913 * a krb5 ticket. */
915 if (kerb_mech) {
916 /* Kill the intermediate vuid */
917 invalidate_vuid(vuid);
918 DEBUG(3,("reply_spnego_auth: network "
919 "misconfiguration, client sent us a "
920 "krb5 ticket and kerberos security "
921 "not enabled\n"));
922 reply_nterror(req, nt_status_squash(
923 NT_STATUS_LOGON_FAILURE));
924 SAFE_FREE(kerb_mech);
928 /* If we get here it wasn't a negTokenTarg auth packet. */
929 data_blob_free(&secblob);
931 if (!*auth_ntlmssp_state) {
932 status = auth_ntlmssp_start(auth_ntlmssp_state);
933 if (!NT_STATUS_IS_OK(status)) {
934 /* Kill the intermediate vuid */
935 invalidate_vuid(vuid);
936 reply_nterror(req, nt_status_squash(status));
937 return;
941 status = auth_ntlmssp_update(*auth_ntlmssp_state,
942 auth, &auth_reply);
944 data_blob_free(&auth);
946 /* Don't send the mechid as we've already sent this (RFC4178). */
948 reply_spnego_ntlmssp(req, vuid,
949 auth_ntlmssp_state,
950 &auth_reply, status, NULL, true);
952 data_blob_free(&auth_reply);
954 /* and tell smbd that we have already replied to this packet */
955 return;
958 /****************************************************************************
959 List to store partial SPNEGO auth fragments.
960 ****************************************************************************/
962 static struct pending_auth_data *pd_list;
964 /****************************************************************************
965 Delete an entry on the list.
966 ****************************************************************************/
968 static void delete_partial_auth(struct pending_auth_data *pad)
970 if (!pad) {
971 return;
973 DLIST_REMOVE(pd_list, pad);
974 data_blob_free(&pad->partial_data);
975 SAFE_FREE(pad);
978 /****************************************************************************
979 Search for a partial SPNEGO auth fragment matching an smbpid.
980 ****************************************************************************/
982 static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
984 struct pending_auth_data *pad;
986 for (pad = pd_list; pad; pad = pad->next) {
987 if (pad->smbpid == smbpid) {
988 break;
991 return pad;
994 /****************************************************************************
995 Check the size of an SPNEGO blob. If we need more return
996 NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
997 the blob to be more than 64k.
998 ****************************************************************************/
1000 static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid,
1001 DATA_BLOB *pblob)
1003 struct pending_auth_data *pad = NULL;
1004 ASN1_DATA data;
1005 size_t needed_len = 0;
1007 pad = get_pending_auth_data(smbpid);
1009 /* Ensure we have some data. */
1010 if (pblob->length == 0) {
1011 /* Caller can cope. */
1012 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
1013 delete_partial_auth(pad);
1014 return NT_STATUS_OK;
1017 /* Were we waiting for more data ? */
1018 if (pad) {
1019 DATA_BLOB tmp_blob;
1020 size_t copy_len = MIN(65536, pblob->length);
1022 /* Integer wrap paranoia.... */
1024 if (pad->partial_data.length + copy_len <
1025 pad->partial_data.length ||
1026 pad->partial_data.length + copy_len < copy_len) {
1028 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1029 "pad->partial_data.length = %u, "
1030 "copy_len = %u\n",
1031 (unsigned int)pad->partial_data.length,
1032 (unsigned int)copy_len ));
1034 delete_partial_auth(pad);
1035 return NT_STATUS_INVALID_PARAMETER;
1038 DEBUG(10,("check_spnego_blob_complete: "
1039 "pad->partial_data.length = %u, "
1040 "pad->needed_len = %u, "
1041 "copy_len = %u, "
1042 "pblob->length = %u,\n",
1043 (unsigned int)pad->partial_data.length,
1044 (unsigned int)pad->needed_len,
1045 (unsigned int)copy_len,
1046 (unsigned int)pblob->length ));
1048 tmp_blob = data_blob(NULL,
1049 pad->partial_data.length + copy_len);
1051 /* Concatenate the two (up to copy_len) bytes. */
1052 memcpy(tmp_blob.data,
1053 pad->partial_data.data,
1054 pad->partial_data.length);
1055 memcpy(tmp_blob.data + pad->partial_data.length,
1056 pblob->data,
1057 copy_len);
1059 /* Replace the partial data. */
1060 data_blob_free(&pad->partial_data);
1061 pad->partial_data = tmp_blob;
1062 ZERO_STRUCT(tmp_blob);
1064 /* Are we done ? */
1065 if (pblob->length >= pad->needed_len) {
1066 /* Yes, replace pblob. */
1067 data_blob_free(pblob);
1068 *pblob = pad->partial_data;
1069 ZERO_STRUCT(pad->partial_data);
1070 delete_partial_auth(pad);
1071 return NT_STATUS_OK;
1074 /* Still need more data. */
1075 pad->needed_len -= copy_len;
1076 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1079 if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
1080 (pblob->data[0] != ASN1_CONTEXT(1))) {
1081 /* Not something we can determine the
1082 * length of.
1084 return NT_STATUS_OK;
1087 /* This is a new SPNEGO sessionsetup - see if
1088 * the data given in this blob is enough.
1091 asn1_load(&data, *pblob);
1092 asn1_start_tag(&data, pblob->data[0]);
1093 if (data.has_error || data.nesting == NULL) {
1094 asn1_free(&data);
1095 /* Let caller catch. */
1096 return NT_STATUS_OK;
1099 /* Integer wrap paranoia.... */
1101 if (data.nesting->taglen + data.nesting->start < data.nesting->taglen ||
1102 data.nesting->taglen + data.nesting->start < data.nesting->start) {
1104 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1105 "data.nesting->taglen = %u, "
1106 "data.nesting->start = %u\n",
1107 (unsigned int)data.nesting->taglen,
1108 (unsigned int)data.nesting->start ));
1110 asn1_free(&data);
1111 return NT_STATUS_INVALID_PARAMETER;
1114 /* Total length of the needed asn1 is the tag length
1115 * plus the current offset. */
1117 needed_len = data.nesting->taglen + data.nesting->start;
1118 asn1_free(&data);
1120 DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
1121 "pblob->length = %u\n",
1122 (unsigned int)needed_len,
1123 (unsigned int)pblob->length ));
1125 if (needed_len <= pblob->length) {
1126 /* Nothing to do - blob is complete. */
1127 return NT_STATUS_OK;
1130 /* Refuse the blob if it's bigger than 64k. */
1131 if (needed_len > 65536) {
1132 DEBUG(2,("check_spnego_blob_complete: needed_len "
1133 "too large (%u)\n",
1134 (unsigned int)needed_len ));
1135 return NT_STATUS_INVALID_PARAMETER;
1138 /* We must store this blob until complete. */
1139 if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
1140 return NT_STATUS_NO_MEMORY;
1142 pad->needed_len = needed_len - pblob->length;
1143 pad->partial_data = data_blob(pblob->data, pblob->length);
1144 if (pad->partial_data.data == NULL) {
1145 SAFE_FREE(pad);
1146 return NT_STATUS_NO_MEMORY;
1148 pad->smbpid = smbpid;
1149 pad->vuid = vuid;
1150 DLIST_ADD(pd_list, pad);
1152 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1155 /****************************************************************************
1156 Reply to a session setup command.
1157 conn POINTER CAN BE NULL HERE !
1158 ****************************************************************************/
1160 static void reply_sesssetup_and_X_spnego(struct smb_request *req)
1162 uint8 *p;
1163 DATA_BLOB blob1;
1164 size_t bufrem;
1165 fstring native_os, native_lanman, primary_domain;
1166 const char *p2;
1167 uint16 data_blob_len = SVAL(req->inbuf, smb_vwv7);
1168 enum remote_arch_types ra_type = get_remote_arch();
1169 int vuid = SVAL(req->inbuf,smb_uid);
1170 user_struct *vuser = NULL;
1171 NTSTATUS status = NT_STATUS_OK;
1172 uint16 smbpid = req->smbpid;
1173 uint16 smb_flag2 = req->flags2;
1175 DEBUG(3,("Doing spnego session setup\n"));
1177 if (global_client_caps == 0) {
1178 global_client_caps = IVAL(req->inbuf,smb_vwv10);
1180 if (!(global_client_caps & CAP_STATUS32)) {
1181 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1186 p = (uint8 *)smb_buf(req->inbuf);
1188 if (data_blob_len == 0) {
1189 /* an invalid request */
1190 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1191 return;
1194 bufrem = smb_bufrem(req->inbuf, p);
1195 /* pull the spnego blob */
1196 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1198 #if 0
1199 file_save("negotiate.dat", blob1.data, blob1.length);
1200 #endif
1202 p2 = (char *)req->inbuf + smb_vwv13 + data_blob_len;
1203 p2 += srvstr_pull_buf(req->inbuf, smb_flag2, native_os, p2,
1204 sizeof(native_os), STR_TERMINATE);
1205 p2 += srvstr_pull_buf(req->inbuf, smb_flag2, native_lanman, p2,
1206 sizeof(native_lanman), STR_TERMINATE);
1207 p2 += srvstr_pull_buf(req->inbuf, smb_flag2, primary_domain, p2,
1208 sizeof(primary_domain), STR_TERMINATE);
1209 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1210 native_os, native_lanman, primary_domain));
1212 if ( ra_type == RA_WIN2K ) {
1213 /* Vista sets neither the OS or lanman strings */
1215 if ( !strlen(native_os) && !strlen(native_lanman) )
1216 set_remote_arch(RA_VISTA);
1218 /* Windows 2003 doesn't set the native lanman string,
1219 but does set primary domain which is a bug I think */
1221 if ( !strlen(native_lanman) ) {
1222 ra_lanman_string( primary_domain );
1223 } else {
1224 ra_lanman_string( native_lanman );
1228 /* Did we get a valid vuid ? */
1229 if (!is_partial_auth_vuid(vuid)) {
1230 /* No, then try and see if this is an intermediate sessionsetup
1231 * for a large SPNEGO packet. */
1232 struct pending_auth_data *pad = get_pending_auth_data(smbpid);
1233 if (pad) {
1234 DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1235 "pending vuid %u\n",
1236 (unsigned int)pad->vuid ));
1237 vuid = pad->vuid;
1241 /* Do we have a valid vuid now ? */
1242 if (!is_partial_auth_vuid(vuid)) {
1243 /* No, start a new authentication setup. */
1244 vuid = register_initial_vuid();
1245 if (vuid == UID_FIELD_INVALID) {
1246 data_blob_free(&blob1);
1247 reply_nterror(req, nt_status_squash(
1248 NT_STATUS_INVALID_PARAMETER));
1249 return;
1253 vuser = get_partial_auth_user_struct(vuid);
1254 /* This MUST be valid. */
1255 if (!vuser) {
1256 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1259 /* Large (greater than 4k) SPNEGO blobs are split into multiple
1260 * sessionsetup requests as the Windows limit on the security blob
1261 * field is 4k. Bug #4400. JRA.
1264 status = check_spnego_blob_complete(smbpid, vuid, &blob1);
1265 if (!NT_STATUS_IS_OK(status)) {
1266 if (!NT_STATUS_EQUAL(status,
1267 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1268 /* Real error - kill the intermediate vuid */
1269 invalidate_vuid(vuid);
1271 data_blob_free(&blob1);
1272 reply_nterror(req, nt_status_squash(status));
1273 return;
1276 if (blob1.data[0] == ASN1_APPLICATION(0)) {
1278 /* its a negTokenTarg packet */
1280 reply_spnego_negotiate(req, vuid, blob1,
1281 &vuser->auth_ntlmssp_state);
1282 data_blob_free(&blob1);
1283 return;
1286 if (blob1.data[0] == ASN1_CONTEXT(1)) {
1288 /* its a auth packet */
1290 reply_spnego_auth(req, vuid, blob1,
1291 &vuser->auth_ntlmssp_state);
1292 data_blob_free(&blob1);
1293 return;
1296 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1297 DATA_BLOB chal;
1299 if (!vuser->auth_ntlmssp_state) {
1300 status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1301 if (!NT_STATUS_IS_OK(status)) {
1302 /* Kill the intermediate vuid */
1303 invalidate_vuid(vuid);
1304 data_blob_free(&blob1);
1305 reply_nterror(req, nt_status_squash(status));
1306 return;
1310 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1311 blob1, &chal);
1313 data_blob_free(&blob1);
1315 reply_spnego_ntlmssp(req, vuid,
1316 &vuser->auth_ntlmssp_state,
1317 &chal, status, OID_NTLMSSP, false);
1318 data_blob_free(&chal);
1319 return;
1322 /* what sort of packet is this? */
1323 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1325 data_blob_free(&blob1);
1327 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1330 /****************************************************************************
1331 On new VC == 0, shutdown *all* old connections and users.
1332 It seems that only NT4.x does this. At W2K and above (XP etc.).
1333 a new session setup with VC==0 is ignored.
1334 ****************************************************************************/
1336 static int shutdown_other_smbds(struct db_record *rec,
1337 const struct connections_key *key,
1338 const struct connections_data *crec,
1339 void *private_data)
1341 const char *ip = (const char *)private_data;
1343 if (!process_exists(crec->pid)) {
1344 return 0;
1347 if (procid_is_me(&crec->pid)) {
1348 return 0;
1351 if (strcmp(ip, crec->addr) != 0) {
1352 return 0;
1355 DEBUG(0,("shutdown_other_smbds: shutting down pid %u "
1356 "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid), ip));
1358 messaging_send(smbd_messaging_context(), crec->pid, MSG_SHUTDOWN,
1359 &data_blob_null);
1360 return 0;
1363 static void setup_new_vc_session(void)
1365 char addr[INET6_ADDRSTRLEN];
1367 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1368 "compatible we would close all old resources.\n"));
1369 #if 0
1370 conn_close_all();
1371 invalidate_all_vuids();
1372 #endif
1373 if (lp_reset_on_zero_vc()) {
1374 connections_forall(shutdown_other_smbds,
1375 CONST_DISCARD(void *,
1376 client_addr(get_client_fd(),addr,sizeof(addr))));
1380 /****************************************************************************
1381 Reply to a session setup command.
1382 ****************************************************************************/
1384 void reply_sesssetup_and_X(struct smb_request *req)
1386 int sess_vuid;
1387 int smb_bufsize;
1388 DATA_BLOB lm_resp;
1389 DATA_BLOB nt_resp;
1390 DATA_BLOB plaintext_password;
1391 fstring user;
1392 fstring sub_user; /* Sainitised username for substituion */
1393 fstring domain;
1394 fstring native_os;
1395 fstring native_lanman;
1396 fstring primary_domain;
1397 static bool done_sesssetup = False;
1398 auth_usersupplied_info *user_info = NULL;
1399 auth_serversupplied_info *server_info = NULL;
1400 uint16 smb_flag2 = req->flags2;
1402 NTSTATUS nt_status;
1404 bool doencrypt = global_encrypted_passwords_negotiated;
1406 START_PROFILE(SMBsesssetupX);
1408 ZERO_STRUCT(lm_resp);
1409 ZERO_STRUCT(nt_resp);
1410 ZERO_STRUCT(plaintext_password);
1412 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1414 /* a SPNEGO session setup has 12 command words, whereas a normal
1415 NT1 session setup has 13. See the cifs spec. */
1416 if (req->wct == 12 &&
1417 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1419 if (!global_spnego_negotiated) {
1420 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1421 "at SPNEGO session setup when it was not "
1422 "negotiated.\n"));
1423 reply_nterror(req, nt_status_squash(
1424 NT_STATUS_LOGON_FAILURE));
1425 END_PROFILE(SMBsesssetupX);
1426 return;
1429 if (SVAL(req->inbuf,smb_vwv4) == 0) {
1430 setup_new_vc_session();
1433 reply_sesssetup_and_X_spnego(req);
1434 END_PROFILE(SMBsesssetupX);
1435 return;
1438 smb_bufsize = SVAL(req->inbuf,smb_vwv2);
1440 if (Protocol < PROTOCOL_NT1) {
1441 uint16 passlen1 = SVAL(req->inbuf,smb_vwv7);
1443 /* Never do NT status codes with protocols before NT1 as we
1444 * don't get client caps. */
1445 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1447 if ((passlen1 > MAX_PASS_LEN)
1448 || (passlen1 > smb_bufrem(req->inbuf,
1449 smb_buf(req->inbuf)))) {
1450 reply_nterror(req, nt_status_squash(
1451 NT_STATUS_INVALID_PARAMETER));
1452 END_PROFILE(SMBsesssetupX);
1453 return;
1456 if (doencrypt) {
1457 lm_resp = data_blob(smb_buf(req->inbuf), passlen1);
1458 } else {
1459 plaintext_password = data_blob(smb_buf(req->inbuf),
1460 passlen1+1);
1461 /* Ensure null termination */
1462 plaintext_password.data[passlen1] = 0;
1465 srvstr_pull_buf(req->inbuf, req->flags2, user,
1466 smb_buf(req->inbuf)+passlen1, sizeof(user),
1467 STR_TERMINATE);
1468 *domain = 0;
1470 } else {
1471 uint16 passlen1 = SVAL(req->inbuf,smb_vwv7);
1472 uint16 passlen2 = SVAL(req->inbuf,smb_vwv8);
1473 enum remote_arch_types ra_type = get_remote_arch();
1474 char *p = smb_buf(req->inbuf);
1475 char *save_p = smb_buf(req->inbuf);
1476 uint16 byte_count;
1479 if(global_client_caps == 0) {
1480 global_client_caps = IVAL(req->inbuf,smb_vwv11);
1482 if (!(global_client_caps & CAP_STATUS32)) {
1483 remove_from_common_flags2(
1484 FLAGS2_32_BIT_ERROR_CODES);
1487 /* client_caps is used as final determination if
1488 * client is NT or Win95. This is needed to return
1489 * the correct error codes in some circumstances.
1492 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1493 ra_type == RA_WIN95) {
1494 if(!(global_client_caps & (CAP_NT_SMBS|
1495 CAP_STATUS32))) {
1496 set_remote_arch( RA_WIN95);
1501 if (!doencrypt) {
1502 /* both Win95 and WinNT stuff up the password
1503 * lengths for non-encrypting systems. Uggh.
1505 if passlen1==24 its a win95 system, and its setting
1506 the password length incorrectly. Luckily it still
1507 works with the default code because Win95 will null
1508 terminate the password anyway
1510 if passlen1>0 and passlen2>0 then maybe its a NT box
1511 and its setting passlen2 to some random value which
1512 really stuffs things up. we need to fix that one. */
1514 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1515 passlen2 != 1) {
1516 passlen2 = 0;
1520 /* check for nasty tricks */
1521 if (passlen1 > MAX_PASS_LEN
1522 || passlen1 > smb_bufrem(req->inbuf, p)) {
1523 reply_nterror(req, nt_status_squash(
1524 NT_STATUS_INVALID_PARAMETER));
1525 END_PROFILE(SMBsesssetupX);
1526 return;
1529 if (passlen2 > MAX_PASS_LEN
1530 || passlen2 > smb_bufrem(req->inbuf, p+passlen1)) {
1531 reply_nterror(req, nt_status_squash(
1532 NT_STATUS_INVALID_PARAMETER));
1533 END_PROFILE(SMBsesssetupX);
1534 return;
1537 /* Save the lanman2 password and the NT md4 password. */
1539 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1540 doencrypt = False;
1543 if (doencrypt) {
1544 lm_resp = data_blob(p, passlen1);
1545 nt_resp = data_blob(p+passlen1, passlen2);
1546 } else if (lp_security() != SEC_SHARE) {
1548 * In share level we should ignore any passwords, so
1549 * only read them if we're not.
1551 char *pass = NULL;
1552 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1554 if (unic && (passlen2 == 0) && passlen1) {
1555 /* Only a ascii plaintext password was sent. */
1556 (void)srvstr_pull_talloc(talloc_tos(),
1557 req->inbuf,
1558 req->flags2,
1559 &pass,
1560 smb_buf(req->inbuf),
1561 passlen1,
1562 STR_TERMINATE|STR_ASCII);
1563 } else {
1564 (void)srvstr_pull_talloc(talloc_tos(),
1565 req->inbuf,
1566 req->flags2,
1567 &pass,
1568 smb_buf(req->inbuf),
1569 unic ? passlen2 : passlen1,
1570 STR_TERMINATE);
1572 if (!pass) {
1573 reply_nterror(req, nt_status_squash(
1574 NT_STATUS_INVALID_PARAMETER));
1575 END_PROFILE(SMBsesssetupX);
1576 return;
1578 plaintext_password = data_blob(pass, strlen(pass)+1);
1581 p += passlen1 + passlen2;
1582 p += srvstr_pull_buf(req->inbuf, req->flags2, user, p,
1583 sizeof(user), STR_TERMINATE);
1584 p += srvstr_pull_buf(req->inbuf, req->flags2, domain, p,
1585 sizeof(domain), STR_TERMINATE);
1586 p += srvstr_pull_buf(req->inbuf, req->flags2, native_os,
1587 p, sizeof(native_os), STR_TERMINATE);
1588 p += srvstr_pull_buf(req->inbuf, req->flags2,
1589 native_lanman, p, sizeof(native_lanman),
1590 STR_TERMINATE);
1592 /* not documented or decoded by Ethereal but there is one more
1593 * string in the extra bytes which is the same as the
1594 * PrimaryDomain when using extended security. Windows NT 4
1595 * and 2003 use this string to store the native lanman string.
1596 * Windows 9x does not include a string here at all so we have
1597 * to check if we have any extra bytes left */
1599 byte_count = SVAL(req->inbuf, smb_vwv13);
1600 if ( PTR_DIFF(p, save_p) < byte_count) {
1601 p += srvstr_pull_buf(req->inbuf, req->flags2,
1602 primary_domain, p,
1603 sizeof(primary_domain),
1604 STR_TERMINATE);
1605 } else {
1606 fstrcpy( primary_domain, "null" );
1609 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
1610 "PrimaryDomain=[%s]\n",
1611 domain, native_os, native_lanman, primary_domain));
1613 if ( ra_type == RA_WIN2K ) {
1614 if ( strlen(native_lanman) == 0 )
1615 ra_lanman_string( primary_domain );
1616 else
1617 ra_lanman_string( native_lanman );
1622 if (SVAL(req->inbuf,smb_vwv4) == 0) {
1623 setup_new_vc_session();
1626 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1627 domain, user, get_remote_machine_name()));
1629 if (*user) {
1630 if (global_spnego_negotiated) {
1632 /* This has to be here, because this is a perfectly
1633 * valid behaviour for guest logons :-( */
1635 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1636 "at 'normal' session setup after "
1637 "negotiating spnego.\n"));
1638 reply_nterror(req, nt_status_squash(
1639 NT_STATUS_LOGON_FAILURE));
1640 END_PROFILE(SMBsesssetupX);
1641 return;
1643 fstrcpy(sub_user, user);
1644 } else {
1645 fstrcpy(sub_user, lp_guestaccount());
1648 sub_set_smb_name(sub_user);
1650 reload_services(True);
1652 if (lp_security() == SEC_SHARE) {
1653 /* In share level we should ignore any passwords */
1655 data_blob_free(&lm_resp);
1656 data_blob_free(&nt_resp);
1657 data_blob_clear_free(&plaintext_password);
1659 map_username(sub_user);
1660 add_session_user(sub_user);
1661 add_session_workgroup(domain);
1662 /* Then force it to null for the benfit of the code below */
1663 *user = 0;
1666 if (!*user) {
1668 nt_status = check_guest_password(&server_info);
1670 } else if (doencrypt) {
1671 if (!negprot_global_auth_context) {
1672 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
1673 "session setup without negprot denied!\n"));
1674 reply_nterror(req, nt_status_squash(
1675 NT_STATUS_LOGON_FAILURE));
1676 END_PROFILE(SMBsesssetupX);
1677 return;
1679 nt_status = make_user_info_for_reply_enc(&user_info, user,
1680 domain,
1681 lm_resp, nt_resp);
1682 if (NT_STATUS_IS_OK(nt_status)) {
1683 nt_status = negprot_global_auth_context->check_ntlm_password(
1684 negprot_global_auth_context,
1685 user_info,
1686 &server_info);
1688 } else {
1689 struct auth_context *plaintext_auth_context = NULL;
1690 const uint8 *chal;
1692 nt_status = make_auth_context_subsystem(
1693 &plaintext_auth_context);
1695 if (NT_STATUS_IS_OK(nt_status)) {
1696 chal = plaintext_auth_context->get_ntlm_challenge(
1697 plaintext_auth_context);
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 (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();
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(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 );
1803 sessionsetup_start_signing_engine(server_info, req->inbuf);
1806 data_blob_free(&nt_resp);
1807 data_blob_free(&lm_resp);
1809 SSVAL(req->outbuf,smb_uid,sess_vuid);
1810 SSVAL(req->inbuf,smb_uid,sess_vuid);
1812 if (!done_sesssetup)
1813 max_send = MIN(max_send,smb_bufsize);
1815 done_sesssetup = True;
1817 END_PROFILE(SMBsesssetupX);
1818 chain_reply(req);
1819 return;