2 Unix SMB/CIFS implementation.
5 Copyright (C) Stefan Metzmacher 2009
6 Copyright (C) Jeremy Allison 2010
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "smbd/globals.h"
24 #include "../libcli/smb/smb_common.h"
25 #include "../libcli/auth/spnego.h"
26 #include "../libcli/auth/ntlmssp.h"
28 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
29 uint64_t in_session_id,
30 uint8_t in_security_mode,
31 DATA_BLOB in_security_buffer,
32 uint16_t *out_session_flags,
33 DATA_BLOB *out_security_buffer,
34 uint64_t *out_session_id);
36 NTSTATUS smbd_smb2_request_process_sesssetup(struct smbd_smb2_request *smb2req)
39 const uint8_t *inbody;
40 int i = smb2req->current_idx;
44 size_t expected_body_size = 0x19;
46 uint64_t in_session_id;
47 uint8_t in_security_mode;
48 uint16_t in_security_offset;
49 uint16_t in_security_length;
50 DATA_BLOB in_security_buffer;
51 uint16_t out_session_flags;
52 uint64_t out_session_id;
53 uint16_t out_security_offset;
54 DATA_BLOB out_security_buffer;
57 inhdr = (const uint8_t *)smb2req->in.vector[i+0].iov_base;
59 if (smb2req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
60 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
63 inbody = (const uint8_t *)smb2req->in.vector[i+1].iov_base;
65 body_size = SVAL(inbody, 0x00);
66 if (body_size != expected_body_size) {
67 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
70 in_security_offset = SVAL(inbody, 0x0C);
71 in_security_length = SVAL(inbody, 0x0E);
73 if (in_security_offset != (SMB2_HDR_BODY + (body_size & 0xFFFFFFFE))) {
74 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
77 if (in_security_length > smb2req->in.vector[i+2].iov_len) {
78 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
81 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
82 in_security_mode = CVAL(inbody, 0x03);
83 in_security_buffer.data = (uint8_t *)smb2req->in.vector[i+2].iov_base;
84 in_security_buffer.length = in_security_length;
86 status = smbd_smb2_session_setup(smb2req,
93 if (!NT_STATUS_IS_OK(status) &&
94 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
95 status = nt_status_squash(status);
96 return smbd_smb2_request_error(smb2req, status);
99 out_security_offset = SMB2_HDR_BODY + 0x08;
101 outhdr = (uint8_t *)smb2req->out.vector[i].iov_base;
103 outbody = data_blob_talloc(smb2req->out.vector, NULL, 0x08);
104 if (outbody.data == NULL) {
105 return smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
108 SBVAL(outhdr, SMB2_HDR_SESSION_ID, out_session_id);
110 SSVAL(outbody.data, 0x00, 0x08 + 1); /* struct size */
111 SSVAL(outbody.data, 0x02,
112 out_session_flags); /* session flags */
113 SSVAL(outbody.data, 0x04,
114 out_security_offset); /* security buffer offset */
115 SSVAL(outbody.data, 0x06,
116 out_security_buffer.length); /* security buffer length */
118 outdyn = out_security_buffer;
120 return smbd_smb2_request_done_ex(smb2req, status, outbody, &outdyn,
124 static int smbd_smb2_session_destructor(struct smbd_smb2_session *session)
126 if (session->sconn == NULL) {
130 /* first free all tcons */
131 while (session->tcons.list) {
132 talloc_free(session->tcons.list);
135 idr_remove(session->sconn->smb2.sessions.idtree, session->vuid);
136 DLIST_REMOVE(session->sconn->smb2.sessions.list, session);
137 invalidate_vuid(session->sconn, session->vuid);
140 session->status = NT_STATUS_USER_SESSION_DELETED;
141 session->sconn = NULL;
147 static NTSTATUS smbd_smb2_session_setup_krb5(struct smbd_smb2_session *session,
148 struct smbd_smb2_request *smb2req,
149 uint8_t in_security_mode,
150 const DATA_BLOB *secblob,
152 uint16_t *out_session_flags,
153 DATA_BLOB *out_security_buffer,
154 uint64_t *out_session_id)
156 DATA_BLOB ap_rep = data_blob_null;
157 DATA_BLOB ap_rep_wrapped = data_blob_null;
158 DATA_BLOB ticket = data_blob_null;
159 DATA_BLOB session_key = data_blob_null;
160 DATA_BLOB secblob_out = data_blob_null;
162 struct PAC_LOGON_INFO *logon_info = NULL;
166 struct passwd *pw = NULL;
169 fstring real_username;
171 bool username_was_mapped = false;
172 bool map_domainuser_to_guest = false;
174 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
175 status = NT_STATUS_LOGON_FAILURE;
179 status = ads_verify_ticket(smb2req, lp_realm(), 0, &ticket,
180 &client, &logon_info, &ap_rep,
183 if (!NT_STATUS_IS_OK(status)) {
184 DEBUG(1,("smb2: Failed to verify incoming ticket with error %s!\n",
186 if (!NT_STATUS_EQUAL(status, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
187 status = NT_STATUS_LOGON_FAILURE;
192 DEBUG(3,("smb2: Ticket name is [%s]\n", client));
194 p = strchr_m(client, '@');
196 DEBUG(3,("smb2: %s Doesn't look like a valid principal\n",
198 status = NT_STATUS_LOGON_FAILURE;
204 /* save the PAC data if we have it */
207 netsamlogon_cache_store(client, &logon_info->info3);
210 if (!strequal(p+1, lp_realm())) {
211 DEBUG(3,("smb2: Ticket for foreign realm %s@%s\n", client, p+1));
212 if (!lp_allow_trusted_domains()) {
213 status = NT_STATUS_LOGON_FAILURE;
218 /* this gives a fully qualified user name (ie. with full realm).
219 that leads to very long usernames, but what else can we do? */
223 if (logon_info && logon_info->info3.base.domain.string) {
224 domain = talloc_strdup(talloc_tos(),
225 logon_info->info3.base.domain.string);
227 status = NT_STATUS_NO_MEMORY;
230 DEBUG(10, ("smb2: Mapped to [%s] (using PAC)\n", domain));
233 /* If we have winbind running, we can (and must) shorten the
234 username by using the short netbios name. Otherwise we will
235 have inconsistent user names. With Kerberos, we get the
236 fully qualified realm, with ntlmssp we get the short
237 name. And even w2k3 does use ntlmssp if you for example
238 connect to an ip address. */
241 struct wbcDomainInfo *info = NULL;
243 DEBUG(10, ("smb2: Mapping [%s] to short name\n", domain));
245 wbc_status = wbcDomainInfo(domain, &info);
247 if (WBC_ERROR_IS_OK(wbc_status)) {
248 domain = talloc_strdup(talloc_tos(), info->short_name);
252 status = NT_STATUS_NO_MEMORY;
255 DEBUG(10, ("smb2: Mapped to [%s] (using Winbind)\n", domain));
257 DEBUG(3, ("smb2: Could not find short name: %s\n",
258 wbcErrorString(wbc_status)));
262 /* We have to use fstring for this - map_username requires it. */
263 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
265 /* lookup the passwd struct, create a new user if necessary */
267 username_was_mapped = map_username(user);
269 pw = smb_getpwnam(talloc_tos(), user, real_username, true );
271 /* if a real user check pam account restrictions */
272 /* only really perfomed if "obey pam restriction" is true */
273 /* do this before an eventual mapping to guest occurs */
274 status = smb_pam_accountcheck(pw->pw_name);
275 if (!NT_STATUS_IS_OK(status)) {
276 DEBUG(1,("smb2: PAM account restriction "
277 "prevents user login\n"));
284 /* this was originally the behavior of Samba 2.2, if a user
285 did not have a local uid but has been authenticated, then
286 map them to a guest account */
288 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
289 map_domainuser_to_guest = true;
290 fstrcpy(user,lp_guestaccount());
291 pw = smb_getpwnam(talloc_tos(), user, real_username, true );
294 /* extra sanity check that the guest account is valid */
297 DEBUG(1,("smb2: Username %s is invalid on this system\n",
299 status = NT_STATUS_LOGON_FAILURE;
304 /* setup the string used by %U */
306 sub_set_smb_name(real_username);
307 reload_services(true);
309 if (map_domainuser_to_guest) {
310 make_server_info_guest(session, &session->server_info);
311 } else if (logon_info) {
312 /* pass the unmapped username here since map_username()
313 will be called again from inside make_server_info_info3() */
315 status = make_server_info_info3(session,
318 &session->server_info,
320 if (!NT_STATUS_IS_OK(status) ) {
321 DEBUG(1,("smb2: make_server_info_info3 failed: %s!\n",
328 * We didn't get a PAC, we have to make up the user
329 * ourselves. Try to ask the pdb backend to provide
330 * SID consistency with ntlmssp session setup
332 struct samu *sampass;
333 /* The stupid make_server_info_XX functions here
334 don't take a talloc context. */
335 struct auth_serversupplied_info *tmp_server_info = NULL;
337 sampass = samu_new(talloc_tos());
338 if (sampass == NULL) {
339 status = NT_STATUS_NO_MEMORY;
343 if (pdb_getsampwnam(sampass, real_username)) {
344 DEBUG(10, ("smb2: found user %s in passdb, calling "
345 "make_server_info_sam\n", real_username));
346 status = make_server_info_sam(&tmp_server_info, sampass);
347 TALLOC_FREE(sampass);
350 * User not in passdb, make it up artificially
352 TALLOC_FREE(sampass);
353 DEBUG(10, ("smb2: didn't find user %s in passdb, calling "
354 "make_server_info_pw\n", real_username));
355 status = make_server_info_pw(&tmp_server_info,
360 if (!NT_STATUS_IS_OK(status)) {
361 DEBUG(1,("smb2: make_server_info_[sam|pw] failed: %s!\n",
366 /* Steal tmp_server_info into the session->server_info
368 session->server_info = talloc_move(session, &tmp_server_info);
370 /* make_server_info_pw does not set the domain. Without this
371 * we end up with the local netbios name in substitutions for
374 if (session->server_info->info3 != NULL) {
375 session->server_info->info3->base.domain.string =
376 talloc_strdup(session->server_info->info3, domain);
381 session->server_info->nss_token |= username_was_mapped;
383 /* we need to build the token for the user. make_server_info_guest()
386 if (!session->server_info->ptok ) {
387 status = create_local_token(session->server_info);
388 if (!NT_STATUS_IS_OK(status)) {
389 DEBUG(10,("smb2: failed to create local token: %s\n",
395 if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
396 lp_server_signing() == Required) {
397 session->do_signing = true;
400 if (session->server_info->guest) {
401 /* we map anonymous to guest internally */
402 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
403 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
404 /* force no signing */
405 session->do_signing = false;
408 data_blob_free(&session->server_info->user_session_key);
409 session->server_info->user_session_key =
411 session->server_info,
414 if (session_key.length > 0) {
415 if (session->server_info->user_session_key.data == NULL) {
416 status = NT_STATUS_NO_MEMORY;
420 session->session_key = session->server_info->user_session_key;
422 session->compat_vuser = talloc_zero(session, user_struct);
423 if (session->compat_vuser == NULL) {
424 status = NT_STATUS_NO_MEMORY;
427 session->compat_vuser->auth_ntlmssp_state = NULL;
428 session->compat_vuser->homes_snum = -1;
429 session->compat_vuser->server_info = session->server_info;
430 session->compat_vuser->session_keystr = NULL;
431 session->compat_vuser->vuid = session->vuid;
432 DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
434 /* This is a potentially untrusted username */
439 session->server_info->sanitized_username = talloc_strdup(
440 session->server_info, tmp);
442 if (!session->server_info->guest) {
443 session->compat_vuser->homes_snum =
444 register_homes_share(session->server_info->unix_name);
447 if (!session_claim(session->compat_vuser)) {
448 DEBUG(1, ("smb2: Failed to claim session "
450 session->compat_vuser->vuid));
454 session->status = NT_STATUS_OK;
457 * we attach the session to the request
458 * so that the response can be signed
460 smb2req->session = session;
461 if (session->do_signing) {
462 smb2req->do_signing = true;
465 global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
466 status = NT_STATUS_OK;
468 /* wrap that up in a nice GSS-API wrapping */
469 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
472 secblob_out = spnego_gen_auth_response(
477 *out_security_buffer = data_blob_talloc(smb2req,
480 if (secblob_out.data && out_security_buffer->data == NULL) {
481 status = NT_STATUS_NO_MEMORY;
485 data_blob_free(&ap_rep);
486 data_blob_free(&ap_rep_wrapped);
487 data_blob_free(&ticket);
488 data_blob_free(&session_key);
489 data_blob_free(&secblob_out);
491 *out_session_id = session->vuid;
497 data_blob_free(&ap_rep);
498 data_blob_free(&ap_rep_wrapped);
499 data_blob_free(&ticket);
500 data_blob_free(&session_key);
501 data_blob_free(&secblob_out);
503 ap_rep_wrapped = data_blob_null;
504 secblob_out = spnego_gen_auth_response(
509 *out_security_buffer = data_blob_talloc(smb2req,
512 data_blob_free(&secblob_out);
517 static NTSTATUS smbd_smb2_spnego_negotiate(struct smbd_smb2_session *session,
518 struct smbd_smb2_request *smb2req,
519 uint8_t in_security_mode,
520 DATA_BLOB in_security_buffer,
521 uint16_t *out_session_flags,
522 DATA_BLOB *out_security_buffer,
523 uint64_t *out_session_id)
525 DATA_BLOB secblob_in = data_blob_null;
526 DATA_BLOB chal_out = data_blob_null;
527 DATA_BLOB secblob_out = data_blob_null;
528 char *kerb_mech = NULL;
531 /* Ensure we have no old NTLM state around. */
532 auth_ntlmssp_end(&session->auth_ntlmssp_state);
534 status = parse_spnego_mechanisms(in_security_buffer,
535 &secblob_in, &kerb_mech);
536 if (!NT_STATUS_IS_OK(status)) {
541 if (kerb_mech && ((lp_security()==SEC_ADS) ||
542 USE_KERBEROS_KEYTAB) ) {
543 status = smbd_smb2_session_setup_krb5(session,
557 /* The mechtoken is a krb5 ticket, but
558 * we need to fall back to NTLM. */
560 DEBUG(3,("smb2: Got krb5 ticket in SPNEGO "
561 "but set to downgrade to NTLMSSP\n"));
563 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
565 /* Fall back to NTLMSSP. */
566 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
567 if (!NT_STATUS_IS_OK(status)) {
571 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
576 if (!NT_STATUS_IS_OK(status) &&
577 !NT_STATUS_EQUAL(status,
578 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
582 secblob_out = spnego_gen_auth_response(&chal_out,
585 *out_security_buffer = data_blob_talloc(smb2req,
588 if (secblob_out.data && out_security_buffer->data == NULL) {
589 status = NT_STATUS_NO_MEMORY;
592 *out_session_id = session->vuid;
596 data_blob_free(&secblob_in);
597 data_blob_free(&secblob_out);
598 data_blob_free(&chal_out);
599 SAFE_FREE(kerb_mech);
600 if (!NT_STATUS_IS_OK(status) &&
601 !NT_STATUS_EQUAL(status,
602 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
603 auth_ntlmssp_end(&session->auth_ntlmssp_state);
604 TALLOC_FREE(session);
609 static NTSTATUS smbd_smb2_common_ntlmssp_auth_return(struct smbd_smb2_session *session,
610 struct smbd_smb2_request *smb2req,
611 uint8_t in_security_mode,
612 DATA_BLOB in_security_buffer,
613 uint16_t *out_session_flags,
614 uint64_t *out_session_id)
617 NTSTATUS status = auth_ntlmssp_server_info(session, session->auth_ntlmssp_state,
618 &session->server_info);
619 if (!NT_STATUS_IS_OK(status)) {
620 auth_ntlmssp_end(&session->auth_ntlmssp_state);
621 TALLOC_FREE(session);
625 if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
626 lp_server_signing() == Required) {
627 session->do_signing = true;
630 if (session->server_info->guest) {
631 /* we map anonymous to guest internally */
632 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
633 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
634 /* force no signing */
635 session->do_signing = false;
638 session->session_key = session->server_info->user_session_key;
640 session->compat_vuser = talloc_zero(session, user_struct);
641 if (session->compat_vuser == NULL) {
642 auth_ntlmssp_end(&session->auth_ntlmssp_state);
643 TALLOC_FREE(session);
644 return NT_STATUS_NO_MEMORY;
646 session->compat_vuser->auth_ntlmssp_state = session->auth_ntlmssp_state;
647 session->compat_vuser->homes_snum = -1;
648 session->compat_vuser->server_info = session->server_info;
649 session->compat_vuser->session_keystr = NULL;
650 session->compat_vuser->vuid = session->vuid;
651 DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
653 /* This is a potentially untrusted username */
655 auth_ntlmssp_get_username(session->auth_ntlmssp_state),
658 session->server_info->sanitized_username = talloc_strdup(
659 session->server_info, tmp);
661 if (!session->compat_vuser->server_info->guest) {
662 session->compat_vuser->homes_snum =
663 register_homes_share(session->server_info->unix_name);
666 if (!session_claim(session->compat_vuser)) {
667 DEBUG(1, ("smb2: Failed to claim session "
669 session->compat_vuser->vuid));
670 auth_ntlmssp_end(&session->auth_ntlmssp_state);
671 TALLOC_FREE(session);
672 return NT_STATUS_LOGON_FAILURE;
676 session->status = NT_STATUS_OK;
679 * we attach the session to the request
680 * so that the response can be signed
682 smb2req->session = session;
683 if (session->do_signing) {
684 smb2req->do_signing = true;
687 global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
689 *out_session_id = session->vuid;
694 static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
695 struct smbd_smb2_request *smb2req,
696 uint8_t in_security_mode,
697 DATA_BLOB in_security_buffer,
698 uint16_t *out_session_flags,
699 DATA_BLOB *out_security_buffer,
700 uint64_t *out_session_id)
702 DATA_BLOB auth = data_blob_null;
703 DATA_BLOB auth_out = data_blob_null;
704 DATA_BLOB secblob_out = data_blob_null;
707 if (!spnego_parse_auth(in_security_buffer, &auth)) {
708 TALLOC_FREE(session);
709 return NT_STATUS_LOGON_FAILURE;
712 if (auth.data[0] == ASN1_APPLICATION(0)) {
713 /* Might be a second negTokenTarg packet */
714 DATA_BLOB secblob_in = data_blob_null;
715 char *kerb_mech = NULL;
717 status = parse_spnego_mechanisms(in_security_buffer,
718 &secblob_in, &kerb_mech);
719 if (!NT_STATUS_IS_OK(status)) {
720 TALLOC_FREE(session);
725 if (kerb_mech && ((lp_security()==SEC_ADS) ||
726 USE_KERBEROS_KEYTAB) ) {
727 status = smbd_smb2_session_setup_krb5(session,
736 data_blob_free(&secblob_in);
737 SAFE_FREE(kerb_mech);
738 if (!NT_STATUS_IS_OK(status)) {
739 TALLOC_FREE(session);
745 /* Can't blunder into NTLMSSP auth if we have
749 DEBUG(3,("smb2: network "
750 "misconfiguration, client sent us a "
751 "krb5 ticket and kerberos security "
753 TALLOC_FREE(session);
754 data_blob_free(&secblob_in);
755 SAFE_FREE(kerb_mech);
756 return NT_STATUS_LOGON_FAILURE;
759 data_blob_free(&secblob_in);
762 if (session->auth_ntlmssp_state == NULL) {
763 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
764 if (!NT_STATUS_IS_OK(status)) {
765 data_blob_free(&auth);
766 TALLOC_FREE(session);
771 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
774 if (!NT_STATUS_IS_OK(status) &&
775 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
776 auth_ntlmssp_end(&session->auth_ntlmssp_state);
777 data_blob_free(&auth);
778 TALLOC_FREE(session);
782 data_blob_free(&auth);
784 secblob_out = spnego_gen_auth_response(&auth_out,
787 *out_security_buffer = data_blob_talloc(smb2req,
790 if (secblob_out.data && out_security_buffer->data == NULL) {
791 auth_ntlmssp_end(&session->auth_ntlmssp_state);
792 TALLOC_FREE(session);
793 return NT_STATUS_NO_MEMORY;
796 *out_session_id = session->vuid;
798 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
799 return NT_STATUS_MORE_PROCESSING_REQUIRED;
802 /* We're done - claim the session. */
803 return smbd_smb2_common_ntlmssp_auth_return(session,
811 static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session,
812 struct smbd_smb2_request *smb2req,
813 uint8_t in_security_mode,
814 DATA_BLOB in_security_buffer,
815 uint16_t *out_session_flags,
816 DATA_BLOB *out_security_buffer,
817 uint64_t *out_session_id)
820 DATA_BLOB secblob_out = data_blob_null;
822 if (session->auth_ntlmssp_state == NULL) {
823 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
824 if (!NT_STATUS_IS_OK(status)) {
825 TALLOC_FREE(session);
831 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
835 if (NT_STATUS_IS_OK(status) ||
836 NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
837 *out_security_buffer = data_blob_talloc(smb2req,
840 if (secblob_out.data && out_security_buffer->data == NULL) {
841 auth_ntlmssp_end(&session->auth_ntlmssp_state);
842 TALLOC_FREE(session);
843 return NT_STATUS_NO_MEMORY;
847 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
848 *out_session_id = session->vuid;
851 if (!NT_STATUS_IS_OK(status)) {
852 auth_ntlmssp_end(&session->auth_ntlmssp_state);
853 TALLOC_FREE(session);
856 *out_session_id = session->vuid;
858 return smbd_smb2_common_ntlmssp_auth_return(session,
866 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
867 uint64_t in_session_id,
868 uint8_t in_security_mode,
869 DATA_BLOB in_security_buffer,
870 uint16_t *out_session_flags,
871 DATA_BLOB *out_security_buffer,
872 uint64_t *out_session_id)
874 struct smbd_smb2_session *session;
876 *out_session_flags = 0;
879 if (in_session_id == 0) {
882 /* create a new session */
883 session = talloc_zero(smb2req->sconn, struct smbd_smb2_session);
884 if (session == NULL) {
885 return NT_STATUS_NO_MEMORY;
887 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
888 id = idr_get_new_random(smb2req->sconn->smb2.sessions.idtree,
890 smb2req->sconn->smb2.sessions.limit);
892 return NT_STATUS_INSUFFICIENT_RESOURCES;
896 session->tcons.idtree = idr_init(session);
897 if (session->tcons.idtree == NULL) {
898 return NT_STATUS_NO_MEMORY;
900 session->tcons.limit = 0x0000FFFE;
901 session->tcons.list = NULL;
903 DLIST_ADD_END(smb2req->sconn->smb2.sessions.list, session,
904 struct smbd_smb2_session *);
905 session->sconn = smb2req->sconn;
906 talloc_set_destructor(session, smbd_smb2_session_destructor);
910 /* lookup an existing session */
911 p = idr_find(smb2req->sconn->smb2.sessions.idtree, in_session_id);
913 return NT_STATUS_USER_SESSION_DELETED;
915 session = talloc_get_type_abort(p, struct smbd_smb2_session);
918 if (NT_STATUS_IS_OK(session->status)) {
919 return NT_STATUS_REQUEST_NOT_ACCEPTED;
922 if (in_security_buffer.data[0] == ASN1_APPLICATION(0)) {
923 return smbd_smb2_spnego_negotiate(session,
930 } else if (in_security_buffer.data[0] == ASN1_CONTEXT(1)) {
931 return smbd_smb2_spnego_auth(session,
938 } else if (strncmp((char *)(in_security_buffer.data), "NTLMSSP", 7) == 0) {
939 return smbd_smb2_raw_ntlmssp_auth(session,
948 /* Unknown packet type. */
949 DEBUG(1,("Unknown packet type %u in smb2 sessionsetup\n",
950 (unsigned int)in_security_buffer.data[0] ));
951 auth_ntlmssp_end(&session->auth_ntlmssp_state);
952 TALLOC_FREE(session);
953 return NT_STATUS_LOGON_FAILURE;
956 NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
958 const uint8_t *inhdr;
959 const uint8_t *outhdr;
960 int i = req->current_idx;
961 uint64_t in_session_id;
963 struct smbd_smb2_session *session;
964 bool chained_fixup = false;
966 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
968 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
970 if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
973 * async request - fill in session_id from
974 * already setup request out.vector[].iov_base.
976 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
977 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
980 * Chained request - fill in session_id from
981 * the previous request out.vector[].iov_base.
983 outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
984 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
985 chained_fixup = true;
989 /* lookup an existing session */
990 p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
992 return NT_STATUS_USER_SESSION_DELETED;
994 session = talloc_get_type_abort(p, struct smbd_smb2_session);
996 if (!NT_STATUS_IS_OK(session->status)) {
997 return NT_STATUS_ACCESS_DENIED;
1000 set_current_user_info(session->server_info->sanitized_username,
1001 session->server_info->unix_name,
1002 session->server_info->info3->base.domain.string);
1004 req->session = session;
1006 if (chained_fixup) {
1007 /* Fix up our own outhdr. */
1008 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1009 SBVAL(outhdr, SMB2_HDR_SESSION_ID, in_session_id);
1011 return NT_STATUS_OK;
1014 NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req)
1016 const uint8_t *inbody;
1017 int i = req->current_idx;
1019 size_t expected_body_size = 0x04;
1022 if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
1023 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1026 inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
1028 body_size = SVAL(inbody, 0x00);
1029 if (body_size != expected_body_size) {
1030 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1034 * TODO: cancel all outstanding requests on the session
1035 * and delete all tree connections.
1037 smbd_smb2_session_destructor(req->session);
1039 * we may need to sign the response, so we need to keep
1040 * the session until the response is sent to the wire.
1042 talloc_steal(req, req->session);
1044 outbody = data_blob_talloc(req->out.vector, NULL, 0x04);
1045 if (outbody.data == NULL) {
1046 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
1049 SSVAL(outbody.data, 0x00, 0x04); /* struct size */
1050 SSVAL(outbody.data, 0x02, 0); /* reserved */
1052 return smbd_smb2_request_done(req, outbody, NULL);