s3: Pass the rhost through smb_pam_accountcheck
[Samba/ita.git] / source3 / smbd / smb2_sesssetup.c
blob4a91e845fc01f66bf918abd1bc83a64ef82d924f
1 /*
2 Unix SMB/CIFS implementation.
3 Core SMB2 server
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/>.
22 #include "includes.h"
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)
41 const uint8_t *inhdr;
42 const uint8_t *inbody;
43 int i = smb2req->current_idx;
44 uint8_t *outhdr;
45 DATA_BLOB outbody;
46 DATA_BLOB outdyn;
47 size_t expected_body_size = 0x19;
48 size_t body_size;
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;
58 NTSTATUS status;
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,
90 in_session_id,
91 in_security_mode,
92 in_security_buffer,
93 &out_session_flags,
94 &out_security_buffer,
95 &out_session_id);
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,
124 __location__);
127 static int smbd_smb2_session_destructor(struct smbd_smb2_session *session)
129 if (session->sconn == NULL) {
130 return 0;
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);
142 session->vuid = 0;
143 session->status = NT_STATUS_USER_SESSION_DELETED;
144 session->sconn = NULL;
146 return 0;
149 static NTSTATUS setup_ntlmssp_server_info(struct smbd_smb2_session *session,
150 NTSTATUS status)
152 if (NT_STATUS_IS_OK(status)) {
153 status = auth_ntlmssp_steal_server_info(session,
154 session->auth_ntlmssp_state,
155 &session->server_info);
156 } else {
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));
166 return status;
169 #ifdef HAVE_KRB5
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,
174 const char *mechOID,
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;
184 uint8 tok_id[2];
185 struct PAC_LOGON_INFO *logon_info = NULL;
186 char *client = NULL;
187 char *p = NULL;
188 char *domain = NULL;
189 struct passwd *pw = NULL;
190 NTSTATUS status;
191 fstring user;
192 fstring real_username;
193 fstring tmp;
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;
199 goto fail;
202 status = ads_verify_ticket(smb2req, lp_realm(), 0, &ticket,
203 &client, &logon_info, &ap_rep,
204 &session_key, true);
206 if (!NT_STATUS_IS_OK(status)) {
207 DEBUG(1,("smb2: Failed to verify incoming ticket with error %s!\n",
208 nt_errstr(status)));
209 if (!NT_STATUS_EQUAL(status, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
210 status = NT_STATUS_LOGON_FAILURE;
212 goto fail;
215 DEBUG(3,("smb2: Ticket name is [%s]\n", client));
217 p = strchr_m(client, '@');
218 if (!p) {
219 DEBUG(3,("smb2: %s Doesn't look like a valid principal\n",
220 client));
221 status = NT_STATUS_LOGON_FAILURE;
222 goto fail;
225 *p = 0;
227 /* save the PAC data if we have it */
229 if (logon_info) {
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;
237 goto fail;
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? */
244 domain = p+1;
246 if (logon_info && logon_info->info3.base.domain.string) {
247 domain = talloc_strdup(talloc_tos(),
248 logon_info->info3.base.domain.string);
249 if (!domain) {
250 status = NT_STATUS_NO_MEMORY;
251 goto fail;
253 DEBUG(10, ("smb2: Mapped to [%s] (using PAC)\n", domain));
254 } else {
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. */
263 wbcErr wbc_status;
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);
273 wbcFreeMemory(info);
274 if (!domain) {
275 status = NT_STATUS_NO_MEMORY;
276 goto fail;
278 DEBUG(10, ("smb2: Mapped to [%s] (using Winbind)\n", domain));
279 } else {
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 );
293 if (pw) {
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(
298 pw->pw_name, smb2req->sconn->client_id.name);
299 if (!NT_STATUS_IS_OK(status)) {
300 DEBUG(1,("smb2: PAM account restriction "
301 "prevents user login\n"));
302 goto fail;
306 if (!pw) {
308 /* this was originally the behavior of Samba 2.2, if a user
309 did not have a local uid but has been authenticated, then
310 map them to a guest account */
312 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
313 map_domainuser_to_guest = true;
314 fstrcpy(user,lp_guestaccount());
315 pw = smb_getpwnam(talloc_tos(), user, real_username, true );
318 /* extra sanity check that the guest account is valid */
320 if (!pw) {
321 DEBUG(1,("smb2: Username %s is invalid on this system\n",
322 user));
323 status = NT_STATUS_LOGON_FAILURE;
324 goto fail;
328 /* setup the string used by %U */
330 sub_set_smb_name(real_username);
331 reload_services(smb2req->sconn->msg_ctx, smb2req->sconn->sock, true);
333 if (map_domainuser_to_guest) {
334 make_server_info_guest(session, &session->server_info);
335 } else if (logon_info) {
336 /* pass the unmapped username here since map_username()
337 will be called again from inside make_server_info_info3() */
339 status = make_server_info_info3(session,
340 client,
341 domain,
342 &session->server_info,
343 &logon_info->info3);
344 if (!NT_STATUS_IS_OK(status) ) {
345 DEBUG(1,("smb2: make_server_info_info3 failed: %s!\n",
346 nt_errstr(status)));
347 goto fail;
350 } else {
352 * We didn't get a PAC, we have to make up the user
353 * ourselves. Try to ask the pdb backend to provide
354 * SID consistency with ntlmssp session setup
356 struct samu *sampass;
357 /* The stupid make_server_info_XX functions here
358 don't take a talloc context. */
359 struct auth_serversupplied_info *tmp_server_info = NULL;
361 sampass = samu_new(talloc_tos());
362 if (sampass == NULL) {
363 status = NT_STATUS_NO_MEMORY;
364 goto fail;
367 if (pdb_getsampwnam(sampass, real_username)) {
368 DEBUG(10, ("smb2: found user %s in passdb, calling "
369 "make_server_info_sam\n", real_username));
370 status = make_server_info_sam(&tmp_server_info, sampass);
371 TALLOC_FREE(sampass);
372 } else {
374 * User not in passdb, make it up artificially
376 TALLOC_FREE(sampass);
377 DEBUG(10, ("smb2: didn't find user %s in passdb, calling "
378 "make_server_info_pw\n", real_username));
379 status = make_server_info_pw(&tmp_server_info,
380 real_username,
381 pw);
384 if (!NT_STATUS_IS_OK(status)) {
385 DEBUG(1,("smb2: make_server_info_[sam|pw] failed: %s!\n",
386 nt_errstr(status)));
387 goto fail;
390 /* Steal tmp_server_info into the session->server_info
391 pointer. */
392 session->server_info = talloc_move(session, &tmp_server_info);
394 /* make_server_info_pw does not set the domain. Without this
395 * we end up with the local netbios name in substitutions for
396 * %D. */
398 if (session->server_info->info3 != NULL) {
399 session->server_info->info3->base.domain.string =
400 talloc_strdup(session->server_info->info3, domain);
405 session->server_info->nss_token |= username_was_mapped;
407 /* we need to build the token for the user. make_server_info_guest()
408 already does this */
410 if (!session->server_info->ptok ) {
411 status = create_local_token(session->server_info);
412 if (!NT_STATUS_IS_OK(status)) {
413 DEBUG(10,("smb2: failed to create local token: %s\n",
414 nt_errstr(status)));
415 goto fail;
419 if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
420 lp_server_signing() == Required) {
421 session->do_signing = true;
424 if (session->server_info->guest) {
425 /* we map anonymous to guest internally */
426 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
427 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
428 /* force no signing */
429 session->do_signing = false;
432 data_blob_free(&session->server_info->user_session_key);
433 session->server_info->user_session_key =
434 data_blob_talloc(
435 session->server_info,
436 session_key.data,
437 session_key.length);
438 if (session_key.length > 0) {
439 if (session->server_info->user_session_key.data == NULL) {
440 status = NT_STATUS_NO_MEMORY;
441 goto fail;
444 session->session_key = session->server_info->user_session_key;
446 session->compat_vuser = talloc_zero(session, user_struct);
447 if (session->compat_vuser == NULL) {
448 status = NT_STATUS_NO_MEMORY;
449 goto fail;
451 session->compat_vuser->auth_ntlmssp_state = NULL;
452 session->compat_vuser->homes_snum = -1;
453 session->compat_vuser->server_info = session->server_info;
454 session->compat_vuser->session_keystr = NULL;
455 session->compat_vuser->vuid = session->vuid;
456 DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
458 /* This is a potentially untrusted username */
459 alpha_strcpy(tmp,
460 client,
461 ". _-$",
462 sizeof(tmp));
463 session->server_info->sanitized_username = talloc_strdup(
464 session->server_info, tmp);
466 if (!session->server_info->guest) {
467 session->compat_vuser->homes_snum =
468 register_homes_share(session->server_info->unix_name);
471 if (!session_claim(session->sconn, session->compat_vuser)) {
472 DEBUG(1, ("smb2: Failed to claim session "
473 "for vuid=%d\n",
474 session->compat_vuser->vuid));
475 goto fail;
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,
494 TOK_ID_KRB_AP_REP);
496 secblob_out = spnego_gen_auth_response(
497 talloc_tos(),
498 &ap_rep_wrapped,
499 status,
500 mechOID);
502 *out_security_buffer = data_blob_talloc(smb2req,
503 secblob_out.data,
504 secblob_out.length);
505 if (secblob_out.data && out_security_buffer->data == NULL) {
506 status = NT_STATUS_NO_MEMORY;
507 goto fail;
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;
518 return NT_STATUS_OK;
520 fail:
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(
530 talloc_tos(),
531 &ap_rep_wrapped,
532 status,
533 mechOID);
535 *out_security_buffer = data_blob_talloc(smb2req,
536 secblob_out.data,
537 secblob_out.length);
538 data_blob_free(&secblob_out);
539 return status;
541 #endif
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;
554 NTSTATUS status;
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)) {
562 goto out;
565 #ifdef HAVE_KRB5
566 if (kerb_mech && ((lp_security()==SEC_ADS) ||
567 USE_KERBEROS_KEYTAB) ) {
568 status = smbd_smb2_session_setup_krb5(session,
569 smb2req,
570 in_security_mode,
571 &secblob_in,
572 kerb_mech,
573 out_session_flags,
574 out_security_buffer,
575 out_session_id);
577 goto out;
579 #endif
581 if (kerb_mech) {
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;
589 } else {
590 /* Fall back to NTLMSSP. */
591 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
592 if (!NT_STATUS_IS_OK(status)) {
593 goto out;
596 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
597 secblob_in,
598 &chal_out);
601 if (!NT_STATUS_IS_OK(status) &&
602 !NT_STATUS_EQUAL(status,
603 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
604 goto out;
607 *out_security_buffer = spnego_gen_auth_response(smb2req,
608 &chal_out,
609 status,
610 OID_NTLMSSP);
611 if (out_security_buffer->data == NULL) {
612 status = NT_STATUS_NO_MEMORY;
613 goto out;
615 *out_session_id = session->vuid;
617 out:
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);
628 return status;
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)
638 fstring tmp;
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 */
669 alpha_strcpy(tmp,
670 auth_ntlmssp_get_username(session->auth_ntlmssp_state),
671 ". _-$",
672 sizeof(tmp));
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(session->sconn, session->compat_vuser)) {
682 DEBUG(1, ("smb2: Failed to claim session "
683 "for vuid=%d\n",
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;
706 return NT_STATUS_OK;
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 NTSTATUS status;
721 if (!spnego_parse_auth(talloc_tos(), in_security_buffer, &auth)) {
722 TALLOC_FREE(session);
723 return NT_STATUS_LOGON_FAILURE;
726 if (auth.data[0] == ASN1_APPLICATION(0)) {
727 /* Might be a second negTokenTarg packet */
728 DATA_BLOB secblob_in = data_blob_null;
729 char *kerb_mech = NULL;
731 status = parse_spnego_mechanisms(talloc_tos(),
732 in_security_buffer,
733 &secblob_in, &kerb_mech);
734 if (!NT_STATUS_IS_OK(status)) {
735 TALLOC_FREE(session);
736 return status;
739 #ifdef HAVE_KRB5
740 if (kerb_mech && ((lp_security()==SEC_ADS) ||
741 USE_KERBEROS_KEYTAB) ) {
742 status = smbd_smb2_session_setup_krb5(session,
743 smb2req,
744 in_security_mode,
745 &secblob_in,
746 kerb_mech,
747 out_session_flags,
748 out_security_buffer,
749 out_session_id);
751 data_blob_free(&secblob_in);
752 TALLOC_FREE(kerb_mech);
753 if (!NT_STATUS_IS_OK(status)) {
754 TALLOC_FREE(session);
756 return status;
758 #endif
760 /* Can't blunder into NTLMSSP auth if we have
761 * a krb5 ticket. */
763 if (kerb_mech) {
764 DEBUG(3,("smb2: network "
765 "misconfiguration, client sent us a "
766 "krb5 ticket and kerberos security "
767 "not enabled\n"));
768 TALLOC_FREE(session);
769 data_blob_free(&secblob_in);
770 TALLOC_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);
782 return status;
786 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
787 auth,
788 &auth_out);
789 /* We need to call setup_ntlmssp_server_info() if status==NT_STATUS_OK,
790 or if status is anything except NT_STATUS_MORE_PROCESSING_REQUIRED,
791 as this can trigger map to guest. */
792 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
793 status = setup_ntlmssp_server_info(session, status);
796 if (!NT_STATUS_IS_OK(status) &&
797 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
798 TALLOC_FREE(session->auth_ntlmssp_state);
799 data_blob_free(&auth);
800 TALLOC_FREE(session);
801 return status;
804 data_blob_free(&auth);
806 *out_security_buffer = spnego_gen_auth_response(smb2req,
807 &auth_out, status, NULL);
809 if (out_security_buffer->data == NULL) {
810 TALLOC_FREE(session->auth_ntlmssp_state);
811 TALLOC_FREE(session);
812 return NT_STATUS_NO_MEMORY;
815 *out_session_id = session->vuid;
817 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
818 return NT_STATUS_MORE_PROCESSING_REQUIRED;
821 /* We're done - claim the session. */
822 return smbd_smb2_common_ntlmssp_auth_return(session,
823 smb2req,
824 in_security_mode,
825 in_security_buffer,
826 out_session_flags,
827 out_session_id);
830 static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session,
831 struct smbd_smb2_request *smb2req,
832 uint8_t in_security_mode,
833 DATA_BLOB in_security_buffer,
834 uint16_t *out_session_flags,
835 DATA_BLOB *out_security_buffer,
836 uint64_t *out_session_id)
838 NTSTATUS status;
839 DATA_BLOB secblob_out = data_blob_null;
841 if (session->auth_ntlmssp_state == NULL) {
842 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
843 if (!NT_STATUS_IS_OK(status)) {
844 TALLOC_FREE(session);
845 return status;
849 /* RAW NTLMSSP */
850 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
851 in_security_buffer,
852 &secblob_out);
854 if (NT_STATUS_IS_OK(status) ||
855 NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
856 *out_security_buffer = data_blob_talloc(smb2req,
857 secblob_out.data,
858 secblob_out.length);
859 if (secblob_out.data && out_security_buffer->data == NULL) {
860 TALLOC_FREE(session->auth_ntlmssp_state);
861 TALLOC_FREE(session);
862 return NT_STATUS_NO_MEMORY;
866 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
867 *out_session_id = session->vuid;
868 return status;
871 status = setup_ntlmssp_server_info(session, status);
873 if (!NT_STATUS_IS_OK(status)) {
874 TALLOC_FREE(session->auth_ntlmssp_state);
875 TALLOC_FREE(session);
876 return status;
878 *out_session_id = session->vuid;
880 return smbd_smb2_common_ntlmssp_auth_return(session,
881 smb2req,
882 in_security_mode,
883 in_security_buffer,
884 out_session_flags,
885 out_session_id);
888 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
889 uint64_t in_session_id,
890 uint8_t in_security_mode,
891 DATA_BLOB in_security_buffer,
892 uint16_t *out_session_flags,
893 DATA_BLOB *out_security_buffer,
894 uint64_t *out_session_id)
896 struct smbd_smb2_session *session;
898 *out_session_flags = 0;
899 *out_session_id = 0;
901 if (in_session_id == 0) {
902 int id;
904 /* create a new session */
905 session = talloc_zero(smb2req->sconn, struct smbd_smb2_session);
906 if (session == NULL) {
907 return NT_STATUS_NO_MEMORY;
909 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
910 id = idr_get_new_random(smb2req->sconn->smb2.sessions.idtree,
911 session,
912 smb2req->sconn->smb2.sessions.limit);
913 if (id == -1) {
914 return NT_STATUS_INSUFFICIENT_RESOURCES;
916 session->vuid = id;
918 session->tcons.idtree = idr_init(session);
919 if (session->tcons.idtree == NULL) {
920 return NT_STATUS_NO_MEMORY;
922 session->tcons.limit = 0x0000FFFE;
923 session->tcons.list = NULL;
925 DLIST_ADD_END(smb2req->sconn->smb2.sessions.list, session,
926 struct smbd_smb2_session *);
927 session->sconn = smb2req->sconn;
928 talloc_set_destructor(session, smbd_smb2_session_destructor);
929 } else {
930 void *p;
932 /* lookup an existing session */
933 p = idr_find(smb2req->sconn->smb2.sessions.idtree, in_session_id);
934 if (p == NULL) {
935 return NT_STATUS_USER_SESSION_DELETED;
937 session = talloc_get_type_abort(p, struct smbd_smb2_session);
940 if (NT_STATUS_IS_OK(session->status)) {
941 return NT_STATUS_REQUEST_NOT_ACCEPTED;
944 if (in_security_buffer.data[0] == ASN1_APPLICATION(0)) {
945 return smbd_smb2_spnego_negotiate(session,
946 smb2req,
947 in_security_mode,
948 in_security_buffer,
949 out_session_flags,
950 out_security_buffer,
951 out_session_id);
952 } else if (in_security_buffer.data[0] == ASN1_CONTEXT(1)) {
953 return smbd_smb2_spnego_auth(session,
954 smb2req,
955 in_security_mode,
956 in_security_buffer,
957 out_session_flags,
958 out_security_buffer,
959 out_session_id);
960 } else if (strncmp((char *)(in_security_buffer.data), "NTLMSSP", 7) == 0) {
961 return smbd_smb2_raw_ntlmssp_auth(session,
962 smb2req,
963 in_security_mode,
964 in_security_buffer,
965 out_session_flags,
966 out_security_buffer,
967 out_session_id);
970 /* Unknown packet type. */
971 DEBUG(1,("Unknown packet type %u in smb2 sessionsetup\n",
972 (unsigned int)in_security_buffer.data[0] ));
973 TALLOC_FREE(session->auth_ntlmssp_state);
974 TALLOC_FREE(session);
975 return NT_STATUS_LOGON_FAILURE;
978 NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
980 const uint8_t *inhdr;
981 const uint8_t *outhdr;
982 int i = req->current_idx;
983 uint64_t in_session_id;
984 void *p;
985 struct smbd_smb2_session *session;
986 bool chained_fixup = false;
988 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
990 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
992 if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
993 if (req->async) {
995 * async request - fill in session_id from
996 * already setup request out.vector[].iov_base.
998 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
999 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1000 } else if (i > 2) {
1002 * Chained request - fill in session_id from
1003 * the previous request out.vector[].iov_base.
1005 outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
1006 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1007 chained_fixup = true;
1011 /* lookup an existing session */
1012 p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
1013 if (p == NULL) {
1014 return NT_STATUS_USER_SESSION_DELETED;
1016 session = talloc_get_type_abort(p, struct smbd_smb2_session);
1018 if (!NT_STATUS_IS_OK(session->status)) {
1019 return NT_STATUS_ACCESS_DENIED;
1022 set_current_user_info(session->server_info->sanitized_username,
1023 session->server_info->unix_name,
1024 session->server_info->info3->base.domain.string);
1026 req->session = session;
1028 if (chained_fixup) {
1029 /* Fix up our own outhdr. */
1030 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1031 SBVAL(outhdr, SMB2_HDR_SESSION_ID, in_session_id);
1033 return NT_STATUS_OK;
1036 NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req)
1038 const uint8_t *inbody;
1039 int i = req->current_idx;
1040 DATA_BLOB outbody;
1041 size_t expected_body_size = 0x04;
1042 size_t body_size;
1044 if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
1045 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1048 inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
1050 body_size = SVAL(inbody, 0x00);
1051 if (body_size != expected_body_size) {
1052 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1056 * TODO: cancel all outstanding requests on the session
1057 * and delete all tree connections.
1059 smbd_smb2_session_destructor(req->session);
1061 * we may need to sign the response, so we need to keep
1062 * the session until the response is sent to the wire.
1064 talloc_steal(req, req->session);
1066 outbody = data_blob_talloc(req->out.vector, NULL, 0x04);
1067 if (outbody.data == NULL) {
1068 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
1071 SSVAL(outbody.data, 0x00, 0x04); /* struct size */
1072 SSVAL(outbody.data, 0x02, 0); /* reserved */
1074 return smbd_smb2_request_done(req, outbody, NULL);