clean up lib64 linking paths the same way as lib
[Samba/gebeck_regimport.git] / source3 / smbd / sesssetup.c
blob2c29192220b1958d0c47ae1eb51faac6bfb0d147
1 /*
2 Unix SMB/CIFS implementation.
3 handle SMBsessionsetup
4 Copyright (C) Andrew Tridgell 1998-2001
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
7 Copyright (C) Luke Howard 2003
8 Copyright (C) Volker Lendecke 2007
9 Copyright (C) Jeremy Allison 2007
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "smbd/globals.h"
28 extern enum protocol_types Protocol;
31 on a logon error possibly map the error to success if "map to guest"
32 is set approriately
34 static NTSTATUS do_map_to_guest(NTSTATUS status,
35 auth_serversupplied_info **server_info,
36 const char *user, const char *domain)
38 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
39 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
40 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
41 DEBUG(3,("No such user %s [%s] - using guest account\n",
42 user, domain));
43 status = make_server_info_guest(NULL, server_info);
47 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
48 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
49 DEBUG(3,("Registered username %s for guest access\n",
50 user));
51 status = make_server_info_guest(NULL, server_info);
55 return status;
58 /****************************************************************************
59 Add the standard 'Samba' signature to the end of the session setup.
60 ****************************************************************************/
62 static int push_signature(uint8 **outbuf)
64 char *lanman;
65 int result, tmp;
67 result = 0;
69 tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
71 if (tmp == -1) return -1;
72 result += tmp;
74 if (asprintf(&lanman, "Samba %s", samba_version_string()) != -1) {
75 tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
76 SAFE_FREE(lanman);
78 else {
79 tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
82 if (tmp == -1) return -1;
83 result += tmp;
85 tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
87 if (tmp == -1) return -1;
88 result += tmp;
90 return result;
93 /****************************************************************************
94 Start the signing engine if needed. Don't fail signing here.
95 ****************************************************************************/
97 static void sessionsetup_start_signing_engine(
98 const auth_serversupplied_info *server_info,
99 const uint8 *inbuf)
101 if (!server_info->guest && !srv_signing_started()) {
102 /* We need to start the signing engine
103 * here but a W2K client sends the old
104 * "BSRSPYL " signature instead of the
105 * correct one. Subsequent packets will
106 * be correct.
108 srv_check_sign_mac((char *)inbuf, False);
112 /****************************************************************************
113 Send a security blob via a session setup reply.
114 ****************************************************************************/
116 static void reply_sesssetup_blob(struct smb_request *req,
117 DATA_BLOB blob,
118 NTSTATUS nt_status)
120 if (!NT_STATUS_IS_OK(nt_status) &&
121 !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
122 reply_nterror(req, nt_status_squash(nt_status));
123 return;
126 nt_status = nt_status_squash(nt_status);
127 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
128 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
129 SSVAL(req->outbuf, smb_vwv3, blob.length);
131 if ((message_push_blob(&req->outbuf, blob) == -1)
132 || (push_signature(&req->outbuf) == -1)) {
133 reply_nterror(req, NT_STATUS_NO_MEMORY);
137 /****************************************************************************
138 Do a 'guest' logon, getting back the
139 ****************************************************************************/
141 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
143 struct auth_context *auth_context;
144 auth_usersupplied_info *user_info = NULL;
146 NTSTATUS nt_status;
147 unsigned char chal[8];
149 ZERO_STRUCT(chal);
151 DEBUG(3,("Got anonymous request\n"));
153 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context,
154 chal))) {
155 return nt_status;
158 if (!make_user_info_guest(&user_info)) {
159 (auth_context->free)(&auth_context);
160 return NT_STATUS_NO_MEMORY;
163 nt_status = auth_context->check_ntlm_password(auth_context,
164 user_info,
165 server_info);
166 (auth_context->free)(&auth_context);
167 free_user_info(&user_info);
168 return nt_status;
172 #ifdef HAVE_KRB5
174 #if 0
175 /* Experiment that failed. See "only happens with a KDC" comment below. */
176 /****************************************************************************
177 Cerate a clock skew error blob for a Windows client.
178 ****************************************************************************/
180 static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
182 krb5_context context = NULL;
183 krb5_error_code kerr = 0;
184 krb5_data reply;
185 krb5_principal host_princ = NULL;
186 char *host_princ_s = NULL;
187 bool ret = False;
189 *pblob_out = data_blob_null;
191 initialize_krb5_error_table();
192 kerr = krb5_init_context(&context);
193 if (kerr) {
194 return False;
196 /* Create server principal. */
197 asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
198 if (!host_princ_s) {
199 goto out;
201 strlower_m(host_princ_s);
203 kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
204 if (kerr) {
205 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
206 "for name %s: Error %s\n",
207 host_princ_s, error_message(kerr) ));
208 goto out;
211 kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
212 host_princ, &reply);
213 if (kerr) {
214 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
215 "failed: Error %s\n",
216 error_message(kerr) ));
217 goto out;
220 *pblob_out = data_blob(reply.data, reply.length);
221 kerberos_free_data_contents(context,&reply);
222 ret = True;
224 out:
226 if (host_princ_s) {
227 SAFE_FREE(host_princ_s);
229 if (host_princ) {
230 krb5_free_principal(context, host_princ);
232 krb5_free_context(context);
233 return ret;
235 #endif
237 /****************************************************************************
238 Reply to a session setup spnego negotiate packet for kerberos.
239 ****************************************************************************/
241 static void reply_spnego_kerberos(struct smb_request *req,
242 DATA_BLOB *secblob,
243 const char *mechOID,
244 uint16 vuid,
245 bool *p_invalidate_vuid)
247 TALLOC_CTX *mem_ctx;
248 DATA_BLOB ticket;
249 char *client, *p, *domain;
250 fstring netbios_domain_name;
251 struct passwd *pw;
252 fstring user;
253 int sess_vuid = req->vuid;
254 NTSTATUS ret = NT_STATUS_OK;
255 struct PAC_DATA *pac_data = NULL;
256 DATA_BLOB ap_rep, ap_rep_wrapped, response;
257 auth_serversupplied_info *server_info = NULL;
258 DATA_BLOB session_key = data_blob_null;
259 uint8 tok_id[2];
260 DATA_BLOB nullblob = data_blob_null;
261 fstring real_username;
262 bool map_domainuser_to_guest = False;
263 bool username_was_mapped;
264 struct PAC_LOGON_INFO *logon_info = NULL;
266 ZERO_STRUCT(ticket);
267 ZERO_STRUCT(ap_rep);
268 ZERO_STRUCT(ap_rep_wrapped);
269 ZERO_STRUCT(response);
271 /* Normally we will always invalidate the intermediate vuid. */
272 *p_invalidate_vuid = True;
274 mem_ctx = talloc_init("reply_spnego_kerberos");
275 if (mem_ctx == NULL) {
276 reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
277 return;
280 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
281 talloc_destroy(mem_ctx);
282 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
283 return;
286 ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
287 &client, &pac_data, &ap_rep,
288 &session_key, True);
290 data_blob_free(&ticket);
292 if (!NT_STATUS_IS_OK(ret)) {
293 #if 0
294 /* Experiment that failed.
295 * See "only happens with a KDC" comment below. */
297 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
300 * Windows in this case returns
301 * NT_STATUS_MORE_PROCESSING_REQUIRED
302 * with a negTokenTarg blob containing an krb5_error
303 * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
304 * The client then fixes its clock and continues rather
305 * than giving an error. JRA.
306 * -- Looks like this only happens with a KDC. JRA.
309 bool ok = make_krb5_skew_error(&ap_rep);
310 if (!ok) {
311 talloc_destroy(mem_ctx);
312 return ERROR_NT(nt_status_squash(
313 NT_STATUS_LOGON_FAILURE));
315 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
316 TOK_ID_KRB_ERROR);
317 response = spnego_gen_auth_response(&ap_rep_wrapped,
318 ret, OID_KERBEROS5_OLD);
319 reply_sesssetup_blob(conn, inbuf, outbuf, response,
320 NT_STATUS_MORE_PROCESSING_REQUIRED);
323 * In this one case we don't invalidate the
324 * intermediate vuid as we're expecting the client
325 * to re-use it for the next sessionsetupX packet. JRA.
328 *p_invalidate_vuid = False;
330 data_blob_free(&ap_rep);
331 data_blob_free(&ap_rep_wrapped);
332 data_blob_free(&response);
333 talloc_destroy(mem_ctx);
334 return -1; /* already replied */
336 #else
337 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
338 ret = NT_STATUS_LOGON_FAILURE;
340 #endif
341 DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
342 nt_errstr(ret)));
343 talloc_destroy(mem_ctx);
344 reply_nterror(req, nt_status_squash(ret));
345 return;
348 DEBUG(3,("Ticket name is [%s]\n", client));
350 p = strchr_m(client, '@');
351 if (!p) {
352 DEBUG(3,("Doesn't look like a valid principal\n"));
353 data_blob_free(&ap_rep);
354 data_blob_free(&session_key);
355 SAFE_FREE(client);
356 talloc_destroy(mem_ctx);
357 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
358 return;
361 *p = 0;
363 /* save the PAC data if we have it */
365 if (pac_data) {
366 logon_info = get_logon_info_from_pac(pac_data);
367 if (logon_info) {
368 netsamlogon_cache_store( client, &logon_info->info3 );
372 if (!strequal(p+1, lp_realm())) {
373 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
374 if (!lp_allow_trusted_domains()) {
375 data_blob_free(&ap_rep);
376 data_blob_free(&session_key);
377 SAFE_FREE(client);
378 talloc_destroy(mem_ctx);
379 reply_nterror(req, nt_status_squash(
380 NT_STATUS_LOGON_FAILURE));
381 return;
385 /* this gives a fully qualified user name (ie. with full realm).
386 that leads to very long usernames, but what else can we do? */
388 domain = p+1;
390 if (logon_info && logon_info->info3.base.domain.string) {
391 fstrcpy(netbios_domain_name,
392 logon_info->info3.base.domain.string);
393 domain = netbios_domain_name;
394 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
396 } else {
398 /* If we have winbind running, we can (and must) shorten the
399 username by using the short netbios name. Otherwise we will
400 have inconsistent user names. With Kerberos, we get the
401 fully qualified realm, with ntlmssp we get the short
402 name. And even w2k3 does use ntlmssp if you for example
403 connect to an ip address. */
405 wbcErr wbc_status;
406 struct wbcDomainInfo *info = NULL;
408 DEBUG(10, ("Mapping [%s] to short name\n", domain));
410 wbc_status = wbcDomainInfo(domain, &info);
412 if (WBC_ERROR_IS_OK(wbc_status)) {
414 fstrcpy(netbios_domain_name,
415 info->short_name);
417 wbcFreeMemory(info);
418 domain = netbios_domain_name;
419 DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
420 } else {
421 DEBUG(3, ("Could not find short name: %s\n",
422 wbcErrorString(wbc_status)));
426 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
428 /* lookup the passwd struct, create a new user if necessary */
430 username_was_mapped = map_username( user );
432 pw = smb_getpwnam( mem_ctx, user, real_username, True );
434 if (pw) {
435 /* if a real user check pam account restrictions */
436 /* only really perfomed if "obey pam restriction" is true */
437 /* do this before an eventual mapping to guest occurs */
438 ret = smb_pam_accountcheck(pw->pw_name);
439 if ( !NT_STATUS_IS_OK(ret)) {
440 DEBUG(1,("PAM account restriction "
441 "prevents user login\n"));
442 data_blob_free(&ap_rep);
443 data_blob_free(&session_key);
444 TALLOC_FREE(mem_ctx);
445 reply_nterror(req, nt_status_squash(ret));
446 return;
450 if (!pw) {
452 /* this was originally the behavior of Samba 2.2, if a user
453 did not have a local uid but has been authenticated, then
454 map them to a guest account */
456 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
457 map_domainuser_to_guest = True;
458 fstrcpy(user,lp_guestaccount());
459 pw = smb_getpwnam( mem_ctx, user, real_username, True );
462 /* extra sanity check that the guest account is valid */
464 if ( !pw ) {
465 DEBUG(1,("Username %s is invalid on this system\n",
466 user));
467 SAFE_FREE(client);
468 data_blob_free(&ap_rep);
469 data_blob_free(&session_key);
470 TALLOC_FREE(mem_ctx);
471 reply_nterror(req, nt_status_squash(
472 NT_STATUS_LOGON_FAILURE));
473 return;
477 /* setup the string used by %U */
479 sub_set_smb_name( real_username );
480 reload_services(True);
482 if ( map_domainuser_to_guest ) {
483 make_server_info_guest(NULL, &server_info);
484 } else if (logon_info) {
485 /* pass the unmapped username here since map_username()
486 will be called again from inside make_server_info_info3() */
488 ret = make_server_info_info3(mem_ctx, client, domain,
489 &server_info, &logon_info->info3);
490 if ( !NT_STATUS_IS_OK(ret) ) {
491 DEBUG(1,("make_server_info_info3 failed: %s!\n",
492 nt_errstr(ret)));
493 SAFE_FREE(client);
494 data_blob_free(&ap_rep);
495 data_blob_free(&session_key);
496 TALLOC_FREE(mem_ctx);
497 reply_nterror(req, nt_status_squash(ret));
498 return;
501 } else {
502 ret = make_server_info_pw(&server_info, real_username, pw);
504 if ( !NT_STATUS_IS_OK(ret) ) {
505 DEBUG(1,("make_server_info_pw failed: %s!\n",
506 nt_errstr(ret)));
507 SAFE_FREE(client);
508 data_blob_free(&ap_rep);
509 data_blob_free(&session_key);
510 TALLOC_FREE(mem_ctx);
511 reply_nterror(req, nt_status_squash(ret));
512 return;
515 /* make_server_info_pw does not set the domain. Without this
516 * we end up with the local netbios name in substitutions for
517 * %D. */
519 if (server_info->sam_account != NULL) {
520 pdb_set_domain(server_info->sam_account,
521 domain, PDB_SET);
525 server_info->nss_token |= username_was_mapped;
527 /* we need to build the token for the user. make_server_info_guest()
528 already does this */
530 if ( !server_info->ptok ) {
531 ret = create_local_token( server_info );
532 if ( !NT_STATUS_IS_OK(ret) ) {
533 DEBUG(10,("failed to create local token: %s\n",
534 nt_errstr(ret)));
535 SAFE_FREE(client);
536 data_blob_free(&ap_rep);
537 data_blob_free(&session_key);
538 TALLOC_FREE( mem_ctx );
539 TALLOC_FREE( server_info );
540 reply_nterror(req, nt_status_squash(ret));
541 return;
545 if (!is_partial_auth_vuid(sess_vuid)) {
546 sess_vuid = register_initial_vuid();
549 data_blob_free(&server_info->user_session_key);
550 server_info->user_session_key = session_key;
551 session_key = data_blob_null;
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 sess_vuid = register_existing_vuid(sess_vuid,
559 server_info,
560 nullblob,
561 client);
563 SAFE_FREE(client);
565 reply_outbuf(req, 4, 0);
566 SSVAL(req->outbuf,smb_uid,sess_vuid);
568 if (sess_vuid == UID_FIELD_INVALID ) {
569 ret = NT_STATUS_LOGON_FAILURE;
570 } else {
571 /* current_user_info is changed on new vuid */
572 reload_services( True );
574 SSVAL(req->outbuf, smb_vwv3, 0);
576 if (server_info->guest) {
577 SSVAL(req->outbuf,smb_vwv2,1);
580 SSVAL(req->outbuf, smb_uid, sess_vuid);
582 sessionsetup_start_signing_engine(server_info, req->inbuf);
583 /* Successful logon. Keep this vuid. */
584 *p_invalidate_vuid = False;
587 /* wrap that up in a nice GSS-API wrapping */
588 if (NT_STATUS_IS_OK(ret)) {
589 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
590 TOK_ID_KRB_AP_REP);
591 } else {
592 ap_rep_wrapped = data_blob_null;
594 response = spnego_gen_auth_response(&ap_rep_wrapped, ret,
595 mechOID);
596 reply_sesssetup_blob(req, response, ret);
598 data_blob_free(&ap_rep);
599 data_blob_free(&ap_rep_wrapped);
600 data_blob_free(&response);
601 TALLOC_FREE(mem_ctx);
604 #endif
606 /****************************************************************************
607 Send a session setup reply, wrapped in SPNEGO.
608 Get vuid and check first.
609 End the NTLMSSP exchange context if we are OK/complete fail
610 This should be split into two functions, one to handle each
611 leg of the NTLM auth steps.
612 ***************************************************************************/
614 static void reply_spnego_ntlmssp(struct smb_request *req,
615 uint16 vuid,
616 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
617 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
618 const char *OID,
619 bool wrap)
621 DATA_BLOB response;
622 struct auth_serversupplied_info *server_info = NULL;
624 if (NT_STATUS_IS_OK(nt_status)) {
625 server_info = (*auth_ntlmssp_state)->server_info;
626 } else {
627 nt_status = do_map_to_guest(nt_status,
628 &server_info,
629 (*auth_ntlmssp_state)->ntlmssp_state->user,
630 (*auth_ntlmssp_state)->ntlmssp_state->domain);
633 reply_outbuf(req, 4, 0);
635 SSVAL(req->outbuf, smb_uid, vuid);
637 if (NT_STATUS_IS_OK(nt_status)) {
638 DATA_BLOB nullblob = data_blob_null;
640 if (!is_partial_auth_vuid(vuid)) {
641 nt_status = NT_STATUS_LOGON_FAILURE;
642 goto out;
645 data_blob_free(&server_info->user_session_key);
646 server_info->user_session_key =
647 data_blob_talloc(
648 server_info,
649 (*auth_ntlmssp_state)->ntlmssp_state->session_key.data,
650 (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
652 /* register_existing_vuid keeps the server info */
653 if (register_existing_vuid(vuid,
654 server_info, nullblob,
655 (*auth_ntlmssp_state)->ntlmssp_state->user) !=
656 vuid) {
657 nt_status = NT_STATUS_LOGON_FAILURE;
658 goto out;
661 (*auth_ntlmssp_state)->server_info = NULL;
663 /* current_user_info is changed on new vuid */
664 reload_services( True );
666 SSVAL(req->outbuf, smb_vwv3, 0);
668 if (server_info->guest) {
669 SSVAL(req->outbuf,smb_vwv2,1);
672 sessionsetup_start_signing_engine(server_info,
673 (uint8 *)req->inbuf);
676 out:
678 if (wrap) {
679 response = spnego_gen_auth_response(ntlmssp_blob,
680 nt_status, OID);
681 } else {
682 response = *ntlmssp_blob;
685 reply_sesssetup_blob(req, response, nt_status);
686 if (wrap) {
687 data_blob_free(&response);
690 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
691 and the other end, that we are not finished yet. */
693 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
694 /* NB. This is *NOT* an error case. JRA */
695 auth_ntlmssp_end(auth_ntlmssp_state);
696 if (!NT_STATUS_IS_OK(nt_status)) {
697 /* Kill the intermediate vuid */
698 invalidate_vuid(vuid);
703 /****************************************************************************
704 Is this a krb5 mechanism ?
705 ****************************************************************************/
707 NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in,
708 DATA_BLOB *pblob_out,
709 char **kerb_mechOID)
711 char *OIDs[ASN1_MAX_OIDS];
712 int i;
713 NTSTATUS ret = NT_STATUS_OK;
715 *kerb_mechOID = NULL;
717 /* parse out the OIDs and the first sec blob */
718 if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
719 return NT_STATUS_LOGON_FAILURE;
722 /* only look at the first OID for determining the mechToken --
723 according to RFC2478, we should choose the one we want
724 and renegotiate, but i smell a client bug here..
726 Problem observed when connecting to a member (samba box)
727 of an AD domain as a user in a Samba domain. Samba member
728 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
729 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
730 NTLMSSP mechtoken. --jerry */
732 #ifdef HAVE_KRB5
733 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
734 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
735 *kerb_mechOID = SMB_STRDUP(OIDs[0]);
736 if (*kerb_mechOID == NULL) {
737 ret = NT_STATUS_NO_MEMORY;
740 #endif
742 for (i=0;OIDs[i];i++) {
743 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
744 talloc_free(OIDs[i]);
746 return ret;
749 /****************************************************************************
750 Fall back from krb5 to NTLMSSP.
751 ****************************************************************************/
753 static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
754 uint16 vuid)
756 DATA_BLOB response;
758 reply_outbuf(req, 4, 0);
759 SSVAL(req->outbuf,smb_uid,vuid);
761 DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
762 "but set to downgrade to NTLMSSP\n"));
764 response = spnego_gen_auth_response(NULL,
765 NT_STATUS_MORE_PROCESSING_REQUIRED,
766 OID_NTLMSSP);
767 reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
768 data_blob_free(&response);
771 /****************************************************************************
772 Reply to a session setup spnego negotiate packet.
773 ****************************************************************************/
775 static void reply_spnego_negotiate(struct smb_request *req,
776 uint16 vuid,
777 DATA_BLOB blob1,
778 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
780 DATA_BLOB secblob;
781 DATA_BLOB chal;
782 char *kerb_mech = NULL;
783 NTSTATUS status;
785 status = parse_spnego_mechanisms(blob1, &secblob, &kerb_mech);
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 (kerb_mech && ((lp_security()==SEC_ADS) ||
798 USE_KERBEROS_KEYTAB) ) {
799 bool destroy_vuid = True;
800 reply_spnego_kerberos(req, &secblob, kerb_mech,
801 vuid, &destroy_vuid);
802 data_blob_free(&secblob);
803 if (destroy_vuid) {
804 /* Kill the intermediate vuid */
805 invalidate_vuid(vuid);
807 SAFE_FREE(kerb_mech);
808 return;
810 #endif
812 if (*auth_ntlmssp_state) {
813 auth_ntlmssp_end(auth_ntlmssp_state);
816 if (kerb_mech) {
817 data_blob_free(&secblob);
818 /* The mechtoken is a krb5 ticket, but
819 * we need to fall back to NTLM. */
820 reply_spnego_downgrade_to_ntlmssp(req, vuid);
821 SAFE_FREE(kerb_mech);
822 return;
825 status = auth_ntlmssp_start(auth_ntlmssp_state);
826 if (!NT_STATUS_IS_OK(status)) {
827 /* Kill the intermediate vuid */
828 invalidate_vuid(vuid);
829 reply_nterror(req, nt_status_squash(status));
830 return;
833 status = auth_ntlmssp_update(*auth_ntlmssp_state,
834 secblob, &chal);
836 data_blob_free(&secblob);
838 reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
839 &chal, status, OID_NTLMSSP, true);
841 data_blob_free(&chal);
843 /* already replied */
844 return;
847 /****************************************************************************
848 Reply to a session setup spnego auth packet.
849 ****************************************************************************/
851 static void reply_spnego_auth(struct smb_request *req,
852 uint16 vuid,
853 DATA_BLOB blob1,
854 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
856 DATA_BLOB auth = data_blob_null;
857 DATA_BLOB auth_reply = data_blob_null;
858 DATA_BLOB secblob = data_blob_null;
859 NTSTATUS status = NT_STATUS_LOGON_FAILURE;
861 if (!spnego_parse_auth(blob1, &auth)) {
862 #if 0
863 file_save("auth.dat", blob1.data, blob1.length);
864 #endif
865 /* Kill the intermediate vuid */
866 invalidate_vuid(vuid);
868 reply_nterror(req, nt_status_squash(
869 NT_STATUS_LOGON_FAILURE));
870 return;
873 if (auth.data[0] == ASN1_APPLICATION(0)) {
874 /* Might be a second negTokenTarg packet */
875 char *kerb_mech = NULL;
877 status = parse_spnego_mechanisms(auth, &secblob, &kerb_mech);
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 (kerb_mech && ((lp_security()==SEC_ADS) ||
890 USE_KERBEROS_KEYTAB)) {
891 bool destroy_vuid = True;
892 reply_spnego_kerberos(req, &secblob, kerb_mech,
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 SAFE_FREE(kerb_mech);
901 return;
903 #endif
904 /* Can't blunder into NTLMSSP auth if we have
905 * a krb5 ticket. */
907 if (kerb_mech) {
908 /* Kill the intermediate vuid */
909 invalidate_vuid(vuid);
910 DEBUG(3,("reply_spnego_auth: network "
911 "misconfiguration, client sent us a "
912 "krb5 ticket and kerberos security "
913 "not enabled\n"));
914 reply_nterror(req, nt_status_squash(
915 NT_STATUS_LOGON_FAILURE));
916 SAFE_FREE(kerb_mech);
920 /* If we get here it wasn't a negTokenTarg auth packet. */
921 data_blob_free(&secblob);
923 if (!*auth_ntlmssp_state) {
924 status = auth_ntlmssp_start(auth_ntlmssp_state);
925 if (!NT_STATUS_IS_OK(status)) {
926 /* Kill the intermediate vuid */
927 invalidate_vuid(vuid);
928 reply_nterror(req, nt_status_squash(status));
929 return;
933 status = auth_ntlmssp_update(*auth_ntlmssp_state,
934 auth, &auth_reply);
936 data_blob_free(&auth);
938 /* Don't send the mechid as we've already sent this (RFC4178). */
940 reply_spnego_ntlmssp(req, vuid,
941 auth_ntlmssp_state,
942 &auth_reply, status, NULL, true);
944 data_blob_free(&auth_reply);
946 /* and tell smbd that we have already replied to this packet */
947 return;
950 /****************************************************************************
951 Delete an entry on the list.
952 ****************************************************************************/
954 static void delete_partial_auth(struct pending_auth_data *pad)
956 if (!pad) {
957 return;
959 DLIST_REMOVE(pd_list, pad);
960 data_blob_free(&pad->partial_data);
961 SAFE_FREE(pad);
964 /****************************************************************************
965 Search for a partial SPNEGO auth fragment matching an smbpid.
966 ****************************************************************************/
968 static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
970 struct pending_auth_data *pad;
972 for (pad = pd_list; pad; pad = pad->next) {
973 if (pad->smbpid == smbpid) {
974 break;
977 return pad;
980 /****************************************************************************
981 Check the size of an SPNEGO blob. If we need more return
982 NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
983 the blob to be more than 64k.
984 ****************************************************************************/
986 static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid,
987 DATA_BLOB *pblob)
989 struct pending_auth_data *pad = NULL;
990 ASN1_DATA *data;
991 size_t needed_len = 0;
993 pad = get_pending_auth_data(smbpid);
995 /* Ensure we have some data. */
996 if (pblob->length == 0) {
997 /* Caller can cope. */
998 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
999 delete_partial_auth(pad);
1000 return NT_STATUS_OK;
1003 /* Were we waiting for more data ? */
1004 if (pad) {
1005 DATA_BLOB tmp_blob;
1006 size_t copy_len = MIN(65536, pblob->length);
1008 /* Integer wrap paranoia.... */
1010 if (pad->partial_data.length + copy_len <
1011 pad->partial_data.length ||
1012 pad->partial_data.length + copy_len < copy_len) {
1014 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1015 "pad->partial_data.length = %u, "
1016 "copy_len = %u\n",
1017 (unsigned int)pad->partial_data.length,
1018 (unsigned int)copy_len ));
1020 delete_partial_auth(pad);
1021 return NT_STATUS_INVALID_PARAMETER;
1024 DEBUG(10,("check_spnego_blob_complete: "
1025 "pad->partial_data.length = %u, "
1026 "pad->needed_len = %u, "
1027 "copy_len = %u, "
1028 "pblob->length = %u,\n",
1029 (unsigned int)pad->partial_data.length,
1030 (unsigned int)pad->needed_len,
1031 (unsigned int)copy_len,
1032 (unsigned int)pblob->length ));
1034 tmp_blob = data_blob(NULL,
1035 pad->partial_data.length + copy_len);
1037 /* Concatenate the two (up to copy_len) bytes. */
1038 memcpy(tmp_blob.data,
1039 pad->partial_data.data,
1040 pad->partial_data.length);
1041 memcpy(tmp_blob.data + pad->partial_data.length,
1042 pblob->data,
1043 copy_len);
1045 /* Replace the partial data. */
1046 data_blob_free(&pad->partial_data);
1047 pad->partial_data = tmp_blob;
1048 ZERO_STRUCT(tmp_blob);
1050 /* Are we done ? */
1051 if (pblob->length >= pad->needed_len) {
1052 /* Yes, replace pblob. */
1053 data_blob_free(pblob);
1054 *pblob = pad->partial_data;
1055 ZERO_STRUCT(pad->partial_data);
1056 delete_partial_auth(pad);
1057 return NT_STATUS_OK;
1060 /* Still need more data. */
1061 pad->needed_len -= copy_len;
1062 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1065 if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
1066 (pblob->data[0] != ASN1_CONTEXT(1))) {
1067 /* Not something we can determine the
1068 * length of.
1070 return NT_STATUS_OK;
1073 /* This is a new SPNEGO sessionsetup - see if
1074 * the data given in this blob is enough.
1077 data = asn1_init(NULL);
1078 if (data == NULL) {
1079 return NT_STATUS_NO_MEMORY;
1082 asn1_load(data, *pblob);
1083 asn1_start_tag(data, pblob->data[0]);
1084 if (data->has_error || data->nesting == NULL) {
1085 asn1_free(data);
1086 /* Let caller catch. */
1087 return NT_STATUS_OK;
1090 /* Integer wrap paranoia.... */
1092 if (data->nesting->taglen + data->nesting->start < data->nesting->taglen ||
1093 data->nesting->taglen + data->nesting->start < data->nesting->start) {
1095 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1096 "data.nesting->taglen = %u, "
1097 "data.nesting->start = %u\n",
1098 (unsigned int)data->nesting->taglen,
1099 (unsigned int)data->nesting->start ));
1101 asn1_free(data);
1102 return NT_STATUS_INVALID_PARAMETER;
1105 /* Total length of the needed asn1 is the tag length
1106 * plus the current offset. */
1108 needed_len = data->nesting->taglen + data->nesting->start;
1109 asn1_free(data);
1111 DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
1112 "pblob->length = %u\n",
1113 (unsigned int)needed_len,
1114 (unsigned int)pblob->length ));
1116 if (needed_len <= pblob->length) {
1117 /* Nothing to do - blob is complete. */
1118 return NT_STATUS_OK;
1121 /* Refuse the blob if it's bigger than 64k. */
1122 if (needed_len > 65536) {
1123 DEBUG(2,("check_spnego_blob_complete: needed_len "
1124 "too large (%u)\n",
1125 (unsigned int)needed_len ));
1126 return NT_STATUS_INVALID_PARAMETER;
1129 /* We must store this blob until complete. */
1130 if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
1131 return NT_STATUS_NO_MEMORY;
1133 pad->needed_len = needed_len - pblob->length;
1134 pad->partial_data = data_blob(pblob->data, pblob->length);
1135 if (pad->partial_data.data == NULL) {
1136 SAFE_FREE(pad);
1137 return NT_STATUS_NO_MEMORY;
1139 pad->smbpid = smbpid;
1140 pad->vuid = vuid;
1141 DLIST_ADD(pd_list, pad);
1143 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1146 /****************************************************************************
1147 Reply to a session setup command.
1148 conn POINTER CAN BE NULL HERE !
1149 ****************************************************************************/
1151 static void reply_sesssetup_and_X_spnego(struct smb_request *req)
1153 const uint8 *p;
1154 DATA_BLOB blob1;
1155 size_t bufrem;
1156 char *tmp;
1157 const char *native_os;
1158 const char *native_lanman;
1159 const char *primary_domain;
1160 const char *p2;
1161 uint16 data_blob_len = SVAL(req->vwv+7, 0);
1162 enum remote_arch_types ra_type = get_remote_arch();
1163 int vuid = req->vuid;
1164 user_struct *vuser = NULL;
1165 NTSTATUS status = NT_STATUS_OK;
1166 uint16 smbpid = req->smbpid;
1168 DEBUG(3,("Doing spnego session setup\n"));
1170 if (global_client_caps == 0) {
1171 global_client_caps = IVAL(req->vwv+10, 0);
1173 if (!(global_client_caps & CAP_STATUS32)) {
1174 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1179 p = req->buf;
1181 if (data_blob_len == 0) {
1182 /* an invalid request */
1183 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1184 return;
1187 bufrem = smbreq_bufrem(req, p);
1188 /* pull the spnego blob */
1189 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1191 #if 0
1192 file_save("negotiate.dat", blob1.data, blob1.length);
1193 #endif
1195 p2 = (char *)req->buf + data_blob_len;
1197 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1198 STR_TERMINATE);
1199 native_os = tmp ? tmp : "";
1201 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1202 STR_TERMINATE);
1203 native_lanman = tmp ? tmp : "";
1205 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1206 STR_TERMINATE);
1207 primary_domain = tmp ? tmp : "";
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 char *tmp;
1392 const char *user;
1393 fstring sub_user; /* Sainitised username for substituion */
1394 const char *domain;
1395 const char *native_os;
1396 const char *native_lanman;
1397 const char *primary_domain;
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->vwv+4, 0) == 0) {
1430 setup_new_vc_session();
1433 reply_sesssetup_and_X_spnego(req);
1434 END_PROFILE(SMBsesssetupX);
1435 return;
1438 smb_bufsize = SVAL(req->vwv+2, 0);
1440 if (Protocol < PROTOCOL_NT1) {
1441 uint16 passlen1 = SVAL(req->vwv+7, 0);
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) || (passlen1 > req->buflen)) {
1448 reply_nterror(req, nt_status_squash(
1449 NT_STATUS_INVALID_PARAMETER));
1450 END_PROFILE(SMBsesssetupX);
1451 return;
1454 if (doencrypt) {
1455 lm_resp = data_blob(req->buf, passlen1);
1456 } else {
1457 plaintext_password = data_blob(req->buf, passlen1+1);
1458 /* Ensure null termination */
1459 plaintext_password.data[passlen1] = 0;
1462 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
1463 req->buf + passlen1, STR_TERMINATE);
1464 user = tmp ? tmp : "";
1466 domain = "";
1468 } else {
1469 uint16 passlen1 = SVAL(req->vwv+7, 0);
1470 uint16 passlen2 = SVAL(req->vwv+8, 0);
1471 enum remote_arch_types ra_type = get_remote_arch();
1472 const uint8_t *p = req->buf;
1473 const uint8_t *save_p = req->buf;
1474 uint16 byte_count;
1477 if(global_client_caps == 0) {
1478 global_client_caps = IVAL(req->vwv+11, 0);
1480 if (!(global_client_caps & CAP_STATUS32)) {
1481 remove_from_common_flags2(
1482 FLAGS2_32_BIT_ERROR_CODES);
1485 /* client_caps is used as final determination if
1486 * client is NT or Win95. This is needed to return
1487 * the correct error codes in some circumstances.
1490 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1491 ra_type == RA_WIN95) {
1492 if(!(global_client_caps & (CAP_NT_SMBS|
1493 CAP_STATUS32))) {
1494 set_remote_arch( RA_WIN95);
1499 if (!doencrypt) {
1500 /* both Win95 and WinNT stuff up the password
1501 * lengths for non-encrypting systems. Uggh.
1503 if passlen1==24 its a win95 system, and its setting
1504 the password length incorrectly. Luckily it still
1505 works with the default code because Win95 will null
1506 terminate the password anyway
1508 if passlen1>0 and passlen2>0 then maybe its a NT box
1509 and its setting passlen2 to some random value which
1510 really stuffs things up. we need to fix that one. */
1512 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1513 passlen2 != 1) {
1514 passlen2 = 0;
1518 /* check for nasty tricks */
1519 if (passlen1 > MAX_PASS_LEN
1520 || passlen1 > smbreq_bufrem(req, p)) {
1521 reply_nterror(req, nt_status_squash(
1522 NT_STATUS_INVALID_PARAMETER));
1523 END_PROFILE(SMBsesssetupX);
1524 return;
1527 if (passlen2 > MAX_PASS_LEN
1528 || passlen2 > smbreq_bufrem(req, p+passlen1)) {
1529 reply_nterror(req, nt_status_squash(
1530 NT_STATUS_INVALID_PARAMETER));
1531 END_PROFILE(SMBsesssetupX);
1532 return;
1535 /* Save the lanman2 password and the NT md4 password. */
1537 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1538 doencrypt = False;
1541 if (doencrypt) {
1542 lm_resp = data_blob(p, passlen1);
1543 nt_resp = data_blob(p+passlen1, passlen2);
1544 } else if (lp_security() != SEC_SHARE) {
1546 * In share level we should ignore any passwords, so
1547 * only read them if we're not.
1549 char *pass = NULL;
1550 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1552 if (unic && (passlen2 == 0) && passlen1) {
1553 /* Only a ascii plaintext password was sent. */
1554 (void)srvstr_pull_talloc(talloc_tos(),
1555 req->inbuf,
1556 req->flags2,
1557 &pass,
1558 req->buf,
1559 passlen1,
1560 STR_TERMINATE|STR_ASCII);
1561 } else {
1562 (void)srvstr_pull_talloc(talloc_tos(),
1563 req->inbuf,
1564 req->flags2,
1565 &pass,
1566 req->buf,
1567 unic ? passlen2 : passlen1,
1568 STR_TERMINATE);
1570 if (!pass) {
1571 reply_nterror(req, nt_status_squash(
1572 NT_STATUS_INVALID_PARAMETER));
1573 END_PROFILE(SMBsesssetupX);
1574 return;
1576 plaintext_password = data_blob(pass, strlen(pass)+1);
1579 p += passlen1 + passlen2;
1581 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1582 STR_TERMINATE);
1583 user = tmp ? tmp : "";
1585 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1586 STR_TERMINATE);
1587 domain = tmp ? tmp : "";
1589 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1590 STR_TERMINATE);
1591 native_os = tmp ? tmp : "";
1593 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1594 STR_TERMINATE);
1595 native_lanman = tmp ? tmp : "";
1597 /* not documented or decoded by Ethereal but there is one more
1598 * string in the extra bytes which is the same as the
1599 * PrimaryDomain when using extended security. Windows NT 4
1600 * and 2003 use this string to store the native lanman string.
1601 * Windows 9x does not include a string here at all so we have
1602 * to check if we have any extra bytes left */
1604 byte_count = SVAL(req->vwv+13, 0);
1605 if ( PTR_DIFF(p, save_p) < byte_count) {
1606 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1607 STR_TERMINATE);
1608 primary_domain = tmp ? tmp : "";
1609 } else {
1610 primary_domain = talloc_strdup(talloc_tos(), "null");
1613 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
1614 "PrimaryDomain=[%s]\n",
1615 domain, native_os, native_lanman, primary_domain));
1617 if ( ra_type == RA_WIN2K ) {
1618 if ( strlen(native_lanman) == 0 )
1619 ra_lanman_string( primary_domain );
1620 else
1621 ra_lanman_string( native_lanman );
1626 if (SVAL(req->vwv+4, 0) == 0) {
1627 setup_new_vc_session();
1630 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1631 domain, user, get_remote_machine_name()));
1633 if (*user) {
1634 if (global_spnego_negotiated) {
1636 /* This has to be here, because this is a perfectly
1637 * valid behaviour for guest logons :-( */
1639 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1640 "at 'normal' session setup after "
1641 "negotiating spnego.\n"));
1642 reply_nterror(req, nt_status_squash(
1643 NT_STATUS_LOGON_FAILURE));
1644 END_PROFILE(SMBsesssetupX);
1645 return;
1647 fstrcpy(sub_user, user);
1648 } else {
1649 fstrcpy(sub_user, lp_guestaccount());
1652 sub_set_smb_name(sub_user);
1654 reload_services(True);
1656 if (lp_security() == SEC_SHARE) {
1657 /* In share level we should ignore any passwords */
1659 data_blob_free(&lm_resp);
1660 data_blob_free(&nt_resp);
1661 data_blob_clear_free(&plaintext_password);
1663 map_username(sub_user);
1664 add_session_user(sub_user);
1665 add_session_workgroup(domain);
1666 /* Then force it to null for the benfit of the code below */
1667 user = "";
1670 if (!*user) {
1672 nt_status = check_guest_password(&server_info);
1674 } else if (doencrypt) {
1675 if (!negprot_global_auth_context) {
1676 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
1677 "session setup without negprot denied!\n"));
1678 reply_nterror(req, nt_status_squash(
1679 NT_STATUS_LOGON_FAILURE));
1680 END_PROFILE(SMBsesssetupX);
1681 return;
1683 nt_status = make_user_info_for_reply_enc(&user_info, user,
1684 domain,
1685 lm_resp, nt_resp);
1686 if (NT_STATUS_IS_OK(nt_status)) {
1687 nt_status = negprot_global_auth_context->check_ntlm_password(
1688 negprot_global_auth_context,
1689 user_info,
1690 &server_info);
1692 } else {
1693 struct auth_context *plaintext_auth_context = NULL;
1695 nt_status = make_auth_context_subsystem(
1696 &plaintext_auth_context);
1698 if (NT_STATUS_IS_OK(nt_status)) {
1699 uint8_t chal[8];
1701 plaintext_auth_context->get_ntlm_challenge(
1702 plaintext_auth_context, chal);
1704 if (!make_user_info_for_reply(&user_info,
1705 user, domain, chal,
1706 plaintext_password)) {
1707 nt_status = NT_STATUS_NO_MEMORY;
1710 if (NT_STATUS_IS_OK(nt_status)) {
1711 nt_status = plaintext_auth_context->check_ntlm_password(
1712 plaintext_auth_context,
1713 user_info,
1714 &server_info);
1716 (plaintext_auth_context->free)(
1717 &plaintext_auth_context);
1722 free_user_info(&user_info);
1724 if (!NT_STATUS_IS_OK(nt_status)) {
1725 nt_status = do_map_to_guest(nt_status, &server_info,
1726 user, domain);
1729 if (!NT_STATUS_IS_OK(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 /* Ensure we can't possible take a code path leading to a
1739 * null defref. */
1740 if (!server_info) {
1741 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1742 END_PROFILE(SMBsesssetupX);
1743 return;
1746 if (!server_info->ptok) {
1747 nt_status = create_local_token(server_info);
1749 if (!NT_STATUS_IS_OK(nt_status)) {
1750 DEBUG(10, ("create_local_token failed: %s\n",
1751 nt_errstr(nt_status)));
1752 data_blob_free(&nt_resp);
1753 data_blob_free(&lm_resp);
1754 data_blob_clear_free(&plaintext_password);
1755 reply_nterror(req, nt_status_squash(nt_status));
1756 END_PROFILE(SMBsesssetupX);
1757 return;
1761 data_blob_clear_free(&plaintext_password);
1763 /* it's ok - setup a reply */
1764 reply_outbuf(req, 3, 0);
1765 if (Protocol >= PROTOCOL_NT1) {
1766 push_signature(&req->outbuf);
1767 /* perhaps grab OS version here?? */
1770 if (server_info->guest) {
1771 SSVAL(req->outbuf,smb_vwv2,1);
1774 /* register the name and uid as being validated, so further connections
1775 to a uid can get through without a password, on the same VC */
1777 if (lp_security() == SEC_SHARE) {
1778 sess_vuid = UID_FIELD_INVALID;
1779 TALLOC_FREE(server_info);
1780 } else {
1781 /* Ignore the initial vuid. */
1782 sess_vuid = register_initial_vuid();
1783 if (sess_vuid == UID_FIELD_INVALID) {
1784 data_blob_free(&nt_resp);
1785 data_blob_free(&lm_resp);
1786 reply_nterror(req, nt_status_squash(
1787 NT_STATUS_LOGON_FAILURE));
1788 END_PROFILE(SMBsesssetupX);
1789 return;
1791 /* register_existing_vuid keeps the server info */
1792 sess_vuid = register_existing_vuid(sess_vuid,
1793 server_info,
1794 nt_resp.data ? nt_resp : lm_resp,
1795 sub_user);
1796 if (sess_vuid == UID_FIELD_INVALID) {
1797 data_blob_free(&nt_resp);
1798 data_blob_free(&lm_resp);
1799 reply_nterror(req, nt_status_squash(
1800 NT_STATUS_LOGON_FAILURE));
1801 END_PROFILE(SMBsesssetupX);
1802 return;
1805 /* current_user_info is changed on new vuid */
1806 reload_services( True );
1808 sessionsetup_start_signing_engine(server_info, req->inbuf);
1811 data_blob_free(&nt_resp);
1812 data_blob_free(&lm_resp);
1814 SSVAL(req->outbuf,smb_uid,sess_vuid);
1815 SSVAL(req->inbuf,smb_uid,sess_vuid);
1817 if (!done_sesssetup)
1818 max_send = MIN(max_send,smb_bufsize);
1820 done_sesssetup = True;
1822 END_PROFILE(SMBsesssetupX);
1823 chain_reply(req);
1824 return;