s4-smbtorture: remove another incarnation of test_ClosePrinter.
[Samba.git] / source3 / smbd / smb2_sesssetup.c
blobaf9157107ec6f829716d9f4ec64cab498d49e7e3
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"
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)
38 const uint8_t *inhdr;
39 const uint8_t *inbody;
40 int i = smb2req->current_idx;
41 uint8_t *outhdr;
42 DATA_BLOB outbody;
43 DATA_BLOB outdyn;
44 size_t expected_body_size = 0x19;
45 size_t body_size;
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;
55 NTSTATUS status;
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,
87 in_session_id,
88 in_security_mode,
89 in_security_buffer,
90 &out_session_flags,
91 &out_security_buffer,
92 &out_session_id);
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,
121 __location__);
124 static int smbd_smb2_session_destructor(struct smbd_smb2_session *session)
126 if (session->sconn == NULL) {
127 return 0;
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);
139 session->vuid = 0;
140 session->status = NT_STATUS_USER_SESSION_DELETED;
141 session->sconn = NULL;
143 return 0;
146 #ifdef HAVE_KRB5
147 static NTSTATUS smbd_smb2_session_setup_krb5(struct smbd_smb2_session *session,
148 struct smbd_smb2_request *smb2req,
149 uint8_t in_security_mode,
150 const DATA_BLOB *secblob,
151 const char *mechOID,
152 uint16_t *out_session_flags,
153 DATA_BLOB *out_security_buffer,
154 uint64_t *out_session_id)
156 DATA_BLOB ap_rep = data_blob_null;
157 DATA_BLOB ap_rep_wrapped = data_blob_null;
158 DATA_BLOB ticket = data_blob_null;
159 DATA_BLOB session_key = data_blob_null;
160 DATA_BLOB secblob_out = data_blob_null;
161 uint8 tok_id[2];
162 struct PAC_LOGON_INFO *logon_info = NULL;
163 char *client = NULL;
164 char *p = NULL;
165 char *domain = NULL;
166 struct passwd *pw = NULL;
167 NTSTATUS status;
168 fstring user;
169 fstring real_username;
170 fstring tmp;
171 bool username_was_mapped = false;
172 bool map_domainuser_to_guest = false;
174 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
175 status = NT_STATUS_LOGON_FAILURE;
176 goto fail;
179 status = ads_verify_ticket(smb2req, lp_realm(), 0, &ticket,
180 &client, &logon_info, &ap_rep,
181 &session_key, true);
183 if (!NT_STATUS_IS_OK(status)) {
184 DEBUG(1,("smb2: Failed to verify incoming ticket with error %s!\n",
185 nt_errstr(status)));
186 if (!NT_STATUS_EQUAL(status, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
187 status = NT_STATUS_LOGON_FAILURE;
189 goto fail;
192 DEBUG(3,("smb2: Ticket name is [%s]\n", client));
194 p = strchr_m(client, '@');
195 if (!p) {
196 DEBUG(3,("smb2: %s Doesn't look like a valid principal\n",
197 client));
198 status = NT_STATUS_LOGON_FAILURE;
199 goto fail;
202 *p = 0;
204 /* save the PAC data if we have it */
206 if (logon_info) {
207 netsamlogon_cache_store(client, &logon_info->info3);
210 if (!strequal(p+1, lp_realm())) {
211 DEBUG(3,("smb2: Ticket for foreign realm %s@%s\n", client, p+1));
212 if (!lp_allow_trusted_domains()) {
213 status = NT_STATUS_LOGON_FAILURE;
214 goto fail;
218 /* this gives a fully qualified user name (ie. with full realm).
219 that leads to very long usernames, but what else can we do? */
221 domain = p+1;
223 if (logon_info && logon_info->info3.base.domain.string) {
224 domain = talloc_strdup(talloc_tos(),
225 logon_info->info3.base.domain.string);
226 if (!domain) {
227 status = NT_STATUS_NO_MEMORY;
228 goto fail;
230 DEBUG(10, ("smb2: Mapped to [%s] (using PAC)\n", domain));
231 } else {
233 /* If we have winbind running, we can (and must) shorten the
234 username by using the short netbios name. Otherwise we will
235 have inconsistent user names. With Kerberos, we get the
236 fully qualified realm, with ntlmssp we get the short
237 name. And even w2k3 does use ntlmssp if you for example
238 connect to an ip address. */
240 wbcErr wbc_status;
241 struct wbcDomainInfo *info = NULL;
243 DEBUG(10, ("smb2: Mapping [%s] to short name\n", domain));
245 wbc_status = wbcDomainInfo(domain, &info);
247 if (WBC_ERROR_IS_OK(wbc_status)) {
248 domain = talloc_strdup(talloc_tos(), info->short_name);
250 wbcFreeMemory(info);
251 if (!domain) {
252 status = NT_STATUS_NO_MEMORY;
253 goto fail;
255 DEBUG(10, ("smb2: Mapped to [%s] (using Winbind)\n", domain));
256 } else {
257 DEBUG(3, ("smb2: Could not find short name: %s\n",
258 wbcErrorString(wbc_status)));
262 /* We have to use fstring for this - map_username requires it. */
263 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
265 /* lookup the passwd struct, create a new user if necessary */
267 username_was_mapped = map_username(user);
269 pw = smb_getpwnam(talloc_tos(), user, real_username, true );
270 if (pw) {
271 /* if a real user check pam account restrictions */
272 /* only really perfomed if "obey pam restriction" is true */
273 /* do this before an eventual mapping to guest occurs */
274 status = smb_pam_accountcheck(pw->pw_name);
275 if (!NT_STATUS_IS_OK(status)) {
276 DEBUG(1,("smb2: PAM account restriction "
277 "prevents user login\n"));
278 goto fail;
282 if (!pw) {
284 /* this was originally the behavior of Samba 2.2, if a user
285 did not have a local uid but has been authenticated, then
286 map them to a guest account */
288 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
289 map_domainuser_to_guest = true;
290 fstrcpy(user,lp_guestaccount());
291 pw = smb_getpwnam(talloc_tos(), user, real_username, true );
294 /* extra sanity check that the guest account is valid */
296 if (!pw) {
297 DEBUG(1,("smb2: Username %s is invalid on this system\n",
298 user));
299 status = NT_STATUS_LOGON_FAILURE;
300 goto fail;
304 /* setup the string used by %U */
306 sub_set_smb_name(real_username);
307 reload_services(true);
309 if (map_domainuser_to_guest) {
310 make_server_info_guest(session, &session->server_info);
311 } else if (logon_info) {
312 /* pass the unmapped username here since map_username()
313 will be called again from inside make_server_info_info3() */
315 status = make_server_info_info3(session,
316 client,
317 domain,
318 &session->server_info,
319 &logon_info->info3);
320 if (!NT_STATUS_IS_OK(status) ) {
321 DEBUG(1,("smb2: make_server_info_info3 failed: %s!\n",
322 nt_errstr(status)));
323 goto fail;
326 } else {
328 * We didn't get a PAC, we have to make up the user
329 * ourselves. Try to ask the pdb backend to provide
330 * SID consistency with ntlmssp session setup
332 struct samu *sampass;
333 /* The stupid make_server_info_XX functions here
334 don't take a talloc context. */
335 struct auth_serversupplied_info *tmp_server_info = NULL;
337 sampass = samu_new(talloc_tos());
338 if (sampass == NULL) {
339 status = NT_STATUS_NO_MEMORY;
340 goto fail;
343 if (pdb_getsampwnam(sampass, real_username)) {
344 DEBUG(10, ("smb2: found user %s in passdb, calling "
345 "make_server_info_sam\n", real_username));
346 status = make_server_info_sam(&tmp_server_info, sampass);
347 TALLOC_FREE(sampass);
348 } else {
350 * User not in passdb, make it up artificially
352 TALLOC_FREE(sampass);
353 DEBUG(10, ("smb2: didn't find user %s in passdb, calling "
354 "make_server_info_pw\n", real_username));
355 status = make_server_info_pw(&tmp_server_info,
356 real_username,
357 pw);
360 if (!NT_STATUS_IS_OK(status)) {
361 DEBUG(1,("smb2: make_server_info_[sam|pw] failed: %s!\n",
362 nt_errstr(status)));
363 goto fail;
366 /* Steal tmp_server_info into the session->server_info
367 pointer. */
368 session->server_info = talloc_move(session, &tmp_server_info);
370 /* make_server_info_pw does not set the domain. Without this
371 * we end up with the local netbios name in substitutions for
372 * %D. */
374 if (session->server_info->info3 != NULL) {
375 session->server_info->info3->base.domain.string =
376 talloc_strdup(session->server_info->info3, domain);
381 session->server_info->nss_token |= username_was_mapped;
383 /* we need to build the token for the user. make_server_info_guest()
384 already does this */
386 if (!session->server_info->ptok ) {
387 status = create_local_token(session->server_info);
388 if (!NT_STATUS_IS_OK(status)) {
389 DEBUG(10,("smb2: failed to create local token: %s\n",
390 nt_errstr(status)));
391 goto fail;
395 if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
396 lp_server_signing() == Required) {
397 session->do_signing = true;
400 if (session->server_info->guest) {
401 /* we map anonymous to guest internally */
402 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
403 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
404 /* force no signing */
405 session->do_signing = false;
408 data_blob_free(&session->server_info->user_session_key);
409 session->server_info->user_session_key =
410 data_blob_talloc(
411 session->server_info,
412 session_key.data,
413 session_key.length);
414 if (session_key.length > 0) {
415 if (session->server_info->user_session_key.data == NULL) {
416 status = NT_STATUS_NO_MEMORY;
417 goto fail;
420 session->session_key = session->server_info->user_session_key;
422 session->compat_vuser = talloc_zero(session, user_struct);
423 if (session->compat_vuser == NULL) {
424 status = NT_STATUS_NO_MEMORY;
425 goto fail;
427 session->compat_vuser->auth_ntlmssp_state = NULL;
428 session->compat_vuser->homes_snum = -1;
429 session->compat_vuser->server_info = session->server_info;
430 session->compat_vuser->session_keystr = NULL;
431 session->compat_vuser->vuid = session->vuid;
432 DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
434 /* This is a potentially untrusted username */
435 alpha_strcpy(tmp,
436 client,
437 ". _-$",
438 sizeof(tmp));
439 session->server_info->sanitized_username = talloc_strdup(
440 session->server_info, tmp);
442 if (!session->server_info->guest) {
443 session->compat_vuser->homes_snum =
444 register_homes_share(session->server_info->unix_name);
447 if (!session_claim(session->compat_vuser)) {
448 DEBUG(1, ("smb2: Failed to claim session "
449 "for vuid=%d\n",
450 session->compat_vuser->vuid));
451 goto fail;
454 session->status = NT_STATUS_OK;
457 * we attach the session to the request
458 * so that the response can be signed
460 smb2req->session = session;
461 if (session->do_signing) {
462 smb2req->do_signing = true;
465 global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
466 status = NT_STATUS_OK;
468 /* wrap that up in a nice GSS-API wrapping */
469 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
470 TOK_ID_KRB_AP_REP);
472 secblob_out = spnego_gen_auth_response(
473 &ap_rep_wrapped,
474 status,
475 mechOID);
477 *out_security_buffer = data_blob_talloc(smb2req,
478 secblob_out.data,
479 secblob_out.length);
480 if (secblob_out.data && out_security_buffer->data == NULL) {
481 status = NT_STATUS_NO_MEMORY;
482 goto fail;
485 data_blob_free(&ap_rep);
486 data_blob_free(&ap_rep_wrapped);
487 data_blob_free(&ticket);
488 data_blob_free(&session_key);
489 data_blob_free(&secblob_out);
491 *out_session_id = session->vuid;
493 return NT_STATUS_OK;
495 fail:
497 data_blob_free(&ap_rep);
498 data_blob_free(&ap_rep_wrapped);
499 data_blob_free(&ticket);
500 data_blob_free(&session_key);
501 data_blob_free(&secblob_out);
503 ap_rep_wrapped = data_blob_null;
504 secblob_out = spnego_gen_auth_response(
505 &ap_rep_wrapped,
506 status,
507 mechOID);
509 *out_security_buffer = data_blob_talloc(smb2req,
510 secblob_out.data,
511 secblob_out.length);
512 data_blob_free(&secblob_out);
513 return status;
515 #endif
517 static NTSTATUS smbd_smb2_spnego_negotiate(struct smbd_smb2_session *session,
518 struct smbd_smb2_request *smb2req,
519 uint8_t in_security_mode,
520 DATA_BLOB in_security_buffer,
521 uint16_t *out_session_flags,
522 DATA_BLOB *out_security_buffer,
523 uint64_t *out_session_id)
525 DATA_BLOB secblob_in = data_blob_null;
526 DATA_BLOB chal_out = data_blob_null;
527 DATA_BLOB secblob_out = data_blob_null;
528 char *kerb_mech = NULL;
529 NTSTATUS status;
531 /* Ensure we have no old NTLM state around. */
532 auth_ntlmssp_end(&session->auth_ntlmssp_state);
534 status = parse_spnego_mechanisms(in_security_buffer,
535 &secblob_in, &kerb_mech);
536 if (!NT_STATUS_IS_OK(status)) {
537 goto out;
540 #ifdef HAVE_KRB5
541 if (kerb_mech && ((lp_security()==SEC_ADS) ||
542 USE_KERBEROS_KEYTAB) ) {
543 status = smbd_smb2_session_setup_krb5(session,
544 smb2req,
545 in_security_mode,
546 &secblob_in,
547 kerb_mech,
548 out_session_flags,
549 out_security_buffer,
550 out_session_id);
552 goto out;
554 #endif
556 if (kerb_mech) {
557 /* The mechtoken is a krb5 ticket, but
558 * we need to fall back to NTLM. */
560 DEBUG(3,("smb2: Got krb5 ticket in SPNEGO "
561 "but set to downgrade to NTLMSSP\n"));
563 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
564 } else {
565 /* Fall back to NTLMSSP. */
566 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
567 if (!NT_STATUS_IS_OK(status)) {
568 goto out;
571 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
572 secblob_in,
573 &chal_out);
576 if (!NT_STATUS_IS_OK(status) &&
577 !NT_STATUS_EQUAL(status,
578 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
579 goto out;
582 secblob_out = spnego_gen_auth_response(&chal_out,
583 status,
584 OID_NTLMSSP);
585 *out_security_buffer = data_blob_talloc(smb2req,
586 secblob_out.data,
587 secblob_out.length);
588 if (secblob_out.data && out_security_buffer->data == NULL) {
589 status = NT_STATUS_NO_MEMORY;
590 goto out;
592 *out_session_id = session->vuid;
594 out:
596 data_blob_free(&secblob_in);
597 data_blob_free(&secblob_out);
598 data_blob_free(&chal_out);
599 SAFE_FREE(kerb_mech);
600 if (!NT_STATUS_IS_OK(status) &&
601 !NT_STATUS_EQUAL(status,
602 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
603 auth_ntlmssp_end(&session->auth_ntlmssp_state);
604 TALLOC_FREE(session);
606 return status;
609 static NTSTATUS smbd_smb2_common_ntlmssp_auth_return(struct smbd_smb2_session *session,
610 struct smbd_smb2_request *smb2req,
611 uint8_t in_security_mode,
612 DATA_BLOB in_security_buffer,
613 uint16_t *out_session_flags,
614 uint64_t *out_session_id)
616 fstring tmp;
617 session->server_info = auth_ntlmssp_server_info(session, session->auth_ntlmssp_state);
618 if (!session->server_info) {
619 auth_ntlmssp_end(&session->auth_ntlmssp_state);
620 TALLOC_FREE(session);
621 return NT_STATUS_NO_MEMORY;
624 if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
625 lp_server_signing() == Required) {
626 session->do_signing = true;
629 if (session->server_info->guest) {
630 /* we map anonymous to guest internally */
631 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
632 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
633 /* force no signing */
634 session->do_signing = false;
637 session->session_key = session->server_info->user_session_key;
639 session->compat_vuser = talloc_zero(session, user_struct);
640 if (session->compat_vuser == NULL) {
641 auth_ntlmssp_end(&session->auth_ntlmssp_state);
642 TALLOC_FREE(session);
643 return NT_STATUS_NO_MEMORY;
645 session->compat_vuser->auth_ntlmssp_state = session->auth_ntlmssp_state;
646 session->compat_vuser->homes_snum = -1;
647 session->compat_vuser->server_info = session->server_info;
648 session->compat_vuser->session_keystr = NULL;
649 session->compat_vuser->vuid = session->vuid;
650 DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
652 /* This is a potentially untrusted username */
653 alpha_strcpy(tmp,
654 auth_ntlmssp_get_username(session->auth_ntlmssp_state),
655 ". _-$",
656 sizeof(tmp));
657 session->server_info->sanitized_username = talloc_strdup(
658 session->server_info, tmp);
660 if (!session->compat_vuser->server_info->guest) {
661 session->compat_vuser->homes_snum =
662 register_homes_share(session->server_info->unix_name);
665 if (!session_claim(session->compat_vuser)) {
666 DEBUG(1, ("smb2: Failed to claim session "
667 "for vuid=%d\n",
668 session->compat_vuser->vuid));
669 auth_ntlmssp_end(&session->auth_ntlmssp_state);
670 TALLOC_FREE(session);
671 return NT_STATUS_LOGON_FAILURE;
675 session->status = NT_STATUS_OK;
678 * we attach the session to the request
679 * so that the response can be signed
681 smb2req->session = session;
682 if (session->do_signing) {
683 smb2req->do_signing = true;
686 global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
688 *out_session_id = session->vuid;
690 return NT_STATUS_OK;
693 static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
694 struct smbd_smb2_request *smb2req,
695 uint8_t in_security_mode,
696 DATA_BLOB in_security_buffer,
697 uint16_t *out_session_flags,
698 DATA_BLOB *out_security_buffer,
699 uint64_t *out_session_id)
701 DATA_BLOB auth = data_blob_null;
702 DATA_BLOB auth_out = data_blob_null;
703 DATA_BLOB secblob_out = data_blob_null;
704 NTSTATUS status;
706 if (!spnego_parse_auth(in_security_buffer, &auth)) {
707 TALLOC_FREE(session);
708 return NT_STATUS_LOGON_FAILURE;
711 if (auth.data[0] == ASN1_APPLICATION(0)) {
712 /* Might be a second negTokenTarg packet */
713 DATA_BLOB secblob_in = data_blob_null;
714 char *kerb_mech = NULL;
716 status = parse_spnego_mechanisms(in_security_buffer,
717 &secblob_in, &kerb_mech);
718 if (!NT_STATUS_IS_OK(status)) {
719 TALLOC_FREE(session);
720 return status;
723 #ifdef HAVE_KRB5
724 if (kerb_mech && ((lp_security()==SEC_ADS) ||
725 USE_KERBEROS_KEYTAB) ) {
726 status = smbd_smb2_session_setup_krb5(session,
727 smb2req,
728 in_security_mode,
729 &secblob_in,
730 kerb_mech,
731 out_session_flags,
732 out_security_buffer,
733 out_session_id);
735 data_blob_free(&secblob_in);
736 SAFE_FREE(kerb_mech);
737 if (!NT_STATUS_IS_OK(status)) {
738 TALLOC_FREE(session);
740 return status;
742 #endif
744 /* Can't blunder into NTLMSSP auth if we have
745 * a krb5 ticket. */
747 if (kerb_mech) {
748 DEBUG(3,("smb2: network "
749 "misconfiguration, client sent us a "
750 "krb5 ticket and kerberos security "
751 "not enabled\n"));
752 TALLOC_FREE(session);
753 data_blob_free(&secblob_in);
754 SAFE_FREE(kerb_mech);
755 return NT_STATUS_LOGON_FAILURE;
758 data_blob_free(&secblob_in);
761 if (session->auth_ntlmssp_state == NULL) {
762 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
763 if (!NT_STATUS_IS_OK(status)) {
764 data_blob_free(&auth);
765 TALLOC_FREE(session);
766 return status;
770 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
771 auth,
772 &auth_out);
773 if (!NT_STATUS_IS_OK(status) &&
774 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
775 auth_ntlmssp_end(&session->auth_ntlmssp_state);
776 data_blob_free(&auth);
777 TALLOC_FREE(session);
778 return status;
781 data_blob_free(&auth);
783 secblob_out = spnego_gen_auth_response(&auth_out,
784 status, NULL);
786 *out_security_buffer = data_blob_talloc(smb2req,
787 secblob_out.data,
788 secblob_out.length);
789 if (secblob_out.data && out_security_buffer->data == NULL) {
790 auth_ntlmssp_end(&session->auth_ntlmssp_state);
791 TALLOC_FREE(session);
792 return NT_STATUS_NO_MEMORY;
795 *out_session_id = session->vuid;
797 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
798 return NT_STATUS_MORE_PROCESSING_REQUIRED;
801 /* We're done - claim the session. */
802 return smbd_smb2_common_ntlmssp_auth_return(session,
803 smb2req,
804 in_security_mode,
805 in_security_buffer,
806 out_session_flags,
807 out_session_id);
810 static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session,
811 struct smbd_smb2_request *smb2req,
812 uint8_t in_security_mode,
813 DATA_BLOB in_security_buffer,
814 uint16_t *out_session_flags,
815 DATA_BLOB *out_security_buffer,
816 uint64_t *out_session_id)
818 NTSTATUS status;
819 DATA_BLOB secblob_out = data_blob_null;
821 if (session->auth_ntlmssp_state == NULL) {
822 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
823 if (!NT_STATUS_IS_OK(status)) {
824 TALLOC_FREE(session);
825 return status;
829 /* RAW NTLMSSP */
830 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
831 in_security_buffer,
832 &secblob_out);
834 if (NT_STATUS_IS_OK(status) ||
835 NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
836 *out_security_buffer = data_blob_talloc(smb2req,
837 secblob_out.data,
838 secblob_out.length);
839 if (secblob_out.data && out_security_buffer->data == NULL) {
840 auth_ntlmssp_end(&session->auth_ntlmssp_state);
841 TALLOC_FREE(session);
842 return NT_STATUS_NO_MEMORY;
846 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
847 *out_session_id = session->vuid;
848 return status;
850 if (!NT_STATUS_IS_OK(status)) {
851 auth_ntlmssp_end(&session->auth_ntlmssp_state);
852 TALLOC_FREE(session);
853 return status;
855 *out_session_id = session->vuid;
857 return smbd_smb2_common_ntlmssp_auth_return(session,
858 smb2req,
859 in_security_mode,
860 in_security_buffer,
861 out_session_flags,
862 out_session_id);
865 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
866 uint64_t in_session_id,
867 uint8_t in_security_mode,
868 DATA_BLOB in_security_buffer,
869 uint16_t *out_session_flags,
870 DATA_BLOB *out_security_buffer,
871 uint64_t *out_session_id)
873 struct smbd_smb2_session *session;
875 *out_session_flags = 0;
876 *out_session_id = 0;
878 if (in_session_id == 0) {
879 int id;
881 /* create a new session */
882 session = talloc_zero(smb2req->sconn, struct smbd_smb2_session);
883 if (session == NULL) {
884 return NT_STATUS_NO_MEMORY;
886 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
887 id = idr_get_new_random(smb2req->sconn->smb2.sessions.idtree,
888 session,
889 smb2req->sconn->smb2.sessions.limit);
890 if (id == -1) {
891 return NT_STATUS_INSUFFICIENT_RESOURCES;
893 session->vuid = id;
895 session->tcons.idtree = idr_init(session);
896 if (session->tcons.idtree == NULL) {
897 return NT_STATUS_NO_MEMORY;
899 session->tcons.limit = 0x0000FFFE;
900 session->tcons.list = NULL;
902 DLIST_ADD_END(smb2req->sconn->smb2.sessions.list, session,
903 struct smbd_smb2_session *);
904 session->sconn = smb2req->sconn;
905 talloc_set_destructor(session, smbd_smb2_session_destructor);
906 } else {
907 void *p;
909 /* lookup an existing session */
910 p = idr_find(smb2req->sconn->smb2.sessions.idtree, in_session_id);
911 if (p == NULL) {
912 return NT_STATUS_USER_SESSION_DELETED;
914 session = talloc_get_type_abort(p, struct smbd_smb2_session);
917 if (NT_STATUS_IS_OK(session->status)) {
918 return NT_STATUS_REQUEST_NOT_ACCEPTED;
921 if (in_security_buffer.data[0] == ASN1_APPLICATION(0)) {
922 return smbd_smb2_spnego_negotiate(session,
923 smb2req,
924 in_security_mode,
925 in_security_buffer,
926 out_session_flags,
927 out_security_buffer,
928 out_session_id);
929 } else if (in_security_buffer.data[0] == ASN1_CONTEXT(1)) {
930 return smbd_smb2_spnego_auth(session,
931 smb2req,
932 in_security_mode,
933 in_security_buffer,
934 out_session_flags,
935 out_security_buffer,
936 out_session_id);
937 } else if (strncmp((char *)(in_security_buffer.data), "NTLMSSP", 7) == 0) {
938 return smbd_smb2_raw_ntlmssp_auth(session,
939 smb2req,
940 in_security_mode,
941 in_security_buffer,
942 out_session_flags,
943 out_security_buffer,
944 out_session_id);
947 /* Unknown packet type. */
948 DEBUG(1,("Unknown packet type %u in smb2 sessionsetup\n",
949 (unsigned int)in_security_buffer.data[0] ));
950 auth_ntlmssp_end(&session->auth_ntlmssp_state);
951 TALLOC_FREE(session);
952 return NT_STATUS_LOGON_FAILURE;
955 NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
957 const uint8_t *inhdr;
958 const uint8_t *outhdr;
959 int i = req->current_idx;
960 uint64_t in_session_id;
961 void *p;
962 struct smbd_smb2_session *session;
963 bool chained_fixup = false;
965 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
967 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
969 if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
970 if (req->async) {
972 * async request - fill in session_id from
973 * already setup request out.vector[].iov_base.
975 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
976 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
977 } else if (i > 2) {
979 * Chained request - fill in session_id from
980 * the previous request out.vector[].iov_base.
982 outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
983 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
984 chained_fixup = true;
988 /* lookup an existing session */
989 p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
990 if (p == NULL) {
991 return NT_STATUS_USER_SESSION_DELETED;
993 session = talloc_get_type_abort(p, struct smbd_smb2_session);
995 if (!NT_STATUS_IS_OK(session->status)) {
996 return NT_STATUS_ACCESS_DENIED;
999 set_current_user_info(session->server_info->sanitized_username,
1000 session->server_info->unix_name,
1001 session->server_info->info3->base.domain.string);
1003 req->session = session;
1005 if (chained_fixup) {
1006 /* Fix up our own outhdr. */
1007 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1008 SBVAL(outhdr, SMB2_HDR_SESSION_ID, in_session_id);
1010 return NT_STATUS_OK;
1013 NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req)
1015 const uint8_t *inbody;
1016 int i = req->current_idx;
1017 DATA_BLOB outbody;
1018 size_t expected_body_size = 0x04;
1019 size_t body_size;
1021 if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
1022 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1025 inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
1027 body_size = SVAL(inbody, 0x00);
1028 if (body_size != expected_body_size) {
1029 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1033 * TODO: cancel all outstanding requests on the session
1034 * and delete all tree connections.
1036 smbd_smb2_session_destructor(req->session);
1038 * we may need to sign the response, so we need to keep
1039 * the session until the response is sent to the wire.
1041 talloc_steal(req, req->session);
1043 outbody = data_blob_talloc(req->out.vector, NULL, 0x04);
1044 if (outbody.data == NULL) {
1045 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
1048 SSVAL(outbody.data, 0x00, 0x04); /* struct size */
1049 SSVAL(outbody.data, 0x02, 0); /* reserved */
1051 return smbd_smb2_request_done(req, outbody, NULL);