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(sconn_server_id(session->sconn),
448 session->compat_vuser)) {
449 DEBUG(1, ("smb2: Failed to claim session "
451 session->compat_vuser->vuid));
455 session->status = NT_STATUS_OK;
458 * we attach the session to the request
459 * so that the response can be signed
461 smb2req->session = session;
462 if (session->do_signing) {
463 smb2req->do_signing = true;
466 global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
467 status = NT_STATUS_OK;
469 /* wrap that up in a nice GSS-API wrapping */
470 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
473 secblob_out = spnego_gen_auth_response(
478 *out_security_buffer = data_blob_talloc(smb2req,
481 if (secblob_out.data && out_security_buffer->data == NULL) {
482 status = NT_STATUS_NO_MEMORY;
486 data_blob_free(&ap_rep);
487 data_blob_free(&ap_rep_wrapped);
488 data_blob_free(&ticket);
489 data_blob_free(&session_key);
490 data_blob_free(&secblob_out);
492 *out_session_id = session->vuid;
498 data_blob_free(&ap_rep);
499 data_blob_free(&ap_rep_wrapped);
500 data_blob_free(&ticket);
501 data_blob_free(&session_key);
502 data_blob_free(&secblob_out);
504 ap_rep_wrapped = data_blob_null;
505 secblob_out = spnego_gen_auth_response(
510 *out_security_buffer = data_blob_talloc(smb2req,
513 data_blob_free(&secblob_out);
518 static NTSTATUS smbd_smb2_spnego_negotiate(struct smbd_smb2_session *session,
519 struct smbd_smb2_request *smb2req,
520 uint8_t in_security_mode,
521 DATA_BLOB in_security_buffer,
522 uint16_t *out_session_flags,
523 DATA_BLOB *out_security_buffer,
524 uint64_t *out_session_id)
526 DATA_BLOB secblob_in = data_blob_null;
527 DATA_BLOB chal_out = data_blob_null;
528 DATA_BLOB secblob_out = data_blob_null;
529 char *kerb_mech = NULL;
532 /* Ensure we have no old NTLM state around. */
533 auth_ntlmssp_end(&session->auth_ntlmssp_state);
535 status = parse_spnego_mechanisms(in_security_buffer,
536 &secblob_in, &kerb_mech);
537 if (!NT_STATUS_IS_OK(status)) {
542 if (kerb_mech && ((lp_security()==SEC_ADS) ||
543 USE_KERBEROS_KEYTAB) ) {
544 status = smbd_smb2_session_setup_krb5(session,
558 /* The mechtoken is a krb5 ticket, but
559 * we need to fall back to NTLM. */
561 DEBUG(3,("smb2: Got krb5 ticket in SPNEGO "
562 "but set to downgrade to NTLMSSP\n"));
564 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
566 /* Fall back to NTLMSSP. */
567 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
568 if (!NT_STATUS_IS_OK(status)) {
572 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
577 if (!NT_STATUS_IS_OK(status) &&
578 !NT_STATUS_EQUAL(status,
579 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
583 secblob_out = spnego_gen_auth_response(&chal_out,
586 *out_security_buffer = data_blob_talloc(smb2req,
589 if (secblob_out.data && out_security_buffer->data == NULL) {
590 status = NT_STATUS_NO_MEMORY;
593 *out_session_id = session->vuid;
597 data_blob_free(&secblob_in);
598 data_blob_free(&secblob_out);
599 data_blob_free(&chal_out);
600 SAFE_FREE(kerb_mech);
601 if (!NT_STATUS_IS_OK(status) &&
602 !NT_STATUS_EQUAL(status,
603 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
604 auth_ntlmssp_end(&session->auth_ntlmssp_state);
605 TALLOC_FREE(session);
610 static NTSTATUS smbd_smb2_common_ntlmssp_auth_return(struct smbd_smb2_session *session,
611 struct smbd_smb2_request *smb2req,
612 uint8_t in_security_mode,
613 DATA_BLOB in_security_buffer,
614 uint16_t *out_session_flags,
615 uint64_t *out_session_id)
618 NTSTATUS status = auth_ntlmssp_server_info(session, session->auth_ntlmssp_state,
619 &session->server_info);
620 if (!NT_STATUS_IS_OK(status)) {
621 auth_ntlmssp_end(&session->auth_ntlmssp_state);
622 TALLOC_FREE(session);
626 if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
627 lp_server_signing() == Required) {
628 session->do_signing = true;
631 if (session->server_info->guest) {
632 /* we map anonymous to guest internally */
633 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
634 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
635 /* force no signing */
636 session->do_signing = false;
639 session->session_key = session->server_info->user_session_key;
641 session->compat_vuser = talloc_zero(session, user_struct);
642 if (session->compat_vuser == NULL) {
643 auth_ntlmssp_end(&session->auth_ntlmssp_state);
644 TALLOC_FREE(session);
645 return NT_STATUS_NO_MEMORY;
647 session->compat_vuser->auth_ntlmssp_state = session->auth_ntlmssp_state;
648 session->compat_vuser->homes_snum = -1;
649 session->compat_vuser->server_info = session->server_info;
650 session->compat_vuser->session_keystr = NULL;
651 session->compat_vuser->vuid = session->vuid;
652 DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
654 /* This is a potentially untrusted username */
656 auth_ntlmssp_get_username(session->auth_ntlmssp_state),
659 session->server_info->sanitized_username = talloc_strdup(
660 session->server_info, tmp);
662 if (!session->compat_vuser->server_info->guest) {
663 session->compat_vuser->homes_snum =
664 register_homes_share(session->server_info->unix_name);
667 if (!session_claim(sconn_server_id(session->sconn),
668 session->compat_vuser)) {
669 DEBUG(1, ("smb2: Failed to claim session "
671 session->compat_vuser->vuid));
672 auth_ntlmssp_end(&session->auth_ntlmssp_state);
673 TALLOC_FREE(session);
674 return NT_STATUS_LOGON_FAILURE;
678 session->status = NT_STATUS_OK;
681 * we attach the session to the request
682 * so that the response can be signed
684 smb2req->session = session;
685 if (session->do_signing) {
686 smb2req->do_signing = true;
689 global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
691 *out_session_id = session->vuid;
696 static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
697 struct smbd_smb2_request *smb2req,
698 uint8_t in_security_mode,
699 DATA_BLOB in_security_buffer,
700 uint16_t *out_session_flags,
701 DATA_BLOB *out_security_buffer,
702 uint64_t *out_session_id)
704 DATA_BLOB auth = data_blob_null;
705 DATA_BLOB auth_out = data_blob_null;
706 DATA_BLOB secblob_out = data_blob_null;
709 if (!spnego_parse_auth(in_security_buffer, &auth)) {
710 TALLOC_FREE(session);
711 return NT_STATUS_LOGON_FAILURE;
714 if (auth.data[0] == ASN1_APPLICATION(0)) {
715 /* Might be a second negTokenTarg packet */
716 DATA_BLOB secblob_in = data_blob_null;
717 char *kerb_mech = NULL;
719 status = parse_spnego_mechanisms(in_security_buffer,
720 &secblob_in, &kerb_mech);
721 if (!NT_STATUS_IS_OK(status)) {
722 TALLOC_FREE(session);
727 if (kerb_mech && ((lp_security()==SEC_ADS) ||
728 USE_KERBEROS_KEYTAB) ) {
729 status = smbd_smb2_session_setup_krb5(session,
738 data_blob_free(&secblob_in);
739 SAFE_FREE(kerb_mech);
740 if (!NT_STATUS_IS_OK(status)) {
741 TALLOC_FREE(session);
747 /* Can't blunder into NTLMSSP auth if we have
751 DEBUG(3,("smb2: network "
752 "misconfiguration, client sent us a "
753 "krb5 ticket and kerberos security "
755 TALLOC_FREE(session);
756 data_blob_free(&secblob_in);
757 SAFE_FREE(kerb_mech);
758 return NT_STATUS_LOGON_FAILURE;
761 data_blob_free(&secblob_in);
764 if (session->auth_ntlmssp_state == NULL) {
765 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
766 if (!NT_STATUS_IS_OK(status)) {
767 data_blob_free(&auth);
768 TALLOC_FREE(session);
773 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
776 if (!NT_STATUS_IS_OK(status) &&
777 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
778 auth_ntlmssp_end(&session->auth_ntlmssp_state);
779 data_blob_free(&auth);
780 TALLOC_FREE(session);
784 data_blob_free(&auth);
786 secblob_out = spnego_gen_auth_response(&auth_out,
789 *out_security_buffer = data_blob_talloc(smb2req,
792 if (secblob_out.data && out_security_buffer->data == NULL) {
793 auth_ntlmssp_end(&session->auth_ntlmssp_state);
794 TALLOC_FREE(session);
795 return NT_STATUS_NO_MEMORY;
798 *out_session_id = session->vuid;
800 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
801 return NT_STATUS_MORE_PROCESSING_REQUIRED;
804 /* We're done - claim the session. */
805 return smbd_smb2_common_ntlmssp_auth_return(session,
813 static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session,
814 struct smbd_smb2_request *smb2req,
815 uint8_t in_security_mode,
816 DATA_BLOB in_security_buffer,
817 uint16_t *out_session_flags,
818 DATA_BLOB *out_security_buffer,
819 uint64_t *out_session_id)
822 DATA_BLOB secblob_out = data_blob_null;
824 if (session->auth_ntlmssp_state == NULL) {
825 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
826 if (!NT_STATUS_IS_OK(status)) {
827 TALLOC_FREE(session);
833 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
837 if (NT_STATUS_IS_OK(status) ||
838 NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
839 *out_security_buffer = data_blob_talloc(smb2req,
842 if (secblob_out.data && out_security_buffer->data == NULL) {
843 auth_ntlmssp_end(&session->auth_ntlmssp_state);
844 TALLOC_FREE(session);
845 return NT_STATUS_NO_MEMORY;
849 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
850 *out_session_id = session->vuid;
853 if (!NT_STATUS_IS_OK(status)) {
854 auth_ntlmssp_end(&session->auth_ntlmssp_state);
855 TALLOC_FREE(session);
858 *out_session_id = session->vuid;
860 return smbd_smb2_common_ntlmssp_auth_return(session,
868 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
869 uint64_t in_session_id,
870 uint8_t in_security_mode,
871 DATA_BLOB in_security_buffer,
872 uint16_t *out_session_flags,
873 DATA_BLOB *out_security_buffer,
874 uint64_t *out_session_id)
876 struct smbd_smb2_session *session;
878 *out_session_flags = 0;
881 if (in_session_id == 0) {
884 /* create a new session */
885 session = talloc_zero(smb2req->sconn, struct smbd_smb2_session);
886 if (session == NULL) {
887 return NT_STATUS_NO_MEMORY;
889 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
890 id = idr_get_new_random(smb2req->sconn->smb2.sessions.idtree,
892 smb2req->sconn->smb2.sessions.limit);
894 return NT_STATUS_INSUFFICIENT_RESOURCES;
898 session->tcons.idtree = idr_init(session);
899 if (session->tcons.idtree == NULL) {
900 return NT_STATUS_NO_MEMORY;
902 session->tcons.limit = 0x0000FFFE;
903 session->tcons.list = NULL;
905 DLIST_ADD_END(smb2req->sconn->smb2.sessions.list, session,
906 struct smbd_smb2_session *);
907 session->sconn = smb2req->sconn;
908 talloc_set_destructor(session, smbd_smb2_session_destructor);
912 /* lookup an existing session */
913 p = idr_find(smb2req->sconn->smb2.sessions.idtree, in_session_id);
915 return NT_STATUS_USER_SESSION_DELETED;
917 session = talloc_get_type_abort(p, struct smbd_smb2_session);
920 if (NT_STATUS_IS_OK(session->status)) {
921 return NT_STATUS_REQUEST_NOT_ACCEPTED;
924 if (in_security_buffer.data[0] == ASN1_APPLICATION(0)) {
925 return smbd_smb2_spnego_negotiate(session,
932 } else if (in_security_buffer.data[0] == ASN1_CONTEXT(1)) {
933 return smbd_smb2_spnego_auth(session,
940 } else if (strncmp((char *)(in_security_buffer.data), "NTLMSSP", 7) == 0) {
941 return smbd_smb2_raw_ntlmssp_auth(session,
950 /* Unknown packet type. */
951 DEBUG(1,("Unknown packet type %u in smb2 sessionsetup\n",
952 (unsigned int)in_security_buffer.data[0] ));
953 auth_ntlmssp_end(&session->auth_ntlmssp_state);
954 TALLOC_FREE(session);
955 return NT_STATUS_LOGON_FAILURE;
958 NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
960 const uint8_t *inhdr;
961 const uint8_t *outhdr;
962 int i = req->current_idx;
963 uint64_t in_session_id;
965 struct smbd_smb2_session *session;
966 bool chained_fixup = false;
968 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
970 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
972 if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
975 * async request - fill in session_id from
976 * already setup request out.vector[].iov_base.
978 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
979 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
982 * Chained request - fill in session_id from
983 * the previous request out.vector[].iov_base.
985 outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
986 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
987 chained_fixup = true;
991 /* lookup an existing session */
992 p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
994 return NT_STATUS_USER_SESSION_DELETED;
996 session = talloc_get_type_abort(p, struct smbd_smb2_session);
998 if (!NT_STATUS_IS_OK(session->status)) {
999 return NT_STATUS_ACCESS_DENIED;
1002 set_current_user_info(session->server_info->sanitized_username,
1003 session->server_info->unix_name,
1004 session->server_info->info3->base.domain.string);
1006 req->session = session;
1008 if (chained_fixup) {
1009 /* Fix up our own outhdr. */
1010 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1011 SBVAL(outhdr, SMB2_HDR_SESSION_ID, in_session_id);
1013 return NT_STATUS_OK;
1016 NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req)
1018 const uint8_t *inbody;
1019 int i = req->current_idx;
1021 size_t expected_body_size = 0x04;
1024 if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
1025 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1028 inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
1030 body_size = SVAL(inbody, 0x00);
1031 if (body_size != expected_body_size) {
1032 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1036 * TODO: cancel all outstanding requests on the session
1037 * and delete all tree connections.
1039 smbd_smb2_session_destructor(req->session);
1041 * we may need to sign the response, so we need to keep
1042 * the session until the response is sent to the wire.
1044 talloc_steal(req, req->session);
1046 outbody = data_blob_talloc(req->out.vector, NULL, 0x04);
1047 if (outbody.data == NULL) {
1048 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
1051 SSVAL(outbody.data, 0x00, 0x04); /* struct size */
1052 SSVAL(outbody.data, 0x02, 0); /* reserved */
1054 return smbd_smb2_request_done(req, outbody, NULL);