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"
27 #include "ntlmssp_wrap.h"
29 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
30 uint64_t in_session_id,
31 uint8_t in_security_mode,
32 DATA_BLOB in_security_buffer,
33 uint16_t *out_session_flags,
34 DATA_BLOB *out_security_buffer,
35 uint64_t *out_session_id);
37 NTSTATUS smbd_smb2_request_process_sesssetup(struct smbd_smb2_request *smb2req)
40 const uint8_t *inbody;
41 int i = smb2req->current_idx;
45 size_t expected_body_size = 0x19;
47 uint64_t in_session_id;
48 uint8_t in_security_mode;
49 uint16_t in_security_offset;
50 uint16_t in_security_length;
51 DATA_BLOB in_security_buffer;
52 uint16_t out_session_flags;
53 uint64_t out_session_id;
54 uint16_t out_security_offset;
55 DATA_BLOB out_security_buffer;
58 inhdr = (const uint8_t *)smb2req->in.vector[i+0].iov_base;
60 if (smb2req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
61 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
64 inbody = (const uint8_t *)smb2req->in.vector[i+1].iov_base;
66 body_size = SVAL(inbody, 0x00);
67 if (body_size != expected_body_size) {
68 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
71 in_security_offset = SVAL(inbody, 0x0C);
72 in_security_length = SVAL(inbody, 0x0E);
74 if (in_security_offset != (SMB2_HDR_BODY + (body_size & 0xFFFFFFFE))) {
75 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
78 if (in_security_length > smb2req->in.vector[i+2].iov_len) {
79 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
82 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
83 in_security_mode = CVAL(inbody, 0x03);
84 in_security_buffer.data = (uint8_t *)smb2req->in.vector[i+2].iov_base;
85 in_security_buffer.length = in_security_length;
87 status = smbd_smb2_session_setup(smb2req,
94 if (!NT_STATUS_IS_OK(status) &&
95 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
96 status = nt_status_squash(status);
97 return smbd_smb2_request_error(smb2req, status);
100 out_security_offset = SMB2_HDR_BODY + 0x08;
102 outhdr = (uint8_t *)smb2req->out.vector[i].iov_base;
104 outbody = data_blob_talloc(smb2req->out.vector, NULL, 0x08);
105 if (outbody.data == NULL) {
106 return smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
109 SBVAL(outhdr, SMB2_HDR_SESSION_ID, out_session_id);
111 SSVAL(outbody.data, 0x00, 0x08 + 1); /* struct size */
112 SSVAL(outbody.data, 0x02,
113 out_session_flags); /* session flags */
114 SSVAL(outbody.data, 0x04,
115 out_security_offset); /* security buffer offset */
116 SSVAL(outbody.data, 0x06,
117 out_security_buffer.length); /* security buffer length */
119 outdyn = out_security_buffer;
121 return smbd_smb2_request_done_ex(smb2req, status, outbody, &outdyn,
125 static int smbd_smb2_session_destructor(struct smbd_smb2_session *session)
127 if (session->sconn == NULL) {
131 /* first free all tcons */
132 while (session->tcons.list) {
133 talloc_free(session->tcons.list);
136 idr_remove(session->sconn->smb2.sessions.idtree, session->vuid);
137 DLIST_REMOVE(session->sconn->smb2.sessions.list, session);
138 invalidate_vuid(session->sconn, session->vuid);
141 session->status = NT_STATUS_USER_SESSION_DELETED;
142 session->sconn = NULL;
147 static NTSTATUS setup_ntlmssp_server_info(struct smbd_smb2_session *session,
150 if (NT_STATUS_IS_OK(status)) {
151 status = auth_ntlmssp_steal_server_info(session,
152 session->auth_ntlmssp_state,
153 &session->server_info);
155 /* Note that this server_info won't have a session
156 * key. But for map to guest, that's exactly the right
157 * thing - we can't reasonably guess the key the
158 * client wants, as the password was wrong */
159 status = do_map_to_guest(status,
160 &session->server_info,
161 auth_ntlmssp_get_username(session->auth_ntlmssp_state),
162 auth_ntlmssp_get_domain(session->auth_ntlmssp_state));
168 static NTSTATUS smbd_smb2_session_setup_krb5(struct smbd_smb2_session *session,
169 struct smbd_smb2_request *smb2req,
170 uint8_t in_security_mode,
171 const DATA_BLOB *secblob,
173 uint16_t *out_session_flags,
174 DATA_BLOB *out_security_buffer,
175 uint64_t *out_session_id)
177 DATA_BLOB ap_rep = data_blob_null;
178 DATA_BLOB ap_rep_wrapped = data_blob_null;
179 DATA_BLOB ticket = data_blob_null;
180 DATA_BLOB session_key = data_blob_null;
181 DATA_BLOB secblob_out = data_blob_null;
183 struct PAC_LOGON_INFO *logon_info = NULL;
187 struct passwd *pw = NULL;
190 fstring real_username;
192 bool username_was_mapped = false;
193 bool map_domainuser_to_guest = false;
195 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
196 status = NT_STATUS_LOGON_FAILURE;
200 status = ads_verify_ticket(smb2req, lp_realm(), 0, &ticket,
201 &client, &logon_info, &ap_rep,
204 if (!NT_STATUS_IS_OK(status)) {
205 DEBUG(1,("smb2: Failed to verify incoming ticket with error %s!\n",
207 if (!NT_STATUS_EQUAL(status, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
208 status = NT_STATUS_LOGON_FAILURE;
213 DEBUG(3,("smb2: Ticket name is [%s]\n", client));
215 p = strchr_m(client, '@');
217 DEBUG(3,("smb2: %s Doesn't look like a valid principal\n",
219 status = NT_STATUS_LOGON_FAILURE;
225 /* save the PAC data if we have it */
228 netsamlogon_cache_store(client, &logon_info->info3);
231 if (!strequal(p+1, lp_realm())) {
232 DEBUG(3,("smb2: Ticket for foreign realm %s@%s\n", client, p+1));
233 if (!lp_allow_trusted_domains()) {
234 status = NT_STATUS_LOGON_FAILURE;
239 /* this gives a fully qualified user name (ie. with full realm).
240 that leads to very long usernames, but what else can we do? */
244 if (logon_info && logon_info->info3.base.domain.string) {
245 domain = talloc_strdup(talloc_tos(),
246 logon_info->info3.base.domain.string);
248 status = NT_STATUS_NO_MEMORY;
251 DEBUG(10, ("smb2: Mapped to [%s] (using PAC)\n", domain));
254 /* If we have winbind running, we can (and must) shorten the
255 username by using the short netbios name. Otherwise we will
256 have inconsistent user names. With Kerberos, we get the
257 fully qualified realm, with ntlmssp we get the short
258 name. And even w2k3 does use ntlmssp if you for example
259 connect to an ip address. */
262 struct wbcDomainInfo *info = NULL;
264 DEBUG(10, ("smb2: Mapping [%s] to short name\n", domain));
266 wbc_status = wbcDomainInfo(domain, &info);
268 if (WBC_ERROR_IS_OK(wbc_status)) {
269 domain = talloc_strdup(talloc_tos(), info->short_name);
273 status = NT_STATUS_NO_MEMORY;
276 DEBUG(10, ("smb2: Mapped to [%s] (using Winbind)\n", domain));
278 DEBUG(3, ("smb2: Could not find short name: %s\n",
279 wbcErrorString(wbc_status)));
283 /* We have to use fstring for this - map_username requires it. */
284 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
286 /* lookup the passwd struct, create a new user if necessary */
288 username_was_mapped = map_username(user);
290 pw = smb_getpwnam(talloc_tos(), user, real_username, true );
292 /* if a real user check pam account restrictions */
293 /* only really perfomed if "obey pam restriction" is true */
294 /* do this before an eventual mapping to guest occurs */
295 status = smb_pam_accountcheck(pw->pw_name);
296 if (!NT_STATUS_IS_OK(status)) {
297 DEBUG(1,("smb2: PAM account restriction "
298 "prevents user login\n"));
305 /* this was originally the behavior of Samba 2.2, if a user
306 did not have a local uid but has been authenticated, then
307 map them to a guest account */
309 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
310 map_domainuser_to_guest = true;
311 fstrcpy(user,lp_guestaccount());
312 pw = smb_getpwnam(talloc_tos(), user, real_username, true );
315 /* extra sanity check that the guest account is valid */
318 DEBUG(1,("smb2: Username %s is invalid on this system\n",
320 status = NT_STATUS_LOGON_FAILURE;
325 /* setup the string used by %U */
327 sub_set_smb_name(real_username);
328 reload_services(true);
330 if (map_domainuser_to_guest) {
331 make_server_info_guest(session, &session->server_info);
332 } else if (logon_info) {
333 /* pass the unmapped username here since map_username()
334 will be called again from inside make_server_info_info3() */
336 status = make_server_info_info3(session,
339 &session->server_info,
341 if (!NT_STATUS_IS_OK(status) ) {
342 DEBUG(1,("smb2: make_server_info_info3 failed: %s!\n",
349 * We didn't get a PAC, we have to make up the user
350 * ourselves. Try to ask the pdb backend to provide
351 * SID consistency with ntlmssp session setup
353 struct samu *sampass;
354 /* The stupid make_server_info_XX functions here
355 don't take a talloc context. */
356 struct auth_serversupplied_info *tmp_server_info = NULL;
358 sampass = samu_new(talloc_tos());
359 if (sampass == NULL) {
360 status = NT_STATUS_NO_MEMORY;
364 if (pdb_getsampwnam(sampass, real_username)) {
365 DEBUG(10, ("smb2: found user %s in passdb, calling "
366 "make_server_info_sam\n", real_username));
367 status = make_server_info_sam(&tmp_server_info, sampass);
368 TALLOC_FREE(sampass);
371 * User not in passdb, make it up artificially
373 TALLOC_FREE(sampass);
374 DEBUG(10, ("smb2: didn't find user %s in passdb, calling "
375 "make_server_info_pw\n", real_username));
376 status = make_server_info_pw(&tmp_server_info,
381 if (!NT_STATUS_IS_OK(status)) {
382 DEBUG(1,("smb2: make_server_info_[sam|pw] failed: %s!\n",
387 /* Steal tmp_server_info into the session->server_info
389 session->server_info = talloc_move(session, &tmp_server_info);
391 /* make_server_info_pw does not set the domain. Without this
392 * we end up with the local netbios name in substitutions for
395 if (session->server_info->info3 != NULL) {
396 session->server_info->info3->base.domain.string =
397 talloc_strdup(session->server_info->info3, domain);
402 session->server_info->nss_token |= username_was_mapped;
404 /* we need to build the token for the user. make_server_info_guest()
407 if (!session->server_info->ptok ) {
408 status = create_local_token(session->server_info);
409 if (!NT_STATUS_IS_OK(status)) {
410 DEBUG(10,("smb2: failed to create local token: %s\n",
416 if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
417 lp_server_signing() == Required) {
418 session->do_signing = true;
421 if (session->server_info->guest) {
422 /* we map anonymous to guest internally */
423 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
424 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
425 /* force no signing */
426 session->do_signing = false;
429 data_blob_free(&session->server_info->user_session_key);
430 session->server_info->user_session_key =
432 session->server_info,
435 if (session_key.length > 0) {
436 if (session->server_info->user_session_key.data == NULL) {
437 status = NT_STATUS_NO_MEMORY;
441 session->session_key = session->server_info->user_session_key;
443 session->compat_vuser = talloc_zero(session, user_struct);
444 if (session->compat_vuser == NULL) {
445 status = NT_STATUS_NO_MEMORY;
448 session->compat_vuser->auth_ntlmssp_state = NULL;
449 session->compat_vuser->homes_snum = -1;
450 session->compat_vuser->server_info = session->server_info;
451 session->compat_vuser->session_keystr = NULL;
452 session->compat_vuser->vuid = session->vuid;
453 DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
455 /* This is a potentially untrusted username */
460 session->server_info->sanitized_username = talloc_strdup(
461 session->server_info, tmp);
463 if (!session->server_info->guest) {
464 session->compat_vuser->homes_snum =
465 register_homes_share(session->server_info->unix_name);
468 if (!session_claim(sconn_server_id(session->sconn),
469 session->compat_vuser)) {
470 DEBUG(1, ("smb2: Failed to claim session "
472 session->compat_vuser->vuid));
476 session->status = NT_STATUS_OK;
479 * we attach the session to the request
480 * so that the response can be signed
482 smb2req->session = session;
483 if (session->do_signing) {
484 smb2req->do_signing = true;
487 global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
488 status = NT_STATUS_OK;
490 /* wrap that up in a nice GSS-API wrapping */
491 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
494 secblob_out = spnego_gen_auth_response(
499 *out_security_buffer = data_blob_talloc(smb2req,
502 if (secblob_out.data && out_security_buffer->data == NULL) {
503 status = NT_STATUS_NO_MEMORY;
507 data_blob_free(&ap_rep);
508 data_blob_free(&ap_rep_wrapped);
509 data_blob_free(&ticket);
510 data_blob_free(&session_key);
511 data_blob_free(&secblob_out);
513 *out_session_id = session->vuid;
519 data_blob_free(&ap_rep);
520 data_blob_free(&ap_rep_wrapped);
521 data_blob_free(&ticket);
522 data_blob_free(&session_key);
523 data_blob_free(&secblob_out);
525 ap_rep_wrapped = data_blob_null;
526 secblob_out = spnego_gen_auth_response(
531 *out_security_buffer = data_blob_talloc(smb2req,
534 data_blob_free(&secblob_out);
539 static NTSTATUS smbd_smb2_spnego_negotiate(struct smbd_smb2_session *session,
540 struct smbd_smb2_request *smb2req,
541 uint8_t in_security_mode,
542 DATA_BLOB in_security_buffer,
543 uint16_t *out_session_flags,
544 DATA_BLOB *out_security_buffer,
545 uint64_t *out_session_id)
547 DATA_BLOB secblob_in = data_blob_null;
548 DATA_BLOB chal_out = data_blob_null;
549 DATA_BLOB secblob_out = data_blob_null;
550 char *kerb_mech = NULL;
553 /* Ensure we have no old NTLM state around. */
554 TALLOC_FREE(session->auth_ntlmssp_state);
556 status = parse_spnego_mechanisms(in_security_buffer,
557 &secblob_in, &kerb_mech);
558 if (!NT_STATUS_IS_OK(status)) {
563 if (kerb_mech && ((lp_security()==SEC_ADS) ||
564 USE_KERBEROS_KEYTAB) ) {
565 status = smbd_smb2_session_setup_krb5(session,
579 /* The mechtoken is a krb5 ticket, but
580 * we need to fall back to NTLM. */
582 DEBUG(3,("smb2: Got krb5 ticket in SPNEGO "
583 "but set to downgrade to NTLMSSP\n"));
585 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
587 /* Fall back to NTLMSSP. */
588 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
589 if (!NT_STATUS_IS_OK(status)) {
593 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
598 if (!NT_STATUS_IS_OK(status) &&
599 !NT_STATUS_EQUAL(status,
600 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
604 secblob_out = spnego_gen_auth_response(&chal_out,
607 *out_security_buffer = data_blob_talloc(smb2req,
610 if (secblob_out.data && out_security_buffer->data == NULL) {
611 status = NT_STATUS_NO_MEMORY;
614 *out_session_id = session->vuid;
618 data_blob_free(&secblob_in);
619 data_blob_free(&secblob_out);
620 data_blob_free(&chal_out);
621 SAFE_FREE(kerb_mech);
622 if (!NT_STATUS_IS_OK(status) &&
623 !NT_STATUS_EQUAL(status,
624 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
625 TALLOC_FREE(session->auth_ntlmssp_state);
626 TALLOC_FREE(session);
631 static NTSTATUS smbd_smb2_common_ntlmssp_auth_return(struct smbd_smb2_session *session,
632 struct smbd_smb2_request *smb2req,
633 uint8_t in_security_mode,
634 DATA_BLOB in_security_buffer,
635 uint16_t *out_session_flags,
636 uint64_t *out_session_id)
640 if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
641 lp_server_signing() == Required) {
642 session->do_signing = true;
645 if (session->server_info->guest) {
646 /* we map anonymous to guest internally */
647 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
648 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
649 /* force no signing */
650 session->do_signing = false;
653 session->session_key = session->server_info->user_session_key;
655 session->compat_vuser = talloc_zero(session, user_struct);
656 if (session->compat_vuser == NULL) {
657 TALLOC_FREE(session->auth_ntlmssp_state);
658 TALLOC_FREE(session);
659 return NT_STATUS_NO_MEMORY;
661 session->compat_vuser->auth_ntlmssp_state = session->auth_ntlmssp_state;
662 session->compat_vuser->homes_snum = -1;
663 session->compat_vuser->server_info = session->server_info;
664 session->compat_vuser->session_keystr = NULL;
665 session->compat_vuser->vuid = session->vuid;
666 DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
668 /* This is a potentially untrusted username */
670 auth_ntlmssp_get_username(session->auth_ntlmssp_state),
673 session->server_info->sanitized_username = talloc_strdup(
674 session->server_info, tmp);
676 if (!session->compat_vuser->server_info->guest) {
677 session->compat_vuser->homes_snum =
678 register_homes_share(session->server_info->unix_name);
681 if (!session_claim(sconn_server_id(session->sconn),
682 session->compat_vuser)) {
683 DEBUG(1, ("smb2: Failed to claim session "
685 session->compat_vuser->vuid));
686 TALLOC_FREE(session->auth_ntlmssp_state);
687 TALLOC_FREE(session);
688 return NT_STATUS_LOGON_FAILURE;
692 session->status = NT_STATUS_OK;
695 * we attach the session to the request
696 * so that the response can be signed
698 smb2req->session = session;
699 if (session->do_signing) {
700 smb2req->do_signing = true;
703 global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
705 *out_session_id = session->vuid;
710 static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
711 struct smbd_smb2_request *smb2req,
712 uint8_t in_security_mode,
713 DATA_BLOB in_security_buffer,
714 uint16_t *out_session_flags,
715 DATA_BLOB *out_security_buffer,
716 uint64_t *out_session_id)
718 DATA_BLOB auth = data_blob_null;
719 DATA_BLOB auth_out = data_blob_null;
720 DATA_BLOB secblob_out = data_blob_null;
723 if (!spnego_parse_auth(in_security_buffer, &auth)) {
724 TALLOC_FREE(session);
725 return NT_STATUS_LOGON_FAILURE;
728 if (auth.data[0] == ASN1_APPLICATION(0)) {
729 /* Might be a second negTokenTarg packet */
730 DATA_BLOB secblob_in = data_blob_null;
731 char *kerb_mech = NULL;
733 status = parse_spnego_mechanisms(in_security_buffer,
734 &secblob_in, &kerb_mech);
735 if (!NT_STATUS_IS_OK(status)) {
736 TALLOC_FREE(session);
741 if (kerb_mech && ((lp_security()==SEC_ADS) ||
742 USE_KERBEROS_KEYTAB) ) {
743 status = smbd_smb2_session_setup_krb5(session,
752 data_blob_free(&secblob_in);
753 SAFE_FREE(kerb_mech);
754 if (!NT_STATUS_IS_OK(status)) {
755 TALLOC_FREE(session);
761 /* Can't blunder into NTLMSSP auth if we have
765 DEBUG(3,("smb2: network "
766 "misconfiguration, client sent us a "
767 "krb5 ticket and kerberos security "
769 TALLOC_FREE(session);
770 data_blob_free(&secblob_in);
771 SAFE_FREE(kerb_mech);
772 return NT_STATUS_LOGON_FAILURE;
775 data_blob_free(&secblob_in);
778 if (session->auth_ntlmssp_state == NULL) {
779 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
780 if (!NT_STATUS_IS_OK(status)) {
781 data_blob_free(&auth);
782 TALLOC_FREE(session);
787 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
790 if (!NT_STATUS_IS_OK(status) &&
791 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
792 status = setup_ntlmssp_server_info(session, status);
795 if (!NT_STATUS_IS_OK(status) &&
796 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
797 TALLOC_FREE(session->auth_ntlmssp_state);
798 data_blob_free(&auth);
799 TALLOC_FREE(session);
803 data_blob_free(&auth);
805 secblob_out = spnego_gen_auth_response(&auth_out,
808 *out_security_buffer = data_blob_talloc(smb2req,
811 if (secblob_out.data && out_security_buffer->data == NULL) {
812 TALLOC_FREE(session->auth_ntlmssp_state);
813 TALLOC_FREE(session);
814 return NT_STATUS_NO_MEMORY;
817 *out_session_id = session->vuid;
819 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
820 return NT_STATUS_MORE_PROCESSING_REQUIRED;
823 /* We're done - claim the session. */
824 return smbd_smb2_common_ntlmssp_auth_return(session,
832 static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session,
833 struct smbd_smb2_request *smb2req,
834 uint8_t in_security_mode,
835 DATA_BLOB in_security_buffer,
836 uint16_t *out_session_flags,
837 DATA_BLOB *out_security_buffer,
838 uint64_t *out_session_id)
841 DATA_BLOB secblob_out = data_blob_null;
843 if (session->auth_ntlmssp_state == NULL) {
844 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
845 if (!NT_STATUS_IS_OK(status)) {
846 TALLOC_FREE(session);
852 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
856 if (NT_STATUS_IS_OK(status) ||
857 NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
858 *out_security_buffer = data_blob_talloc(smb2req,
861 if (secblob_out.data && out_security_buffer->data == NULL) {
862 TALLOC_FREE(session->auth_ntlmssp_state);
863 TALLOC_FREE(session);
864 return NT_STATUS_NO_MEMORY;
868 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
869 *out_session_id = session->vuid;
873 status = setup_ntlmssp_server_info(session, status);
875 if (!NT_STATUS_IS_OK(status)) {
876 TALLOC_FREE(session->auth_ntlmssp_state);
877 TALLOC_FREE(session);
880 *out_session_id = session->vuid;
882 return smbd_smb2_common_ntlmssp_auth_return(session,
890 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
891 uint64_t in_session_id,
892 uint8_t in_security_mode,
893 DATA_BLOB in_security_buffer,
894 uint16_t *out_session_flags,
895 DATA_BLOB *out_security_buffer,
896 uint64_t *out_session_id)
898 struct smbd_smb2_session *session;
900 *out_session_flags = 0;
903 if (in_session_id == 0) {
906 /* create a new session */
907 session = talloc_zero(smb2req->sconn, struct smbd_smb2_session);
908 if (session == NULL) {
909 return NT_STATUS_NO_MEMORY;
911 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
912 id = idr_get_new_random(smb2req->sconn->smb2.sessions.idtree,
914 smb2req->sconn->smb2.sessions.limit);
916 return NT_STATUS_INSUFFICIENT_RESOURCES;
920 session->tcons.idtree = idr_init(session);
921 if (session->tcons.idtree == NULL) {
922 return NT_STATUS_NO_MEMORY;
924 session->tcons.limit = 0x0000FFFE;
925 session->tcons.list = NULL;
927 DLIST_ADD_END(smb2req->sconn->smb2.sessions.list, session,
928 struct smbd_smb2_session *);
929 session->sconn = smb2req->sconn;
930 talloc_set_destructor(session, smbd_smb2_session_destructor);
934 /* lookup an existing session */
935 p = idr_find(smb2req->sconn->smb2.sessions.idtree, in_session_id);
937 return NT_STATUS_USER_SESSION_DELETED;
939 session = talloc_get_type_abort(p, struct smbd_smb2_session);
942 if (NT_STATUS_IS_OK(session->status)) {
943 return NT_STATUS_REQUEST_NOT_ACCEPTED;
946 if (in_security_buffer.data[0] == ASN1_APPLICATION(0)) {
947 return smbd_smb2_spnego_negotiate(session,
954 } else if (in_security_buffer.data[0] == ASN1_CONTEXT(1)) {
955 return smbd_smb2_spnego_auth(session,
962 } else if (strncmp((char *)(in_security_buffer.data), "NTLMSSP", 7) == 0) {
963 return smbd_smb2_raw_ntlmssp_auth(session,
972 /* Unknown packet type. */
973 DEBUG(1,("Unknown packet type %u in smb2 sessionsetup\n",
974 (unsigned int)in_security_buffer.data[0] ));
975 TALLOC_FREE(session->auth_ntlmssp_state);
976 TALLOC_FREE(session);
977 return NT_STATUS_LOGON_FAILURE;
980 NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
982 const uint8_t *inhdr;
983 const uint8_t *outhdr;
984 int i = req->current_idx;
985 uint64_t in_session_id;
987 struct smbd_smb2_session *session;
988 bool chained_fixup = false;
990 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
992 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
994 if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
997 * async request - fill in session_id from
998 * already setup request out.vector[].iov_base.
1000 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1001 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1004 * Chained request - fill in session_id from
1005 * the previous request out.vector[].iov_base.
1007 outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
1008 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1009 chained_fixup = true;
1013 /* lookup an existing session */
1014 p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
1016 return NT_STATUS_USER_SESSION_DELETED;
1018 session = talloc_get_type_abort(p, struct smbd_smb2_session);
1020 if (!NT_STATUS_IS_OK(session->status)) {
1021 return NT_STATUS_ACCESS_DENIED;
1024 set_current_user_info(session->server_info->sanitized_username,
1025 session->server_info->unix_name,
1026 session->server_info->info3->base.domain.string);
1028 req->session = session;
1030 if (chained_fixup) {
1031 /* Fix up our own outhdr. */
1032 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1033 SBVAL(outhdr, SMB2_HDR_SESSION_ID, in_session_id);
1035 return NT_STATUS_OK;
1038 NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req)
1040 const uint8_t *inbody;
1041 int i = req->current_idx;
1043 size_t expected_body_size = 0x04;
1046 if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
1047 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1050 inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
1052 body_size = SVAL(inbody, 0x00);
1053 if (body_size != expected_body_size) {
1054 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1058 * TODO: cancel all outstanding requests on the session
1059 * and delete all tree connections.
1061 smbd_smb2_session_destructor(req->session);
1063 * we may need to sign the response, so we need to keep
1064 * the session until the response is sent to the wire.
1066 talloc_steal(req, req->session);
1068 outbody = data_blob_talloc(req->out.vector, NULL, 0x04);
1069 if (outbody.data == NULL) {
1070 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
1073 SSVAL(outbody.data, 0x00, 0x04); /* struct size */
1074 SSVAL(outbody.data, 0x02, 0); /* reserved */
1076 return smbd_smb2_request_done(req, outbody, NULL);