s3:smb2_sesssetup: add support for SMB 2.24/3.00 signing
[Samba/gebeck_regimport.git] / source3 / smbd / smb2_sesssetup.c
blob9aa73d39cacac2815c4df0a238a7c6150d82d281
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/smbd.h"
24 #include "smbd/globals.h"
25 #include "../libcli/smb/smb_common.h"
26 #include "../auth/gensec/gensec.h"
27 #include "auth.h"
28 #include "../lib/tsocket/tsocket.h"
29 #include "../libcli/security/security.h"
30 #include "../lib/util/tevent_ntstatus.h"
32 static struct tevent_req *smbd_smb2_session_setup_send(TALLOC_CTX *mem_ctx,
33 struct tevent_context *ev,
34 struct smbd_smb2_request *smb2req,
35 uint64_t in_session_id,
36 uint8_t in_flags,
37 uint8_t in_security_mode,
38 uint64_t in_previous_session_id,
39 DATA_BLOB in_security_buffer);
40 static NTSTATUS smbd_smb2_session_setup_recv(struct tevent_req *req,
41 uint16_t *out_session_flags,
42 TALLOC_CTX *mem_ctx,
43 DATA_BLOB *out_security_buffer,
44 uint64_t *out_session_id);
46 static void smbd_smb2_request_sesssetup_done(struct tevent_req *subreq);
48 NTSTATUS smbd_smb2_request_process_sesssetup(struct smbd_smb2_request *smb2req)
50 const uint8_t *inhdr;
51 const uint8_t *inbody;
52 int i = smb2req->current_idx;
53 uint64_t in_session_id;
54 uint8_t in_flags;
55 uint8_t in_security_mode;
56 uint64_t in_previous_session_id;
57 uint16_t in_security_offset;
58 uint16_t in_security_length;
59 DATA_BLOB in_security_buffer;
60 NTSTATUS status;
61 struct tevent_req *subreq;
63 status = smbd_smb2_request_verify_sizes(smb2req, 0x19);
64 if (!NT_STATUS_IS_OK(status)) {
65 return smbd_smb2_request_error(smb2req, status);
67 inhdr = (const uint8_t *)smb2req->in.vector[i+0].iov_base;
68 inbody = (const uint8_t *)smb2req->in.vector[i+1].iov_base;
70 in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
72 in_flags = CVAL(inbody, 0x02);
73 in_security_mode = CVAL(inbody, 0x03);
74 /* Capabilities = IVAL(inbody, 0x04) */
75 /* Channel = IVAL(inbody, 0x08) */
76 in_security_offset = SVAL(inbody, 0x0C);
77 in_security_length = SVAL(inbody, 0x0E);
78 in_previous_session_id = BVAL(inbody, 0x10);
80 if (in_security_offset != (SMB2_HDR_BODY + smb2req->in.vector[i+1].iov_len)) {
81 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
84 if (in_security_length > smb2req->in.vector[i+2].iov_len) {
85 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
88 in_security_buffer.data = (uint8_t *)smb2req->in.vector[i+2].iov_base;
89 in_security_buffer.length = in_security_length;
91 subreq = smbd_smb2_session_setup_send(smb2req,
92 smb2req->sconn->ev_ctx,
93 smb2req,
94 in_session_id,
95 in_flags,
96 in_security_mode,
97 in_previous_session_id,
98 in_security_buffer);
99 if (subreq == NULL) {
100 return smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
102 tevent_req_set_callback(subreq, smbd_smb2_request_sesssetup_done, smb2req);
104 return smbd_smb2_request_pending_queue(smb2req, subreq, 500);
107 static void smbd_smb2_request_sesssetup_done(struct tevent_req *subreq)
109 struct smbd_smb2_request *smb2req =
110 tevent_req_callback_data(subreq,
111 struct smbd_smb2_request);
112 int i = smb2req->current_idx;
113 uint8_t *outhdr;
114 DATA_BLOB outbody;
115 DATA_BLOB outdyn;
116 uint16_t out_session_flags;
117 uint64_t out_session_id;
118 uint16_t out_security_offset;
119 DATA_BLOB out_security_buffer = data_blob_null;
120 NTSTATUS status;
121 NTSTATUS error; /* transport error */
123 status = smbd_smb2_session_setup_recv(subreq,
124 &out_session_flags,
125 smb2req,
126 &out_security_buffer,
127 &out_session_id);
128 TALLOC_FREE(subreq);
129 if (!NT_STATUS_IS_OK(status) &&
130 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
131 status = nt_status_squash(status);
132 error = smbd_smb2_request_error(smb2req, status);
133 if (!NT_STATUS_IS_OK(error)) {
134 smbd_server_connection_terminate(smb2req->sconn,
135 nt_errstr(error));
136 return;
138 return;
141 out_security_offset = SMB2_HDR_BODY + 0x08;
143 outhdr = (uint8_t *)smb2req->out.vector[i].iov_base;
145 outbody = data_blob_talloc(smb2req->out.vector, NULL, 0x08);
146 if (outbody.data == NULL) {
147 error = smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
148 if (!NT_STATUS_IS_OK(error)) {
149 smbd_server_connection_terminate(smb2req->sconn,
150 nt_errstr(error));
151 return;
153 return;
156 SBVAL(outhdr, SMB2_HDR_SESSION_ID, out_session_id);
158 SSVAL(outbody.data, 0x00, 0x08 + 1); /* struct size */
159 SSVAL(outbody.data, 0x02,
160 out_session_flags); /* session flags */
161 SSVAL(outbody.data, 0x04,
162 out_security_offset); /* security buffer offset */
163 SSVAL(outbody.data, 0x06,
164 out_security_buffer.length); /* security buffer length */
166 outdyn = out_security_buffer;
168 error = smbd_smb2_request_done_ex(smb2req, status, outbody, &outdyn,
169 __location__);
170 if (!NT_STATUS_IS_OK(error)) {
171 smbd_server_connection_terminate(smb2req->sconn,
172 nt_errstr(error));
173 return;
177 static int smbd_smb2_session_destructor(struct smbd_smb2_session *session)
179 if (session->sconn == NULL) {
180 return 0;
183 file_close_user(session->sconn, session->vuid);
185 /* first free all tcons */
186 while (session->tcons.list) {
187 talloc_free(session->tcons.list);
190 DLIST_REMOVE(session->sconn->smb2.sessions.list, session);
191 invalidate_vuid(session->sconn, session->vuid);
193 session->vuid = 0;
194 session->status = NT_STATUS_USER_SESSION_DELETED;
195 session->sconn = NULL;
197 session->smbXsrv->compat = NULL;
198 TALLOC_FREE(session->smbXsrv);
200 return 0;
203 static NTSTATUS smbd_smb2_auth_generic_return(struct smbd_smb2_session *session,
204 struct smbd_smb2_request *smb2req,
205 uint8_t in_security_mode,
206 uint64_t in_previous_session_id,
207 DATA_BLOB in_security_buffer,
208 uint16_t *out_session_flags,
209 uint64_t *out_session_id)
211 NTSTATUS status;
212 bool guest = false;
213 uint8_t session_key[16];
214 struct smbXsrv_session *x = session->smbXsrv;
215 struct auth_session_info *session_info = session->session_info;
216 struct smbXsrv_connection *conn = x->connection;
218 if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
219 lp_server_signing() == SMB_SIGNING_REQUIRED) {
220 x->global->signing_required = true;
223 if (security_session_user_level(session->session_info, NULL) < SECURITY_USER) {
224 /* we map anonymous to guest internally */
225 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
226 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
227 /* force no signing */
228 x->global->signing_required = false;
229 guest = true;
232 ZERO_STRUCT(session_key);
233 memcpy(session_key, session->session_info->session_key.data,
234 MIN(session->session_info->session_key.length, sizeof(session_key)));
236 x->global->signing_key = data_blob_talloc(x->global,
237 session_key,
238 sizeof(session_key));
239 if (x->global->signing_key.data == NULL) {
240 ZERO_STRUCT(session_key);
241 TALLOC_FREE(session);
242 return NT_STATUS_NO_MEMORY;
245 if (conn->protocol >= PROTOCOL_SMB2_24) {
246 const DATA_BLOB label = data_blob_string_const_null("SMB2AESCMAC");
247 const DATA_BLOB context = data_blob_string_const_null("SmbSign");
249 smb2_key_derivation(session_key, sizeof(session_key),
250 label.data, label.length,
251 context.data, context.length,
252 x->global->signing_key.data);
255 x->global->application_key = data_blob_dup_talloc(x->global,
256 x->global->signing_key);
257 if (x->global->application_key.data == NULL) {
258 ZERO_STRUCT(session_key);
259 TALLOC_FREE(session);
260 return NT_STATUS_NO_MEMORY;
263 if (conn->protocol >= PROTOCOL_SMB2_24) {
264 const DATA_BLOB label = data_blob_string_const_null("SMB2APP");
265 const DATA_BLOB context = data_blob_string_const_null("SmbRpc");
267 smb2_key_derivation(session_key, sizeof(session_key),
268 label.data, label.length,
269 context.data, context.length,
270 x->global->application_key.data);
272 ZERO_STRUCT(session_key);
274 x->global->channels[0].signing_key = data_blob_dup_talloc(x->global->channels,
275 x->global->signing_key);
276 if (x->global->channels[0].signing_key.data == NULL) {
277 TALLOC_FREE(session);
278 return NT_STATUS_NO_MEMORY;
281 data_blob_clear_free(&session_info->session_key);
282 session_info->session_key = data_blob_dup_talloc(session_info,
283 x->global->application_key);
284 if (session_info->session_key.data == NULL) {
285 TALLOC_FREE(session);
286 return NT_STATUS_NO_MEMORY;
289 session->compat_vuser = talloc_zero(session, struct user_struct);
290 if (session->compat_vuser == NULL) {
291 TALLOC_FREE(session);
292 return NT_STATUS_NO_MEMORY;
294 session->compat_vuser->gensec_security = session->gensec_security;
295 session->compat_vuser->homes_snum = -1;
296 session->compat_vuser->session_info = session->session_info;
297 session->compat_vuser->session_keystr = NULL;
298 session->compat_vuser->vuid = session->vuid;
299 DLIST_ADD(session->sconn->users, session->compat_vuser);
300 session->sconn->num_users++;
302 if (security_session_user_level(session->session_info, NULL) >= SECURITY_USER) {
303 session->compat_vuser->homes_snum =
304 register_homes_share(session->session_info->unix_info->unix_name);
307 if (!session_claim(session->sconn, session->compat_vuser)) {
308 DEBUG(1, ("smb2: Failed to claim session "
309 "for vuid=%llu\n",
310 (unsigned long long)session->compat_vuser->vuid));
311 TALLOC_FREE(session);
312 return NT_STATUS_LOGON_FAILURE;
315 set_current_user_info(session->session_info->unix_info->sanitized_username,
316 session->session_info->unix_info->unix_name,
317 session->session_info->info->domain_name);
319 reload_services(smb2req->sconn, conn_snum_used, true);
321 session->smbXsrv->status = NT_STATUS_OK;
322 session->smbXsrv->global->auth_session_info = session->session_info;
323 session->smbXsrv->global->auth_session_info_seqnum += 1;
324 session->smbXsrv->global->channels[0].auth_session_info_seqnum =
325 session->smbXsrv->global->auth_session_info_seqnum;
327 status = smbXsrv_session_update(session->smbXsrv);
328 if (!NT_STATUS_IS_OK(status)) {
329 DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n",
330 (unsigned long long)session->compat_vuser->vuid,
331 nt_errstr(status)));
332 TALLOC_FREE(session);
333 return NT_STATUS_LOGON_FAILURE;
336 session->status = NT_STATUS_OK;
339 * we attach the session to the request
340 * so that the response can be signed
342 smb2req->session = session;
343 if (!guest) {
344 smb2req->do_signing = true;
347 global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
349 *out_session_id = session->vuid;
351 return NT_STATUS_OK;
354 static NTSTATUS smbd_smb2_auth_generic(struct smbd_smb2_session *session,
355 struct smbd_smb2_request *smb2req,
356 uint8_t in_security_mode,
357 uint64_t in_previous_session_id,
358 DATA_BLOB in_security_buffer,
359 uint16_t *out_session_flags,
360 DATA_BLOB *out_security_buffer,
361 uint64_t *out_session_id)
363 NTSTATUS status;
365 *out_security_buffer = data_blob_null;
367 if (session->gensec_security == NULL) {
368 status = auth_generic_prepare(session, session->sconn->remote_address,
369 &session->gensec_security);
370 if (!NT_STATUS_IS_OK(status)) {
371 TALLOC_FREE(session);
372 return status;
375 gensec_want_feature(session->gensec_security, GENSEC_FEATURE_SESSION_KEY);
376 gensec_want_feature(session->gensec_security, GENSEC_FEATURE_UNIX_TOKEN);
378 status = gensec_start_mech_by_oid(session->gensec_security, GENSEC_OID_SPNEGO);
379 if (!NT_STATUS_IS_OK(status)) {
380 TALLOC_FREE(session);
381 return status;
385 become_root();
386 status = gensec_update(session->gensec_security,
387 smb2req, NULL,
388 in_security_buffer,
389 out_security_buffer);
390 unbecome_root();
391 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
392 !NT_STATUS_IS_OK(status)) {
393 TALLOC_FREE(session);
394 return nt_status_squash(status);
397 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
398 *out_session_id = session->vuid;
399 return status;
402 status = gensec_session_info(session->gensec_security,
403 session,
404 &session->session_info);
406 if (!NT_STATUS_IS_OK(status)) {
407 TALLOC_FREE(session);
408 return status;
410 *out_session_id = session->vuid;
412 return smbd_smb2_auth_generic_return(session,
413 smb2req,
414 in_security_mode,
415 in_previous_session_id,
416 in_security_buffer,
417 out_session_flags,
418 out_session_id);
421 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
422 uint64_t in_session_id,
423 uint8_t in_flags,
424 uint8_t in_security_mode,
425 uint64_t in_previous_session_id,
426 DATA_BLOB in_security_buffer,
427 uint16_t *out_session_flags,
428 DATA_BLOB *out_security_buffer,
429 uint64_t *out_session_id)
431 struct smbd_smb2_session *smb2sess;
432 struct smbXsrv_session *session;
433 NTSTATUS status;
434 NTTIME now = timeval_to_nttime(&smb2req->request_time);
436 *out_session_flags = 0;
437 *out_session_id = 0;
439 if (in_session_id == 0) {
440 /* create a new session */
441 smb2sess = talloc_zero(smb2req->sconn, struct smbd_smb2_session);
442 if (smb2sess == NULL) {
443 return NT_STATUS_NO_MEMORY;
446 status = smbXsrv_session_create(smb2req->sconn->conn,
447 now, &session);
448 if (!NT_STATUS_IS_OK(status)) {
449 return status;
451 smb2sess->smbXsrv = session;
452 session->smb2sess = smb2sess;
453 talloc_set_destructor(smb2sess, smbd_smb2_session_destructor);
455 smb2sess->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
456 smb2sess->vuid = session->global->session_wire_id;
458 smb2sess->tcons.idtree = idr_init(smb2sess);
459 if (smb2sess->tcons.idtree == NULL) {
460 return NT_STATUS_NO_MEMORY;
462 smb2sess->tcons.limit = 0x0000FFFE;
463 smb2sess->tcons.list = NULL;
465 DLIST_ADD_END(smb2req->sconn->smb2.sessions.list, smb2sess,
466 struct smbd_smb2_session *);
467 smb2sess->sconn = smb2req->sconn;
468 } else {
469 status = smb2srv_session_lookup(smb2req->sconn->conn,
470 in_session_id, now,
471 &session);
472 if (NT_STATUS_IS_OK(status)) {
473 return NT_STATUS_REQUEST_NOT_ACCEPTED;
475 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
477 return status;
480 smb2sess = session->smb2sess;
483 if (NT_STATUS_IS_OK(smb2sess->status)) {
484 return NT_STATUS_REQUEST_NOT_ACCEPTED;
487 return smbd_smb2_auth_generic(smb2sess,
488 smb2req,
489 in_security_mode,
490 in_previous_session_id,
491 in_security_buffer,
492 out_session_flags,
493 out_security_buffer,
494 out_session_id);
497 struct smbd_smb2_session_setup_state {
498 struct tevent_context *ev;
499 struct smbd_smb2_request *smb2req;
500 uint64_t in_session_id;
501 uint8_t in_flags;
502 uint8_t in_security_mode;
503 uint64_t in_previous_session_id;
504 DATA_BLOB in_security_buffer;
505 uint16_t out_session_flags;
506 DATA_BLOB out_security_buffer;
507 uint64_t out_session_id;
510 static struct tevent_req *smbd_smb2_session_setup_send(TALLOC_CTX *mem_ctx,
511 struct tevent_context *ev,
512 struct smbd_smb2_request *smb2req,
513 uint64_t in_session_id,
514 uint8_t in_flags,
515 uint8_t in_security_mode,
516 uint64_t in_previous_session_id,
517 DATA_BLOB in_security_buffer)
519 struct tevent_req *req;
520 struct smbd_smb2_session_setup_state *state;
521 NTSTATUS status;
523 req = tevent_req_create(mem_ctx, &state,
524 struct smbd_smb2_session_setup_state);
525 if (req == NULL) {
526 return NULL;
528 state->ev = ev;
529 state->smb2req = smb2req;
530 state->in_session_id = in_session_id;
531 state->in_flags = in_flags;
532 state->in_security_mode = in_security_mode;
533 state->in_previous_session_id = in_previous_session_id;
534 state->in_security_buffer = in_security_buffer;
536 status = smbd_smb2_session_setup(smb2req,
537 in_session_id,
538 in_flags,
539 in_security_mode,
540 in_previous_session_id,
541 in_security_buffer,
542 &state->out_session_flags,
543 &state->out_security_buffer,
544 &state->out_session_id);
545 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) ||
546 NT_STATUS_IS_OK(status))
548 talloc_steal(state, state->out_security_buffer.data);
550 if (tevent_req_nterror(req, status)) {
551 return tevent_req_post(req, ev);
554 tevent_req_done(req);
555 return tevent_req_post(req, ev);
558 static NTSTATUS smbd_smb2_session_setup_recv(struct tevent_req *req,
559 uint16_t *out_session_flags,
560 TALLOC_CTX *mem_ctx,
561 DATA_BLOB *out_security_buffer,
562 uint64_t *out_session_id)
564 struct smbd_smb2_session_setup_state *state =
565 tevent_req_data(req,
566 struct smbd_smb2_session_setup_state);
567 NTSTATUS status;
569 if (tevent_req_is_nterror(req, &status)) {
570 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
571 tevent_req_received(req);
572 return nt_status_squash(status);
574 } else {
575 status = NT_STATUS_OK;
578 *out_session_flags = state->out_session_flags;
579 *out_security_buffer = state->out_security_buffer;
580 *out_session_id = state->out_session_id;
582 talloc_steal(mem_ctx, out_security_buffer->data);
583 tevent_req_received(req);
584 return status;
587 NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req)
589 NTSTATUS status;
590 DATA_BLOB outbody;
592 status = smbd_smb2_request_verify_sizes(req, 0x04);
593 if (!NT_STATUS_IS_OK(status)) {
594 return smbd_smb2_request_error(req, status);
598 * TODO: cancel all outstanding requests on the session
599 * and delete all tree connections.
601 smbd_smb2_session_destructor(req->session);
603 * we may need to sign the response, so we need to keep
604 * the session until the response is sent to the wire.
606 talloc_steal(req, req->session);
608 outbody = data_blob_talloc(req->out.vector, NULL, 0x04);
609 if (outbody.data == NULL) {
610 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
613 SSVAL(outbody.data, 0x00, 0x04); /* struct size */
614 SSVAL(outbody.data, 0x02, 0); /* reserved */
616 return smbd_smb2_request_done(req, outbody, NULL);