s3: async cli_list
[Samba/gbeck.git] / source3 / smbd / smb2_sesssetup.c
blobdf00b4f6541e4b32379242b237ea2caf63bb045a
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(pw->pw_name);
298 if (!NT_STATUS_IS_OK(status)) {
299 DEBUG(1,("smb2: PAM account restriction "
300 "prevents user login\n"));
301 goto fail;
305 if (!pw) {
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 */
319 if (!pw) {
320 DEBUG(1,("smb2: Username %s is invalid on this system\n",
321 user));
322 status = NT_STATUS_LOGON_FAILURE;
323 goto fail;
327 /* setup the string used by %U */
329 sub_set_smb_name(real_username);
330 reload_services(smb2req->sconn->msg_ctx, smb2req->sconn->sock, 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,
339 client,
340 domain,
341 &session->server_info,
342 &logon_info->info3);
343 if (!NT_STATUS_IS_OK(status) ) {
344 DEBUG(1,("smb2: make_server_info_info3 failed: %s!\n",
345 nt_errstr(status)));
346 goto fail;
349 } else {
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;
363 goto fail;
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);
371 } else {
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,
379 real_username,
380 pw);
383 if (!NT_STATUS_IS_OK(status)) {
384 DEBUG(1,("smb2: make_server_info_[sam|pw] failed: %s!\n",
385 nt_errstr(status)));
386 goto fail;
389 /* Steal tmp_server_info into the session->server_info
390 pointer. */
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
395 * %D. */
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()
407 already does this */
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",
413 nt_errstr(status)));
414 goto fail;
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 =
433 data_blob_talloc(
434 session->server_info,
435 session_key.data,
436 session_key.length);
437 if (session_key.length > 0) {
438 if (session->server_info->user_session_key.data == NULL) {
439 status = NT_STATUS_NO_MEMORY;
440 goto fail;
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;
448 goto fail;
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 */
458 alpha_strcpy(tmp,
459 client,
460 ". _-$",
461 sizeof(tmp));
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(session->sconn, session->compat_vuser)) {
471 DEBUG(1, ("smb2: Failed to claim session "
472 "for vuid=%d\n",
473 session->compat_vuser->vuid));
474 goto fail;
477 session->status = NT_STATUS_OK;
480 * we attach the session to the request
481 * so that the response can be signed
483 smb2req->session = session;
484 if (session->do_signing) {
485 smb2req->do_signing = true;
488 global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
489 status = NT_STATUS_OK;
491 /* wrap that up in a nice GSS-API wrapping */
492 ap_rep_wrapped = spnego_gen_krb5_wrap(talloc_tos(), ap_rep,
493 TOK_ID_KRB_AP_REP);
495 secblob_out = spnego_gen_auth_response(
496 talloc_tos(),
497 &ap_rep_wrapped,
498 status,
499 mechOID);
501 *out_security_buffer = data_blob_talloc(smb2req,
502 secblob_out.data,
503 secblob_out.length);
504 if (secblob_out.data && out_security_buffer->data == NULL) {
505 status = NT_STATUS_NO_MEMORY;
506 goto fail;
509 data_blob_free(&ap_rep);
510 data_blob_free(&ap_rep_wrapped);
511 data_blob_free(&ticket);
512 data_blob_free(&session_key);
513 data_blob_free(&secblob_out);
515 *out_session_id = session->vuid;
517 return NT_STATUS_OK;
519 fail:
521 data_blob_free(&ap_rep);
522 data_blob_free(&ap_rep_wrapped);
523 data_blob_free(&ticket);
524 data_blob_free(&session_key);
525 data_blob_free(&secblob_out);
527 ap_rep_wrapped = data_blob_null;
528 secblob_out = spnego_gen_auth_response(
529 talloc_tos(),
530 &ap_rep_wrapped,
531 status,
532 mechOID);
534 *out_security_buffer = data_blob_talloc(smb2req,
535 secblob_out.data,
536 secblob_out.length);
537 data_blob_free(&secblob_out);
538 return status;
540 #endif
542 static NTSTATUS smbd_smb2_spnego_negotiate(struct smbd_smb2_session *session,
543 struct smbd_smb2_request *smb2req,
544 uint8_t in_security_mode,
545 DATA_BLOB in_security_buffer,
546 uint16_t *out_session_flags,
547 DATA_BLOB *out_security_buffer,
548 uint64_t *out_session_id)
550 DATA_BLOB secblob_in = data_blob_null;
551 DATA_BLOB chal_out = data_blob_null;
552 char *kerb_mech = NULL;
553 NTSTATUS status;
555 /* Ensure we have no old NTLM state around. */
556 TALLOC_FREE(session->auth_ntlmssp_state);
558 status = parse_spnego_mechanisms(talloc_tos(), in_security_buffer,
559 &secblob_in, &kerb_mech);
560 if (!NT_STATUS_IS_OK(status)) {
561 goto out;
564 #ifdef HAVE_KRB5
565 if (kerb_mech && ((lp_security()==SEC_ADS) ||
566 USE_KERBEROS_KEYTAB) ) {
567 status = smbd_smb2_session_setup_krb5(session,
568 smb2req,
569 in_security_mode,
570 &secblob_in,
571 kerb_mech,
572 out_session_flags,
573 out_security_buffer,
574 out_session_id);
576 goto out;
578 #endif
580 if (kerb_mech) {
581 /* The mechtoken is a krb5 ticket, but
582 * we need to fall back to NTLM. */
584 DEBUG(3,("smb2: Got krb5 ticket in SPNEGO "
585 "but set to downgrade to NTLMSSP\n"));
587 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
588 } else {
589 /* Fall back to NTLMSSP. */
590 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
591 if (!NT_STATUS_IS_OK(status)) {
592 goto out;
595 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
596 secblob_in,
597 &chal_out);
600 if (!NT_STATUS_IS_OK(status) &&
601 !NT_STATUS_EQUAL(status,
602 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
603 goto out;
606 *out_security_buffer = spnego_gen_auth_response(smb2req,
607 &chal_out,
608 status,
609 OID_NTLMSSP);
610 if (out_security_buffer->data == NULL) {
611 status = NT_STATUS_NO_MEMORY;
612 goto out;
614 *out_session_id = session->vuid;
616 out:
618 data_blob_free(&secblob_in);
619 data_blob_free(&chal_out);
620 TALLOC_FREE(kerb_mech);
621 if (!NT_STATUS_IS_OK(status) &&
622 !NT_STATUS_EQUAL(status,
623 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
624 TALLOC_FREE(session->auth_ntlmssp_state);
625 TALLOC_FREE(session);
627 return status;
630 static NTSTATUS smbd_smb2_common_ntlmssp_auth_return(struct smbd_smb2_session *session,
631 struct smbd_smb2_request *smb2req,
632 uint8_t in_security_mode,
633 DATA_BLOB in_security_buffer,
634 uint16_t *out_session_flags,
635 uint64_t *out_session_id)
637 fstring tmp;
639 if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
640 lp_server_signing() == Required) {
641 session->do_signing = true;
644 if (session->server_info->guest) {
645 /* we map anonymous to guest internally */
646 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
647 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
648 /* force no signing */
649 session->do_signing = false;
652 session->session_key = session->server_info->user_session_key;
654 session->compat_vuser = talloc_zero(session, user_struct);
655 if (session->compat_vuser == NULL) {
656 TALLOC_FREE(session->auth_ntlmssp_state);
657 TALLOC_FREE(session);
658 return NT_STATUS_NO_MEMORY;
660 session->compat_vuser->auth_ntlmssp_state = session->auth_ntlmssp_state;
661 session->compat_vuser->homes_snum = -1;
662 session->compat_vuser->server_info = session->server_info;
663 session->compat_vuser->session_keystr = NULL;
664 session->compat_vuser->vuid = session->vuid;
665 DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
667 /* This is a potentially untrusted username */
668 alpha_strcpy(tmp,
669 auth_ntlmssp_get_username(session->auth_ntlmssp_state),
670 ". _-$",
671 sizeof(tmp));
672 session->server_info->sanitized_username = talloc_strdup(
673 session->server_info, tmp);
675 if (!session->compat_vuser->server_info->guest) {
676 session->compat_vuser->homes_snum =
677 register_homes_share(session->server_info->unix_name);
680 if (!session_claim(session->sconn, session->compat_vuser)) {
681 DEBUG(1, ("smb2: Failed to claim session "
682 "for vuid=%d\n",
683 session->compat_vuser->vuid));
684 TALLOC_FREE(session->auth_ntlmssp_state);
685 TALLOC_FREE(session);
686 return NT_STATUS_LOGON_FAILURE;
690 session->status = NT_STATUS_OK;
693 * we attach the session to the request
694 * so that the response can be signed
696 smb2req->session = session;
697 if (session->do_signing) {
698 smb2req->do_signing = true;
701 global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
703 *out_session_id = session->vuid;
705 return NT_STATUS_OK;
708 static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
709 struct smbd_smb2_request *smb2req,
710 uint8_t in_security_mode,
711 DATA_BLOB in_security_buffer,
712 uint16_t *out_session_flags,
713 DATA_BLOB *out_security_buffer,
714 uint64_t *out_session_id)
716 DATA_BLOB auth = data_blob_null;
717 DATA_BLOB auth_out = data_blob_null;
718 NTSTATUS status;
720 if (!spnego_parse_auth(talloc_tos(), in_security_buffer, &auth)) {
721 TALLOC_FREE(session);
722 return NT_STATUS_LOGON_FAILURE;
725 if (auth.data[0] == ASN1_APPLICATION(0)) {
726 /* Might be a second negTokenTarg packet */
727 DATA_BLOB secblob_in = data_blob_null;
728 char *kerb_mech = NULL;
730 status = parse_spnego_mechanisms(talloc_tos(),
731 in_security_buffer,
732 &secblob_in, &kerb_mech);
733 if (!NT_STATUS_IS_OK(status)) {
734 TALLOC_FREE(session);
735 return status;
738 #ifdef HAVE_KRB5
739 if (kerb_mech && ((lp_security()==SEC_ADS) ||
740 USE_KERBEROS_KEYTAB) ) {
741 status = smbd_smb2_session_setup_krb5(session,
742 smb2req,
743 in_security_mode,
744 &secblob_in,
745 kerb_mech,
746 out_session_flags,
747 out_security_buffer,
748 out_session_id);
750 data_blob_free(&secblob_in);
751 TALLOC_FREE(kerb_mech);
752 if (!NT_STATUS_IS_OK(status)) {
753 TALLOC_FREE(session);
755 return status;
757 #endif
759 /* Can't blunder into NTLMSSP auth if we have
760 * a krb5 ticket. */
762 if (kerb_mech) {
763 DEBUG(3,("smb2: network "
764 "misconfiguration, client sent us a "
765 "krb5 ticket and kerberos security "
766 "not enabled\n"));
767 TALLOC_FREE(session);
768 data_blob_free(&secblob_in);
769 TALLOC_FREE(kerb_mech);
770 return NT_STATUS_LOGON_FAILURE;
773 data_blob_free(&secblob_in);
776 if (session->auth_ntlmssp_state == NULL) {
777 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
778 if (!NT_STATUS_IS_OK(status)) {
779 data_blob_free(&auth);
780 TALLOC_FREE(session);
781 return status;
785 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
786 auth,
787 &auth_out);
788 /* We need to call setup_ntlmssp_server_info() if status==NT_STATUS_OK,
789 or if status is anything except NT_STATUS_MORE_PROCESSING_REQUIRED,
790 as this can trigger map to guest. */
791 if (!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);
800 return status;
803 data_blob_free(&auth);
805 *out_security_buffer = spnego_gen_auth_response(smb2req,
806 &auth_out, status, NULL);
808 if (out_security_buffer->data == NULL) {
809 TALLOC_FREE(session->auth_ntlmssp_state);
810 TALLOC_FREE(session);
811 return NT_STATUS_NO_MEMORY;
814 *out_session_id = session->vuid;
816 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
817 return NT_STATUS_MORE_PROCESSING_REQUIRED;
820 /* We're done - claim the session. */
821 return smbd_smb2_common_ntlmssp_auth_return(session,
822 smb2req,
823 in_security_mode,
824 in_security_buffer,
825 out_session_flags,
826 out_session_id);
829 static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session,
830 struct smbd_smb2_request *smb2req,
831 uint8_t in_security_mode,
832 DATA_BLOB in_security_buffer,
833 uint16_t *out_session_flags,
834 DATA_BLOB *out_security_buffer,
835 uint64_t *out_session_id)
837 NTSTATUS status;
838 DATA_BLOB secblob_out = data_blob_null;
840 if (session->auth_ntlmssp_state == NULL) {
841 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
842 if (!NT_STATUS_IS_OK(status)) {
843 TALLOC_FREE(session);
844 return status;
848 /* RAW NTLMSSP */
849 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
850 in_security_buffer,
851 &secblob_out);
853 if (NT_STATUS_IS_OK(status) ||
854 NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
855 *out_security_buffer = data_blob_talloc(smb2req,
856 secblob_out.data,
857 secblob_out.length);
858 if (secblob_out.data && out_security_buffer->data == NULL) {
859 TALLOC_FREE(session->auth_ntlmssp_state);
860 TALLOC_FREE(session);
861 return NT_STATUS_NO_MEMORY;
865 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
866 *out_session_id = session->vuid;
867 return status;
870 status = setup_ntlmssp_server_info(session, status);
872 if (!NT_STATUS_IS_OK(status)) {
873 TALLOC_FREE(session->auth_ntlmssp_state);
874 TALLOC_FREE(session);
875 return status;
877 *out_session_id = session->vuid;
879 return smbd_smb2_common_ntlmssp_auth_return(session,
880 smb2req,
881 in_security_mode,
882 in_security_buffer,
883 out_session_flags,
884 out_session_id);
887 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
888 uint64_t in_session_id,
889 uint8_t in_security_mode,
890 DATA_BLOB in_security_buffer,
891 uint16_t *out_session_flags,
892 DATA_BLOB *out_security_buffer,
893 uint64_t *out_session_id)
895 struct smbd_smb2_session *session;
897 *out_session_flags = 0;
898 *out_session_id = 0;
900 if (in_session_id == 0) {
901 int id;
903 /* create a new session */
904 session = talloc_zero(smb2req->sconn, struct smbd_smb2_session);
905 if (session == NULL) {
906 return NT_STATUS_NO_MEMORY;
908 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
909 id = idr_get_new_random(smb2req->sconn->smb2.sessions.idtree,
910 session,
911 smb2req->sconn->smb2.sessions.limit);
912 if (id == -1) {
913 return NT_STATUS_INSUFFICIENT_RESOURCES;
915 session->vuid = id;
917 session->tcons.idtree = idr_init(session);
918 if (session->tcons.idtree == NULL) {
919 return NT_STATUS_NO_MEMORY;
921 session->tcons.limit = 0x0000FFFE;
922 session->tcons.list = NULL;
924 DLIST_ADD_END(smb2req->sconn->smb2.sessions.list, session,
925 struct smbd_smb2_session *);
926 session->sconn = smb2req->sconn;
927 talloc_set_destructor(session, smbd_smb2_session_destructor);
928 } else {
929 void *p;
931 /* lookup an existing session */
932 p = idr_find(smb2req->sconn->smb2.sessions.idtree, in_session_id);
933 if (p == NULL) {
934 return NT_STATUS_USER_SESSION_DELETED;
936 session = talloc_get_type_abort(p, struct smbd_smb2_session);
939 if (NT_STATUS_IS_OK(session->status)) {
940 return NT_STATUS_REQUEST_NOT_ACCEPTED;
943 if (in_security_buffer.data[0] == ASN1_APPLICATION(0)) {
944 return smbd_smb2_spnego_negotiate(session,
945 smb2req,
946 in_security_mode,
947 in_security_buffer,
948 out_session_flags,
949 out_security_buffer,
950 out_session_id);
951 } else if (in_security_buffer.data[0] == ASN1_CONTEXT(1)) {
952 return smbd_smb2_spnego_auth(session,
953 smb2req,
954 in_security_mode,
955 in_security_buffer,
956 out_session_flags,
957 out_security_buffer,
958 out_session_id);
959 } else if (strncmp((char *)(in_security_buffer.data), "NTLMSSP", 7) == 0) {
960 return smbd_smb2_raw_ntlmssp_auth(session,
961 smb2req,
962 in_security_mode,
963 in_security_buffer,
964 out_session_flags,
965 out_security_buffer,
966 out_session_id);
969 /* Unknown packet type. */
970 DEBUG(1,("Unknown packet type %u in smb2 sessionsetup\n",
971 (unsigned int)in_security_buffer.data[0] ));
972 TALLOC_FREE(session->auth_ntlmssp_state);
973 TALLOC_FREE(session);
974 return NT_STATUS_LOGON_FAILURE;
977 NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
979 const uint8_t *inhdr;
980 const uint8_t *outhdr;
981 int i = req->current_idx;
982 uint64_t in_session_id;
983 void *p;
984 struct smbd_smb2_session *session;
985 bool chained_fixup = false;
987 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
989 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
991 if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
992 if (req->async) {
994 * async request - fill in session_id from
995 * already setup request out.vector[].iov_base.
997 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
998 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
999 } else if (i > 2) {
1001 * Chained request - fill in session_id from
1002 * the previous request out.vector[].iov_base.
1004 outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
1005 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1006 chained_fixup = true;
1010 /* lookup an existing session */
1011 p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
1012 if (p == NULL) {
1013 return NT_STATUS_USER_SESSION_DELETED;
1015 session = talloc_get_type_abort(p, struct smbd_smb2_session);
1017 if (!NT_STATUS_IS_OK(session->status)) {
1018 return NT_STATUS_ACCESS_DENIED;
1021 set_current_user_info(session->server_info->sanitized_username,
1022 session->server_info->unix_name,
1023 session->server_info->info3->base.domain.string);
1025 req->session = session;
1027 if (chained_fixup) {
1028 /* Fix up our own outhdr. */
1029 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1030 SBVAL(outhdr, SMB2_HDR_SESSION_ID, in_session_id);
1032 return NT_STATUS_OK;
1035 NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req)
1037 const uint8_t *inbody;
1038 int i = req->current_idx;
1039 DATA_BLOB outbody;
1040 size_t expected_body_size = 0x04;
1041 size_t body_size;
1043 if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
1044 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1047 inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
1049 body_size = SVAL(inbody, 0x00);
1050 if (body_size != expected_body_size) {
1051 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1055 * TODO: cancel all outstanding requests on the session
1056 * and delete all tree connections.
1058 smbd_smb2_session_destructor(req->session);
1060 * we may need to sign the response, so we need to keep
1061 * the session until the response is sent to the wire.
1063 talloc_steal(req, req->session);
1065 outbody = data_blob_talloc(req->out.vector, NULL, 0x04);
1066 if (outbody.data == NULL) {
1067 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
1070 SSVAL(outbody.data, 0x00, 0x04); /* struct size */
1071 SSVAL(outbody.data, 0x02, 0); /* reserved */
1073 return smbd_smb2_request_done(req, outbody, NULL);