Use vfs_cifs as a basis for vfs_proxy
[Samba/vfs_proxy.git] / source3 / smbd / sesssetup.c
blob24a201013ad5e2c102f9f71638c7465fb4de7b13
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 return;
131 nt_status = nt_status_squash(nt_status);
132 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
133 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
134 SSVAL(req->outbuf, smb_vwv3, blob.length);
136 if ((message_push_blob(&req->outbuf, blob) == -1)
137 || (push_signature(&req->outbuf) == -1)) {
138 reply_nterror(req, NT_STATUS_NO_MEMORY);
142 /****************************************************************************
143 Do a 'guest' logon, getting back the
144 ****************************************************************************/
146 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
148 struct auth_context *auth_context;
149 auth_usersupplied_info *user_info = NULL;
151 NTSTATUS nt_status;
152 unsigned char chal[8];
154 ZERO_STRUCT(chal);
156 DEBUG(3,("Got anonymous request\n"));
158 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context,
159 chal))) {
160 return nt_status;
163 if (!make_user_info_guest(&user_info)) {
164 (auth_context->free)(&auth_context);
165 return NT_STATUS_NO_MEMORY;
168 nt_status = auth_context->check_ntlm_password(auth_context,
169 user_info,
170 server_info);
171 (auth_context->free)(&auth_context);
172 free_user_info(&user_info);
173 return nt_status;
177 #ifdef HAVE_KRB5
179 #if 0
180 /* Experiment that failed. See "only happens with a KDC" comment below. */
181 /****************************************************************************
182 Cerate a clock skew error blob for a Windows client.
183 ****************************************************************************/
185 static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
187 krb5_context context = NULL;
188 krb5_error_code kerr = 0;
189 krb5_data reply;
190 krb5_principal host_princ = NULL;
191 char *host_princ_s = NULL;
192 bool ret = False;
194 *pblob_out = data_blob_null;
196 initialize_krb5_error_table();
197 kerr = krb5_init_context(&context);
198 if (kerr) {
199 return False;
201 /* Create server principal. */
202 asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
203 if (!host_princ_s) {
204 goto out;
206 strlower_m(host_princ_s);
208 kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
209 if (kerr) {
210 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
211 "for name %s: Error %s\n",
212 host_princ_s, error_message(kerr) ));
213 goto out;
216 kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
217 host_princ, &reply);
218 if (kerr) {
219 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
220 "failed: Error %s\n",
221 error_message(kerr) ));
222 goto out;
225 *pblob_out = data_blob(reply.data, reply.length);
226 kerberos_free_data_contents(context,&reply);
227 ret = True;
229 out:
231 if (host_princ_s) {
232 SAFE_FREE(host_princ_s);
234 if (host_princ) {
235 krb5_free_principal(context, host_princ);
237 krb5_free_context(context);
238 return ret;
240 #endif
242 /****************************************************************************
243 Reply to a session setup spnego negotiate packet for kerberos.
244 ****************************************************************************/
246 static void reply_spnego_kerberos(struct smb_request *req,
247 DATA_BLOB *secblob,
248 const char *mechOID,
249 uint16 vuid,
250 bool *p_invalidate_vuid)
252 TALLOC_CTX *mem_ctx;
253 DATA_BLOB ticket;
254 char *client, *p, *domain;
255 fstring netbios_domain_name;
256 struct passwd *pw;
257 fstring user;
258 int sess_vuid = req->vuid;
259 NTSTATUS ret = NT_STATUS_OK;
260 struct PAC_DATA *pac_data = NULL;
261 DATA_BLOB ap_rep, ap_rep_wrapped, response;
262 auth_serversupplied_info *server_info = NULL;
263 DATA_BLOB session_key = data_blob_null;
264 uint8 tok_id[2];
265 DATA_BLOB nullblob = data_blob_null;
266 fstring real_username;
267 bool map_domainuser_to_guest = False;
268 bool username_was_mapped;
269 struct PAC_LOGON_INFO *logon_info = NULL;
271 ZERO_STRUCT(ticket);
272 ZERO_STRUCT(ap_rep);
273 ZERO_STRUCT(ap_rep_wrapped);
274 ZERO_STRUCT(response);
276 /* Normally we will always invalidate the intermediate vuid. */
277 *p_invalidate_vuid = True;
279 mem_ctx = talloc_init("reply_spnego_kerberos");
280 if (mem_ctx == NULL) {
281 reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
282 return;
285 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
286 talloc_destroy(mem_ctx);
287 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
288 return;
291 ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
292 &client, &pac_data, &ap_rep,
293 &session_key, True);
295 data_blob_free(&ticket);
297 if (!NT_STATUS_IS_OK(ret)) {
298 #if 0
299 /* Experiment that failed.
300 * See "only happens with a KDC" comment below. */
302 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
305 * Windows in this case returns
306 * NT_STATUS_MORE_PROCESSING_REQUIRED
307 * with a negTokenTarg blob containing an krb5_error
308 * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
309 * The client then fixes its clock and continues rather
310 * than giving an error. JRA.
311 * -- Looks like this only happens with a KDC. JRA.
314 bool ok = make_krb5_skew_error(&ap_rep);
315 if (!ok) {
316 talloc_destroy(mem_ctx);
317 return ERROR_NT(nt_status_squash(
318 NT_STATUS_LOGON_FAILURE));
320 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
321 TOK_ID_KRB_ERROR);
322 response = spnego_gen_auth_response(&ap_rep_wrapped,
323 ret, OID_KERBEROS5_OLD);
324 reply_sesssetup_blob(conn, inbuf, outbuf, response,
325 NT_STATUS_MORE_PROCESSING_REQUIRED);
328 * In this one case we don't invalidate the
329 * intermediate vuid as we're expecting the client
330 * to re-use it for the next sessionsetupX packet. JRA.
333 *p_invalidate_vuid = False;
335 data_blob_free(&ap_rep);
336 data_blob_free(&ap_rep_wrapped);
337 data_blob_free(&response);
338 talloc_destroy(mem_ctx);
339 return -1; /* already replied */
341 #else
342 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
343 ret = NT_STATUS_LOGON_FAILURE;
345 #endif
346 DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
347 nt_errstr(ret)));
348 talloc_destroy(mem_ctx);
349 reply_nterror(req, nt_status_squash(ret));
350 return;
353 DEBUG(3,("Ticket name is [%s]\n", client));
355 p = strchr_m(client, '@');
356 if (!p) {
357 DEBUG(3,("Doesn't look like a valid principal\n"));
358 data_blob_free(&ap_rep);
359 data_blob_free(&session_key);
360 SAFE_FREE(client);
361 talloc_destroy(mem_ctx);
362 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
363 return;
366 *p = 0;
368 /* save the PAC data if we have it */
370 if (pac_data) {
371 logon_info = get_logon_info_from_pac(pac_data);
372 if (logon_info) {
373 netsamlogon_cache_store( client, &logon_info->info3 );
377 if (!strequal(p+1, lp_realm())) {
378 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
379 if (!lp_allow_trusted_domains()) {
380 data_blob_free(&ap_rep);
381 data_blob_free(&session_key);
382 SAFE_FREE(client);
383 talloc_destroy(mem_ctx);
384 reply_nterror(req, nt_status_squash(
385 NT_STATUS_LOGON_FAILURE));
386 return;
390 /* this gives a fully qualified user name (ie. with full realm).
391 that leads to very long usernames, but what else can we do? */
393 domain = p+1;
395 if (logon_info && logon_info->info3.base.domain.string) {
396 fstrcpy(netbios_domain_name,
397 logon_info->info3.base.domain.string);
398 domain = netbios_domain_name;
399 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
401 } else {
403 /* If we have winbind running, we can (and must) shorten the
404 username by using the short netbios name. Otherwise we will
405 have inconsistent user names. With Kerberos, we get the
406 fully qualified realm, with ntlmssp we get the short
407 name. And even w2k3 does use ntlmssp if you for example
408 connect to an ip address. */
410 wbcErr wbc_status;
411 struct wbcDomainInfo *info = NULL;
413 DEBUG(10, ("Mapping [%s] to short name\n", domain));
415 wbc_status = wbcDomainInfo(domain, &info);
417 if (WBC_ERROR_IS_OK(wbc_status)) {
419 fstrcpy(netbios_domain_name,
420 info->short_name);
422 wbcFreeMemory(info);
423 domain = netbios_domain_name;
424 DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
425 } else {
426 DEBUG(3, ("Could not find short name: %s\n",
427 wbcErrorString(wbc_status)));
431 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
433 /* lookup the passwd struct, create a new user if necessary */
435 username_was_mapped = map_username( user );
437 pw = smb_getpwnam( mem_ctx, user, real_username, True );
439 if (pw) {
440 /* if a real user check pam account restrictions */
441 /* only really perfomed if "obey pam restriction" is true */
442 /* do this before an eventual mapping to guest occurs */
443 ret = smb_pam_accountcheck(pw->pw_name);
444 if ( !NT_STATUS_IS_OK(ret)) {
445 DEBUG(1,("PAM account restriction "
446 "prevents user login\n"));
447 data_blob_free(&ap_rep);
448 data_blob_free(&session_key);
449 TALLOC_FREE(mem_ctx);
450 reply_nterror(req, nt_status_squash(ret));
451 return;
455 if (!pw) {
457 /* this was originally the behavior of Samba 2.2, if a user
458 did not have a local uid but has been authenticated, then
459 map them to a guest account */
461 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
462 map_domainuser_to_guest = True;
463 fstrcpy(user,lp_guestaccount());
464 pw = smb_getpwnam( mem_ctx, user, real_username, True );
467 /* extra sanity check that the guest account is valid */
469 if ( !pw ) {
470 DEBUG(1,("Username %s is invalid on this system\n",
471 user));
472 SAFE_FREE(client);
473 data_blob_free(&ap_rep);
474 data_blob_free(&session_key);
475 TALLOC_FREE(mem_ctx);
476 reply_nterror(req, nt_status_squash(
477 NT_STATUS_LOGON_FAILURE));
478 return;
482 /* setup the string used by %U */
484 sub_set_smb_name( real_username );
485 reload_services(True);
487 if ( map_domainuser_to_guest ) {
488 make_server_info_guest(NULL, &server_info);
489 } else if (logon_info) {
490 /* pass the unmapped username here since map_username()
491 will be called again from inside make_server_info_info3() */
493 ret = make_server_info_info3(mem_ctx, client, domain,
494 &server_info, &logon_info->info3);
495 if ( !NT_STATUS_IS_OK(ret) ) {
496 DEBUG(1,("make_server_info_info3 failed: %s!\n",
497 nt_errstr(ret)));
498 SAFE_FREE(client);
499 data_blob_free(&ap_rep);
500 data_blob_free(&session_key);
501 TALLOC_FREE(mem_ctx);
502 reply_nterror(req, nt_status_squash(ret));
503 return;
506 } else {
507 ret = make_server_info_pw(&server_info, real_username, pw);
509 if ( !NT_STATUS_IS_OK(ret) ) {
510 DEBUG(1,("make_server_info_pw failed: %s!\n",
511 nt_errstr(ret)));
512 SAFE_FREE(client);
513 data_blob_free(&ap_rep);
514 data_blob_free(&session_key);
515 TALLOC_FREE(mem_ctx);
516 reply_nterror(req, nt_status_squash(ret));
517 return;
520 /* make_server_info_pw does not set the domain. Without this
521 * we end up with the local netbios name in substitutions for
522 * %D. */
524 if (server_info->sam_account != NULL) {
525 pdb_set_domain(server_info->sam_account,
526 domain, PDB_SET);
530 server_info->nss_token |= username_was_mapped;
532 /* we need to build the token for the user. make_server_info_guest()
533 already does this */
535 if ( !server_info->ptok ) {
536 ret = create_local_token( server_info );
537 if ( !NT_STATUS_IS_OK(ret) ) {
538 DEBUG(10,("failed to create local token: %s\n",
539 nt_errstr(ret)));
540 SAFE_FREE(client);
541 data_blob_free(&ap_rep);
542 data_blob_free(&session_key);
543 TALLOC_FREE( mem_ctx );
544 TALLOC_FREE( server_info );
545 reply_nterror(req, nt_status_squash(ret));
546 return;
550 /* register_existing_vuid keeps the server info */
551 /* register_existing_vuid takes ownership of session_key on success,
552 * no need to free after this on success. A better interface would copy
553 * it.... */
555 if (!is_partial_auth_vuid(sess_vuid)) {
556 sess_vuid = register_initial_vuid();
559 data_blob_free(&server_info->user_session_key);
560 server_info->user_session_key = session_key;
561 session_key = data_blob_null;
563 sess_vuid = register_existing_vuid(sess_vuid,
564 server_info,
565 nullblob,
566 client);
568 SAFE_FREE(client);
570 reply_outbuf(req, 4, 0);
571 SSVAL(req->outbuf,smb_uid,sess_vuid);
573 if (sess_vuid == UID_FIELD_INVALID ) {
574 ret = NT_STATUS_LOGON_FAILURE;
575 } else {
576 /* current_user_info is changed on new vuid */
577 reload_services( True );
579 SSVAL(req->outbuf, smb_vwv3, 0);
581 if (server_info->guest) {
582 SSVAL(req->outbuf,smb_vwv2,1);
585 SSVAL(req->outbuf, smb_uid, sess_vuid);
587 sessionsetup_start_signing_engine(server_info, req->inbuf);
588 /* Successful logon. Keep this vuid. */
589 *p_invalidate_vuid = False;
592 /* wrap that up in a nice GSS-API wrapping */
593 if (NT_STATUS_IS_OK(ret)) {
594 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
595 TOK_ID_KRB_AP_REP);
596 } else {
597 ap_rep_wrapped = data_blob_null;
599 response = spnego_gen_auth_response(&ap_rep_wrapped, ret,
600 mechOID);
601 reply_sesssetup_blob(req, response, ret);
603 data_blob_free(&ap_rep);
604 data_blob_free(&ap_rep_wrapped);
605 data_blob_free(&response);
606 TALLOC_FREE(mem_ctx);
609 #endif
611 /****************************************************************************
612 Send a session setup reply, wrapped in SPNEGO.
613 Get vuid and check first.
614 End the NTLMSSP exchange context if we are OK/complete fail
615 This should be split into two functions, one to handle each
616 leg of the NTLM auth steps.
617 ***************************************************************************/
619 static void reply_spnego_ntlmssp(struct smb_request *req,
620 uint16 vuid,
621 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
622 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
623 const char *OID,
624 bool wrap)
626 DATA_BLOB response;
627 struct auth_serversupplied_info *server_info = NULL;
629 if (NT_STATUS_IS_OK(nt_status)) {
630 server_info = (*auth_ntlmssp_state)->server_info;
631 } else {
632 nt_status = do_map_to_guest(nt_status,
633 &server_info,
634 (*auth_ntlmssp_state)->ntlmssp_state->user,
635 (*auth_ntlmssp_state)->ntlmssp_state->domain);
638 reply_outbuf(req, 4, 0);
640 SSVAL(req->outbuf, smb_uid, vuid);
642 if (NT_STATUS_IS_OK(nt_status)) {
643 DATA_BLOB nullblob = data_blob_null;
645 if (!is_partial_auth_vuid(vuid)) {
646 nt_status = NT_STATUS_LOGON_FAILURE;
647 goto out;
650 data_blob_free(&server_info->user_session_key);
651 server_info->user_session_key =
652 data_blob_talloc(
653 server_info,
654 (*auth_ntlmssp_state)->ntlmssp_state->session_key.data,
655 (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
657 /* register_existing_vuid keeps the server info */
658 if (register_existing_vuid(vuid,
659 server_info, nullblob,
660 (*auth_ntlmssp_state)->ntlmssp_state->user) !=
661 vuid) {
662 nt_status = NT_STATUS_LOGON_FAILURE;
663 goto out;
666 (*auth_ntlmssp_state)->server_info = NULL;
668 /* current_user_info is changed on new vuid */
669 reload_services( True );
671 SSVAL(req->outbuf, smb_vwv3, 0);
673 if (server_info->guest) {
674 SSVAL(req->outbuf,smb_vwv2,1);
677 sessionsetup_start_signing_engine(server_info,
678 (uint8 *)req->inbuf);
681 out:
683 if (wrap) {
684 response = spnego_gen_auth_response(ntlmssp_blob,
685 nt_status, OID);
686 } else {
687 response = *ntlmssp_blob;
690 reply_sesssetup_blob(req, response, nt_status);
691 if (wrap) {
692 data_blob_free(&response);
695 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
696 and the other end, that we are not finished yet. */
698 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
699 /* NB. This is *NOT* an error case. JRA */
700 auth_ntlmssp_end(auth_ntlmssp_state);
701 if (!NT_STATUS_IS_OK(nt_status)) {
702 /* Kill the intermediate vuid */
703 invalidate_vuid(vuid);
708 /****************************************************************************
709 Is this a krb5 mechanism ?
710 ****************************************************************************/
712 NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in,
713 DATA_BLOB *pblob_out,
714 char **kerb_mechOID)
716 char *OIDs[ASN1_MAX_OIDS];
717 int i;
718 NTSTATUS ret = NT_STATUS_OK;
720 *kerb_mechOID = NULL;
722 /* parse out the OIDs and the first sec blob */
723 if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
724 return NT_STATUS_LOGON_FAILURE;
727 /* only look at the first OID for determining the mechToken --
728 according to RFC2478, we should choose the one we want
729 and renegotiate, but i smell a client bug here..
731 Problem observed when connecting to a member (samba box)
732 of an AD domain as a user in a Samba domain. Samba member
733 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
734 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
735 NTLMSSP mechtoken. --jerry */
737 #ifdef HAVE_KRB5
738 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
739 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
740 *kerb_mechOID = SMB_STRDUP(OIDs[0]);
741 if (*kerb_mechOID == NULL) {
742 ret = NT_STATUS_NO_MEMORY;
745 #endif
747 for (i=0;OIDs[i];i++) {
748 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
749 talloc_free(OIDs[i]);
751 return ret;
754 /****************************************************************************
755 Fall back from krb5 to NTLMSSP.
756 ****************************************************************************/
758 static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
759 uint16 vuid)
761 DATA_BLOB response;
763 reply_outbuf(req, 4, 0);
764 SSVAL(req->outbuf,smb_uid,vuid);
766 DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
767 "but set to downgrade to NTLMSSP\n"));
769 response = spnego_gen_auth_response(NULL,
770 NT_STATUS_MORE_PROCESSING_REQUIRED,
771 OID_NTLMSSP);
772 reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
773 data_blob_free(&response);
776 /****************************************************************************
777 Reply to a session setup spnego negotiate packet.
778 ****************************************************************************/
780 static void reply_spnego_negotiate(struct smb_request *req,
781 uint16 vuid,
782 DATA_BLOB blob1,
783 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
785 DATA_BLOB secblob;
786 DATA_BLOB chal;
787 char *kerb_mech = NULL;
788 NTSTATUS status;
790 status = parse_spnego_mechanisms(blob1, &secblob, &kerb_mech);
791 if (!NT_STATUS_IS_OK(status)) {
792 /* Kill the intermediate vuid */
793 invalidate_vuid(vuid);
794 reply_nterror(req, nt_status_squash(status));
795 return;
798 DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
799 (unsigned long)secblob.length));
801 #ifdef HAVE_KRB5
802 if (kerb_mech && ((lp_security()==SEC_ADS) ||
803 lp_use_kerberos_keytab()) ) {
804 bool destroy_vuid = True;
805 reply_spnego_kerberos(req, &secblob, kerb_mech,
806 vuid, &destroy_vuid);
807 data_blob_free(&secblob);
808 if (destroy_vuid) {
809 /* Kill the intermediate vuid */
810 invalidate_vuid(vuid);
812 SAFE_FREE(kerb_mech);
813 return;
815 #endif
817 if (*auth_ntlmssp_state) {
818 auth_ntlmssp_end(auth_ntlmssp_state);
821 if (kerb_mech) {
822 data_blob_free(&secblob);
823 /* The mechtoken is a krb5 ticket, but
824 * we need to fall back to NTLM. */
825 reply_spnego_downgrade_to_ntlmssp(req, vuid);
826 SAFE_FREE(kerb_mech);
827 return;
830 status = auth_ntlmssp_start(auth_ntlmssp_state);
831 if (!NT_STATUS_IS_OK(status)) {
832 /* Kill the intermediate vuid */
833 invalidate_vuid(vuid);
834 reply_nterror(req, nt_status_squash(status));
835 return;
838 status = auth_ntlmssp_update(*auth_ntlmssp_state,
839 secblob, &chal);
841 data_blob_free(&secblob);
843 reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
844 &chal, status, OID_NTLMSSP, true);
846 data_blob_free(&chal);
848 /* already replied */
849 return;
852 /****************************************************************************
853 Reply to a session setup spnego auth packet.
854 ****************************************************************************/
856 static void reply_spnego_auth(struct smb_request *req,
857 uint16 vuid,
858 DATA_BLOB blob1,
859 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
861 DATA_BLOB auth = data_blob_null;
862 DATA_BLOB auth_reply = data_blob_null;
863 DATA_BLOB secblob = data_blob_null;
864 NTSTATUS status = NT_STATUS_LOGON_FAILURE;
866 if (!spnego_parse_auth(blob1, &auth)) {
867 #if 0
868 file_save("auth.dat", blob1.data, blob1.length);
869 #endif
870 /* Kill the intermediate vuid */
871 invalidate_vuid(vuid);
873 reply_nterror(req, nt_status_squash(
874 NT_STATUS_LOGON_FAILURE));
875 return;
878 if (auth.data[0] == ASN1_APPLICATION(0)) {
879 /* Might be a second negTokenTarg packet */
880 char *kerb_mech = NULL;
882 status = parse_spnego_mechanisms(auth, &secblob, &kerb_mech);
884 if (!NT_STATUS_IS_OK(status)) {
885 /* Kill the intermediate vuid */
886 invalidate_vuid(vuid);
887 reply_nterror(req, nt_status_squash(status));
888 return;
891 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
892 (unsigned long)secblob.length));
893 #ifdef HAVE_KRB5
894 if (kerb_mech && ((lp_security()==SEC_ADS) ||
895 lp_use_kerberos_keytab()) ) {
896 bool destroy_vuid = True;
897 reply_spnego_kerberos(req, &secblob, kerb_mech,
898 vuid, &destroy_vuid);
899 data_blob_free(&secblob);
900 data_blob_free(&auth);
901 if (destroy_vuid) {
902 /* Kill the intermediate vuid */
903 invalidate_vuid(vuid);
905 SAFE_FREE(kerb_mech);
906 return;
908 #endif
909 /* Can't blunder into NTLMSSP auth if we have
910 * a krb5 ticket. */
912 if (kerb_mech) {
913 /* Kill the intermediate vuid */
914 invalidate_vuid(vuid);
915 DEBUG(3,("reply_spnego_auth: network "
916 "misconfiguration, client sent us a "
917 "krb5 ticket and kerberos security "
918 "not enabled"));
919 reply_nterror(req, nt_status_squash(
920 NT_STATUS_LOGON_FAILURE));
921 SAFE_FREE(kerb_mech);
925 /* If we get here it wasn't a negTokenTarg auth packet. */
926 data_blob_free(&secblob);
928 if (!*auth_ntlmssp_state) {
929 status = auth_ntlmssp_start(auth_ntlmssp_state);
930 if (!NT_STATUS_IS_OK(status)) {
931 /* Kill the intermediate vuid */
932 invalidate_vuid(vuid);
933 reply_nterror(req, nt_status_squash(status));
934 return;
938 status = auth_ntlmssp_update(*auth_ntlmssp_state,
939 auth, &auth_reply);
941 data_blob_free(&auth);
943 /* Don't send the mechid as we've already sent this (RFC4178). */
945 reply_spnego_ntlmssp(req, vuid,
946 auth_ntlmssp_state,
947 &auth_reply, status, NULL, true);
949 data_blob_free(&auth_reply);
951 /* and tell smbd that we have already replied to this packet */
952 return;
955 /****************************************************************************
956 List to store partial SPNEGO auth fragments.
957 ****************************************************************************/
959 static struct pending_auth_data *pd_list;
961 /****************************************************************************
962 Delete an entry on the list.
963 ****************************************************************************/
965 static void delete_partial_auth(struct pending_auth_data *pad)
967 if (!pad) {
968 return;
970 DLIST_REMOVE(pd_list, pad);
971 data_blob_free(&pad->partial_data);
972 SAFE_FREE(pad);
975 /****************************************************************************
976 Search for a partial SPNEGO auth fragment matching an smbpid.
977 ****************************************************************************/
979 static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
981 struct pending_auth_data *pad;
983 for (pad = pd_list; pad; pad = pad->next) {
984 if (pad->smbpid == smbpid) {
985 break;
988 return pad;
991 /****************************************************************************
992 Check the size of an SPNEGO blob. If we need more return
993 NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
994 the blob to be more than 64k.
995 ****************************************************************************/
997 static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid,
998 DATA_BLOB *pblob)
1000 struct pending_auth_data *pad = NULL;
1001 ASN1_DATA *data;
1002 size_t needed_len = 0;
1004 pad = get_pending_auth_data(smbpid);
1006 /* Ensure we have some data. */
1007 if (pblob->length == 0) {
1008 /* Caller can cope. */
1009 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
1010 delete_partial_auth(pad);
1011 return NT_STATUS_OK;
1014 /* Were we waiting for more data ? */
1015 if (pad) {
1016 DATA_BLOB tmp_blob;
1017 size_t copy_len = MIN(65536, pblob->length);
1019 /* Integer wrap paranoia.... */
1021 if (pad->partial_data.length + copy_len <
1022 pad->partial_data.length ||
1023 pad->partial_data.length + copy_len < copy_len) {
1025 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1026 "pad->partial_data.length = %u, "
1027 "copy_len = %u\n",
1028 (unsigned int)pad->partial_data.length,
1029 (unsigned int)copy_len ));
1031 delete_partial_auth(pad);
1032 return NT_STATUS_INVALID_PARAMETER;
1035 DEBUG(10,("check_spnego_blob_complete: "
1036 "pad->partial_data.length = %u, "
1037 "pad->needed_len = %u, "
1038 "copy_len = %u, "
1039 "pblob->length = %u,\n",
1040 (unsigned int)pad->partial_data.length,
1041 (unsigned int)pad->needed_len,
1042 (unsigned int)copy_len,
1043 (unsigned int)pblob->length ));
1045 tmp_blob = data_blob(NULL,
1046 pad->partial_data.length + copy_len);
1048 /* Concatenate the two (up to copy_len) bytes. */
1049 memcpy(tmp_blob.data,
1050 pad->partial_data.data,
1051 pad->partial_data.length);
1052 memcpy(tmp_blob.data + pad->partial_data.length,
1053 pblob->data,
1054 copy_len);
1056 /* Replace the partial data. */
1057 data_blob_free(&pad->partial_data);
1058 pad->partial_data = tmp_blob;
1059 ZERO_STRUCT(tmp_blob);
1061 /* Are we done ? */
1062 if (pblob->length >= pad->needed_len) {
1063 /* Yes, replace pblob. */
1064 data_blob_free(pblob);
1065 *pblob = pad->partial_data;
1066 ZERO_STRUCT(pad->partial_data);
1067 delete_partial_auth(pad);
1068 return NT_STATUS_OK;
1071 /* Still need more data. */
1072 pad->needed_len -= copy_len;
1073 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1076 if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
1077 (pblob->data[0] != ASN1_CONTEXT(1))) {
1078 /* Not something we can determine the
1079 * length of.
1081 return NT_STATUS_OK;
1084 /* This is a new SPNEGO sessionsetup - see if
1085 * the data given in this blob is enough.
1088 data = asn1_init(NULL);
1089 if (data == NULL) {
1090 return NT_STATUS_NO_MEMORY;
1093 asn1_load(data, *pblob);
1094 asn1_start_tag(data, pblob->data[0]);
1095 if (data->has_error || data->nesting == NULL) {
1096 asn1_free(data);
1097 /* Let caller catch. */
1098 return NT_STATUS_OK;
1101 /* Integer wrap paranoia.... */
1103 if (data->nesting->taglen + data->nesting->start < data->nesting->taglen ||
1104 data->nesting->taglen + data->nesting->start < data->nesting->start) {
1106 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1107 "data.nesting->taglen = %u, "
1108 "data.nesting->start = %u\n",
1109 (unsigned int)data->nesting->taglen,
1110 (unsigned int)data->nesting->start ));
1112 asn1_free(data);
1113 return NT_STATUS_INVALID_PARAMETER;
1116 /* Total length of the needed asn1 is the tag length
1117 * plus the current offset. */
1119 needed_len = data->nesting->taglen + data->nesting->start;
1120 asn1_free(data);
1122 DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
1123 "pblob->length = %u\n",
1124 (unsigned int)needed_len,
1125 (unsigned int)pblob->length ));
1127 if (needed_len <= pblob->length) {
1128 /* Nothing to do - blob is complete. */
1129 return NT_STATUS_OK;
1132 /* Refuse the blob if it's bigger than 64k. */
1133 if (needed_len > 65536) {
1134 DEBUG(2,("check_spnego_blob_complete: needed_len "
1135 "too large (%u)\n",
1136 (unsigned int)needed_len ));
1137 return NT_STATUS_INVALID_PARAMETER;
1140 /* We must store this blob until complete. */
1141 if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
1142 return NT_STATUS_NO_MEMORY;
1144 pad->needed_len = needed_len - pblob->length;
1145 pad->partial_data = data_blob(pblob->data, pblob->length);
1146 if (pad->partial_data.data == NULL) {
1147 SAFE_FREE(pad);
1148 return NT_STATUS_NO_MEMORY;
1150 pad->smbpid = smbpid;
1151 pad->vuid = vuid;
1152 DLIST_ADD(pd_list, pad);
1154 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1157 /****************************************************************************
1158 Reply to a session setup command.
1159 conn POINTER CAN BE NULL HERE !
1160 ****************************************************************************/
1162 static void reply_sesssetup_and_X_spnego(struct smb_request *req)
1164 const uint8 *p;
1165 DATA_BLOB blob1;
1166 size_t bufrem;
1167 char *tmp;
1168 const char *native_os;
1169 const char *native_lanman;
1170 const char *primary_domain;
1171 const char *p2;
1172 uint16 data_blob_len = SVAL(req->vwv+7, 0);
1173 enum remote_arch_types ra_type = get_remote_arch();
1174 int vuid = req->vuid;
1175 user_struct *vuser = NULL;
1176 NTSTATUS status = NT_STATUS_OK;
1177 uint16 smbpid = req->smbpid;
1179 DEBUG(3,("Doing spnego session setup\n"));
1181 if (global_client_caps == 0) {
1182 global_client_caps = IVAL(req->vwv+10, 0);
1184 if (!(global_client_caps & CAP_STATUS32)) {
1185 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1190 p = req->buf;
1192 if (data_blob_len == 0) {
1193 /* an invalid request */
1194 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1195 return;
1198 bufrem = smbreq_bufrem(req, p);
1199 /* pull the spnego blob */
1200 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1202 #if 0
1203 file_save("negotiate.dat", blob1.data, blob1.length);
1204 #endif
1206 p2 = (char *)req->buf + data_blob_len;
1208 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1209 STR_TERMINATE);
1210 native_os = tmp ? tmp : "";
1212 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1213 STR_TERMINATE);
1214 native_lanman = tmp ? tmp : "";
1216 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1217 STR_TERMINATE);
1218 primary_domain = tmp ? tmp : "";
1220 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1221 native_os, native_lanman, primary_domain));
1223 if ( ra_type == RA_WIN2K ) {
1224 /* Vista sets neither the OS or lanman strings */
1226 if ( !strlen(native_os) && !strlen(native_lanman) )
1227 set_remote_arch(RA_VISTA);
1229 /* Windows 2003 doesn't set the native lanman string,
1230 but does set primary domain which is a bug I think */
1232 if ( !strlen(native_lanman) ) {
1233 ra_lanman_string( primary_domain );
1234 } else {
1235 ra_lanman_string( native_lanman );
1239 /* Did we get a valid vuid ? */
1240 if (!is_partial_auth_vuid(vuid)) {
1241 /* No, then try and see if this is an intermediate sessionsetup
1242 * for a large SPNEGO packet. */
1243 struct pending_auth_data *pad = get_pending_auth_data(smbpid);
1244 if (pad) {
1245 DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1246 "pending vuid %u\n",
1247 (unsigned int)pad->vuid ));
1248 vuid = pad->vuid;
1252 /* Do we have a valid vuid now ? */
1253 if (!is_partial_auth_vuid(vuid)) {
1254 /* No, start a new authentication setup. */
1255 vuid = register_initial_vuid();
1256 if (vuid == UID_FIELD_INVALID) {
1257 data_blob_free(&blob1);
1258 reply_nterror(req, nt_status_squash(
1259 NT_STATUS_INVALID_PARAMETER));
1260 return;
1264 vuser = get_partial_auth_user_struct(vuid);
1265 /* This MUST be valid. */
1266 if (!vuser) {
1267 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1270 /* Large (greater than 4k) SPNEGO blobs are split into multiple
1271 * sessionsetup requests as the Windows limit on the security blob
1272 * field is 4k. Bug #4400. JRA.
1275 status = check_spnego_blob_complete(smbpid, vuid, &blob1);
1276 if (!NT_STATUS_IS_OK(status)) {
1277 if (!NT_STATUS_EQUAL(status,
1278 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1279 /* Real error - kill the intermediate vuid */
1280 invalidate_vuid(vuid);
1282 data_blob_free(&blob1);
1283 reply_nterror(req, nt_status_squash(status));
1284 return;
1287 if (blob1.data[0] == ASN1_APPLICATION(0)) {
1289 /* its a negTokenTarg packet */
1291 reply_spnego_negotiate(req, vuid, blob1,
1292 &vuser->auth_ntlmssp_state);
1293 data_blob_free(&blob1);
1294 return;
1297 if (blob1.data[0] == ASN1_CONTEXT(1)) {
1299 /* its a auth packet */
1301 reply_spnego_auth(req, vuid, blob1,
1302 &vuser->auth_ntlmssp_state);
1303 data_blob_free(&blob1);
1304 return;
1307 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1308 DATA_BLOB chal;
1310 if (!vuser->auth_ntlmssp_state) {
1311 status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1312 if (!NT_STATUS_IS_OK(status)) {
1313 /* Kill the intermediate vuid */
1314 invalidate_vuid(vuid);
1315 data_blob_free(&blob1);
1316 reply_nterror(req, nt_status_squash(status));
1317 return;
1321 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1322 blob1, &chal);
1324 data_blob_free(&blob1);
1326 reply_spnego_ntlmssp(req, vuid,
1327 &vuser->auth_ntlmssp_state,
1328 &chal, status, OID_NTLMSSP, false);
1329 data_blob_free(&chal);
1330 return;
1333 /* what sort of packet is this? */
1334 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1336 data_blob_free(&blob1);
1338 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1341 /****************************************************************************
1342 On new VC == 0, shutdown *all* old connections and users.
1343 It seems that only NT4.x does this. At W2K and above (XP etc.).
1344 a new session setup with VC==0 is ignored.
1345 ****************************************************************************/
1347 static int shutdown_other_smbds(struct db_record *rec,
1348 const struct connections_key *key,
1349 const struct connections_data *crec,
1350 void *private_data)
1352 const char *ip = (const char *)private_data;
1354 if (!process_exists(crec->pid)) {
1355 return 0;
1358 if (procid_is_me(&crec->pid)) {
1359 return 0;
1362 if (strcmp(ip, crec->addr) != 0) {
1363 return 0;
1366 DEBUG(0,("shutdown_other_smbds: shutting down pid %d "
1367 "(IP %s)\n", procid_to_pid(&crec->pid), ip));
1369 messaging_send(smbd_messaging_context(), crec->pid, MSG_SHUTDOWN,
1370 &data_blob_null);
1371 return 0;
1374 static void setup_new_vc_session(void)
1376 char addr[INET6_ADDRSTRLEN];
1378 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1379 "compatible we would close all old resources.\n"));
1380 #if 0
1381 conn_close_all();
1382 invalidate_all_vuids();
1383 #endif
1384 if (lp_reset_on_zero_vc()) {
1385 connections_forall(shutdown_other_smbds,
1386 CONST_DISCARD(void *,
1387 client_addr(get_client_fd(),addr,sizeof(addr))));
1391 /****************************************************************************
1392 Reply to a session setup command.
1393 ****************************************************************************/
1395 void reply_sesssetup_and_X(struct smb_request *req)
1397 int sess_vuid;
1398 int smb_bufsize;
1399 DATA_BLOB lm_resp;
1400 DATA_BLOB nt_resp;
1401 DATA_BLOB plaintext_password;
1402 char *tmp;
1403 const char *user;
1404 fstring sub_user; /* Sainitised username for substituion */
1405 const char *domain;
1406 const char *native_os;
1407 const char *native_lanman;
1408 const char *primary_domain;
1409 static bool done_sesssetup = False;
1410 auth_usersupplied_info *user_info = NULL;
1411 auth_serversupplied_info *server_info = NULL;
1412 uint16 smb_flag2 = req->flags2;
1414 NTSTATUS nt_status;
1416 bool doencrypt = global_encrypted_passwords_negotiated;
1418 START_PROFILE(SMBsesssetupX);
1420 ZERO_STRUCT(lm_resp);
1421 ZERO_STRUCT(nt_resp);
1422 ZERO_STRUCT(plaintext_password);
1424 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1426 /* a SPNEGO session setup has 12 command words, whereas a normal
1427 NT1 session setup has 13. See the cifs spec. */
1428 if (req->wct == 12 &&
1429 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1431 if (!global_spnego_negotiated) {
1432 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1433 "at SPNEGO session setup when it was not "
1434 "negotiated.\n"));
1435 reply_nterror(req, nt_status_squash(
1436 NT_STATUS_LOGON_FAILURE));
1437 END_PROFILE(SMBsesssetupX);
1438 return;
1441 if (SVAL(req->vwv+4, 0) == 0) {
1442 setup_new_vc_session();
1445 reply_sesssetup_and_X_spnego(req);
1446 END_PROFILE(SMBsesssetupX);
1447 return;
1450 smb_bufsize = SVAL(req->vwv+2, 0);
1452 if (Protocol < PROTOCOL_NT1) {
1453 uint16 passlen1 = SVAL(req->vwv+7, 0);
1455 /* Never do NT status codes with protocols before NT1 as we
1456 * don't get client caps. */
1457 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1459 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
1460 reply_nterror(req, nt_status_squash(
1461 NT_STATUS_INVALID_PARAMETER));
1462 END_PROFILE(SMBsesssetupX);
1463 return;
1466 if (doencrypt) {
1467 lm_resp = data_blob(req->buf, passlen1);
1468 } else {
1469 plaintext_password = data_blob(req->buf, passlen1+1);
1470 /* Ensure null termination */
1471 plaintext_password.data[passlen1] = 0;
1474 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
1475 req->buf + passlen1, STR_TERMINATE);
1476 user = tmp ? tmp : "";
1478 domain = "";
1480 } else {
1481 uint16 passlen1 = SVAL(req->vwv+7, 0);
1482 uint16 passlen2 = SVAL(req->vwv+8, 0);
1483 enum remote_arch_types ra_type = get_remote_arch();
1484 const uint8_t *p = req->buf;
1485 const uint8_t *save_p = req->buf;
1486 uint16 byte_count;
1489 if(global_client_caps == 0) {
1490 global_client_caps = IVAL(req->vwv+11, 0);
1492 if (!(global_client_caps & CAP_STATUS32)) {
1493 remove_from_common_flags2(
1494 FLAGS2_32_BIT_ERROR_CODES);
1497 /* client_caps is used as final determination if
1498 * client is NT or Win95. This is needed to return
1499 * the correct error codes in some circumstances.
1502 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1503 ra_type == RA_WIN95) {
1504 if(!(global_client_caps & (CAP_NT_SMBS|
1505 CAP_STATUS32))) {
1506 set_remote_arch( RA_WIN95);
1511 if (!doencrypt) {
1512 /* both Win95 and WinNT stuff up the password
1513 * lengths for non-encrypting systems. Uggh.
1515 if passlen1==24 its a win95 system, and its setting
1516 the password length incorrectly. Luckily it still
1517 works with the default code because Win95 will null
1518 terminate the password anyway
1520 if passlen1>0 and passlen2>0 then maybe its a NT box
1521 and its setting passlen2 to some random value which
1522 really stuffs things up. we need to fix that one. */
1524 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1525 passlen2 != 1) {
1526 passlen2 = 0;
1530 /* check for nasty tricks */
1531 if (passlen1 > MAX_PASS_LEN
1532 || passlen1 > smbreq_bufrem(req, p)) {
1533 reply_nterror(req, nt_status_squash(
1534 NT_STATUS_INVALID_PARAMETER));
1535 END_PROFILE(SMBsesssetupX);
1536 return;
1539 if (passlen2 > MAX_PASS_LEN
1540 || passlen2 > smbreq_bufrem(req, p+passlen1)) {
1541 reply_nterror(req, nt_status_squash(
1542 NT_STATUS_INVALID_PARAMETER));
1543 END_PROFILE(SMBsesssetupX);
1544 return;
1547 /* Save the lanman2 password and the NT md4 password. */
1549 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1550 doencrypt = False;
1553 if (doencrypt) {
1554 lm_resp = data_blob(p, passlen1);
1555 nt_resp = data_blob(p+passlen1, passlen2);
1556 } else if (lp_security() != SEC_SHARE) {
1558 * In share level we should ignore any passwords, so
1559 * only read them if we're not.
1561 char *pass = NULL;
1562 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1564 if (unic && (passlen2 == 0) && passlen1) {
1565 /* Only a ascii plaintext password was sent. */
1566 (void)srvstr_pull_talloc(talloc_tos(),
1567 req->inbuf,
1568 req->flags2,
1569 &pass,
1570 req->buf,
1571 passlen1,
1572 STR_TERMINATE|STR_ASCII);
1573 } else {
1574 (void)srvstr_pull_talloc(talloc_tos(),
1575 req->inbuf,
1576 req->flags2,
1577 &pass,
1578 req->buf,
1579 unic ? passlen2 : passlen1,
1580 STR_TERMINATE);
1582 if (!pass) {
1583 reply_nterror(req, nt_status_squash(
1584 NT_STATUS_INVALID_PARAMETER));
1585 END_PROFILE(SMBsesssetupX);
1586 return;
1588 plaintext_password = data_blob(pass, strlen(pass)+1);
1591 p += passlen1 + passlen2;
1593 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1594 STR_TERMINATE);
1595 user = tmp ? tmp : "";
1597 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1598 STR_TERMINATE);
1599 domain = tmp ? tmp : "";
1601 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1602 STR_TERMINATE);
1603 native_os = tmp ? tmp : "";
1605 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1606 STR_TERMINATE);
1607 native_lanman = tmp ? tmp : "";
1609 /* not documented or decoded by Ethereal but there is one more
1610 * string in the extra bytes which is the same as the
1611 * PrimaryDomain when using extended security. Windows NT 4
1612 * and 2003 use this string to store the native lanman string.
1613 * Windows 9x does not include a string here at all so we have
1614 * to check if we have any extra bytes left */
1616 byte_count = SVAL(req->vwv+13, 0);
1617 if ( PTR_DIFF(p, save_p) < byte_count) {
1618 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1619 STR_TERMINATE);
1620 primary_domain = tmp ? tmp : "";
1621 } else {
1622 primary_domain = talloc_strdup(talloc_tos(), "null");
1625 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
1626 "PrimaryDomain=[%s]\n",
1627 domain, native_os, native_lanman, primary_domain));
1629 if ( ra_type == RA_WIN2K ) {
1630 if ( strlen(native_lanman) == 0 )
1631 ra_lanman_string( primary_domain );
1632 else
1633 ra_lanman_string( native_lanman );
1638 if (SVAL(req->vwv+4, 0) == 0) {
1639 setup_new_vc_session();
1642 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1643 domain, user, get_remote_machine_name()));
1645 if (*user) {
1646 if (global_spnego_negotiated) {
1648 /* This has to be here, because this is a perfectly
1649 * valid behaviour for guest logons :-( */
1651 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1652 "at 'normal' session setup after "
1653 "negotiating spnego.\n"));
1654 reply_nterror(req, nt_status_squash(
1655 NT_STATUS_LOGON_FAILURE));
1656 END_PROFILE(SMBsesssetupX);
1657 return;
1659 fstrcpy(sub_user, user);
1660 } else {
1661 fstrcpy(sub_user, lp_guestaccount());
1664 sub_set_smb_name(sub_user);
1666 reload_services(True);
1668 if (lp_security() == SEC_SHARE) {
1669 /* In share level we should ignore any passwords */
1671 data_blob_free(&lm_resp);
1672 data_blob_free(&nt_resp);
1673 data_blob_clear_free(&plaintext_password);
1675 map_username(sub_user);
1676 add_session_user(sub_user);
1677 add_session_workgroup(domain);
1678 /* Then force it to null for the benfit of the code below */
1679 user = "";
1682 if (!*user) {
1684 nt_status = check_guest_password(&server_info);
1686 } else if (doencrypt) {
1687 if (!negprot_global_auth_context) {
1688 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
1689 "session setup without negprot denied!\n"));
1690 reply_nterror(req, nt_status_squash(
1691 NT_STATUS_LOGON_FAILURE));
1692 END_PROFILE(SMBsesssetupX);
1693 return;
1695 nt_status = make_user_info_for_reply_enc(&user_info, user,
1696 domain,
1697 lm_resp, nt_resp);
1698 if (NT_STATUS_IS_OK(nt_status)) {
1699 nt_status = negprot_global_auth_context->check_ntlm_password(
1700 negprot_global_auth_context,
1701 user_info,
1702 &server_info);
1704 } else {
1705 struct auth_context *plaintext_auth_context = NULL;
1706 const uint8 *chal;
1708 nt_status = make_auth_context_subsystem(
1709 &plaintext_auth_context);
1711 if (NT_STATUS_IS_OK(nt_status)) {
1712 chal = plaintext_auth_context->get_ntlm_challenge(
1713 plaintext_auth_context);
1715 if (!make_user_info_for_reply(&user_info,
1716 user, domain, chal,
1717 plaintext_password)) {
1718 nt_status = NT_STATUS_NO_MEMORY;
1721 if (NT_STATUS_IS_OK(nt_status)) {
1722 nt_status = plaintext_auth_context->check_ntlm_password(
1723 plaintext_auth_context,
1724 user_info,
1725 &server_info);
1727 (plaintext_auth_context->free)(
1728 &plaintext_auth_context);
1733 free_user_info(&user_info);
1735 if (!NT_STATUS_IS_OK(nt_status)) {
1736 nt_status = do_map_to_guest(nt_status, &server_info,
1737 user, domain);
1740 if (!NT_STATUS_IS_OK(nt_status)) {
1741 data_blob_free(&nt_resp);
1742 data_blob_free(&lm_resp);
1743 data_blob_clear_free(&plaintext_password);
1744 reply_nterror(req, nt_status_squash(nt_status));
1745 END_PROFILE(SMBsesssetupX);
1746 return;
1749 /* Ensure we can't possible take a code path leading to a
1750 * null defref. */
1751 if (!server_info) {
1752 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1753 END_PROFILE(SMBsesssetupX);
1754 return;
1757 if (!server_info->ptok) {
1758 nt_status = create_local_token(server_info);
1760 if (!NT_STATUS_IS_OK(nt_status)) {
1761 DEBUG(10, ("create_local_token failed: %s\n",
1762 nt_errstr(nt_status)));
1763 data_blob_free(&nt_resp);
1764 data_blob_free(&lm_resp);
1765 data_blob_clear_free(&plaintext_password);
1766 reply_nterror(req, nt_status_squash(nt_status));
1767 END_PROFILE(SMBsesssetupX);
1768 return;
1772 data_blob_clear_free(&plaintext_password);
1774 /* it's ok - setup a reply */
1775 reply_outbuf(req, 3, 0);
1776 if (Protocol >= PROTOCOL_NT1) {
1777 push_signature(&req->outbuf);
1778 /* perhaps grab OS version here?? */
1781 if (server_info->guest) {
1782 SSVAL(req->outbuf,smb_vwv2,1);
1785 /* register the name and uid as being validated, so further connections
1786 to a uid can get through without a password, on the same VC */
1788 if (lp_security() == SEC_SHARE) {
1789 sess_vuid = UID_FIELD_INVALID;
1790 TALLOC_FREE(server_info);
1791 } else {
1792 /* Ignore the initial vuid. */
1793 sess_vuid = register_initial_vuid();
1794 if (sess_vuid == UID_FIELD_INVALID) {
1795 data_blob_free(&nt_resp);
1796 data_blob_free(&lm_resp);
1797 reply_nterror(req, nt_status_squash(
1798 NT_STATUS_LOGON_FAILURE));
1799 END_PROFILE(SMBsesssetupX);
1800 return;
1802 /* register_existing_vuid keeps the server info */
1803 sess_vuid = register_existing_vuid(sess_vuid,
1804 server_info,
1805 nt_resp.data ? nt_resp : lm_resp,
1806 sub_user);
1807 if (sess_vuid == UID_FIELD_INVALID) {
1808 data_blob_free(&nt_resp);
1809 data_blob_free(&lm_resp);
1810 reply_nterror(req, nt_status_squash(
1811 NT_STATUS_LOGON_FAILURE));
1812 END_PROFILE(SMBsesssetupX);
1813 return;
1816 /* current_user_info is changed on new vuid */
1817 reload_services( True );
1819 sessionsetup_start_signing_engine(server_info, req->inbuf);
1822 data_blob_free(&nt_resp);
1823 data_blob_free(&lm_resp);
1825 SSVAL(req->outbuf,smb_uid,sess_vuid);
1826 SSVAL(req->inbuf,smb_uid,sess_vuid);
1828 if (!done_sesssetup)
1829 max_send = MIN(max_send,smb_bufsize);
1831 done_sesssetup = True;
1833 END_PROFILE(SMBsesssetupX);
1834 chain_reply(req);
1835 return;