Allow set attributes on a stream fnum to be redirected to the base filename.
[Samba.git] / source / smbd / sesssetup.c
blob98594b0769f80215a9a97da6f68f6cd96081aa70
1 /*
2 Unix SMB/CIFS implementation.
3 handle SMBsessionsetup
4 Copyright (C) Andrew Tridgell 1998-2001
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
7 Copyright (C) Luke Howard 2003
8 Copyright (C) Volker Lendecke 2007
9 Copyright (C) Jeremy Allison 2007
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
27 extern struct auth_context *negprot_global_auth_context;
28 extern bool global_encrypted_passwords_negotiated;
29 extern bool global_spnego_negotiated;
30 extern enum protocol_types Protocol;
31 extern int max_send;
33 uint32 global_client_caps = 0;
36 on a logon error possibly map the error to success if "map to guest"
37 is set approriately
39 static NTSTATUS do_map_to_guest(NTSTATUS status,
40 auth_serversupplied_info **server_info,
41 const char *user, const char *domain)
43 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
44 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
45 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
46 DEBUG(3,("No such user %s [%s] - using guest account\n",
47 user, domain));
48 status = make_server_info_guest(server_info);
52 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
53 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
54 DEBUG(3,("Registered username %s for guest access\n",
55 user));
56 status = make_server_info_guest(server_info);
60 return status;
63 /****************************************************************************
64 Add the standard 'Samba' signature to the end of the session setup.
65 ****************************************************************************/
67 static int push_signature(uint8 **outbuf)
69 char *lanman;
70 int result, tmp;
72 result = 0;
74 tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
76 if (tmp == -1) return -1;
77 result += tmp;
79 if (asprintf(&lanman, "Samba %s", SAMBA_VERSION_STRING) != -1) {
80 tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
81 SAFE_FREE(lanman);
83 else {
84 tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
87 if (tmp == -1) return -1;
88 result += tmp;
90 tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
92 if (tmp == -1) return -1;
93 result += tmp;
95 return result;
98 /****************************************************************************
99 Start the signing engine if needed. Don't fail signing here.
100 ****************************************************************************/
102 static void sessionsetup_start_signing_engine(
103 const auth_serversupplied_info *server_info,
104 const uint8 *inbuf)
106 if (!server_info->guest && !srv_signing_started()) {
107 /* We need to start the signing engine
108 * here but a W2K client sends the old
109 * "BSRSPYL " signature instead of the
110 * correct one. Subsequent packets will
111 * be correct.
113 srv_check_sign_mac((char *)inbuf, False);
117 /****************************************************************************
118 Send a security blob via a session setup reply.
119 ****************************************************************************/
121 static void reply_sesssetup_blob(struct smb_request *req,
122 DATA_BLOB blob,
123 NTSTATUS nt_status)
125 if (!NT_STATUS_IS_OK(nt_status) &&
126 !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
127 reply_nterror(req, nt_status_squash(nt_status));
128 } else {
129 nt_status = nt_status_squash(nt_status);
130 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
131 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
132 SSVAL(req->outbuf, smb_vwv3, blob.length);
134 if ((message_push_blob(&req->outbuf, blob) == -1)
135 || (push_signature(&req->outbuf) == -1)) {
136 reply_nterror(req, NT_STATUS_NO_MEMORY);
140 show_msg((char *)req->outbuf);
141 srv_send_smb(smbd_server_fd(),(char *)req->outbuf,req->encrypted);
142 TALLOC_FREE(req->outbuf);
145 /****************************************************************************
146 Do a 'guest' logon, getting back the
147 ****************************************************************************/
149 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
151 struct auth_context *auth_context;
152 auth_usersupplied_info *user_info = NULL;
154 NTSTATUS nt_status;
155 unsigned char chal[8];
157 ZERO_STRUCT(chal);
159 DEBUG(3,("Got anonymous request\n"));
161 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context,
162 chal))) {
163 return nt_status;
166 if (!make_user_info_guest(&user_info)) {
167 (auth_context->free)(&auth_context);
168 return NT_STATUS_NO_MEMORY;
171 nt_status = auth_context->check_ntlm_password(auth_context,
172 user_info,
173 server_info);
174 (auth_context->free)(&auth_context);
175 free_user_info(&user_info);
176 return nt_status;
180 #ifdef HAVE_KRB5
182 #if 0
183 /* Experiment that failed. See "only happens with a KDC" comment below. */
184 /****************************************************************************
185 Cerate a clock skew error blob for a Windows client.
186 ****************************************************************************/
188 static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
190 krb5_context context = NULL;
191 krb5_error_code kerr = 0;
192 krb5_data reply;
193 krb5_principal host_princ = NULL;
194 char *host_princ_s = NULL;
195 bool ret = False;
197 *pblob_out = data_blob_null;
199 initialize_krb5_error_table();
200 kerr = krb5_init_context(&context);
201 if (kerr) {
202 return False;
204 /* Create server principal. */
205 asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
206 if (!host_princ_s) {
207 goto out;
209 strlower_m(host_princ_s);
211 kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
212 if (kerr) {
213 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
214 "for name %s: Error %s\n",
215 host_princ_s, error_message(kerr) ));
216 goto out;
219 kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
220 host_princ, &reply);
221 if (kerr) {
222 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
223 "failed: Error %s\n",
224 error_message(kerr) ));
225 goto out;
228 *pblob_out = data_blob(reply.data, reply.length);
229 kerberos_free_data_contents(context,&reply);
230 ret = True;
232 out:
234 if (host_princ_s) {
235 SAFE_FREE(host_princ_s);
237 if (host_princ) {
238 krb5_free_principal(context, host_princ);
240 krb5_free_context(context);
241 return ret;
243 #endif
245 /****************************************************************************
246 Reply to a session setup spnego negotiate packet for kerberos.
247 ****************************************************************************/
249 static void reply_spnego_kerberos(struct smb_request *req,
250 DATA_BLOB *secblob,
251 const char *mechOID,
252 uint16 vuid,
253 bool *p_invalidate_vuid)
255 TALLOC_CTX *mem_ctx;
256 DATA_BLOB ticket;
257 char *client, *p, *domain;
258 fstring netbios_domain_name;
259 struct passwd *pw;
260 fstring user;
261 int sess_vuid = req->vuid;
262 NTSTATUS ret = NT_STATUS_OK;
263 struct PAC_DATA *pac_data = NULL;
264 DATA_BLOB ap_rep, ap_rep_wrapped, response;
265 auth_serversupplied_info *server_info = NULL;
266 DATA_BLOB session_key = data_blob_null;
267 uint8 tok_id[2];
268 DATA_BLOB nullblob = data_blob_null;
269 fstring real_username;
270 bool map_domainuser_to_guest = False;
271 bool username_was_mapped;
272 struct PAC_LOGON_INFO *logon_info = NULL;
274 ZERO_STRUCT(ticket);
275 ZERO_STRUCT(ap_rep);
276 ZERO_STRUCT(ap_rep_wrapped);
277 ZERO_STRUCT(response);
279 /* Normally we will always invalidate the intermediate vuid. */
280 *p_invalidate_vuid = True;
282 mem_ctx = talloc_init("reply_spnego_kerberos");
283 if (mem_ctx == NULL) {
284 reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
285 return;
288 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
289 talloc_destroy(mem_ctx);
290 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
291 return;
294 ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
295 &client, &pac_data, &ap_rep,
296 &session_key, True);
298 data_blob_free(&ticket);
300 if (!NT_STATUS_IS_OK(ret)) {
301 #if 0
302 /* Experiment that failed.
303 * See "only happens with a KDC" comment below. */
305 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
308 * Windows in this case returns
309 * NT_STATUS_MORE_PROCESSING_REQUIRED
310 * with a negTokenTarg blob containing an krb5_error
311 * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
312 * The client then fixes its clock and continues rather
313 * than giving an error. JRA.
314 * -- Looks like this only happens with a KDC. JRA.
317 bool ok = make_krb5_skew_error(&ap_rep);
318 if (!ok) {
319 talloc_destroy(mem_ctx);
320 return ERROR_NT(nt_status_squash(
321 NT_STATUS_LOGON_FAILURE));
323 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
324 TOK_ID_KRB_ERROR);
325 response = spnego_gen_auth_response(&ap_rep_wrapped,
326 ret, OID_KERBEROS5_OLD);
327 reply_sesssetup_blob(conn, inbuf, outbuf, response,
328 NT_STATUS_MORE_PROCESSING_REQUIRED);
331 * In this one case we don't invalidate the
332 * intermediate vuid as we're expecting the client
333 * to re-use it for the next sessionsetupX packet. JRA.
336 *p_invalidate_vuid = False;
338 data_blob_free(&ap_rep);
339 data_blob_free(&ap_rep_wrapped);
340 data_blob_free(&response);
341 talloc_destroy(mem_ctx);
342 return -1; /* already replied */
344 #else
345 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
346 ret = NT_STATUS_LOGON_FAILURE;
348 #endif
349 DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
350 nt_errstr(ret)));
351 talloc_destroy(mem_ctx);
352 reply_nterror(req, nt_status_squash(ret));
353 return;
356 DEBUG(3,("Ticket name is [%s]\n", client));
358 p = strchr_m(client, '@');
359 if (!p) {
360 DEBUG(3,("Doesn't look like a valid principal\n"));
361 data_blob_free(&ap_rep);
362 data_blob_free(&session_key);
363 SAFE_FREE(client);
364 talloc_destroy(mem_ctx);
365 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
366 return;
369 *p = 0;
371 /* save the PAC data if we have it */
373 if (pac_data) {
374 logon_info = get_logon_info_from_pac(pac_data);
375 if (logon_info) {
376 netsamlogon_cache_store( client, &logon_info->info3 );
380 if (!strequal(p+1, lp_realm())) {
381 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
382 if (!lp_allow_trusted_domains()) {
383 data_blob_free(&ap_rep);
384 data_blob_free(&session_key);
385 SAFE_FREE(client);
386 talloc_destroy(mem_ctx);
387 reply_nterror(req, nt_status_squash(
388 NT_STATUS_LOGON_FAILURE));
389 return;
393 /* this gives a fully qualified user name (ie. with full realm).
394 that leads to very long usernames, but what else can we do? */
396 domain = p+1;
398 if (logon_info && logon_info->info3.base.domain.string) {
399 fstrcpy(netbios_domain_name,
400 logon_info->info3.base.domain.string);
401 domain = netbios_domain_name;
402 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
404 } else {
406 /* If we have winbind running, we can (and must) shorten the
407 username by using the short netbios name. Otherwise we will
408 have inconsistent user names. With Kerberos, we get the
409 fully qualified realm, with ntlmssp we get the short
410 name. And even w2k3 does use ntlmssp if you for example
411 connect to an ip address. */
413 wbcErr wbc_status;
414 struct wbcDomainInfo *info = NULL;
416 DEBUG(10, ("Mapping [%s] to short name\n", domain));
418 wbc_status = wbcDomainInfo(domain, &info);
420 if (WBC_ERROR_IS_OK(wbc_status)) {
422 fstrcpy(netbios_domain_name,
423 info->short_name);
425 wbcFreeMemory(info);
426 domain = netbios_domain_name;
427 DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
428 } else {
429 DEBUG(3, ("Could not find short name: %s\n",
430 wbcErrorString(wbc_status)));
434 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
436 /* lookup the passwd struct, create a new user if necessary */
438 username_was_mapped = map_username( user );
440 pw = smb_getpwnam( mem_ctx, user, real_username, True );
442 if (pw) {
443 /* if a real user check pam account restrictions */
444 /* only really perfomed if "obey pam restriction" is true */
445 /* do this before an eventual mappign to guest occurs */
446 ret = smb_pam_accountcheck(pw->pw_name);
447 if ( !NT_STATUS_IS_OK(ret)) {
448 DEBUG(1,("PAM account restriction "
449 "prevents user login\n"));
450 data_blob_free(&ap_rep);
451 data_blob_free(&session_key);
452 TALLOC_FREE(mem_ctx);
453 reply_nterror(req, nt_status_squash(ret));
454 return;
458 if (!pw) {
460 /* this was originally the behavior of Samba 2.2, if a user
461 did not have a local uid but has been authenticated, then
462 map them to a guest account */
464 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
465 map_domainuser_to_guest = True;
466 fstrcpy(user,lp_guestaccount());
467 pw = smb_getpwnam( mem_ctx, user, real_username, True );
470 /* extra sanity check that the guest account is valid */
472 if ( !pw ) {
473 DEBUG(1,("Username %s is invalid on this system\n",
474 user));
475 SAFE_FREE(client);
476 data_blob_free(&ap_rep);
477 data_blob_free(&session_key);
478 TALLOC_FREE(mem_ctx);
479 reply_nterror(req, nt_status_squash(
480 NT_STATUS_LOGON_FAILURE));
481 return;
485 /* setup the string used by %U */
487 sub_set_smb_name( real_username );
488 reload_services(True);
490 if ( map_domainuser_to_guest ) {
491 make_server_info_guest(&server_info);
492 } else if (logon_info) {
493 /* pass the unmapped username here since map_username()
494 will be called again from inside make_server_info_info3() */
496 ret = make_server_info_info3(mem_ctx, client, domain,
497 &server_info, &logon_info->info3);
498 if ( !NT_STATUS_IS_OK(ret) ) {
499 DEBUG(1,("make_server_info_info3 failed: %s!\n",
500 nt_errstr(ret)));
501 SAFE_FREE(client);
502 data_blob_free(&ap_rep);
503 data_blob_free(&session_key);
504 TALLOC_FREE(mem_ctx);
505 reply_nterror(req, nt_status_squash(ret));
506 return;
509 } else {
510 ret = make_server_info_pw(&server_info, real_username, pw);
512 if ( !NT_STATUS_IS_OK(ret) ) {
513 DEBUG(1,("make_server_info_pw failed: %s!\n",
514 nt_errstr(ret)));
515 SAFE_FREE(client);
516 data_blob_free(&ap_rep);
517 data_blob_free(&session_key);
518 TALLOC_FREE(mem_ctx);
519 reply_nterror(req, nt_status_squash(ret));
520 return;
523 /* make_server_info_pw does not set the domain. Without this
524 * we end up with the local netbios name in substitutions for
525 * %D. */
527 if (server_info->sam_account != NULL) {
528 pdb_set_domain(server_info->sam_account,
529 domain, PDB_SET);
533 if (username_was_mapped) {
534 server_info->was_mapped = username_was_mapped;
537 /* we need to build the token for the user. make_server_info_guest()
538 already does this */
540 if ( !server_info->ptok ) {
541 ret = create_local_token( server_info );
542 if ( !NT_STATUS_IS_OK(ret) ) {
543 DEBUG(10,("failed to create local token: %s\n",
544 nt_errstr(ret)));
545 SAFE_FREE(client);
546 data_blob_free(&ap_rep);
547 data_blob_free(&session_key);
548 TALLOC_FREE( mem_ctx );
549 TALLOC_FREE( server_info );
550 reply_nterror(req, nt_status_squash(ret));
551 return;
555 /* register_existing_vuid keeps the server info */
556 /* register_existing_vuid takes ownership of session_key on success,
557 * no need to free after this on success. A better interface would copy
558 * it.... */
560 if (!is_partial_auth_vuid(sess_vuid)) {
561 sess_vuid = register_initial_vuid();
563 sess_vuid = register_existing_vuid(sess_vuid,
564 server_info,
565 session_key,
566 nullblob,
567 client);
569 SAFE_FREE(client);
571 reply_outbuf(req, 4, 0);
572 SSVAL(req->outbuf,smb_uid,sess_vuid);
574 if (sess_vuid == UID_FIELD_INVALID ) {
575 ret = NT_STATUS_LOGON_FAILURE;
576 data_blob_free(&session_key);
577 } else {
578 /* current_user_info is changed on new vuid */
579 reload_services( True );
581 SSVAL(req->outbuf, smb_vwv3, 0);
583 if (server_info->guest) {
584 SSVAL(req->outbuf,smb_vwv2,1);
587 SSVAL(req->outbuf, smb_uid, sess_vuid);
589 sessionsetup_start_signing_engine(server_info, req->inbuf);
590 /* Successful logon. Keep this vuid. */
591 *p_invalidate_vuid = False;
594 /* wrap that up in a nice GSS-API wrapping */
595 if (NT_STATUS_IS_OK(ret)) {
596 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
597 TOK_ID_KRB_AP_REP);
598 } else {
599 ap_rep_wrapped = data_blob_null;
601 response = spnego_gen_auth_response(&ap_rep_wrapped, ret,
602 mechOID);
603 reply_sesssetup_blob(req, response, ret);
605 data_blob_free(&ap_rep);
606 data_blob_free(&ap_rep_wrapped);
607 data_blob_free(&response);
608 TALLOC_FREE(mem_ctx);
611 #endif
613 /****************************************************************************
614 Send a session setup reply, wrapped in SPNEGO.
615 Get vuid and check first.
616 End the NTLMSSP exchange context if we are OK/complete fail
617 This should be split into two functions, one to handle each
618 leg of the NTLM auth steps.
619 ***************************************************************************/
621 static void reply_spnego_ntlmssp(struct smb_request *req,
622 uint16 vuid,
623 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
624 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
625 const char *OID,
626 bool wrap)
628 DATA_BLOB response;
629 struct auth_serversupplied_info *server_info = NULL;
631 if (NT_STATUS_IS_OK(nt_status)) {
632 server_info = (*auth_ntlmssp_state)->server_info;
633 } else {
634 nt_status = do_map_to_guest(nt_status,
635 &server_info,
636 (*auth_ntlmssp_state)->ntlmssp_state->user,
637 (*auth_ntlmssp_state)->ntlmssp_state->domain);
640 reply_outbuf(req, 4, 0);
642 SSVAL(req->outbuf, smb_uid, vuid);
644 if (NT_STATUS_IS_OK(nt_status)) {
645 DATA_BLOB nullblob = data_blob_null;
646 DATA_BLOB session_key =
647 data_blob(
648 (*auth_ntlmssp_state)->ntlmssp_state->session_key.data,
649 (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
651 if (!is_partial_auth_vuid(vuid)) {
652 data_blob_free(&session_key);
653 nt_status = NT_STATUS_LOGON_FAILURE;
654 goto out;
656 /* register_existing_vuid keeps the server info */
657 if (register_existing_vuid(vuid,
658 server_info,
659 session_key, nullblob,
660 (*auth_ntlmssp_state)->ntlmssp_state->user) !=
661 vuid) {
662 data_blob_free(&session_key);
663 nt_status = NT_STATUS_LOGON_FAILURE;
664 goto out;
667 (*auth_ntlmssp_state)->server_info = NULL;
669 /* current_user_info is changed on new vuid */
670 reload_services( True );
672 SSVAL(req->outbuf, smb_vwv3, 0);
674 if (server_info->guest) {
675 SSVAL(req->outbuf,smb_vwv2,1);
678 sessionsetup_start_signing_engine(server_info,
679 (uint8 *)req->inbuf);
682 out:
684 if (wrap) {
685 response = spnego_gen_auth_response(ntlmssp_blob,
686 nt_status, OID);
687 } else {
688 response = *ntlmssp_blob;
691 reply_sesssetup_blob(req, response, nt_status);
692 if (wrap) {
693 data_blob_free(&response);
696 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
697 and the other end, that we are not finished yet. */
699 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
700 /* NB. This is *NOT* an error case. JRA */
701 auth_ntlmssp_end(auth_ntlmssp_state);
702 if (!NT_STATUS_IS_OK(nt_status)) {
703 /* Kill the intermediate vuid */
704 invalidate_vuid(vuid);
709 /****************************************************************************
710 Is this a krb5 mechanism ?
711 ****************************************************************************/
713 NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in,
714 DATA_BLOB *pblob_out,
715 char **kerb_mechOID)
717 char *OIDs[ASN1_MAX_OIDS];
718 int i;
719 NTSTATUS ret = NT_STATUS_OK;
721 *kerb_mechOID = NULL;
723 /* parse out the OIDs and the first sec blob */
724 if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
725 return NT_STATUS_LOGON_FAILURE;
728 /* only look at the first OID for determining the mechToken --
729 according to RFC2478, we should choose the one we want
730 and renegotiate, but i smell a client bug here..
732 Problem observed when connecting to a member (samba box)
733 of an AD domain as a user in a Samba domain. Samba member
734 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
735 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
736 NTLMSSP mechtoken. --jerry */
738 #ifdef HAVE_KRB5
739 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
740 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
741 *kerb_mechOID = SMB_STRDUP(OIDs[0]);
742 if (*kerb_mechOID == NULL) {
743 ret = NT_STATUS_NO_MEMORY;
746 #endif
748 for (i=0;OIDs[i];i++) {
749 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
750 free(OIDs[i]);
752 return ret;
755 /****************************************************************************
756 Fall back from krb5 to NTLMSSP.
757 ****************************************************************************/
759 static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
760 uint16 vuid)
762 DATA_BLOB response;
764 reply_outbuf(req, 4, 0);
765 SSVAL(req->outbuf,smb_uid,vuid);
767 DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
768 "but set to downgrade to NTLMSSP\n"));
770 response = spnego_gen_auth_response(NULL,
771 NT_STATUS_MORE_PROCESSING_REQUIRED,
772 OID_NTLMSSP);
773 reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
774 data_blob_free(&response);
777 /****************************************************************************
778 Reply to a session setup spnego negotiate packet.
779 ****************************************************************************/
781 static void reply_spnego_negotiate(struct smb_request *req,
782 uint16 vuid,
783 DATA_BLOB blob1,
784 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
786 DATA_BLOB secblob;
787 DATA_BLOB chal;
788 char *kerb_mech = NULL;
789 NTSTATUS status;
791 status = parse_spnego_mechanisms(blob1, &secblob, &kerb_mech);
792 if (!NT_STATUS_IS_OK(status)) {
793 /* Kill the intermediate vuid */
794 invalidate_vuid(vuid);
795 reply_nterror(req, nt_status_squash(status));
796 return;
799 DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
800 (unsigned long)secblob.length));
802 #ifdef HAVE_KRB5
803 if (kerb_mech && ((lp_security()==SEC_ADS) ||
804 lp_use_kerberos_keytab()) ) {
805 bool destroy_vuid = True;
806 reply_spnego_kerberos(req, &secblob, kerb_mech,
807 vuid, &destroy_vuid);
808 data_blob_free(&secblob);
809 if (destroy_vuid) {
810 /* Kill the intermediate vuid */
811 invalidate_vuid(vuid);
813 SAFE_FREE(kerb_mech);
814 return;
816 #endif
818 if (*auth_ntlmssp_state) {
819 auth_ntlmssp_end(auth_ntlmssp_state);
822 if (kerb_mech) {
823 data_blob_free(&secblob);
824 /* The mechtoken is a krb5 ticket, but
825 * we need to fall back to NTLM. */
826 reply_spnego_downgrade_to_ntlmssp(req, vuid);
827 SAFE_FREE(kerb_mech);
828 return;
831 status = auth_ntlmssp_start(auth_ntlmssp_state);
832 if (!NT_STATUS_IS_OK(status)) {
833 /* Kill the intermediate vuid */
834 invalidate_vuid(vuid);
835 reply_nterror(req, nt_status_squash(status));
836 return;
839 status = auth_ntlmssp_update(*auth_ntlmssp_state,
840 secblob, &chal);
842 data_blob_free(&secblob);
844 reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
845 &chal, status, OID_NTLMSSP, true);
847 data_blob_free(&chal);
849 /* already replied */
850 return;
853 /****************************************************************************
854 Reply to a session setup spnego auth packet.
855 ****************************************************************************/
857 static void reply_spnego_auth(struct smb_request *req,
858 uint16 vuid,
859 DATA_BLOB blob1,
860 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
862 DATA_BLOB auth = data_blob_null;
863 DATA_BLOB auth_reply = data_blob_null;
864 DATA_BLOB secblob = data_blob_null;
865 NTSTATUS status = NT_STATUS_LOGON_FAILURE;
867 if (!spnego_parse_auth(blob1, &auth)) {
868 #if 0
869 file_save("auth.dat", blob1.data, blob1.length);
870 #endif
871 /* Kill the intermediate vuid */
872 invalidate_vuid(vuid);
874 reply_nterror(req, nt_status_squash(
875 NT_STATUS_LOGON_FAILURE));
876 return;
879 if (auth.data[0] == ASN1_APPLICATION(0)) {
880 /* Might be a second negTokenTarg packet */
881 char *kerb_mech = NULL;
883 status = parse_spnego_mechanisms(auth, &secblob, &kerb_mech);
885 if (!NT_STATUS_IS_OK(status)) {
886 /* Kill the intermediate vuid */
887 invalidate_vuid(vuid);
888 reply_nterror(req, nt_status_squash(status));
889 return;
892 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
893 (unsigned long)secblob.length));
894 #ifdef HAVE_KRB5
895 if (kerb_mech && ((lp_security()==SEC_ADS) ||
896 lp_use_kerberos_keytab()) ) {
897 bool destroy_vuid = True;
898 reply_spnego_kerberos(req, &secblob, kerb_mech,
899 vuid, &destroy_vuid);
900 data_blob_free(&secblob);
901 data_blob_free(&auth);
902 if (destroy_vuid) {
903 /* Kill the intermediate vuid */
904 invalidate_vuid(vuid);
906 SAFE_FREE(kerb_mech);
907 return;
909 #endif
910 /* Can't blunder into NTLMSSP auth if we have
911 * a krb5 ticket. */
913 if (kerb_mech) {
914 /* Kill the intermediate vuid */
915 invalidate_vuid(vuid);
916 DEBUG(3,("reply_spnego_auth: network "
917 "misconfiguration, client sent us a "
918 "krb5 ticket and kerberos security "
919 "not enabled"));
920 reply_nterror(req, nt_status_squash(
921 NT_STATUS_LOGON_FAILURE));
922 SAFE_FREE(kerb_mech);
926 /* If we get here it wasn't a negTokenTarg auth packet. */
927 data_blob_free(&secblob);
929 if (!*auth_ntlmssp_state) {
930 status = auth_ntlmssp_start(auth_ntlmssp_state);
931 if (!NT_STATUS_IS_OK(status)) {
932 /* Kill the intermediate vuid */
933 invalidate_vuid(vuid);
934 reply_nterror(req, nt_status_squash(status));
935 return;
939 status = auth_ntlmssp_update(*auth_ntlmssp_state,
940 auth, &auth_reply);
942 data_blob_free(&auth);
944 /* Don't send the mechid as we've already sent this (RFC4178). */
946 reply_spnego_ntlmssp(req, vuid,
947 auth_ntlmssp_state,
948 &auth_reply, status, NULL, true);
950 data_blob_free(&auth_reply);
952 /* and tell smbd that we have already replied to this packet */
953 return;
956 /****************************************************************************
957 List to store partial SPNEGO auth fragments.
958 ****************************************************************************/
960 static struct pending_auth_data *pd_list;
962 /****************************************************************************
963 Delete an entry on the list.
964 ****************************************************************************/
966 static void delete_partial_auth(struct pending_auth_data *pad)
968 if (!pad) {
969 return;
971 DLIST_REMOVE(pd_list, pad);
972 data_blob_free(&pad->partial_data);
973 SAFE_FREE(pad);
976 /****************************************************************************
977 Search for a partial SPNEGO auth fragment matching an smbpid.
978 ****************************************************************************/
980 static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
982 struct pending_auth_data *pad;
984 for (pad = pd_list; pad; pad = pad->next) {
985 if (pad->smbpid == smbpid) {
986 break;
989 return pad;
992 /****************************************************************************
993 Check the size of an SPNEGO blob. If we need more return
994 NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
995 the blob to be more than 64k.
996 ****************************************************************************/
998 static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid,
999 DATA_BLOB *pblob)
1001 struct pending_auth_data *pad = NULL;
1002 ASN1_DATA data;
1003 size_t needed_len = 0;
1005 pad = get_pending_auth_data(smbpid);
1007 /* Ensure we have some data. */
1008 if (pblob->length == 0) {
1009 /* Caller can cope. */
1010 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
1011 delete_partial_auth(pad);
1012 return NT_STATUS_OK;
1015 /* Were we waiting for more data ? */
1016 if (pad) {
1017 DATA_BLOB tmp_blob;
1018 size_t copy_len = MIN(65536, pblob->length);
1020 /* Integer wrap paranoia.... */
1022 if (pad->partial_data.length + copy_len <
1023 pad->partial_data.length ||
1024 pad->partial_data.length + copy_len < copy_len) {
1026 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1027 "pad->partial_data.length = %u, "
1028 "copy_len = %u\n",
1029 (unsigned int)pad->partial_data.length,
1030 (unsigned int)copy_len ));
1032 delete_partial_auth(pad);
1033 return NT_STATUS_INVALID_PARAMETER;
1036 DEBUG(10,("check_spnego_blob_complete: "
1037 "pad->partial_data.length = %u, "
1038 "pad->needed_len = %u, "
1039 "copy_len = %u, "
1040 "pblob->length = %u,\n",
1041 (unsigned int)pad->partial_data.length,
1042 (unsigned int)pad->needed_len,
1043 (unsigned int)copy_len,
1044 (unsigned int)pblob->length ));
1046 tmp_blob = data_blob(NULL,
1047 pad->partial_data.length + copy_len);
1049 /* Concatenate the two (up to copy_len) bytes. */
1050 memcpy(tmp_blob.data,
1051 pad->partial_data.data,
1052 pad->partial_data.length);
1053 memcpy(tmp_blob.data + pad->partial_data.length,
1054 pblob->data,
1055 copy_len);
1057 /* Replace the partial data. */
1058 data_blob_free(&pad->partial_data);
1059 pad->partial_data = tmp_blob;
1060 ZERO_STRUCT(tmp_blob);
1062 /* Are we done ? */
1063 if (pblob->length >= pad->needed_len) {
1064 /* Yes, replace pblob. */
1065 data_blob_free(pblob);
1066 *pblob = pad->partial_data;
1067 ZERO_STRUCT(pad->partial_data);
1068 delete_partial_auth(pad);
1069 return NT_STATUS_OK;
1072 /* Still need more data. */
1073 pad->needed_len -= copy_len;
1074 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1077 if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
1078 (pblob->data[0] != ASN1_CONTEXT(1))) {
1079 /* Not something we can determine the
1080 * length of.
1082 return NT_STATUS_OK;
1085 /* This is a new SPNEGO sessionsetup - see if
1086 * the data given in this blob is enough.
1089 asn1_load(&data, *pblob);
1090 asn1_start_tag(&data, pblob->data[0]);
1091 if (data.has_error || data.nesting == NULL) {
1092 asn1_free(&data);
1093 /* Let caller catch. */
1094 return NT_STATUS_OK;
1097 /* Integer wrap paranoia.... */
1099 if (data.nesting->taglen + data.nesting->start < data.nesting->taglen ||
1100 data.nesting->taglen + data.nesting->start < data.nesting->start) {
1102 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1103 "data.nesting->taglen = %u, "
1104 "data.nesting->start = %u\n",
1105 (unsigned int)data.nesting->taglen,
1106 (unsigned int)data.nesting->start ));
1108 asn1_free(&data);
1109 return NT_STATUS_INVALID_PARAMETER;
1112 /* Total length of the needed asn1 is the tag length
1113 * plus the current offset. */
1115 needed_len = data.nesting->taglen + data.nesting->start;
1116 asn1_free(&data);
1118 DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
1119 "pblob->length = %u\n",
1120 (unsigned int)needed_len,
1121 (unsigned int)pblob->length ));
1123 if (needed_len <= pblob->length) {
1124 /* Nothing to do - blob is complete. */
1125 return NT_STATUS_OK;
1128 /* Refuse the blob if it's bigger than 64k. */
1129 if (needed_len > 65536) {
1130 DEBUG(2,("check_spnego_blob_complete: needed_len "
1131 "too large (%u)\n",
1132 (unsigned int)needed_len ));
1133 return NT_STATUS_INVALID_PARAMETER;
1136 /* We must store this blob until complete. */
1137 if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
1138 return NT_STATUS_NO_MEMORY;
1140 pad->needed_len = needed_len - pblob->length;
1141 pad->partial_data = data_blob(pblob->data, pblob->length);
1142 if (pad->partial_data.data == NULL) {
1143 SAFE_FREE(pad);
1144 return NT_STATUS_NO_MEMORY;
1146 pad->smbpid = smbpid;
1147 pad->vuid = vuid;
1148 DLIST_ADD(pd_list, pad);
1150 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1153 /****************************************************************************
1154 Reply to a session setup command.
1155 conn POINTER CAN BE NULL HERE !
1156 ****************************************************************************/
1158 static void reply_sesssetup_and_X_spnego(struct smb_request *req)
1160 uint8 *p;
1161 DATA_BLOB blob1;
1162 size_t bufrem;
1163 fstring native_os, native_lanman, primary_domain;
1164 const char *p2;
1165 uint16 data_blob_len = SVAL(req->inbuf, smb_vwv7);
1166 enum remote_arch_types ra_type = get_remote_arch();
1167 int vuid = SVAL(req->inbuf,smb_uid);
1168 user_struct *vuser = NULL;
1169 NTSTATUS status = NT_STATUS_OK;
1170 uint16 smbpid = req->smbpid;
1171 uint16 smb_flag2 = req->flags2;
1173 DEBUG(3,("Doing spnego session setup\n"));
1175 if (global_client_caps == 0) {
1176 global_client_caps = IVAL(req->inbuf,smb_vwv10);
1178 if (!(global_client_caps & CAP_STATUS32)) {
1179 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1184 p = (uint8 *)smb_buf(req->inbuf);
1186 if (data_blob_len == 0) {
1187 /* an invalid request */
1188 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1189 return;
1192 bufrem = smb_bufrem(req->inbuf, p);
1193 /* pull the spnego blob */
1194 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1196 #if 0
1197 file_save("negotiate.dat", blob1.data, blob1.length);
1198 #endif
1200 p2 = (char *)req->inbuf + smb_vwv13 + data_blob_len;
1201 p2 += srvstr_pull_buf(req->inbuf, smb_flag2, native_os, p2,
1202 sizeof(native_os), STR_TERMINATE);
1203 p2 += srvstr_pull_buf(req->inbuf, smb_flag2, native_lanman, p2,
1204 sizeof(native_lanman), STR_TERMINATE);
1205 p2 += srvstr_pull_buf(req->inbuf, smb_flag2, primary_domain, p2,
1206 sizeof(primary_domain), STR_TERMINATE);
1207 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1208 native_os, native_lanman, primary_domain));
1210 if ( ra_type == RA_WIN2K ) {
1211 /* Vista sets neither the OS or lanman strings */
1213 if ( !strlen(native_os) && !strlen(native_lanman) )
1214 set_remote_arch(RA_VISTA);
1216 /* Windows 2003 doesn't set the native lanman string,
1217 but does set primary domain which is a bug I think */
1219 if ( !strlen(native_lanman) ) {
1220 ra_lanman_string( primary_domain );
1221 } else {
1222 ra_lanman_string( native_lanman );
1226 /* Did we get a valid vuid ? */
1227 if (!is_partial_auth_vuid(vuid)) {
1228 /* No, then try and see if this is an intermediate sessionsetup
1229 * for a large SPNEGO packet. */
1230 struct pending_auth_data *pad = get_pending_auth_data(smbpid);
1231 if (pad) {
1232 DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1233 "pending vuid %u\n",
1234 (unsigned int)pad->vuid ));
1235 vuid = pad->vuid;
1239 /* Do we have a valid vuid now ? */
1240 if (!is_partial_auth_vuid(vuid)) {
1241 /* No, start a new authentication setup. */
1242 vuid = register_initial_vuid();
1243 if (vuid == UID_FIELD_INVALID) {
1244 data_blob_free(&blob1);
1245 reply_nterror(req, nt_status_squash(
1246 NT_STATUS_INVALID_PARAMETER));
1247 return;
1251 vuser = get_partial_auth_user_struct(vuid);
1252 /* This MUST be valid. */
1253 if (!vuser) {
1254 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1257 /* Large (greater than 4k) SPNEGO blobs are split into multiple
1258 * sessionsetup requests as the Windows limit on the security blob
1259 * field is 4k. Bug #4400. JRA.
1262 status = check_spnego_blob_complete(smbpid, vuid, &blob1);
1263 if (!NT_STATUS_IS_OK(status)) {
1264 if (!NT_STATUS_EQUAL(status,
1265 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1266 /* Real error - kill the intermediate vuid */
1267 invalidate_vuid(vuid);
1269 data_blob_free(&blob1);
1270 reply_nterror(req, nt_status_squash(status));
1271 return;
1274 if (blob1.data[0] == ASN1_APPLICATION(0)) {
1276 /* its a negTokenTarg packet */
1278 reply_spnego_negotiate(req, vuid, blob1,
1279 &vuser->auth_ntlmssp_state);
1280 data_blob_free(&blob1);
1281 return;
1284 if (blob1.data[0] == ASN1_CONTEXT(1)) {
1286 /* its a auth packet */
1288 reply_spnego_auth(req, vuid, blob1,
1289 &vuser->auth_ntlmssp_state);
1290 data_blob_free(&blob1);
1291 return;
1294 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1295 DATA_BLOB chal;
1297 if (!vuser->auth_ntlmssp_state) {
1298 status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1299 if (!NT_STATUS_IS_OK(status)) {
1300 /* Kill the intermediate vuid */
1301 invalidate_vuid(vuid);
1302 data_blob_free(&blob1);
1303 reply_nterror(req, nt_status_squash(status));
1304 return;
1308 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1309 blob1, &chal);
1311 data_blob_free(&blob1);
1313 reply_spnego_ntlmssp(req, vuid,
1314 &vuser->auth_ntlmssp_state,
1315 &chal, status, OID_NTLMSSP, false);
1316 data_blob_free(&chal);
1317 return;
1320 /* what sort of packet is this? */
1321 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1323 data_blob_free(&blob1);
1325 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1328 /****************************************************************************
1329 On new VC == 0, shutdown *all* old connections and users.
1330 It seems that only NT4.x does this. At W2K and above (XP etc.).
1331 a new session setup with VC==0 is ignored.
1332 ****************************************************************************/
1334 static int shutdown_other_smbds(struct db_record *rec,
1335 const struct connections_key *key,
1336 const struct connections_data *crec,
1337 void *private_data)
1339 const char *ip = (const char *)private_data;
1341 if (!process_exists(crec->pid)) {
1342 return 0;
1345 if (procid_is_me(&crec->pid)) {
1346 return 0;
1349 if (strcmp(ip, crec->addr) != 0) {
1350 return 0;
1353 messaging_send(smbd_messaging_context(), crec->pid, MSG_SHUTDOWN,
1354 &data_blob_null);
1355 return 0;
1358 static void setup_new_vc_session(void)
1360 char addr[INET6_ADDRSTRLEN];
1362 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1363 "compatible we would close all old resources.\n"));
1364 #if 0
1365 conn_close_all();
1366 invalidate_all_vuids();
1367 #endif
1368 if (lp_reset_on_zero_vc()) {
1369 connections_forall(shutdown_other_smbds,
1370 CONST_DISCARD(void *,
1371 client_addr(get_client_fd(),addr,sizeof(addr))));
1375 /****************************************************************************
1376 Reply to a session setup command.
1377 ****************************************************************************/
1379 void reply_sesssetup_and_X(struct smb_request *req)
1381 int sess_vuid;
1382 int smb_bufsize;
1383 DATA_BLOB lm_resp;
1384 DATA_BLOB nt_resp;
1385 DATA_BLOB plaintext_password;
1386 fstring user;
1387 fstring sub_user; /* Sainitised username for substituion */
1388 fstring domain;
1389 fstring native_os;
1390 fstring native_lanman;
1391 fstring primary_domain;
1392 static bool done_sesssetup = False;
1393 auth_usersupplied_info *user_info = NULL;
1394 auth_serversupplied_info *server_info = NULL;
1395 uint16 smb_flag2 = req->flags2;
1397 NTSTATUS nt_status;
1399 bool doencrypt = global_encrypted_passwords_negotiated;
1401 DATA_BLOB session_key;
1403 START_PROFILE(SMBsesssetupX);
1405 ZERO_STRUCT(lm_resp);
1406 ZERO_STRUCT(nt_resp);
1407 ZERO_STRUCT(plaintext_password);
1409 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1411 /* a SPNEGO session setup has 12 command words, whereas a normal
1412 NT1 session setup has 13. See the cifs spec. */
1413 if (req->wct == 12 &&
1414 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1416 if (!global_spnego_negotiated) {
1417 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1418 "at SPNEGO session setup when it was not "
1419 "negotiated.\n"));
1420 reply_nterror(req, nt_status_squash(
1421 NT_STATUS_LOGON_FAILURE));
1422 END_PROFILE(SMBsesssetupX);
1423 return;
1426 if (SVAL(req->inbuf,smb_vwv4) == 0) {
1427 setup_new_vc_session();
1430 reply_sesssetup_and_X_spnego(req);
1431 END_PROFILE(SMBsesssetupX);
1432 return;
1435 smb_bufsize = SVAL(req->inbuf,smb_vwv2);
1437 if (Protocol < PROTOCOL_NT1) {
1438 uint16 passlen1 = SVAL(req->inbuf,smb_vwv7);
1440 /* Never do NT status codes with protocols before NT1 as we
1441 * don't get client caps. */
1442 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1444 if ((passlen1 > MAX_PASS_LEN)
1445 || (passlen1 > smb_bufrem(req->inbuf,
1446 smb_buf(req->inbuf)))) {
1447 reply_nterror(req, nt_status_squash(
1448 NT_STATUS_INVALID_PARAMETER));
1449 END_PROFILE(SMBsesssetupX);
1450 return;
1453 if (doencrypt) {
1454 lm_resp = data_blob(smb_buf(req->inbuf), passlen1);
1455 } else {
1456 plaintext_password = data_blob(smb_buf(req->inbuf),
1457 passlen1+1);
1458 /* Ensure null termination */
1459 plaintext_password.data[passlen1] = 0;
1462 srvstr_pull_buf(req->inbuf, req->flags2, user,
1463 smb_buf(req->inbuf)+passlen1, sizeof(user),
1464 STR_TERMINATE);
1465 *domain = 0;
1467 } else {
1468 uint16 passlen1 = SVAL(req->inbuf,smb_vwv7);
1469 uint16 passlen2 = SVAL(req->inbuf,smb_vwv8);
1470 enum remote_arch_types ra_type = get_remote_arch();
1471 char *p = smb_buf(req->inbuf);
1472 char *save_p = smb_buf(req->inbuf);
1473 uint16 byte_count;
1476 if(global_client_caps == 0) {
1477 global_client_caps = IVAL(req->inbuf,smb_vwv11);
1479 if (!(global_client_caps & CAP_STATUS32)) {
1480 remove_from_common_flags2(
1481 FLAGS2_32_BIT_ERROR_CODES);
1484 /* client_caps is used as final determination if
1485 * client is NT or Win95. This is needed to return
1486 * the correct error codes in some circumstances.
1489 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1490 ra_type == RA_WIN95) {
1491 if(!(global_client_caps & (CAP_NT_SMBS|
1492 CAP_STATUS32))) {
1493 set_remote_arch( RA_WIN95);
1498 if (!doencrypt) {
1499 /* both Win95 and WinNT stuff up the password
1500 * lengths for non-encrypting systems. Uggh.
1502 if passlen1==24 its a win95 system, and its setting
1503 the password length incorrectly. Luckily it still
1504 works with the default code because Win95 will null
1505 terminate the password anyway
1507 if passlen1>0 and passlen2>0 then maybe its a NT box
1508 and its setting passlen2 to some random value which
1509 really stuffs things up. we need to fix that one. */
1511 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1512 passlen2 != 1) {
1513 passlen2 = 0;
1517 /* check for nasty tricks */
1518 if (passlen1 > MAX_PASS_LEN
1519 || passlen1 > smb_bufrem(req->inbuf, p)) {
1520 reply_nterror(req, nt_status_squash(
1521 NT_STATUS_INVALID_PARAMETER));
1522 END_PROFILE(SMBsesssetupX);
1523 return;
1526 if (passlen2 > MAX_PASS_LEN
1527 || passlen2 > smb_bufrem(req->inbuf, p+passlen1)) {
1528 reply_nterror(req, nt_status_squash(
1529 NT_STATUS_INVALID_PARAMETER));
1530 END_PROFILE(SMBsesssetupX);
1531 return;
1534 /* Save the lanman2 password and the NT md4 password. */
1536 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1537 doencrypt = False;
1540 if (doencrypt) {
1541 lm_resp = data_blob(p, passlen1);
1542 nt_resp = data_blob(p+passlen1, passlen2);
1543 } else if (lp_security() != SEC_SHARE) {
1545 * In share level we should ignore any passwords, so
1546 * only read them if we're not.
1548 char *pass = NULL;
1549 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1551 if (unic && (passlen2 == 0) && passlen1) {
1552 /* Only a ascii plaintext password was sent. */
1553 (void)srvstr_pull_talloc(talloc_tos(),
1554 req->inbuf,
1555 req->flags2,
1556 &pass,
1557 smb_buf(req->inbuf),
1558 passlen1,
1559 STR_TERMINATE|STR_ASCII);
1560 } else {
1561 (void)srvstr_pull_talloc(talloc_tos(),
1562 req->inbuf,
1563 req->flags2,
1564 &pass,
1565 smb_buf(req->inbuf),
1566 unic ? passlen2 : passlen1,
1567 STR_TERMINATE);
1569 if (!pass) {
1570 reply_nterror(req, nt_status_squash(
1571 NT_STATUS_INVALID_PARAMETER));
1572 END_PROFILE(SMBsesssetupX);
1573 return;
1575 plaintext_password = data_blob(pass, strlen(pass)+1);
1578 p += passlen1 + passlen2;
1579 p += srvstr_pull_buf(req->inbuf, req->flags2, user, p,
1580 sizeof(user), STR_TERMINATE);
1581 p += srvstr_pull_buf(req->inbuf, req->flags2, domain, p,
1582 sizeof(domain), STR_TERMINATE);
1583 p += srvstr_pull_buf(req->inbuf, req->flags2, native_os,
1584 p, sizeof(native_os), STR_TERMINATE);
1585 p += srvstr_pull_buf(req->inbuf, req->flags2,
1586 native_lanman, p, sizeof(native_lanman),
1587 STR_TERMINATE);
1589 /* not documented or decoded by Ethereal but there is one more
1590 * string in the extra bytes which is the same as the
1591 * PrimaryDomain when using extended security. Windows NT 4
1592 * and 2003 use this string to store the native lanman string.
1593 * Windows 9x does not include a string here at all so we have
1594 * to check if we have any extra bytes left */
1596 byte_count = SVAL(req->inbuf, smb_vwv13);
1597 if ( PTR_DIFF(p, save_p) < byte_count) {
1598 p += srvstr_pull_buf(req->inbuf, req->flags2,
1599 primary_domain, p,
1600 sizeof(primary_domain),
1601 STR_TERMINATE);
1602 } else {
1603 fstrcpy( primary_domain, "null" );
1606 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
1607 "PrimaryDomain=[%s]\n",
1608 domain, native_os, native_lanman, primary_domain));
1610 if ( ra_type == RA_WIN2K ) {
1611 if ( strlen(native_lanman) == 0 )
1612 ra_lanman_string( primary_domain );
1613 else
1614 ra_lanman_string( native_lanman );
1619 if (SVAL(req->inbuf,smb_vwv4) == 0) {
1620 setup_new_vc_session();
1623 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1624 domain, user, get_remote_machine_name()));
1626 if (*user) {
1627 if (global_spnego_negotiated) {
1629 /* This has to be here, because this is a perfectly
1630 * valid behaviour for guest logons :-( */
1632 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1633 "at 'normal' session setup after "
1634 "negotiating spnego.\n"));
1635 reply_nterror(req, nt_status_squash(
1636 NT_STATUS_LOGON_FAILURE));
1637 END_PROFILE(SMBsesssetupX);
1638 return;
1640 fstrcpy(sub_user, user);
1641 } else {
1642 fstrcpy(sub_user, lp_guestaccount());
1645 sub_set_smb_name(sub_user);
1647 reload_services(True);
1649 if (lp_security() == SEC_SHARE) {
1650 /* In share level we should ignore any passwords */
1652 data_blob_free(&lm_resp);
1653 data_blob_free(&nt_resp);
1654 data_blob_clear_free(&plaintext_password);
1656 map_username(sub_user);
1657 add_session_user(sub_user);
1658 add_session_workgroup(domain);
1659 /* Then force it to null for the benfit of the code below */
1660 *user = 0;
1663 if (!*user) {
1665 nt_status = check_guest_password(&server_info);
1667 } else if (doencrypt) {
1668 if (!negprot_global_auth_context) {
1669 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
1670 "session setup without negprot denied!\n"));
1671 reply_nterror(req, nt_status_squash(
1672 NT_STATUS_LOGON_FAILURE));
1673 END_PROFILE(SMBsesssetupX);
1674 return;
1676 nt_status = make_user_info_for_reply_enc(&user_info, user,
1677 domain,
1678 lm_resp, nt_resp);
1679 if (NT_STATUS_IS_OK(nt_status)) {
1680 nt_status = negprot_global_auth_context->check_ntlm_password(
1681 negprot_global_auth_context,
1682 user_info,
1683 &server_info);
1685 } else {
1686 struct auth_context *plaintext_auth_context = NULL;
1687 const uint8 *chal;
1689 nt_status = make_auth_context_subsystem(
1690 &plaintext_auth_context);
1692 if (NT_STATUS_IS_OK(nt_status)) {
1693 chal = plaintext_auth_context->get_ntlm_challenge(
1694 plaintext_auth_context);
1696 if (!make_user_info_for_reply(&user_info,
1697 user, domain, chal,
1698 plaintext_password)) {
1699 nt_status = NT_STATUS_NO_MEMORY;
1702 if (NT_STATUS_IS_OK(nt_status)) {
1703 nt_status = plaintext_auth_context->check_ntlm_password(
1704 plaintext_auth_context,
1705 user_info,
1706 &server_info);
1708 (plaintext_auth_context->free)(
1709 &plaintext_auth_context);
1714 free_user_info(&user_info);
1716 if (!NT_STATUS_IS_OK(nt_status)) {
1717 nt_status = do_map_to_guest(nt_status, &server_info,
1718 user, domain);
1721 if (!NT_STATUS_IS_OK(nt_status)) {
1722 data_blob_free(&nt_resp);
1723 data_blob_free(&lm_resp);
1724 data_blob_clear_free(&plaintext_password);
1725 reply_nterror(req, nt_status_squash(nt_status));
1726 END_PROFILE(SMBsesssetupX);
1727 return;
1730 /* Ensure we can't possible take a code path leading to a
1731 * null defref. */
1732 if (!server_info) {
1733 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1734 END_PROFILE(SMBsesssetupX);
1735 return;
1738 if (!server_info->ptok) {
1739 nt_status = create_local_token(server_info);
1741 if (!NT_STATUS_IS_OK(nt_status)) {
1742 DEBUG(10, ("create_local_token failed: %s\n",
1743 nt_errstr(nt_status)));
1744 data_blob_free(&nt_resp);
1745 data_blob_free(&lm_resp);
1746 data_blob_clear_free(&plaintext_password);
1747 reply_nterror(req, nt_status_squash(nt_status));
1748 END_PROFILE(SMBsesssetupX);
1749 return;
1753 if (server_info->user_session_key.data) {
1754 session_key = data_blob(server_info->user_session_key.data,
1755 server_info->user_session_key.length);
1756 } else {
1757 session_key = data_blob_null;
1760 data_blob_clear_free(&plaintext_password);
1762 /* it's ok - setup a reply */
1763 reply_outbuf(req, 3, 0);
1764 if (Protocol >= PROTOCOL_NT1) {
1765 push_signature(&req->outbuf);
1766 /* perhaps grab OS version here?? */
1769 if (server_info->guest) {
1770 SSVAL(req->outbuf,smb_vwv2,1);
1773 /* register the name and uid as being validated, so further connections
1774 to a uid can get through without a password, on the same VC */
1776 if (lp_security() == SEC_SHARE) {
1777 sess_vuid = UID_FIELD_INVALID;
1778 data_blob_free(&session_key);
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 data_blob_free(&session_key);
1787 reply_nterror(req, nt_status_squash(
1788 NT_STATUS_LOGON_FAILURE));
1789 END_PROFILE(SMBsesssetupX);
1790 return;
1792 /* register_existing_vuid keeps the server info */
1793 sess_vuid = register_existing_vuid(sess_vuid,
1794 server_info,
1795 session_key,
1796 nt_resp.data ? nt_resp : lm_resp,
1797 sub_user);
1798 if (sess_vuid == UID_FIELD_INVALID) {
1799 data_blob_free(&nt_resp);
1800 data_blob_free(&lm_resp);
1801 data_blob_free(&session_key);
1802 reply_nterror(req, nt_status_squash(
1803 NT_STATUS_LOGON_FAILURE));
1804 END_PROFILE(SMBsesssetupX);
1805 return;
1808 /* current_user_info is changed on new vuid */
1809 reload_services( True );
1811 sessionsetup_start_signing_engine(server_info, req->inbuf);
1814 data_blob_free(&nt_resp);
1815 data_blob_free(&lm_resp);
1817 SSVAL(req->outbuf,smb_uid,sess_vuid);
1818 SSVAL(req->inbuf,smb_uid,sess_vuid);
1820 if (!done_sesssetup)
1821 max_send = MIN(max_send,smb_bufsize);
1823 done_sesssetup = True;
1825 END_PROFILE(SMBsesssetupX);
1826 chain_reply(req);
1827 return;