ntlmssp: Make the ntlmssp.h from source3/ a common header
[Samba/ekacnet.git] / source3 / smbd / smb2_sesssetup.c
blobd91d0fe510a0891e58221acbf6f038b8248e3115
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;
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;
608 session->server_info = auth_ntlmssp_server_info(session, session->auth_ntlmssp_state);
609 if (!session->server_info) {
610 auth_ntlmssp_end(&session->auth_ntlmssp_state);
611 TALLOC_FREE(session);
612 return NT_STATUS_NO_MEMORY;
615 if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
616 lp_server_signing() == Required) {
617 session->do_signing = true;
620 if (session->server_info->guest) {
621 /* we map anonymous to guest internally */
622 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
623 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
624 /* force no signing */
625 session->do_signing = false;
628 session->session_key = session->server_info->user_session_key;
630 session->compat_vuser = talloc_zero(session, user_struct);
631 if (session->compat_vuser == NULL) {
632 auth_ntlmssp_end(&session->auth_ntlmssp_state);
633 TALLOC_FREE(session);
634 return NT_STATUS_NO_MEMORY;
636 session->compat_vuser->auth_ntlmssp_state = session->auth_ntlmssp_state;
637 session->compat_vuser->homes_snum = -1;
638 session->compat_vuser->server_info = session->server_info;
639 session->compat_vuser->session_keystr = NULL;
640 session->compat_vuser->vuid = session->vuid;
641 DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
643 /* This is a potentially untrusted username */
644 alpha_strcpy(tmp,
645 auth_ntlmssp_get_username(session->auth_ntlmssp_state),
646 ". _-$",
647 sizeof(tmp));
648 session->server_info->sanitized_username = talloc_strdup(
649 session->server_info, tmp);
651 if (!session->compat_vuser->server_info->guest) {
652 session->compat_vuser->homes_snum =
653 register_homes_share(session->server_info->unix_name);
656 if (!session_claim(session->compat_vuser)) {
657 DEBUG(1, ("smb2: Failed to claim session "
658 "for vuid=%d\n",
659 session->compat_vuser->vuid));
660 auth_ntlmssp_end(&session->auth_ntlmssp_state);
661 TALLOC_FREE(session);
662 return NT_STATUS_LOGON_FAILURE;
666 session->status = NT_STATUS_OK;
669 * we attach the session to the request
670 * so that the response can be signed
672 smb2req->session = session;
673 if (session->do_signing) {
674 smb2req->do_signing = true;
677 global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
679 *out_session_id = session->vuid;
681 return NT_STATUS_OK;
684 static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
685 struct smbd_smb2_request *smb2req,
686 uint8_t in_security_mode,
687 DATA_BLOB in_security_buffer,
688 uint16_t *out_session_flags,
689 DATA_BLOB *out_security_buffer,
690 uint64_t *out_session_id)
692 DATA_BLOB auth = data_blob_null;
693 DATA_BLOB auth_out = data_blob_null;
694 DATA_BLOB secblob_out = data_blob_null;
695 NTSTATUS status;
697 if (!spnego_parse_auth(in_security_buffer, &auth)) {
698 TALLOC_FREE(session);
699 return NT_STATUS_LOGON_FAILURE;
702 if (auth.data[0] == ASN1_APPLICATION(0)) {
703 /* Might be a second negTokenTarg packet */
704 DATA_BLOB secblob_in = data_blob_null;
705 char *kerb_mech = NULL;
707 status = parse_spnego_mechanisms(in_security_buffer,
708 &secblob_in, &kerb_mech);
709 if (!NT_STATUS_IS_OK(status)) {
710 TALLOC_FREE(session);
711 return status;
714 #ifdef HAVE_KRB5
715 if (kerb_mech && ((lp_security()==SEC_ADS) ||
716 USE_KERBEROS_KEYTAB) ) {
717 status = smbd_smb2_session_setup_krb5(session,
718 smb2req,
719 in_security_mode,
720 &secblob_in,
721 kerb_mech,
722 out_session_flags,
723 out_security_buffer,
724 out_session_id);
726 data_blob_free(&secblob_in);
727 SAFE_FREE(kerb_mech);
728 if (!NT_STATUS_IS_OK(status)) {
729 TALLOC_FREE(session);
731 return status;
733 #endif
735 /* Can't blunder into NTLMSSP auth if we have
736 * a krb5 ticket. */
738 if (kerb_mech) {
739 DEBUG(3,("smb2: network "
740 "misconfiguration, client sent us a "
741 "krb5 ticket and kerberos security "
742 "not enabled\n"));
743 TALLOC_FREE(session);
744 data_blob_free(&secblob_in);
745 SAFE_FREE(kerb_mech);
746 return NT_STATUS_LOGON_FAILURE;
750 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
751 auth,
752 &auth_out);
753 if (!NT_STATUS_IS_OK(status)) {
754 auth_ntlmssp_end(&session->auth_ntlmssp_state);
755 data_blob_free(&auth);
756 TALLOC_FREE(session);
757 return status;
760 data_blob_free(&auth);
762 secblob_out = spnego_gen_auth_response(&auth_out,
763 status, NULL);
765 *out_security_buffer = data_blob_talloc(smb2req,
766 secblob_out.data,
767 secblob_out.length);
768 if (secblob_out.data && out_security_buffer->data == NULL) {
769 auth_ntlmssp_end(&session->auth_ntlmssp_state);
770 TALLOC_FREE(session);
771 return NT_STATUS_NO_MEMORY;
774 *out_session_id = session->vuid;
776 return smbd_smb2_common_ntlmssp_auth_return(session,
777 smb2req,
778 in_security_mode,
779 in_security_buffer,
780 out_session_flags,
781 out_session_id);
784 static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session,
785 struct smbd_smb2_request *smb2req,
786 uint8_t in_security_mode,
787 DATA_BLOB in_security_buffer,
788 uint16_t *out_session_flags,
789 DATA_BLOB *out_security_buffer,
790 uint64_t *out_session_id)
792 NTSTATUS status;
793 DATA_BLOB secblob_out = data_blob_null;
795 if (session->auth_ntlmssp_state == NULL) {
796 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
797 if (!NT_STATUS_IS_OK(status)) {
798 TALLOC_FREE(session);
799 return status;
803 /* RAW NTLMSSP */
804 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
805 in_security_buffer,
806 &secblob_out);
808 if (NT_STATUS_IS_OK(status) ||
809 NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
810 *out_security_buffer = data_blob_talloc(smb2req,
811 secblob_out.data,
812 secblob_out.length);
813 if (secblob_out.data && out_security_buffer->data == NULL) {
814 auth_ntlmssp_end(&session->auth_ntlmssp_state);
815 TALLOC_FREE(session);
816 return NT_STATUS_NO_MEMORY;
820 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
821 *out_session_id = session->vuid;
822 return status;
824 if (!NT_STATUS_IS_OK(status)) {
825 auth_ntlmssp_end(&session->auth_ntlmssp_state);
826 TALLOC_FREE(session);
827 return status;
829 *out_session_id = session->vuid;
831 return smbd_smb2_common_ntlmssp_auth_return(session,
832 smb2req,
833 in_security_mode,
834 in_security_buffer,
835 out_session_flags,
836 out_session_id);
839 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
840 uint64_t in_session_id,
841 uint8_t in_security_mode,
842 DATA_BLOB in_security_buffer,
843 uint16_t *out_session_flags,
844 DATA_BLOB *out_security_buffer,
845 uint64_t *out_session_id)
847 struct smbd_smb2_session *session;
849 *out_session_flags = 0;
850 *out_session_id = 0;
852 if (in_session_id == 0) {
853 int id;
855 /* create a new session */
856 session = talloc_zero(smb2req->sconn, struct smbd_smb2_session);
857 if (session == NULL) {
858 return NT_STATUS_NO_MEMORY;
860 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
861 id = idr_get_new_random(smb2req->sconn->smb2.sessions.idtree,
862 session,
863 smb2req->sconn->smb2.sessions.limit);
864 if (id == -1) {
865 return NT_STATUS_INSUFFICIENT_RESOURCES;
867 session->vuid = id;
869 session->tcons.idtree = idr_init(session);
870 if (session->tcons.idtree == NULL) {
871 return NT_STATUS_NO_MEMORY;
873 session->tcons.limit = 0x0000FFFE;
874 session->tcons.list = NULL;
876 DLIST_ADD_END(smb2req->sconn->smb2.sessions.list, session,
877 struct smbd_smb2_session *);
878 session->sconn = smb2req->sconn;
879 talloc_set_destructor(session, smbd_smb2_session_destructor);
880 } else {
881 void *p;
883 /* lookup an existing session */
884 p = idr_find(smb2req->sconn->smb2.sessions.idtree, in_session_id);
885 if (p == NULL) {
886 return NT_STATUS_USER_SESSION_DELETED;
888 session = talloc_get_type_abort(p, struct smbd_smb2_session);
891 if (NT_STATUS_IS_OK(session->status)) {
892 return NT_STATUS_REQUEST_NOT_ACCEPTED;
895 if (in_security_buffer.data[0] == ASN1_APPLICATION(0)) {
896 return smbd_smb2_spnego_negotiate(session,
897 smb2req,
898 in_security_mode,
899 in_security_buffer,
900 out_session_flags,
901 out_security_buffer,
902 out_session_id);
903 } else if (in_security_buffer.data[0] == ASN1_CONTEXT(1)) {
904 return smbd_smb2_spnego_auth(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 (strncmp((char *)(in_security_buffer.data), "NTLMSSP", 7) == 0) {
912 return smbd_smb2_raw_ntlmssp_auth(session,
913 smb2req,
914 in_security_mode,
915 in_security_buffer,
916 out_session_flags,
917 out_security_buffer,
918 out_session_id);
921 /* Unknown packet type. */
922 DEBUG(1,("Unknown packet type %u in smb2 sessionsetup\n",
923 (unsigned int)in_security_buffer.data[0] ));
924 auth_ntlmssp_end(&session->auth_ntlmssp_state);
925 TALLOC_FREE(session);
926 return NT_STATUS_LOGON_FAILURE;
929 NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
931 const uint8_t *inhdr;
932 const uint8_t *outhdr;
933 int i = req->current_idx;
934 uint64_t in_session_id;
935 void *p;
936 struct smbd_smb2_session *session;
937 bool chained_fixup = false;
939 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
941 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
943 if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
944 if (req->async) {
946 * async request - fill in session_id from
947 * already setup request out.vector[].iov_base.
949 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
950 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
951 } else if (i > 2) {
953 * Chained request - fill in session_id from
954 * the previous request out.vector[].iov_base.
956 outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
957 in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
958 chained_fixup = true;
962 /* lookup an existing session */
963 p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
964 if (p == NULL) {
965 return NT_STATUS_USER_SESSION_DELETED;
967 session = talloc_get_type_abort(p, struct smbd_smb2_session);
969 if (!NT_STATUS_IS_OK(session->status)) {
970 return NT_STATUS_ACCESS_DENIED;
973 set_current_user_info(session->server_info->sanitized_username,
974 session->server_info->unix_name,
975 session->server_info->info3->base.domain.string);
977 req->session = session;
979 if (chained_fixup) {
980 /* Fix up our own outhdr. */
981 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
982 SBVAL(outhdr, SMB2_HDR_SESSION_ID, in_session_id);
984 return NT_STATUS_OK;
987 NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req)
989 const uint8_t *inbody;
990 int i = req->current_idx;
991 DATA_BLOB outbody;
992 size_t expected_body_size = 0x04;
993 size_t body_size;
995 if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
996 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
999 inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
1001 body_size = SVAL(inbody, 0x00);
1002 if (body_size != expected_body_size) {
1003 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1007 * TODO: cancel all outstanding requests on the session
1008 * and delete all tree connections.
1010 smbd_smb2_session_destructor(req->session);
1012 * we may need to sign the response, so we need to keep
1013 * the session until the response is sent to the wire.
1015 talloc_steal(req, req->session);
1017 outbody = data_blob_talloc(req->out.vector, NULL, 0x04);
1018 if (outbody.data == NULL) {
1019 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
1022 SSVAL(outbody.data, 0x00, 0x04); /* struct size */
1023 SSVAL(outbody.data, 0x02, 0); /* reserved */
1025 return smbd_smb2_request_done(req, outbody, NULL);