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;
146 static NTSTATUS setup_ntlmssp_server_info(struct smbd_smb2_session *session,
149 if (NT_STATUS_IS_OK(status)) {
150 status = auth_ntlmssp_server_info(session,
151 session->auth_ntlmssp_state,
152 &session->server_info);
154 /* Note that this server_info won't have a session
155 * key. But for map to guest, that's exactly the right
156 * thing - we can't reasonably guess the key the
157 * client wants, as the password was wrong */
158 status = do_map_to_guest(status,
159 &session->server_info,
160 auth_ntlmssp_get_username(session->auth_ntlmssp_state),
161 auth_ntlmssp_get_domain(session->auth_ntlmssp_state));
167 static NTSTATUS smbd_smb2_session_setup_krb5(struct smbd_smb2_session *session,
168 struct smbd_smb2_request *smb2req,
169 uint8_t in_security_mode,
170 const DATA_BLOB *secblob,
172 uint16_t *out_session_flags,
173 DATA_BLOB *out_security_buffer,
174 uint64_t *out_session_id)
176 DATA_BLOB ap_rep = data_blob_null;
177 DATA_BLOB ap_rep_wrapped = data_blob_null;
178 DATA_BLOB ticket = data_blob_null;
179 DATA_BLOB session_key = data_blob_null;
180 DATA_BLOB secblob_out = data_blob_null;
182 struct PAC_LOGON_INFO *logon_info = NULL;
186 struct passwd *pw = NULL;
189 fstring real_username;
191 bool username_was_mapped = false;
192 bool map_domainuser_to_guest = false;
194 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
195 status = NT_STATUS_LOGON_FAILURE;
199 status = ads_verify_ticket(smb2req, lp_realm(), 0, &ticket,
200 &client, &logon_info, &ap_rep,
203 if (!NT_STATUS_IS_OK(status)) {
204 DEBUG(1,("smb2: Failed to verify incoming ticket with error %s!\n",
206 if (!NT_STATUS_EQUAL(status, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
207 status = NT_STATUS_LOGON_FAILURE;
212 DEBUG(3,("smb2: Ticket name is [%s]\n", client));
214 p = strchr_m(client, '@');
216 DEBUG(3,("smb2: %s Doesn't look like a valid principal\n",
218 status = NT_STATUS_LOGON_FAILURE;
224 /* save the PAC data if we have it */
227 netsamlogon_cache_store(client, &logon_info->info3);
230 if (!strequal(p+1, lp_realm())) {
231 DEBUG(3,("smb2: Ticket for foreign realm %s@%s\n", client, p+1));
232 if (!lp_allow_trusted_domains()) {
233 status = NT_STATUS_LOGON_FAILURE;
238 /* this gives a fully qualified user name (ie. with full realm).
239 that leads to very long usernames, but what else can we do? */
243 if (logon_info && logon_info->info3.base.domain.string) {
244 domain = talloc_strdup(talloc_tos(),
245 logon_info->info3.base.domain.string);
247 status = NT_STATUS_NO_MEMORY;
250 DEBUG(10, ("smb2: Mapped to [%s] (using PAC)\n", domain));
253 /* If we have winbind running, we can (and must) shorten the
254 username by using the short netbios name. Otherwise we will
255 have inconsistent user names. With Kerberos, we get the
256 fully qualified realm, with ntlmssp we get the short
257 name. And even w2k3 does use ntlmssp if you for example
258 connect to an ip address. */
261 struct wbcDomainInfo *info = NULL;
263 DEBUG(10, ("smb2: Mapping [%s] to short name\n", domain));
265 wbc_status = wbcDomainInfo(domain, &info);
267 if (WBC_ERROR_IS_OK(wbc_status)) {
268 domain = talloc_strdup(talloc_tos(), info->short_name);
272 status = NT_STATUS_NO_MEMORY;
275 DEBUG(10, ("smb2: Mapped to [%s] (using Winbind)\n", domain));
277 DEBUG(3, ("smb2: Could not find short name: %s\n",
278 wbcErrorString(wbc_status)));
282 /* We have to use fstring for this - map_username requires it. */
283 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
285 /* lookup the passwd struct, create a new user if necessary */
287 username_was_mapped = map_username(user);
289 pw = smb_getpwnam(talloc_tos(), user, real_username, true );
291 /* if a real user check pam account restrictions */
292 /* only really perfomed if "obey pam restriction" is true */
293 /* do this before an eventual mapping to guest occurs */
294 status = smb_pam_accountcheck(pw->pw_name);
295 if (!NT_STATUS_IS_OK(status)) {
296 DEBUG(1,("smb2: PAM account restriction "
297 "prevents user login\n"));
304 /* this was originally the behavior of Samba 2.2, if a user
305 did not have a local uid but has been authenticated, then
306 map them to a guest account */
308 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
309 map_domainuser_to_guest = true;
310 fstrcpy(user,lp_guestaccount());
311 pw = smb_getpwnam(talloc_tos(), user, real_username, true );
314 /* extra sanity check that the guest account is valid */
317 DEBUG(1,("smb2: Username %s is invalid on this system\n",
319 status = NT_STATUS_LOGON_FAILURE;
324 /* setup the string used by %U */
326 sub_set_smb_name(real_username);
327 reload_services(true);
329 if (map_domainuser_to_guest) {
330 make_server_info_guest(session, &session->server_info);
331 } else if (logon_info) {
332 /* pass the unmapped username here since map_username()
333 will be called again from inside make_server_info_info3() */
335 status = make_server_info_info3(session,
338 &session->server_info,
340 if (!NT_STATUS_IS_OK(status) ) {
341 DEBUG(1,("smb2: make_server_info_info3 failed: %s!\n",
348 * We didn't get a PAC, we have to make up the user
349 * ourselves. Try to ask the pdb backend to provide
350 * SID consistency with ntlmssp session setup
352 struct samu *sampass;
353 /* The stupid make_server_info_XX functions here
354 don't take a talloc context. */
355 struct auth_serversupplied_info *tmp_server_info = NULL;
357 sampass = samu_new(talloc_tos());
358 if (sampass == NULL) {
359 status = NT_STATUS_NO_MEMORY;
363 if (pdb_getsampwnam(sampass, real_username)) {
364 DEBUG(10, ("smb2: found user %s in passdb, calling "
365 "make_server_info_sam\n", real_username));
366 status = make_server_info_sam(&tmp_server_info, sampass);
367 TALLOC_FREE(sampass);
370 * User not in passdb, make it up artificially
372 TALLOC_FREE(sampass);
373 DEBUG(10, ("smb2: didn't find user %s in passdb, calling "
374 "make_server_info_pw\n", real_username));
375 status = make_server_info_pw(&tmp_server_info,
380 if (!NT_STATUS_IS_OK(status)) {
381 DEBUG(1,("smb2: make_server_info_[sam|pw] failed: %s!\n",
386 /* Steal tmp_server_info into the session->server_info
388 session->server_info = talloc_move(session, &tmp_server_info);
390 /* make_server_info_pw does not set the domain. Without this
391 * we end up with the local netbios name in substitutions for
394 if (session->server_info->info3 != NULL) {
395 session->server_info->info3->base.domain.string =
396 talloc_strdup(session->server_info->info3, domain);
401 session->server_info->nss_token |= username_was_mapped;
403 /* we need to build the token for the user. make_server_info_guest()
406 if (!session->server_info->ptok ) {
407 status = create_local_token(session->server_info);
408 if (!NT_STATUS_IS_OK(status)) {
409 DEBUG(10,("smb2: failed to create local token: %s\n",
415 if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
416 lp_server_signing() == Required) {
417 session->do_signing = true;
420 if (session->server_info->guest) {
421 /* we map anonymous to guest internally */
422 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
423 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
424 /* force no signing */
425 session->do_signing = false;
428 data_blob_free(&session->server_info->user_session_key);
429 session->server_info->user_session_key =
431 session->server_info,
434 if (session_key.length > 0) {
435 if (session->server_info->user_session_key.data == NULL) {
436 status = NT_STATUS_NO_MEMORY;
440 session->session_key = session->server_info->user_session_key;
442 session->compat_vuser = talloc_zero(session, user_struct);
443 if (session->compat_vuser == NULL) {
444 status = NT_STATUS_NO_MEMORY;
447 session->compat_vuser->auth_ntlmssp_state = NULL;
448 session->compat_vuser->homes_snum = -1;
449 session->compat_vuser->server_info = session->server_info;
450 session->compat_vuser->session_keystr = NULL;
451 session->compat_vuser->vuid = session->vuid;
452 DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
454 /* This is a potentially untrusted username */
459 session->server_info->sanitized_username = talloc_strdup(
460 session->server_info, tmp);
462 if (!session->server_info->guest) {
463 session->compat_vuser->homes_snum =
464 register_homes_share(session->server_info->unix_name);
467 if (!session_claim(sconn_server_id(session->sconn),
468 session->compat_vuser)) {
469 DEBUG(1, ("smb2: Failed to claim session "
471 session->compat_vuser->vuid));
475 session->status = NT_STATUS_OK;
478 * we attach the session to the request
479 * so that the response can be signed
481 smb2req->session = session;
482 if (session->do_signing) {
483 smb2req->do_signing = true;
486 global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
487 status = NT_STATUS_OK;
489 /* wrap that up in a nice GSS-API wrapping */
490 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
493 secblob_out = spnego_gen_auth_response(
498 *out_security_buffer = data_blob_talloc(smb2req,
501 if (secblob_out.data && out_security_buffer->data == NULL) {
502 status = NT_STATUS_NO_MEMORY;
506 data_blob_free(&ap_rep);
507 data_blob_free(&ap_rep_wrapped);
508 data_blob_free(&ticket);
509 data_blob_free(&session_key);
510 data_blob_free(&secblob_out);
512 *out_session_id = session->vuid;
518 data_blob_free(&ap_rep);
519 data_blob_free(&ap_rep_wrapped);
520 data_blob_free(&ticket);
521 data_blob_free(&session_key);
522 data_blob_free(&secblob_out);
524 ap_rep_wrapped = data_blob_null;
525 secblob_out = spnego_gen_auth_response(
530 *out_security_buffer = data_blob_talloc(smb2req,
533 data_blob_free(&secblob_out);
538 static NTSTATUS smbd_smb2_spnego_negotiate(struct smbd_smb2_session *session,
539 struct smbd_smb2_request *smb2req,
540 uint8_t in_security_mode,
541 DATA_BLOB in_security_buffer,
542 uint16_t *out_session_flags,
543 DATA_BLOB *out_security_buffer,
544 uint64_t *out_session_id)
546 DATA_BLOB secblob_in = data_blob_null;
547 DATA_BLOB chal_out = data_blob_null;
548 DATA_BLOB secblob_out = data_blob_null;
549 char *kerb_mech = NULL;
552 /* Ensure we have no old NTLM state around. */
553 TALLOC_FREE(session->auth_ntlmssp_state);
555 status = parse_spnego_mechanisms(in_security_buffer,
556 &secblob_in, &kerb_mech);
557 if (!NT_STATUS_IS_OK(status)) {
562 if (kerb_mech && ((lp_security()==SEC_ADS) ||
563 USE_KERBEROS_KEYTAB) ) {
564 status = smbd_smb2_session_setup_krb5(session,
578 /* The mechtoken is a krb5 ticket, but
579 * we need to fall back to NTLM. */
581 DEBUG(3,("smb2: Got krb5 ticket in SPNEGO "
582 "but set to downgrade to NTLMSSP\n"));
584 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
586 /* Fall back to NTLMSSP. */
587 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
588 if (!NT_STATUS_IS_OK(status)) {
592 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
597 if (!NT_STATUS_IS_OK(status) &&
598 !NT_STATUS_EQUAL(status,
599 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
603 secblob_out = spnego_gen_auth_response(&chal_out,
606 *out_security_buffer = data_blob_talloc(smb2req,
609 if (secblob_out.data && out_security_buffer->data == NULL) {
610 status = NT_STATUS_NO_MEMORY;
613 *out_session_id = session->vuid;
617 data_blob_free(&secblob_in);
618 data_blob_free(&secblob_out);
619 data_blob_free(&chal_out);
620 SAFE_FREE(kerb_mech);
621 if (!NT_STATUS_IS_OK(status) &&
622 !NT_STATUS_EQUAL(status,
623 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
624 TALLOC_FREE(session->auth_ntlmssp_state);
625 TALLOC_FREE(session);
630 static NTSTATUS smbd_smb2_common_ntlmssp_auth_return(struct smbd_smb2_session *session,
631 struct smbd_smb2_request *smb2req,
632 uint8_t in_security_mode,
633 DATA_BLOB in_security_buffer,
634 uint16_t *out_session_flags,
635 uint64_t *out_session_id)
639 if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
640 lp_server_signing() == Required) {
641 session->do_signing = true;
644 if (session->server_info->guest) {
645 /* we map anonymous to guest internally */
646 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
647 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
648 /* force no signing */
649 session->do_signing = false;
652 session->session_key = session->server_info->user_session_key;
654 session->compat_vuser = talloc_zero(session, user_struct);
655 if (session->compat_vuser == NULL) {
656 TALLOC_FREE(session->auth_ntlmssp_state);
657 TALLOC_FREE(session);
658 return NT_STATUS_NO_MEMORY;
660 session->compat_vuser->auth_ntlmssp_state = session->auth_ntlmssp_state;
661 session->compat_vuser->homes_snum = -1;
662 session->compat_vuser->server_info = session->server_info;
663 session->compat_vuser->session_keystr = NULL;
664 session->compat_vuser->vuid = session->vuid;
665 DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
667 /* This is a potentially untrusted username */
669 auth_ntlmssp_get_username(session->auth_ntlmssp_state),
672 session->server_info->sanitized_username = talloc_strdup(
673 session->server_info, tmp);
675 if (!session->compat_vuser->server_info->guest) {
676 session->compat_vuser->homes_snum =
677 register_homes_share(session->server_info->unix_name);
680 if (!session_claim(sconn_server_id(session->sconn),
681 session->compat_vuser)) {
682 DEBUG(1, ("smb2: Failed to claim session "
684 session->compat_vuser->vuid));
685 TALLOC_FREE(session->auth_ntlmssp_state);
686 TALLOC_FREE(session);
687 return NT_STATUS_LOGON_FAILURE;
691 session->status = NT_STATUS_OK;
694 * we attach the session to the request
695 * so that the response can be signed
697 smb2req->session = session;
698 if (session->do_signing) {
699 smb2req->do_signing = true;
702 global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
704 *out_session_id = session->vuid;
709 static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
710 struct smbd_smb2_request *smb2req,
711 uint8_t in_security_mode,
712 DATA_BLOB in_security_buffer,
713 uint16_t *out_session_flags,
714 DATA_BLOB *out_security_buffer,
715 uint64_t *out_session_id)
717 DATA_BLOB auth = data_blob_null;
718 DATA_BLOB auth_out = data_blob_null;
719 DATA_BLOB secblob_out = data_blob_null;
722 if (!spnego_parse_auth(in_security_buffer, &auth)) {
723 TALLOC_FREE(session);
724 return NT_STATUS_LOGON_FAILURE;
727 if (auth.data[0] == ASN1_APPLICATION(0)) {
728 /* Might be a second negTokenTarg packet */
729 DATA_BLOB secblob_in = data_blob_null;
730 char *kerb_mech = NULL;
732 status = parse_spnego_mechanisms(in_security_buffer,
733 &secblob_in, &kerb_mech);
734 if (!NT_STATUS_IS_OK(status)) {
735 TALLOC_FREE(session);
740 if (kerb_mech && ((lp_security()==SEC_ADS) ||
741 USE_KERBEROS_KEYTAB) ) {
742 status = smbd_smb2_session_setup_krb5(session,
751 data_blob_free(&secblob_in);
752 SAFE_FREE(kerb_mech);
753 if (!NT_STATUS_IS_OK(status)) {
754 TALLOC_FREE(session);
760 /* Can't blunder into NTLMSSP auth if we have
764 DEBUG(3,("smb2: network "
765 "misconfiguration, client sent us a "
766 "krb5 ticket and kerberos security "
768 TALLOC_FREE(session);
769 data_blob_free(&secblob_in);
770 SAFE_FREE(kerb_mech);
771 return NT_STATUS_LOGON_FAILURE;
774 data_blob_free(&secblob_in);
777 if (session->auth_ntlmssp_state == NULL) {
778 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
779 if (!NT_STATUS_IS_OK(status)) {
780 data_blob_free(&auth);
781 TALLOC_FREE(session);
786 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
789 if (!NT_STATUS_IS_OK(status) &&
790 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
791 status = setup_ntlmssp_server_info(session, status);
794 if (!NT_STATUS_IS_OK(status) &&
795 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
796 TALLOC_FREE(session->auth_ntlmssp_state);
797 data_blob_free(&auth);
798 TALLOC_FREE(session);
802 data_blob_free(&auth);
804 secblob_out = spnego_gen_auth_response(&auth_out,
807 *out_security_buffer = data_blob_talloc(smb2req,
810 if (secblob_out.data && out_security_buffer->data == NULL) {
811 TALLOC_FREE(session->auth_ntlmssp_state);
812 TALLOC_FREE(session);
813 return NT_STATUS_NO_MEMORY;
816 *out_session_id = session->vuid;
818 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
819 return NT_STATUS_MORE_PROCESSING_REQUIRED;
822 /* We're done - claim the session. */
823 return smbd_smb2_common_ntlmssp_auth_return(session,
831 static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session,
832 struct smbd_smb2_request *smb2req,
833 uint8_t in_security_mode,
834 DATA_BLOB in_security_buffer,
835 uint16_t *out_session_flags,
836 DATA_BLOB *out_security_buffer,
837 uint64_t *out_session_id)
840 DATA_BLOB secblob_out = data_blob_null;
842 if (session->auth_ntlmssp_state == NULL) {
843 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
844 if (!NT_STATUS_IS_OK(status)) {
845 TALLOC_FREE(session);
851 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
855 if (NT_STATUS_IS_OK(status) ||
856 NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
857 *out_security_buffer = data_blob_talloc(smb2req,
860 if (secblob_out.data && out_security_buffer->data == NULL) {
861 TALLOC_FREE(session->auth_ntlmssp_state);
862 TALLOC_FREE(session);
863 return NT_STATUS_NO_MEMORY;
867 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
868 *out_session_id = session->vuid;
872 status = setup_ntlmssp_server_info(session, status);
874 if (!NT_STATUS_IS_OK(status)) {
875 TALLOC_FREE(session->auth_ntlmssp_state);
876 TALLOC_FREE(session);
879 *out_session_id = session->vuid;
881 return smbd_smb2_common_ntlmssp_auth_return(session,
889 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
890 uint64_t in_session_id,
891 uint8_t in_security_mode,
892 DATA_BLOB in_security_buffer,
893 uint16_t *out_session_flags,
894 DATA_BLOB *out_security_buffer,
895 uint64_t *out_session_id)
897 struct smbd_smb2_session *session;
899 *out_session_flags = 0;
902 if (in_session_id == 0) {
905 /* create a new session */
906 session = talloc_zero(smb2req->sconn, struct smbd_smb2_session);
907 if (session == NULL) {
908 return NT_STATUS_NO_MEMORY;
910 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
911 id = idr_get_new_random(smb2req->sconn->smb2.sessions.idtree,
913 smb2req->sconn->smb2.sessions.limit);
915 return NT_STATUS_INSUFFICIENT_RESOURCES;
919 session->tcons.idtree = idr_init(session);
920 if (session->tcons.idtree == NULL) {
921 return NT_STATUS_NO_MEMORY;
923 session->tcons.limit = 0x0000FFFE;
924 session->tcons.list = NULL;
926 DLIST_ADD_END(smb2req->sconn->smb2.sessions.list, session,
927 struct smbd_smb2_session *);
928 session->sconn = smb2req->sconn;
929 talloc_set_destructor(session, smbd_smb2_session_destructor);
933 /* lookup an existing session */
934 p = idr_find(smb2req->sconn->smb2.sessions.idtree, in_session_id);
936 return NT_STATUS_USER_SESSION_DELETED;
938 session = talloc_get_type_abort(p, struct smbd_smb2_session);
941 if (NT_STATUS_IS_OK(session->status)) {
942 return NT_STATUS_REQUEST_NOT_ACCEPTED;
945 if (in_security_buffer.data[0] == ASN1_APPLICATION(0)) {
946 return smbd_smb2_spnego_negotiate(session,
953 } else if (in_security_buffer.data[0] == ASN1_CONTEXT(1)) {
954 return smbd_smb2_spnego_auth(session,
961 } else if (strncmp((char *)(in_security_buffer.data), "NTLMSSP", 7) == 0) {
962 return smbd_smb2_raw_ntlmssp_auth(session,
971 /* Unknown packet type. */
972 DEBUG(1,("Unknown packet type %u in smb2 sessionsetup\n",
973 (unsigned int)in_security_buffer.data[0] ));
974 TALLOC_FREE(session->auth_ntlmssp_state);
975 TALLOC_FREE(session);
976 return NT_STATUS_LOGON_FAILURE;
979 NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
981 const uint8_t *inhdr;
982 const uint8_t *outhdr;
983 int i = req->current_idx;
984 uint64_t in_session_id;
986 struct smbd_smb2_session *session;
987 bool chained_fixup = false;
989 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
991 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
993 if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
996 * async request - fill in session_id from
997 * already setup request out.vector[].iov_base.
999 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1000 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1003 * Chained request - fill in session_id from
1004 * the previous request out.vector[].iov_base.
1006 outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
1007 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1008 chained_fixup = true;
1012 /* lookup an existing session */
1013 p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
1015 return NT_STATUS_USER_SESSION_DELETED;
1017 session = talloc_get_type_abort(p, struct smbd_smb2_session);
1019 if (!NT_STATUS_IS_OK(session->status)) {
1020 return NT_STATUS_ACCESS_DENIED;
1023 set_current_user_info(session->server_info->sanitized_username,
1024 session->server_info->unix_name,
1025 session->server_info->info3->base.domain.string);
1027 req->session = session;
1029 if (chained_fixup) {
1030 /* Fix up our own outhdr. */
1031 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1032 SBVAL(outhdr, SMB2_HDR_SESSION_ID, in_session_id);
1034 return NT_STATUS_OK;
1037 NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req)
1039 const uint8_t *inbody;
1040 int i = req->current_idx;
1042 size_t expected_body_size = 0x04;
1045 if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
1046 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1049 inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
1051 body_size = SVAL(inbody, 0x00);
1052 if (body_size != expected_body_size) {
1053 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1057 * TODO: cancel all outstanding requests on the session
1058 * and delete all tree connections.
1060 smbd_smb2_session_destructor(req->session);
1062 * we may need to sign the response, so we need to keep
1063 * the session until the response is sent to the wire.
1065 talloc_steal(req, req->session);
1067 outbody = data_blob_talloc(req->out.vector, NULL, 0x04);
1068 if (outbody.data == NULL) {
1069 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
1072 SSVAL(outbody.data, 0x00, 0x04); /* struct size */
1073 SSVAL(outbody.data, 0x02, 0); /* reserved */
1075 return smbd_smb2_request_done(req, outbody, NULL);