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"
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;
173 struct smbd_server_connection *sconn = smbd_server_conn;
175 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
176 status = NT_STATUS_LOGON_FAILURE;
180 status = ads_verify_ticket(smb2req, lp_realm(), 0, &ticket,
181 &client, &logon_info, &ap_rep,
184 if (!NT_STATUS_IS_OK(status)) {
185 DEBUG(1,("smb2: Failed to verify incoming ticket with error %s!\n",
187 if (!NT_STATUS_EQUAL(status, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
188 status = NT_STATUS_LOGON_FAILURE;
193 DEBUG(3,("smb2: Ticket name is [%s]\n", client));
195 p = strchr_m(client, '@');
197 DEBUG(3,("smb2: %s Doesn't look like a valid principal\n",
199 status = NT_STATUS_LOGON_FAILURE;
205 /* save the PAC data if we have it */
208 netsamlogon_cache_store(client, &logon_info->info3);
211 if (!strequal(p+1, lp_realm())) {
212 DEBUG(3,("smb2: Ticket for foreign realm %s@%s\n", client, p+1));
213 if (!lp_allow_trusted_domains()) {
214 status = NT_STATUS_LOGON_FAILURE;
219 /* this gives a fully qualified user name (ie. with full realm).
220 that leads to very long usernames, but what else can we do? */
224 if (logon_info && logon_info->info3.base.domain.string) {
225 domain = talloc_strdup(talloc_tos(),
226 logon_info->info3.base.domain.string);
228 status = NT_STATUS_NO_MEMORY;
231 DEBUG(10, ("smb2: Mapped to [%s] (using PAC)\n", domain));
234 /* If we have winbind running, we can (and must) shorten the
235 username by using the short netbios name. Otherwise we will
236 have inconsistent user names. With Kerberos, we get the
237 fully qualified realm, with ntlmssp we get the short
238 name. And even w2k3 does use ntlmssp if you for example
239 connect to an ip address. */
242 struct wbcDomainInfo *info = NULL;
244 DEBUG(10, ("smb2: Mapping [%s] to short name\n", domain));
246 wbc_status = wbcDomainInfo(domain, &info);
248 if (WBC_ERROR_IS_OK(wbc_status)) {
249 domain = talloc_strdup(talloc_tos(), info->short_name);
253 status = NT_STATUS_NO_MEMORY;
256 DEBUG(10, ("smb2: Mapped to [%s] (using Winbind)\n", domain));
258 DEBUG(3, ("smb2: Could not find short name: %s\n",
259 wbcErrorString(wbc_status)));
263 /* We have to use fstring for this - map_username requires it. */
264 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
266 /* lookup the passwd struct, create a new user if necessary */
268 username_was_mapped = map_username(sconn, user);
270 pw = smb_getpwnam(talloc_tos(), user, real_username, true );
272 /* if a real user check pam account restrictions */
273 /* only really perfomed if "obey pam restriction" is true */
274 /* do this before an eventual mapping to guest occurs */
275 status = smb_pam_accountcheck(pw->pw_name);
276 if (!NT_STATUS_IS_OK(status)) {
277 DEBUG(1,("smb2: PAM account restriction "
278 "prevents user login\n"));
285 /* this was originally the behavior of Samba 2.2, if a user
286 did not have a local uid but has been authenticated, then
287 map them to a guest account */
289 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
290 map_domainuser_to_guest = true;
291 fstrcpy(user,lp_guestaccount());
292 pw = smb_getpwnam(talloc_tos(), user, real_username, true );
295 /* extra sanity check that the guest account is valid */
298 DEBUG(1,("smb2: Username %s is invalid on this system\n",
300 status = NT_STATUS_LOGON_FAILURE;
305 /* setup the string used by %U */
307 sub_set_smb_name(real_username);
308 reload_services(true);
310 if (map_domainuser_to_guest) {
311 make_server_info_guest(session, &session->server_info);
312 } else if (logon_info) {
313 /* pass the unmapped username here since map_username()
314 will be called again from inside make_server_info_info3() */
316 status = make_server_info_info3(session,
319 &session->server_info,
321 if (!NT_STATUS_IS_OK(status) ) {
322 DEBUG(1,("smb2: make_server_info_info3 failed: %s!\n",
329 * We didn't get a PAC, we have to make up the user
330 * ourselves. Try to ask the pdb backend to provide
331 * SID consistency with ntlmssp session setup
333 struct samu *sampass;
334 /* The stupid make_server_info_XX functions here
335 don't take a talloc context. */
336 struct auth_serversupplied_info *tmp_server_info = NULL;
338 sampass = samu_new(talloc_tos());
339 if (sampass == NULL) {
340 status = NT_STATUS_NO_MEMORY;
344 if (pdb_getsampwnam(sampass, real_username)) {
345 DEBUG(10, ("smb2: found user %s in passdb, calling "
346 "make_server_info_sam\n", real_username));
347 status = make_server_info_sam(&tmp_server_info, 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->sam_account != NULL) {
375 pdb_set_domain(session->server_info->sam_account,
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,
556 /* Fall back to NTLMSSP. */
557 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
558 if (!NT_STATUS_IS_OK(status)) {
562 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
566 if (!NT_STATUS_IS_OK(status) &&
567 !NT_STATUS_EQUAL(status,
568 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
572 secblob_out = spnego_gen_auth_response(&chal_out,
575 *out_security_buffer = data_blob_talloc(smb2req,
578 if (secblob_out.data && out_security_buffer->data == NULL) {
579 status = NT_STATUS_NO_MEMORY;
582 *out_session_id = session->vuid;
586 data_blob_free(&secblob_in);
587 data_blob_free(&secblob_out);
588 data_blob_free(&chal_out);
589 SAFE_FREE(kerb_mech);
590 if (!NT_STATUS_IS_OK(status) &&
591 !NT_STATUS_EQUAL(status,
592 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
593 auth_ntlmssp_end(&session->auth_ntlmssp_state);
594 TALLOC_FREE(session);
599 static NTSTATUS smbd_smb2_common_ntlmssp_auth_return(struct smbd_smb2_session *session,
600 struct smbd_smb2_request *smb2req,
601 uint8_t in_security_mode,
602 DATA_BLOB in_security_buffer,
603 uint16_t *out_session_flags,
604 uint64_t *out_session_id)
608 if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
609 lp_server_signing() == Required) {
610 session->do_signing = true;
613 if (session->auth_ntlmssp_state->server_info->guest) {
614 /* we map anonymous to guest internally */
615 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
616 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
617 /* force no signing */
618 session->do_signing = false;
621 session->server_info = session->auth_ntlmssp_state->server_info;
622 data_blob_free(&session->server_info->user_session_key);
623 session->server_info->user_session_key =
625 session->server_info,
626 session->auth_ntlmssp_state->ntlmssp_state->session_key.data,
627 session->auth_ntlmssp_state->ntlmssp_state->session_key.length);
628 if (session->auth_ntlmssp_state->ntlmssp_state->session_key.length > 0) {
629 if (session->server_info->user_session_key.data == NULL) {
630 auth_ntlmssp_end(&session->auth_ntlmssp_state);
631 TALLOC_FREE(session);
632 return NT_STATUS_NO_MEMORY;
635 session->session_key = session->server_info->user_session_key;
637 session->compat_vuser = talloc_zero(session, user_struct);
638 if (session->compat_vuser == NULL) {
639 auth_ntlmssp_end(&session->auth_ntlmssp_state);
640 TALLOC_FREE(session);
641 return NT_STATUS_NO_MEMORY;
643 session->compat_vuser->auth_ntlmssp_state = session->auth_ntlmssp_state;
644 session->compat_vuser->homes_snum = -1;
645 session->compat_vuser->server_info = session->server_info;
646 session->compat_vuser->session_keystr = NULL;
647 session->compat_vuser->vuid = session->vuid;
648 DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
650 /* This is a potentially untrusted username */
652 session->auth_ntlmssp_state->ntlmssp_state->user,
655 session->server_info->sanitized_username = talloc_strdup(
656 session->server_info, tmp);
658 if (!session->compat_vuser->server_info->guest) {
659 session->compat_vuser->homes_snum =
660 register_homes_share(session->server_info->unix_name);
663 if (!session_claim(session->compat_vuser)) {
664 DEBUG(1, ("smb2: Failed to claim session "
666 session->compat_vuser->vuid));
667 auth_ntlmssp_end(&session->auth_ntlmssp_state);
668 TALLOC_FREE(session);
669 return NT_STATUS_LOGON_FAILURE;
673 session->status = NT_STATUS_OK;
676 * we attach the session to the request
677 * so that the response can be signed
679 smb2req->session = session;
680 if (session->do_signing) {
681 smb2req->do_signing = true;
684 global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
686 *out_session_id = session->vuid;
691 static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
692 struct smbd_smb2_request *smb2req,
693 uint8_t in_security_mode,
694 DATA_BLOB in_security_buffer,
695 uint16_t *out_session_flags,
696 DATA_BLOB *out_security_buffer,
697 uint64_t *out_session_id)
699 DATA_BLOB auth = data_blob_null;
700 DATA_BLOB auth_out = data_blob_null;
701 DATA_BLOB secblob_out = data_blob_null;
704 if (!spnego_parse_auth(in_security_buffer, &auth)) {
705 TALLOC_FREE(session);
706 return NT_STATUS_LOGON_FAILURE;
709 if (auth.data[0] == ASN1_APPLICATION(0)) {
710 /* Might be a second negTokenTarg packet */
711 DATA_BLOB secblob_in = data_blob_null;
712 char *kerb_mech = NULL;
714 status = parse_spnego_mechanisms(in_security_buffer,
715 &secblob_in, &kerb_mech);
716 if (!NT_STATUS_IS_OK(status)) {
717 TALLOC_FREE(session);
722 if (kerb_mech && ((lp_security()==SEC_ADS) ||
723 USE_KERBEROS_KEYTAB) ) {
724 status = smbd_smb2_session_setup_krb5(session,
733 data_blob_free(&secblob_in);
734 SAFE_FREE(kerb_mech);
735 if (!NT_STATUS_IS_OK(status)) {
736 TALLOC_FREE(session);
742 /* Can't blunder into NTLMSSP auth if we have
746 DEBUG(3,("smb2: network "
747 "misconfiguration, client sent us a "
748 "krb5 ticket and kerberos security "
750 TALLOC_FREE(session);
751 data_blob_free(&secblob_in);
752 SAFE_FREE(kerb_mech);
753 return NT_STATUS_LOGON_FAILURE;
757 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
760 if (!NT_STATUS_IS_OK(status)) {
761 auth_ntlmssp_end(&session->auth_ntlmssp_state);
762 data_blob_free(&auth);
763 TALLOC_FREE(session);
767 data_blob_free(&auth);
769 secblob_out = spnego_gen_auth_response(&auth_out,
772 *out_security_buffer = data_blob_talloc(smb2req,
775 if (secblob_out.data && out_security_buffer->data == NULL) {
776 auth_ntlmssp_end(&session->auth_ntlmssp_state);
777 TALLOC_FREE(session);
778 return NT_STATUS_NO_MEMORY;
781 *out_session_id = session->vuid;
783 return smbd_smb2_common_ntlmssp_auth_return(session,
791 static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session,
792 struct smbd_smb2_request *smb2req,
793 uint8_t in_security_mode,
794 DATA_BLOB in_security_buffer,
795 uint16_t *out_session_flags,
796 DATA_BLOB *out_security_buffer,
797 uint64_t *out_session_id)
800 DATA_BLOB secblob_out = data_blob_null;
802 if (session->auth_ntlmssp_state == NULL) {
803 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
804 if (!NT_STATUS_IS_OK(status)) {
805 TALLOC_FREE(session);
811 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
815 if (NT_STATUS_IS_OK(status) ||
816 NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
817 *out_security_buffer = data_blob_talloc(smb2req,
820 if (secblob_out.data && out_security_buffer->data == NULL) {
821 auth_ntlmssp_end(&session->auth_ntlmssp_state);
822 TALLOC_FREE(session);
823 return NT_STATUS_NO_MEMORY;
827 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
828 *out_session_id = session->vuid;
831 if (!NT_STATUS_IS_OK(status)) {
832 auth_ntlmssp_end(&session->auth_ntlmssp_state);
833 TALLOC_FREE(session);
836 *out_session_id = session->vuid;
838 return smbd_smb2_common_ntlmssp_auth_return(session,
846 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
847 uint64_t in_session_id,
848 uint8_t in_security_mode,
849 DATA_BLOB in_security_buffer,
850 uint16_t *out_session_flags,
851 DATA_BLOB *out_security_buffer,
852 uint64_t *out_session_id)
854 struct smbd_smb2_session *session;
856 *out_session_flags = 0;
859 if (in_session_id == 0) {
862 /* create a new session */
863 session = talloc_zero(smb2req->sconn, struct smbd_smb2_session);
864 if (session == NULL) {
865 return NT_STATUS_NO_MEMORY;
867 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
868 id = idr_get_new_random(smb2req->sconn->smb2.sessions.idtree,
870 smb2req->sconn->smb2.sessions.limit);
872 return NT_STATUS_INSUFFICIENT_RESOURCES;
876 session->tcons.idtree = idr_init(session);
877 if (session->tcons.idtree == NULL) {
878 return NT_STATUS_NO_MEMORY;
880 session->tcons.limit = 0x0000FFFE;
881 session->tcons.list = NULL;
883 DLIST_ADD_END(smb2req->sconn->smb2.sessions.list, session,
884 struct smbd_smb2_session *);
885 session->sconn = smb2req->sconn;
886 talloc_set_destructor(session, smbd_smb2_session_destructor);
890 /* lookup an existing session */
891 p = idr_find(smb2req->sconn->smb2.sessions.idtree, in_session_id);
893 return NT_STATUS_USER_SESSION_DELETED;
895 session = talloc_get_type_abort(p, struct smbd_smb2_session);
898 if (NT_STATUS_IS_OK(session->status)) {
899 return NT_STATUS_REQUEST_NOT_ACCEPTED;
902 if (in_security_buffer.data[0] == ASN1_APPLICATION(0)) {
903 return smbd_smb2_spnego_negotiate(session,
910 } else if (in_security_buffer.data[0] == ASN1_CONTEXT(1)) {
911 return smbd_smb2_spnego_auth(session,
918 } else if (strncmp((char *)(in_security_buffer.data), "NTLMSSP", 7) == 0) {
919 return smbd_smb2_raw_ntlmssp_auth(session,
928 /* Unknown packet type. */
929 DEBUG(1,("Unknown packet type %u in smb2 sessionsetup\n",
930 (unsigned int)in_security_buffer.data[0] ));
931 auth_ntlmssp_end(&session->auth_ntlmssp_state);
932 TALLOC_FREE(session);
933 return NT_STATUS_LOGON_FAILURE;
936 NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
938 const uint8_t *inhdr;
939 const uint8_t *outhdr;
940 int i = req->current_idx;
941 uint64_t in_session_id;
943 struct smbd_smb2_session *session;
944 bool chained_fixup = false;
946 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
948 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
950 if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
953 * async request - fill in session_id from
954 * already setup request out.vector[].iov_base.
956 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
957 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
960 * Chained request - fill in session_id from
961 * the previous request out.vector[].iov_base.
963 outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
964 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
965 chained_fixup = true;
969 /* lookup an existing session */
970 p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
972 return NT_STATUS_USER_SESSION_DELETED;
974 session = talloc_get_type_abort(p, struct smbd_smb2_session);
976 if (!NT_STATUS_IS_OK(session->status)) {
977 return NT_STATUS_ACCESS_DENIED;
980 set_current_user_info(session->server_info->sanitized_username,
981 session->server_info->unix_name,
982 pdb_get_domain(session->server_info->sam_account));
984 req->session = session;
987 /* Fix up our own outhdr. */
988 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
989 SBVAL(outhdr, SMB2_HDR_SESSION_ID, in_session_id);
994 NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req)
996 const uint8_t *inbody;
997 int i = req->current_idx;
999 size_t expected_body_size = 0x04;
1002 if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
1003 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1006 inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
1008 body_size = SVAL(inbody, 0x00);
1009 if (body_size != expected_body_size) {
1010 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1014 * TODO: cancel all outstanding requests on the session
1015 * and delete all tree connections.
1017 smbd_smb2_session_destructor(req->session);
1019 * we may need to sign the response, so we need to keep
1020 * the session until the response is sent to the wire.
1022 talloc_steal(req, req->session);
1024 outbody = data_blob_talloc(req->out.vector, NULL, 0x04);
1025 if (outbody.data == NULL) {
1026 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
1029 SSVAL(outbody.data, 0x00, 0x04); /* struct size */
1030 SSVAL(outbody.data, 0x02, 0); /* reserved */
1032 return smbd_smb2_request_done(req, outbody, NULL);