s3:auth Free sampass as soon as we have server_info
[Samba/ekacnet.git] / source3 / smbd / smb2_sesssetup.c
blobd8972156a196f353441798e3b868fcaf34de1c15
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 "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;
173 struct smbd_server_connection *sconn = smbd_server_conn;
175 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
176 status = NT_STATUS_LOGON_FAILURE;
177 goto fail;
180 status = ads_verify_ticket(smb2req, lp_realm(), 0, &ticket,
181 &client, &logon_info, &ap_rep,
182 &session_key, true);
184 if (!NT_STATUS_IS_OK(status)) {
185 DEBUG(1,("smb2: Failed to verify incoming ticket with error %s!\n",
186 nt_errstr(status)));
187 if (!NT_STATUS_EQUAL(status, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
188 status = NT_STATUS_LOGON_FAILURE;
190 goto fail;
193 DEBUG(3,("smb2: Ticket name is [%s]\n", client));
195 p = strchr_m(client, '@');
196 if (!p) {
197 DEBUG(3,("smb2: %s Doesn't look like a valid principal\n",
198 client));
199 status = NT_STATUS_LOGON_FAILURE;
200 goto fail;
203 *p = 0;
205 /* save the PAC data if we have it */
207 if (logon_info) {
208 netsamlogon_cache_store(client, &logon_info->info3);
211 if (!strequal(p+1, lp_realm())) {
212 DEBUG(3,("smb2: Ticket for foreign realm %s@%s\n", client, p+1));
213 if (!lp_allow_trusted_domains()) {
214 status = NT_STATUS_LOGON_FAILURE;
215 goto fail;
219 /* this gives a fully qualified user name (ie. with full realm).
220 that leads to very long usernames, but what else can we do? */
222 domain = p+1;
224 if (logon_info && logon_info->info3.base.domain.string) {
225 domain = talloc_strdup(talloc_tos(),
226 logon_info->info3.base.domain.string);
227 if (!domain) {
228 status = NT_STATUS_NO_MEMORY;
229 goto fail;
231 DEBUG(10, ("smb2: Mapped to [%s] (using PAC)\n", domain));
232 } else {
234 /* If we have winbind running, we can (and must) shorten the
235 username by using the short netbios name. Otherwise we will
236 have inconsistent user names. With Kerberos, we get the
237 fully qualified realm, with ntlmssp we get the short
238 name. And even w2k3 does use ntlmssp if you for example
239 connect to an ip address. */
241 wbcErr wbc_status;
242 struct wbcDomainInfo *info = NULL;
244 DEBUG(10, ("smb2: Mapping [%s] to short name\n", domain));
246 wbc_status = wbcDomainInfo(domain, &info);
248 if (WBC_ERROR_IS_OK(wbc_status)) {
249 domain = talloc_strdup(talloc_tos(), info->short_name);
251 wbcFreeMemory(info);
252 if (!domain) {
253 status = NT_STATUS_NO_MEMORY;
254 goto fail;
256 DEBUG(10, ("smb2: Mapped to [%s] (using Winbind)\n", domain));
257 } else {
258 DEBUG(3, ("smb2: Could not find short name: %s\n",
259 wbcErrorString(wbc_status)));
263 /* We have to use fstring for this - map_username requires it. */
264 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
266 /* lookup the passwd struct, create a new user if necessary */
268 username_was_mapped = map_username(sconn, user);
270 pw = smb_getpwnam(talloc_tos(), user, real_username, true );
271 if (pw) {
272 /* if a real user check pam account restrictions */
273 /* only really perfomed if "obey pam restriction" is true */
274 /* do this before an eventual mapping to guest occurs */
275 status = smb_pam_accountcheck(pw->pw_name);
276 if (!NT_STATUS_IS_OK(status)) {
277 DEBUG(1,("smb2: PAM account restriction "
278 "prevents user login\n"));
279 goto fail;
283 if (!pw) {
285 /* this was originally the behavior of Samba 2.2, if a user
286 did not have a local uid but has been authenticated, then
287 map them to a guest account */
289 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
290 map_domainuser_to_guest = true;
291 fstrcpy(user,lp_guestaccount());
292 pw = smb_getpwnam(talloc_tos(), user, real_username, true );
295 /* extra sanity check that the guest account is valid */
297 if (!pw) {
298 DEBUG(1,("smb2: Username %s is invalid on this system\n",
299 user));
300 status = NT_STATUS_LOGON_FAILURE;
301 goto fail;
305 /* setup the string used by %U */
307 sub_set_smb_name(real_username);
308 reload_services(true);
310 if (map_domainuser_to_guest) {
311 make_server_info_guest(session, &session->server_info);
312 } else if (logon_info) {
313 /* pass the unmapped username here since map_username()
314 will be called again from inside make_server_info_info3() */
316 status = make_server_info_info3(session,
317 client,
318 domain,
319 &session->server_info,
320 &logon_info->info3);
321 if (!NT_STATUS_IS_OK(status) ) {
322 DEBUG(1,("smb2: make_server_info_info3 failed: %s!\n",
323 nt_errstr(status)));
324 goto fail;
327 } else {
329 * We didn't get a PAC, we have to make up the user
330 * ourselves. Try to ask the pdb backend to provide
331 * SID consistency with ntlmssp session setup
333 struct samu *sampass;
334 /* The stupid make_server_info_XX functions here
335 don't take a talloc context. */
336 struct auth_serversupplied_info *tmp_server_info = NULL;
338 sampass = samu_new(talloc_tos());
339 if (sampass == NULL) {
340 status = NT_STATUS_NO_MEMORY;
341 goto fail;
344 if (pdb_getsampwnam(sampass, real_username)) {
345 DEBUG(10, ("smb2: found user %s in passdb, calling "
346 "make_server_info_sam\n", real_username));
347 status = make_server_info_sam(&tmp_server_info, sampass);
348 TALLOC_FREE(sampass);
349 } else {
351 * User not in passdb, make it up artificially
353 TALLOC_FREE(sampass);
354 DEBUG(10, ("smb2: didn't find user %s in passdb, calling "
355 "make_server_info_pw\n", real_username));
356 status = make_server_info_pw(&tmp_server_info,
357 real_username,
358 pw);
361 if (!NT_STATUS_IS_OK(status)) {
362 DEBUG(1,("smb2: make_server_info_[sam|pw] failed: %s!\n",
363 nt_errstr(status)));
364 goto fail;
367 /* Steal tmp_server_info into the session->server_info
368 pointer. */
369 session->server_info = talloc_move(session, &tmp_server_info);
371 /* make_server_info_pw does not set the domain. Without this
372 * we end up with the local netbios name in substitutions for
373 * %D. */
375 if (session->server_info->info3 != NULL) {
376 session->server_info->info3->base.domain.string =
377 talloc_strdup(session->server_info->info3, domain);
382 session->server_info->nss_token |= username_was_mapped;
384 /* we need to build the token for the user. make_server_info_guest()
385 already does this */
387 if (!session->server_info->ptok ) {
388 status = create_local_token(session->server_info);
389 if (!NT_STATUS_IS_OK(status)) {
390 DEBUG(10,("smb2: failed to create local token: %s\n",
391 nt_errstr(status)));
392 goto fail;
396 if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
397 lp_server_signing() == Required) {
398 session->do_signing = true;
401 if (session->server_info->guest) {
402 /* we map anonymous to guest internally */
403 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
404 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
405 /* force no signing */
406 session->do_signing = false;
409 data_blob_free(&session->server_info->user_session_key);
410 session->server_info->user_session_key =
411 data_blob_talloc(
412 session->server_info,
413 session_key.data,
414 session_key.length);
415 if (session_key.length > 0) {
416 if (session->server_info->user_session_key.data == NULL) {
417 status = NT_STATUS_NO_MEMORY;
418 goto fail;
421 session->session_key = session->server_info->user_session_key;
423 session->compat_vuser = talloc_zero(session, user_struct);
424 if (session->compat_vuser == NULL) {
425 status = NT_STATUS_NO_MEMORY;
426 goto fail;
428 session->compat_vuser->auth_ntlmssp_state = NULL;
429 session->compat_vuser->homes_snum = -1;
430 session->compat_vuser->server_info = session->server_info;
431 session->compat_vuser->session_keystr = NULL;
432 session->compat_vuser->vuid = session->vuid;
433 DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
435 /* This is a potentially untrusted username */
436 alpha_strcpy(tmp,
437 client,
438 ". _-$",
439 sizeof(tmp));
440 session->server_info->sanitized_username = talloc_strdup(
441 session->server_info, tmp);
443 if (!session->server_info->guest) {
444 session->compat_vuser->homes_snum =
445 register_homes_share(session->server_info->unix_name);
448 if (!session_claim(session->compat_vuser)) {
449 DEBUG(1, ("smb2: Failed to claim session "
450 "for vuid=%d\n",
451 session->compat_vuser->vuid));
452 goto fail;
455 session->status = NT_STATUS_OK;
458 * we attach the session to the request
459 * so that the response can be signed
461 smb2req->session = session;
462 if (session->do_signing) {
463 smb2req->do_signing = true;
466 global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
467 status = NT_STATUS_OK;
469 /* wrap that up in a nice GSS-API wrapping */
470 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
471 TOK_ID_KRB_AP_REP);
473 secblob_out = spnego_gen_auth_response(
474 &ap_rep_wrapped,
475 status,
476 mechOID);
478 *out_security_buffer = data_blob_talloc(smb2req,
479 secblob_out.data,
480 secblob_out.length);
481 if (secblob_out.data && out_security_buffer->data == NULL) {
482 status = NT_STATUS_NO_MEMORY;
483 goto fail;
486 data_blob_free(&ap_rep);
487 data_blob_free(&ap_rep_wrapped);
488 data_blob_free(&ticket);
489 data_blob_free(&session_key);
490 data_blob_free(&secblob_out);
492 *out_session_id = session->vuid;
494 return NT_STATUS_OK;
496 fail:
498 data_blob_free(&ap_rep);
499 data_blob_free(&ap_rep_wrapped);
500 data_blob_free(&ticket);
501 data_blob_free(&session_key);
502 data_blob_free(&secblob_out);
504 ap_rep_wrapped = data_blob_null;
505 secblob_out = spnego_gen_auth_response(
506 &ap_rep_wrapped,
507 status,
508 mechOID);
510 *out_security_buffer = data_blob_talloc(smb2req,
511 secblob_out.data,
512 secblob_out.length);
513 data_blob_free(&secblob_out);
514 return status;
516 #endif
518 static NTSTATUS smbd_smb2_spnego_negotiate(struct smbd_smb2_session *session,
519 struct smbd_smb2_request *smb2req,
520 uint8_t in_security_mode,
521 DATA_BLOB in_security_buffer,
522 uint16_t *out_session_flags,
523 DATA_BLOB *out_security_buffer,
524 uint64_t *out_session_id)
526 DATA_BLOB secblob_in = data_blob_null;
527 DATA_BLOB chal_out = data_blob_null;
528 DATA_BLOB secblob_out = data_blob_null;
529 char *kerb_mech = NULL;
530 NTSTATUS status;
532 /* Ensure we have no old NTLM state around. */
533 auth_ntlmssp_end(&session->auth_ntlmssp_state);
535 status = parse_spnego_mechanisms(in_security_buffer,
536 &secblob_in, &kerb_mech);
537 if (!NT_STATUS_IS_OK(status)) {
538 goto out;
541 #ifdef HAVE_KRB5
542 if (kerb_mech && ((lp_security()==SEC_ADS) ||
543 USE_KERBEROS_KEYTAB) ) {
544 status = smbd_smb2_session_setup_krb5(session,
545 smb2req,
546 in_security_mode,
547 &secblob_in,
548 kerb_mech,
549 out_session_flags,
550 out_security_buffer,
551 out_session_id);
553 goto out;
555 #endif
557 /* Fall back to NTLMSSP. */
558 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
559 if (!NT_STATUS_IS_OK(status)) {
560 goto out;
563 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
564 secblob_in,
565 &chal_out);
567 if (!NT_STATUS_IS_OK(status) &&
568 !NT_STATUS_EQUAL(status,
569 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
570 goto out;
573 secblob_out = spnego_gen_auth_response(&chal_out,
574 status,
575 OID_NTLMSSP);
576 *out_security_buffer = data_blob_talloc(smb2req,
577 secblob_out.data,
578 secblob_out.length);
579 if (secblob_out.data && out_security_buffer->data == NULL) {
580 status = NT_STATUS_NO_MEMORY;
581 goto out;
583 *out_session_id = session->vuid;
585 out:
587 data_blob_free(&secblob_in);
588 data_blob_free(&secblob_out);
589 data_blob_free(&chal_out);
590 SAFE_FREE(kerb_mech);
591 if (!NT_STATUS_IS_OK(status) &&
592 !NT_STATUS_EQUAL(status,
593 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
594 auth_ntlmssp_end(&session->auth_ntlmssp_state);
595 TALLOC_FREE(session);
597 return status;
600 static NTSTATUS smbd_smb2_common_ntlmssp_auth_return(struct smbd_smb2_session *session,
601 struct smbd_smb2_request *smb2req,
602 uint8_t in_security_mode,
603 DATA_BLOB in_security_buffer,
604 uint16_t *out_session_flags,
605 uint64_t *out_session_id)
607 fstring tmp;
609 if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
610 lp_server_signing() == Required) {
611 session->do_signing = true;
614 if (session->auth_ntlmssp_state->server_info->guest) {
615 /* we map anonymous to guest internally */
616 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
617 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
618 /* force no signing */
619 session->do_signing = false;
622 session->server_info = session->auth_ntlmssp_state->server_info;
623 data_blob_free(&session->server_info->user_session_key);
624 session->server_info->user_session_key =
625 data_blob_talloc(
626 session->server_info,
627 session->auth_ntlmssp_state->ntlmssp_state->session_key.data,
628 session->auth_ntlmssp_state->ntlmssp_state->session_key.length);
629 if (session->auth_ntlmssp_state->ntlmssp_state->session_key.length > 0) {
630 if (session->server_info->user_session_key.data == NULL) {
631 auth_ntlmssp_end(&session->auth_ntlmssp_state);
632 TALLOC_FREE(session);
633 return NT_STATUS_NO_MEMORY;
636 session->session_key = session->server_info->user_session_key;
638 session->compat_vuser = talloc_zero(session, user_struct);
639 if (session->compat_vuser == NULL) {
640 auth_ntlmssp_end(&session->auth_ntlmssp_state);
641 TALLOC_FREE(session);
642 return NT_STATUS_NO_MEMORY;
644 session->compat_vuser->auth_ntlmssp_state = session->auth_ntlmssp_state;
645 session->compat_vuser->homes_snum = -1;
646 session->compat_vuser->server_info = session->server_info;
647 session->compat_vuser->session_keystr = NULL;
648 session->compat_vuser->vuid = session->vuid;
649 DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
651 /* This is a potentially untrusted username */
652 alpha_strcpy(tmp,
653 session->auth_ntlmssp_state->ntlmssp_state->user,
654 ". _-$",
655 sizeof(tmp));
656 session->server_info->sanitized_username = talloc_strdup(
657 session->server_info, tmp);
659 if (!session->compat_vuser->server_info->guest) {
660 session->compat_vuser->homes_snum =
661 register_homes_share(session->server_info->unix_name);
664 if (!session_claim(session->compat_vuser)) {
665 DEBUG(1, ("smb2: Failed to claim session "
666 "for vuid=%d\n",
667 session->compat_vuser->vuid));
668 auth_ntlmssp_end(&session->auth_ntlmssp_state);
669 TALLOC_FREE(session);
670 return NT_STATUS_LOGON_FAILURE;
674 session->status = NT_STATUS_OK;
677 * we attach the session to the request
678 * so that the response can be signed
680 smb2req->session = session;
681 if (session->do_signing) {
682 smb2req->do_signing = true;
685 global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
687 *out_session_id = session->vuid;
689 return NT_STATUS_OK;
692 static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
693 struct smbd_smb2_request *smb2req,
694 uint8_t in_security_mode,
695 DATA_BLOB in_security_buffer,
696 uint16_t *out_session_flags,
697 DATA_BLOB *out_security_buffer,
698 uint64_t *out_session_id)
700 DATA_BLOB auth = data_blob_null;
701 DATA_BLOB auth_out = data_blob_null;
702 DATA_BLOB secblob_out = data_blob_null;
703 NTSTATUS status;
705 if (!spnego_parse_auth(in_security_buffer, &auth)) {
706 TALLOC_FREE(session);
707 return NT_STATUS_LOGON_FAILURE;
710 if (auth.data[0] == ASN1_APPLICATION(0)) {
711 /* Might be a second negTokenTarg packet */
712 DATA_BLOB secblob_in = data_blob_null;
713 char *kerb_mech = NULL;
715 status = parse_spnego_mechanisms(in_security_buffer,
716 &secblob_in, &kerb_mech);
717 if (!NT_STATUS_IS_OK(status)) {
718 TALLOC_FREE(session);
719 return status;
722 #ifdef HAVE_KRB5
723 if (kerb_mech && ((lp_security()==SEC_ADS) ||
724 USE_KERBEROS_KEYTAB) ) {
725 status = smbd_smb2_session_setup_krb5(session,
726 smb2req,
727 in_security_mode,
728 &secblob_in,
729 kerb_mech,
730 out_session_flags,
731 out_security_buffer,
732 out_session_id);
734 data_blob_free(&secblob_in);
735 SAFE_FREE(kerb_mech);
736 if (!NT_STATUS_IS_OK(status)) {
737 TALLOC_FREE(session);
739 return status;
741 #endif
743 /* Can't blunder into NTLMSSP auth if we have
744 * a krb5 ticket. */
746 if (kerb_mech) {
747 DEBUG(3,("smb2: network "
748 "misconfiguration, client sent us a "
749 "krb5 ticket and kerberos security "
750 "not enabled\n"));
751 TALLOC_FREE(session);
752 data_blob_free(&secblob_in);
753 SAFE_FREE(kerb_mech);
754 return NT_STATUS_LOGON_FAILURE;
758 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
759 auth,
760 &auth_out);
761 if (!NT_STATUS_IS_OK(status)) {
762 auth_ntlmssp_end(&session->auth_ntlmssp_state);
763 data_blob_free(&auth);
764 TALLOC_FREE(session);
765 return status;
768 data_blob_free(&auth);
770 secblob_out = spnego_gen_auth_response(&auth_out,
771 status, NULL);
773 *out_security_buffer = data_blob_talloc(smb2req,
774 secblob_out.data,
775 secblob_out.length);
776 if (secblob_out.data && out_security_buffer->data == NULL) {
777 auth_ntlmssp_end(&session->auth_ntlmssp_state);
778 TALLOC_FREE(session);
779 return NT_STATUS_NO_MEMORY;
782 *out_session_id = session->vuid;
784 return smbd_smb2_common_ntlmssp_auth_return(session,
785 smb2req,
786 in_security_mode,
787 in_security_buffer,
788 out_session_flags,
789 out_session_id);
792 static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session,
793 struct smbd_smb2_request *smb2req,
794 uint8_t in_security_mode,
795 DATA_BLOB in_security_buffer,
796 uint16_t *out_session_flags,
797 DATA_BLOB *out_security_buffer,
798 uint64_t *out_session_id)
800 NTSTATUS status;
801 DATA_BLOB secblob_out = data_blob_null;
803 if (session->auth_ntlmssp_state == NULL) {
804 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
805 if (!NT_STATUS_IS_OK(status)) {
806 TALLOC_FREE(session);
807 return status;
811 /* RAW NTLMSSP */
812 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
813 in_security_buffer,
814 &secblob_out);
816 if (NT_STATUS_IS_OK(status) ||
817 NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
818 *out_security_buffer = data_blob_talloc(smb2req,
819 secblob_out.data,
820 secblob_out.length);
821 if (secblob_out.data && out_security_buffer->data == NULL) {
822 auth_ntlmssp_end(&session->auth_ntlmssp_state);
823 TALLOC_FREE(session);
824 return NT_STATUS_NO_MEMORY;
828 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
829 *out_session_id = session->vuid;
830 return status;
832 if (!NT_STATUS_IS_OK(status)) {
833 auth_ntlmssp_end(&session->auth_ntlmssp_state);
834 TALLOC_FREE(session);
835 return status;
837 *out_session_id = session->vuid;
839 return smbd_smb2_common_ntlmssp_auth_return(session,
840 smb2req,
841 in_security_mode,
842 in_security_buffer,
843 out_session_flags,
844 out_session_id);
847 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
848 uint64_t in_session_id,
849 uint8_t in_security_mode,
850 DATA_BLOB in_security_buffer,
851 uint16_t *out_session_flags,
852 DATA_BLOB *out_security_buffer,
853 uint64_t *out_session_id)
855 struct smbd_smb2_session *session;
857 *out_session_flags = 0;
858 *out_session_id = 0;
860 if (in_session_id == 0) {
861 int id;
863 /* create a new session */
864 session = talloc_zero(smb2req->sconn, struct smbd_smb2_session);
865 if (session == NULL) {
866 return NT_STATUS_NO_MEMORY;
868 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
869 id = idr_get_new_random(smb2req->sconn->smb2.sessions.idtree,
870 session,
871 smb2req->sconn->smb2.sessions.limit);
872 if (id == -1) {
873 return NT_STATUS_INSUFFICIENT_RESOURCES;
875 session->vuid = id;
877 session->tcons.idtree = idr_init(session);
878 if (session->tcons.idtree == NULL) {
879 return NT_STATUS_NO_MEMORY;
881 session->tcons.limit = 0x0000FFFE;
882 session->tcons.list = NULL;
884 DLIST_ADD_END(smb2req->sconn->smb2.sessions.list, session,
885 struct smbd_smb2_session *);
886 session->sconn = smb2req->sconn;
887 talloc_set_destructor(session, smbd_smb2_session_destructor);
888 } else {
889 void *p;
891 /* lookup an existing session */
892 p = idr_find(smb2req->sconn->smb2.sessions.idtree, in_session_id);
893 if (p == NULL) {
894 return NT_STATUS_USER_SESSION_DELETED;
896 session = talloc_get_type_abort(p, struct smbd_smb2_session);
899 if (NT_STATUS_IS_OK(session->status)) {
900 return NT_STATUS_REQUEST_NOT_ACCEPTED;
903 if (in_security_buffer.data[0] == ASN1_APPLICATION(0)) {
904 return smbd_smb2_spnego_negotiate(session,
905 smb2req,
906 in_security_mode,
907 in_security_buffer,
908 out_session_flags,
909 out_security_buffer,
910 out_session_id);
911 } else if (in_security_buffer.data[0] == ASN1_CONTEXT(1)) {
912 return smbd_smb2_spnego_auth(session,
913 smb2req,
914 in_security_mode,
915 in_security_buffer,
916 out_session_flags,
917 out_security_buffer,
918 out_session_id);
919 } else if (strncmp((char *)(in_security_buffer.data), "NTLMSSP", 7) == 0) {
920 return smbd_smb2_raw_ntlmssp_auth(session,
921 smb2req,
922 in_security_mode,
923 in_security_buffer,
924 out_session_flags,
925 out_security_buffer,
926 out_session_id);
929 /* Unknown packet type. */
930 DEBUG(1,("Unknown packet type %u in smb2 sessionsetup\n",
931 (unsigned int)in_security_buffer.data[0] ));
932 auth_ntlmssp_end(&session->auth_ntlmssp_state);
933 TALLOC_FREE(session);
934 return NT_STATUS_LOGON_FAILURE;
937 NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
939 const uint8_t *inhdr;
940 const uint8_t *outhdr;
941 int i = req->current_idx;
942 uint64_t in_session_id;
943 void *p;
944 struct smbd_smb2_session *session;
945 bool chained_fixup = false;
947 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
949 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
951 if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
952 if (req->async) {
954 * async request - fill in session_id from
955 * already setup request out.vector[].iov_base.
957 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
958 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
959 } else if (i > 2) {
961 * Chained request - fill in session_id from
962 * the previous request out.vector[].iov_base.
964 outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
965 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
966 chained_fixup = true;
970 /* lookup an existing session */
971 p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
972 if (p == NULL) {
973 return NT_STATUS_USER_SESSION_DELETED;
975 session = talloc_get_type_abort(p, struct smbd_smb2_session);
977 if (!NT_STATUS_IS_OK(session->status)) {
978 return NT_STATUS_ACCESS_DENIED;
981 set_current_user_info(session->server_info->sanitized_username,
982 session->server_info->unix_name,
983 session->server_info->info3->base.domain.string);
985 req->session = session;
987 if (chained_fixup) {
988 /* Fix up our own outhdr. */
989 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
990 SBVAL(outhdr, SMB2_HDR_SESSION_ID, in_session_id);
992 return NT_STATUS_OK;
995 NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req)
997 const uint8_t *inbody;
998 int i = req->current_idx;
999 DATA_BLOB outbody;
1000 size_t expected_body_size = 0x04;
1001 size_t body_size;
1003 if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
1004 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1007 inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
1009 body_size = SVAL(inbody, 0x00);
1010 if (body_size != expected_body_size) {
1011 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1015 * TODO: cancel all outstanding requests on the session
1016 * and delete all tree connections.
1018 smbd_smb2_session_destructor(req->session);
1020 * we may need to sign the response, so we need to keep
1021 * the session until the response is sent to the wire.
1023 talloc_steal(req, req->session);
1025 outbody = data_blob_talloc(req->out.vector, NULL, 0x04);
1026 if (outbody.data == NULL) {
1027 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
1030 SSVAL(outbody.data, 0x00, 0x04); /* struct size */
1031 SSVAL(outbody.data, 0x02, 0); /* reserved */
1033 return smbd_smb2_request_done(req, outbody, NULL);