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"
28 #include "../librpc/gen_ndr/krb5pac.h"
29 #include "libads/kerberos_proto.h"
31 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
32 uint64_t in_session_id,
33 uint8_t in_security_mode,
34 DATA_BLOB in_security_buffer,
35 uint16_t *out_session_flags,
36 DATA_BLOB *out_security_buffer,
37 uint64_t *out_session_id);
39 NTSTATUS smbd_smb2_request_process_sesssetup(struct smbd_smb2_request *smb2req)
42 const uint8_t *inbody;
43 int i = smb2req->current_idx;
47 size_t expected_body_size = 0x19;
49 uint64_t in_session_id;
50 uint8_t in_security_mode;
51 uint16_t in_security_offset;
52 uint16_t in_security_length;
53 DATA_BLOB in_security_buffer;
54 uint16_t out_session_flags;
55 uint64_t out_session_id;
56 uint16_t out_security_offset;
57 DATA_BLOB out_security_buffer;
60 inhdr = (const uint8_t *)smb2req->in.vector[i+0].iov_base;
62 if (smb2req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
63 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
66 inbody = (const uint8_t *)smb2req->in.vector[i+1].iov_base;
68 body_size = SVAL(inbody, 0x00);
69 if (body_size != expected_body_size) {
70 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
73 in_security_offset = SVAL(inbody, 0x0C);
74 in_security_length = SVAL(inbody, 0x0E);
76 if (in_security_offset != (SMB2_HDR_BODY + (body_size & 0xFFFFFFFE))) {
77 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
80 if (in_security_length > smb2req->in.vector[i+2].iov_len) {
81 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
84 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
85 in_security_mode = CVAL(inbody, 0x03);
86 in_security_buffer.data = (uint8_t *)smb2req->in.vector[i+2].iov_base;
87 in_security_buffer.length = in_security_length;
89 status = smbd_smb2_session_setup(smb2req,
96 if (!NT_STATUS_IS_OK(status) &&
97 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
98 status = nt_status_squash(status);
99 return smbd_smb2_request_error(smb2req, status);
102 out_security_offset = SMB2_HDR_BODY + 0x08;
104 outhdr = (uint8_t *)smb2req->out.vector[i].iov_base;
106 outbody = data_blob_talloc(smb2req->out.vector, NULL, 0x08);
107 if (outbody.data == NULL) {
108 return smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
111 SBVAL(outhdr, SMB2_HDR_SESSION_ID, out_session_id);
113 SSVAL(outbody.data, 0x00, 0x08 + 1); /* struct size */
114 SSVAL(outbody.data, 0x02,
115 out_session_flags); /* session flags */
116 SSVAL(outbody.data, 0x04,
117 out_security_offset); /* security buffer offset */
118 SSVAL(outbody.data, 0x06,
119 out_security_buffer.length); /* security buffer length */
121 outdyn = out_security_buffer;
123 return smbd_smb2_request_done_ex(smb2req, status, outbody, &outdyn,
127 static int smbd_smb2_session_destructor(struct smbd_smb2_session *session)
129 if (session->sconn == NULL) {
133 /* first free all tcons */
134 while (session->tcons.list) {
135 talloc_free(session->tcons.list);
138 idr_remove(session->sconn->smb2.sessions.idtree, session->vuid);
139 DLIST_REMOVE(session->sconn->smb2.sessions.list, session);
140 invalidate_vuid(session->sconn, session->vuid);
143 session->status = NT_STATUS_USER_SESSION_DELETED;
144 session->sconn = NULL;
149 static NTSTATUS setup_ntlmssp_server_info(struct smbd_smb2_session *session,
152 if (NT_STATUS_IS_OK(status)) {
153 status = auth_ntlmssp_steal_server_info(session,
154 session->auth_ntlmssp_state,
155 &session->server_info);
157 /* Note that this server_info won't have a session
158 * key. But for map to guest, that's exactly the right
159 * thing - we can't reasonably guess the key the
160 * client wants, as the password was wrong */
161 status = do_map_to_guest(status,
162 &session->server_info,
163 auth_ntlmssp_get_username(session->auth_ntlmssp_state),
164 auth_ntlmssp_get_domain(session->auth_ntlmssp_state));
170 static NTSTATUS smbd_smb2_session_setup_krb5(struct smbd_smb2_session *session,
171 struct smbd_smb2_request *smb2req,
172 uint8_t in_security_mode,
173 const DATA_BLOB *secblob,
175 uint16_t *out_session_flags,
176 DATA_BLOB *out_security_buffer,
177 uint64_t *out_session_id)
179 DATA_BLOB ap_rep = data_blob_null;
180 DATA_BLOB ap_rep_wrapped = data_blob_null;
181 DATA_BLOB ticket = data_blob_null;
182 DATA_BLOB session_key = data_blob_null;
183 DATA_BLOB secblob_out = data_blob_null;
185 struct PAC_LOGON_INFO *logon_info = NULL;
189 struct passwd *pw = NULL;
192 fstring real_username;
194 bool username_was_mapped = false;
195 bool map_domainuser_to_guest = false;
197 if (!spnego_parse_krb5_wrap(talloc_tos(), *secblob, &ticket, tok_id)) {
198 status = NT_STATUS_LOGON_FAILURE;
202 status = ads_verify_ticket(smb2req, lp_realm(), 0, &ticket,
203 &client, &logon_info, &ap_rep,
206 if (!NT_STATUS_IS_OK(status)) {
207 DEBUG(1,("smb2: Failed to verify incoming ticket with error %s!\n",
209 if (!NT_STATUS_EQUAL(status, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
210 status = NT_STATUS_LOGON_FAILURE;
215 DEBUG(3,("smb2: Ticket name is [%s]\n", client));
217 p = strchr_m(client, '@');
219 DEBUG(3,("smb2: %s Doesn't look like a valid principal\n",
221 status = NT_STATUS_LOGON_FAILURE;
227 /* save the PAC data if we have it */
230 netsamlogon_cache_store(client, &logon_info->info3);
233 if (!strequal(p+1, lp_realm())) {
234 DEBUG(3,("smb2: Ticket for foreign realm %s@%s\n", client, p+1));
235 if (!lp_allow_trusted_domains()) {
236 status = NT_STATUS_LOGON_FAILURE;
241 /* this gives a fully qualified user name (ie. with full realm).
242 that leads to very long usernames, but what else can we do? */
246 if (logon_info && logon_info->info3.base.domain.string) {
247 domain = talloc_strdup(talloc_tos(),
248 logon_info->info3.base.domain.string);
250 status = NT_STATUS_NO_MEMORY;
253 DEBUG(10, ("smb2: Mapped to [%s] (using PAC)\n", domain));
256 /* If we have winbind running, we can (and must) shorten the
257 username by using the short netbios name. Otherwise we will
258 have inconsistent user names. With Kerberos, we get the
259 fully qualified realm, with ntlmssp we get the short
260 name. And even w2k3 does use ntlmssp if you for example
261 connect to an ip address. */
264 struct wbcDomainInfo *info = NULL;
266 DEBUG(10, ("smb2: Mapping [%s] to short name\n", domain));
268 wbc_status = wbcDomainInfo(domain, &info);
270 if (WBC_ERROR_IS_OK(wbc_status)) {
271 domain = talloc_strdup(talloc_tos(), info->short_name);
275 status = NT_STATUS_NO_MEMORY;
278 DEBUG(10, ("smb2: Mapped to [%s] (using Winbind)\n", domain));
280 DEBUG(3, ("smb2: Could not find short name: %s\n",
281 wbcErrorString(wbc_status)));
285 /* We have to use fstring for this - map_username requires it. */
286 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
288 /* lookup the passwd struct, create a new user if necessary */
290 username_was_mapped = map_username(user);
292 pw = smb_getpwnam(talloc_tos(), user, real_username, true );
294 /* if a real user check pam account restrictions */
295 /* only really perfomed if "obey pam restriction" is true */
296 /* do this before an eventual mapping to guest occurs */
297 status = smb_pam_accountcheck(pw->pw_name);
298 if (!NT_STATUS_IS_OK(status)) {
299 DEBUG(1,("smb2: PAM account restriction "
300 "prevents user login\n"));
307 /* this was originally the behavior of Samba 2.2, if a user
308 did not have a local uid but has been authenticated, then
309 map them to a guest account */
311 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
312 map_domainuser_to_guest = true;
313 fstrcpy(user,lp_guestaccount());
314 pw = smb_getpwnam(talloc_tos(), user, real_username, true );
317 /* extra sanity check that the guest account is valid */
320 DEBUG(1,("smb2: Username %s is invalid on this system\n",
322 status = NT_STATUS_LOGON_FAILURE;
327 /* setup the string used by %U */
329 sub_set_smb_name(real_username);
330 reload_services(smb2req->sconn->msg_ctx, true);
332 if (map_domainuser_to_guest) {
333 make_server_info_guest(session, &session->server_info);
334 } else if (logon_info) {
335 /* pass the unmapped username here since map_username()
336 will be called again from inside make_server_info_info3() */
338 status = make_server_info_info3(session,
341 &session->server_info,
343 if (!NT_STATUS_IS_OK(status) ) {
344 DEBUG(1,("smb2: make_server_info_info3 failed: %s!\n",
351 * We didn't get a PAC, we have to make up the user
352 * ourselves. Try to ask the pdb backend to provide
353 * SID consistency with ntlmssp session setup
355 struct samu *sampass;
356 /* The stupid make_server_info_XX functions here
357 don't take a talloc context. */
358 struct auth_serversupplied_info *tmp_server_info = NULL;
360 sampass = samu_new(talloc_tos());
361 if (sampass == NULL) {
362 status = NT_STATUS_NO_MEMORY;
366 if (pdb_getsampwnam(sampass, real_username)) {
367 DEBUG(10, ("smb2: found user %s in passdb, calling "
368 "make_server_info_sam\n", real_username));
369 status = make_server_info_sam(&tmp_server_info, sampass);
370 TALLOC_FREE(sampass);
373 * User not in passdb, make it up artificially
375 TALLOC_FREE(sampass);
376 DEBUG(10, ("smb2: didn't find user %s in passdb, calling "
377 "make_server_info_pw\n", real_username));
378 status = make_server_info_pw(&tmp_server_info,
383 if (!NT_STATUS_IS_OK(status)) {
384 DEBUG(1,("smb2: make_server_info_[sam|pw] failed: %s!\n",
389 /* Steal tmp_server_info into the session->server_info
391 session->server_info = talloc_move(session, &tmp_server_info);
393 /* make_server_info_pw does not set the domain. Without this
394 * we end up with the local netbios name in substitutions for
397 if (session->server_info->info3 != NULL) {
398 session->server_info->info3->base.domain.string =
399 talloc_strdup(session->server_info->info3, domain);
404 session->server_info->nss_token |= username_was_mapped;
406 /* we need to build the token for the user. make_server_info_guest()
409 if (!session->server_info->ptok ) {
410 status = create_local_token(session->server_info);
411 if (!NT_STATUS_IS_OK(status)) {
412 DEBUG(10,("smb2: failed to create local token: %s\n",
418 if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
419 lp_server_signing() == Required) {
420 session->do_signing = true;
423 if (session->server_info->guest) {
424 /* we map anonymous to guest internally */
425 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
426 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
427 /* force no signing */
428 session->do_signing = false;
431 data_blob_free(&session->server_info->user_session_key);
432 session->server_info->user_session_key =
434 session->server_info,
437 if (session_key.length > 0) {
438 if (session->server_info->user_session_key.data == NULL) {
439 status = NT_STATUS_NO_MEMORY;
443 session->session_key = session->server_info->user_session_key;
445 session->compat_vuser = talloc_zero(session, user_struct);
446 if (session->compat_vuser == NULL) {
447 status = NT_STATUS_NO_MEMORY;
450 session->compat_vuser->auth_ntlmssp_state = NULL;
451 session->compat_vuser->homes_snum = -1;
452 session->compat_vuser->server_info = session->server_info;
453 session->compat_vuser->session_keystr = NULL;
454 session->compat_vuser->vuid = session->vuid;
455 DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
457 /* This is a potentially untrusted username */
462 session->server_info->sanitized_username = talloc_strdup(
463 session->server_info, tmp);
465 if (!session->server_info->guest) {
466 session->compat_vuser->homes_snum =
467 register_homes_share(session->server_info->unix_name);
470 if (!session_claim(sconn_server_id(session->sconn),
471 session->compat_vuser)) {
472 DEBUG(1, ("smb2: Failed to claim session "
474 session->compat_vuser->vuid));
478 session->status = NT_STATUS_OK;
481 * we attach the session to the request
482 * so that the response can be signed
484 smb2req->session = session;
485 if (session->do_signing) {
486 smb2req->do_signing = true;
489 global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
490 status = NT_STATUS_OK;
492 /* wrap that up in a nice GSS-API wrapping */
493 ap_rep_wrapped = spnego_gen_krb5_wrap(talloc_tos(), ap_rep,
496 secblob_out = spnego_gen_auth_response(
502 *out_security_buffer = data_blob_talloc(smb2req,
505 if (secblob_out.data && out_security_buffer->data == NULL) {
506 status = NT_STATUS_NO_MEMORY;
510 data_blob_free(&ap_rep);
511 data_blob_free(&ap_rep_wrapped);
512 data_blob_free(&ticket);
513 data_blob_free(&session_key);
514 data_blob_free(&secblob_out);
516 *out_session_id = session->vuid;
522 data_blob_free(&ap_rep);
523 data_blob_free(&ap_rep_wrapped);
524 data_blob_free(&ticket);
525 data_blob_free(&session_key);
526 data_blob_free(&secblob_out);
528 ap_rep_wrapped = data_blob_null;
529 secblob_out = spnego_gen_auth_response(
535 *out_security_buffer = data_blob_talloc(smb2req,
538 data_blob_free(&secblob_out);
543 static NTSTATUS smbd_smb2_spnego_negotiate(struct smbd_smb2_session *session,
544 struct smbd_smb2_request *smb2req,
545 uint8_t in_security_mode,
546 DATA_BLOB in_security_buffer,
547 uint16_t *out_session_flags,
548 DATA_BLOB *out_security_buffer,
549 uint64_t *out_session_id)
551 DATA_BLOB secblob_in = data_blob_null;
552 DATA_BLOB chal_out = data_blob_null;
553 char *kerb_mech = NULL;
556 /* Ensure we have no old NTLM state around. */
557 TALLOC_FREE(session->auth_ntlmssp_state);
559 status = parse_spnego_mechanisms(talloc_tos(), in_security_buffer,
560 &secblob_in, &kerb_mech);
561 if (!NT_STATUS_IS_OK(status)) {
566 if (kerb_mech && ((lp_security()==SEC_ADS) ||
567 USE_KERBEROS_KEYTAB) ) {
568 status = smbd_smb2_session_setup_krb5(session,
582 /* The mechtoken is a krb5 ticket, but
583 * we need to fall back to NTLM. */
585 DEBUG(3,("smb2: Got krb5 ticket in SPNEGO "
586 "but set to downgrade to NTLMSSP\n"));
588 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
590 /* Fall back to NTLMSSP. */
591 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
592 if (!NT_STATUS_IS_OK(status)) {
596 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
601 if (!NT_STATUS_IS_OK(status) &&
602 !NT_STATUS_EQUAL(status,
603 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
607 *out_security_buffer = spnego_gen_auth_response(smb2req,
611 if (out_security_buffer->data == NULL) {
612 status = NT_STATUS_NO_MEMORY;
615 *out_session_id = session->vuid;
619 data_blob_free(&secblob_in);
620 data_blob_free(&chal_out);
621 TALLOC_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;
722 if (!spnego_parse_auth(talloc_tos(), 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(talloc_tos(),
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 TALLOC_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 TALLOC_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 /* We need to call setup_ntlmssp_server_info() if status==NT_STATUS_OK,
791 or if status is anything except NT_STATUS_MORE_PROCESSING_REQUIRED,
792 as this can trigger map to guest. */
793 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
794 status = setup_ntlmssp_server_info(session, status);
797 if (!NT_STATUS_IS_OK(status) &&
798 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
799 TALLOC_FREE(session->auth_ntlmssp_state);
800 data_blob_free(&auth);
801 TALLOC_FREE(session);
805 data_blob_free(&auth);
807 *out_security_buffer = spnego_gen_auth_response(smb2req,
808 &auth_out, status, NULL);
810 if (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);