2 Unix SMB/CIFS implementation.
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/>.
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "../libcli/smb/smb_common.h"
26 #include "../auth/gensec/gensec.h"
28 #include "../lib/tsocket/tsocket.h"
29 #include "../libcli/security/security.h"
30 #include "../lib/util/tevent_ntstatus.h"
31 #include "lib/smbd_tevent_queue.h"
33 static struct tevent_req
*smbd_smb2_session_setup_send(TALLOC_CTX
*mem_ctx
,
34 struct tevent_context
*ev
,
35 struct smbd_smb2_request
*smb2req
,
36 uint64_t in_session_id
,
38 uint8_t in_security_mode
,
39 uint64_t in_previous_session_id
,
40 DATA_BLOB in_security_buffer
);
41 static NTSTATUS
smbd_smb2_session_setup_recv(struct tevent_req
*req
,
42 uint16_t *out_session_flags
,
44 DATA_BLOB
*out_security_buffer
,
45 uint64_t *out_session_id
);
47 static void smbd_smb2_request_sesssetup_done(struct tevent_req
*subreq
);
49 NTSTATUS
smbd_smb2_request_process_sesssetup(struct smbd_smb2_request
*smb2req
)
52 const uint8_t *inbody
;
53 uint64_t in_session_id
;
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
;
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
= SMBD_SMB2_IN_HDR_PTR(smb2req
);
68 inbody
= SMBD_SMB2_IN_BODY_PTR(smb2req
);
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
+ SMBD_SMB2_IN_BODY_LEN(smb2req
))) {
81 return smbd_smb2_request_error(smb2req
, NT_STATUS_INVALID_PARAMETER
);
84 if (in_security_length
> SMBD_SMB2_IN_DYN_LEN(smb2req
)) {
85 return smbd_smb2_request_error(smb2req
, NT_STATUS_INVALID_PARAMETER
);
88 in_security_buffer
.data
= SMBD_SMB2_IN_DYN_PTR(smb2req
);
89 in_security_buffer
.length
= in_security_length
;
91 subreq
= smbd_smb2_session_setup_send(smb2req
,
92 smb2req
->sconn
->ev_ctx
,
97 in_previous_session_id
,
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
);
115 uint16_t out_session_flags
;
116 uint64_t out_session_id
;
117 uint16_t out_security_offset
;
118 DATA_BLOB out_security_buffer
= data_blob_null
;
120 NTSTATUS error
; /* transport error */
122 status
= smbd_smb2_session_setup_recv(subreq
,
125 &out_security_buffer
,
128 if (!NT_STATUS_IS_OK(status
) &&
129 !NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
130 status
= nt_status_squash(status
);
131 error
= smbd_smb2_request_error(smb2req
, status
);
132 if (!NT_STATUS_IS_OK(error
)) {
133 smbd_server_connection_terminate(smb2req
->sconn
,
140 out_security_offset
= SMB2_HDR_BODY
+ 0x08;
142 outhdr
= SMBD_SMB2_OUT_HDR_PTR(smb2req
);
144 outbody
= data_blob_talloc(smb2req
->out
.vector
, NULL
, 0x08);
145 if (outbody
.data
== NULL
) {
146 error
= smbd_smb2_request_error(smb2req
, NT_STATUS_NO_MEMORY
);
147 if (!NT_STATUS_IS_OK(error
)) {
148 smbd_server_connection_terminate(smb2req
->sconn
,
155 SBVAL(outhdr
, SMB2_HDR_SESSION_ID
, out_session_id
);
157 SSVAL(outbody
.data
, 0x00, 0x08 + 1); /* struct size */
158 SSVAL(outbody
.data
, 0x02,
159 out_session_flags
); /* session flags */
160 SSVAL(outbody
.data
, 0x04,
161 out_security_offset
); /* security buffer offset */
162 SSVAL(outbody
.data
, 0x06,
163 out_security_buffer
.length
); /* security buffer length */
165 outdyn
= out_security_buffer
;
167 error
= smbd_smb2_request_done_ex(smb2req
, status
, outbody
, &outdyn
,
169 if (!NT_STATUS_IS_OK(error
)) {
170 smbd_server_connection_terminate(smb2req
->sconn
,
176 static NTSTATUS
smbd_smb2_auth_generic_return(struct smbXsrv_session
*session
,
177 struct smbd_smb2_request
*smb2req
,
178 uint8_t in_security_mode
,
179 struct auth_session_info
*session_info
,
180 uint16_t *out_session_flags
,
181 uint64_t *out_session_id
)
185 uint8_t session_key
[16];
186 struct smbXsrv_session
*x
= session
;
187 struct smbXsrv_connection
*conn
= session
->connection
;
189 if ((in_security_mode
& SMB2_NEGOTIATE_SIGNING_REQUIRED
) ||
190 lp_server_signing() == SMB_SIGNING_REQUIRED
) {
191 x
->global
->signing_required
= true;
194 if (lp_smb_encrypt(-1) == SMB_SIGNING_REQUIRED
) {
195 x
->global
->encryption_required
= true;
198 if (security_session_user_level(session_info
, NULL
) < SECURITY_USER
) {
199 /* we map anonymous to guest internally */
200 *out_session_flags
|= SMB2_SESSION_FLAG_IS_GUEST
;
201 *out_session_flags
|= SMB2_SESSION_FLAG_IS_NULL
;
202 /* force no signing */
203 x
->global
->signing_required
= false;
207 if (guest
&& x
->global
->encryption_required
) {
208 DEBUG(1,("reject guest session as encryption is required\n"));
209 return NT_STATUS_ACCESS_DENIED
;
212 if (!(conn
->smb2
.server
.capabilities
& SMB2_CAP_ENCRYPTION
)) {
213 if (x
->global
->encryption_required
) {
214 DEBUG(1,("reject session with dialect[0x%04X] "
215 "as encryption is required\n",
216 conn
->smb2
.server
.dialect
));
217 return NT_STATUS_ACCESS_DENIED
;
221 if (x
->global
->encryption_required
) {
222 *out_session_flags
|= SMB2_SESSION_FLAG_ENCRYPT_DATA
;
225 ZERO_STRUCT(session_key
);
226 memcpy(session_key
, session_info
->session_key
.data
,
227 MIN(session_info
->session_key
.length
, sizeof(session_key
)));
229 x
->global
->signing_key
= data_blob_talloc(x
->global
,
231 sizeof(session_key
));
232 if (x
->global
->signing_key
.data
== NULL
) {
233 ZERO_STRUCT(session_key
);
234 return NT_STATUS_NO_MEMORY
;
237 if (conn
->protocol
>= PROTOCOL_SMB2_24
) {
238 const DATA_BLOB label
= data_blob_string_const_null("SMB2AESCMAC");
239 const DATA_BLOB context
= data_blob_string_const_null("SmbSign");
241 smb2_key_derivation(session_key
, sizeof(session_key
),
242 label
.data
, label
.length
,
243 context
.data
, context
.length
,
244 x
->global
->signing_key
.data
);
247 if (conn
->protocol
>= PROTOCOL_SMB2_24
) {
248 const DATA_BLOB label
= data_blob_string_const_null("SMB2AESCCM");
249 const DATA_BLOB context
= data_blob_string_const_null("ServerIn ");
251 x
->global
->decryption_key
= data_blob_talloc(x
->global
,
253 sizeof(session_key
));
254 if (x
->global
->decryption_key
.data
== NULL
) {
255 ZERO_STRUCT(session_key
);
256 return NT_STATUS_NO_MEMORY
;
259 smb2_key_derivation(session_key
, sizeof(session_key
),
260 label
.data
, label
.length
,
261 context
.data
, context
.length
,
262 x
->global
->decryption_key
.data
);
265 if (conn
->protocol
>= PROTOCOL_SMB2_24
) {
266 const DATA_BLOB label
= data_blob_string_const_null("SMB2AESCCM");
267 const DATA_BLOB context
= data_blob_string_const_null("ServerOut");
269 x
->global
->encryption_key
= data_blob_talloc(x
->global
,
271 sizeof(session_key
));
272 if (x
->global
->encryption_key
.data
== NULL
) {
273 ZERO_STRUCT(session_key
);
274 return NT_STATUS_NO_MEMORY
;
277 smb2_key_derivation(session_key
, sizeof(session_key
),
278 label
.data
, label
.length
,
279 context
.data
, context
.length
,
280 x
->global
->encryption_key
.data
);
282 generate_random_buffer((uint8_t *)&x
->nonce_high
, sizeof(x
->nonce_high
));
286 x
->global
->application_key
= data_blob_dup_talloc(x
->global
,
287 x
->global
->signing_key
);
288 if (x
->global
->application_key
.data
== NULL
) {
289 ZERO_STRUCT(session_key
);
290 return NT_STATUS_NO_MEMORY
;
293 if (conn
->protocol
>= PROTOCOL_SMB2_24
) {
294 const DATA_BLOB label
= data_blob_string_const_null("SMB2APP");
295 const DATA_BLOB context
= data_blob_string_const_null("SmbRpc");
297 smb2_key_derivation(session_key
, sizeof(session_key
),
298 label
.data
, label
.length
,
299 context
.data
, context
.length
,
300 x
->global
->application_key
.data
);
302 ZERO_STRUCT(session_key
);
304 x
->global
->channels
[0].signing_key
= data_blob_dup_talloc(x
->global
->channels
,
305 x
->global
->signing_key
);
306 if (x
->global
->channels
[0].signing_key
.data
== NULL
) {
307 return NT_STATUS_NO_MEMORY
;
310 data_blob_clear_free(&session_info
->session_key
);
311 session_info
->session_key
= data_blob_dup_talloc(session_info
,
312 x
->global
->application_key
);
313 if (session_info
->session_key
.data
== NULL
) {
314 return NT_STATUS_NO_MEMORY
;
317 session
->compat
= talloc_zero(session
, struct user_struct
);
318 if (session
->compat
== NULL
) {
319 return NT_STATUS_NO_MEMORY
;
321 session
->compat
->session
= session
;
322 session
->compat
->homes_snum
= -1;
323 session
->compat
->session_info
= session_info
;
324 session
->compat
->session_keystr
= NULL
;
325 session
->compat
->vuid
= session
->global
->session_wire_id
;
326 DLIST_ADD(smb2req
->sconn
->users
, session
->compat
);
327 smb2req
->sconn
->num_users
++;
329 if (security_session_user_level(session_info
, NULL
) >= SECURITY_USER
) {
330 session
->compat
->homes_snum
=
331 register_homes_share(session_info
->unix_info
->unix_name
);
334 set_current_user_info(session_info
->unix_info
->sanitized_username
,
335 session_info
->unix_info
->unix_name
,
336 session_info
->info
->domain_name
);
338 reload_services(smb2req
->sconn
, conn_snum_used
, true);
340 session
->status
= NT_STATUS_OK
;
341 session
->global
->auth_session_info
= session_info
;
342 session
->global
->auth_session_info_seqnum
+= 1;
343 session
->global
->channels
[0].auth_session_info_seqnum
=
344 session
->global
->auth_session_info_seqnum
;
345 session
->global
->expiration_time
= gensec_expire_time(session
->gensec
);
347 if (!session_claim(session
)) {
348 DEBUG(1, ("smb2: Failed to claim session "
350 (unsigned long long)session
->compat
->vuid
));
351 return NT_STATUS_LOGON_FAILURE
;
354 status
= smbXsrv_session_update(session
);
355 if (!NT_STATUS_IS_OK(status
)) {
356 DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n",
357 (unsigned long long)session
->compat
->vuid
,
359 return NT_STATUS_LOGON_FAILURE
;
363 * we attach the session to the request
364 * so that the response can be signed
366 smb2req
->session
= session
;
368 smb2req
->do_signing
= true;
371 global_client_caps
|= (CAP_LEVEL_II_OPLOCKS
|CAP_STATUS32
);
373 *out_session_id
= session
->global
->session_wire_id
;
378 static NTSTATUS
smbd_smb2_reauth_generic_return(struct smbXsrv_session
*session
,
379 struct smbd_smb2_request
*smb2req
,
380 struct auth_session_info
*session_info
,
381 uint16_t *out_session_flags
,
382 uint64_t *out_session_id
)
385 struct smbXsrv_session
*x
= session
;
386 struct smbXsrv_connection
*conn
= session
->connection
;
388 data_blob_clear_free(&session_info
->session_key
);
389 session_info
->session_key
= data_blob_dup_talloc(session_info
,
390 x
->global
->application_key
);
391 if (session_info
->session_key
.data
== NULL
) {
392 return NT_STATUS_NO_MEMORY
;
395 session
->compat
->session_info
= session_info
;
396 session
->compat
->vuid
= session
->global
->session_wire_id
;
398 session
->compat
->homes_snum
=
399 register_homes_share(session_info
->unix_info
->unix_name
);
401 set_current_user_info(session_info
->unix_info
->sanitized_username
,
402 session_info
->unix_info
->unix_name
,
403 session_info
->info
->domain_name
);
405 reload_services(smb2req
->sconn
, conn_snum_used
, true);
407 session
->status
= NT_STATUS_OK
;
408 TALLOC_FREE(session
->global
->auth_session_info
);
409 session
->global
->auth_session_info
= session_info
;
410 session
->global
->auth_session_info_seqnum
+= 1;
411 session
->global
->channels
[0].auth_session_info_seqnum
=
412 session
->global
->auth_session_info_seqnum
;
413 session
->global
->expiration_time
= gensec_expire_time(session
->gensec
);
415 status
= smbXsrv_session_update(session
);
416 if (!NT_STATUS_IS_OK(status
)) {
417 DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n",
418 (unsigned long long)session
->compat
->vuid
,
420 return NT_STATUS_LOGON_FAILURE
;
423 conn_clear_vuid_caches(conn
->sconn
, session
->compat
->vuid
);
425 *out_session_id
= session
->global
->session_wire_id
;
430 struct smbd_smb2_session_setup_state
{
431 struct tevent_context
*ev
;
432 struct smbd_smb2_request
*smb2req
;
433 uint64_t in_session_id
;
435 uint8_t in_security_mode
;
436 uint64_t in_previous_session_id
;
437 DATA_BLOB in_security_buffer
;
438 struct smbXsrv_session
*session
;
439 struct auth_session_info
*session_info
;
440 uint16_t out_session_flags
;
441 DATA_BLOB out_security_buffer
;
442 uint64_t out_session_id
;
443 /* The following pointer is owned by state->session. */
444 struct smbd_smb2_session_setup_state
**pp_self_ref
;
447 static int pp_self_ref_destructor(struct smbd_smb2_session_setup_state
**pp_state
)
449 (*pp_state
)->session
= NULL
;
451 * To make things clearer, ensure the pp_self_ref
452 * pointer is nulled out. We're never going to
455 (*pp_state
)->pp_self_ref
= NULL
;
459 static int smbd_smb2_session_setup_state_destructor(struct smbd_smb2_session_setup_state
*state
)
462 * if state->session is not NULL,
463 * we remove the session on failure
465 TALLOC_FREE(state
->session
);
469 static void smbd_smb2_session_setup_gensec_done(struct tevent_req
*subreq
);
470 static void smbd_smb2_session_setup_previous_done(struct tevent_req
*subreq
);
472 /************************************************************************
473 We have to tag the state->session pointer with memory talloc'ed
474 on it to ensure it gets NULL'ed out if the underlying struct smbXsrv_session
475 is deleted by shutdown whilst this request is in flight.
476 ************************************************************************/
478 static NTSTATUS
tag_state_session_ptr(struct smbd_smb2_session_setup_state
*state
)
480 state
->pp_self_ref
= talloc_zero(state
->session
,
481 struct smbd_smb2_session_setup_state
*);
482 if (state
->pp_self_ref
== NULL
) {
483 return NT_STATUS_NO_MEMORY
;
485 *state
->pp_self_ref
= state
;
486 talloc_set_destructor(state
->pp_self_ref
, pp_self_ref_destructor
);
490 static struct tevent_req
*smbd_smb2_session_setup_send(TALLOC_CTX
*mem_ctx
,
491 struct tevent_context
*ev
,
492 struct smbd_smb2_request
*smb2req
,
493 uint64_t in_session_id
,
495 uint8_t in_security_mode
,
496 uint64_t in_previous_session_id
,
497 DATA_BLOB in_security_buffer
)
499 struct tevent_req
*req
;
500 struct smbd_smb2_session_setup_state
*state
;
502 NTTIME now
= timeval_to_nttime(&smb2req
->request_time
);
503 struct tevent_req
*subreq
;
505 req
= tevent_req_create(mem_ctx
, &state
,
506 struct smbd_smb2_session_setup_state
);
511 state
->smb2req
= smb2req
;
512 state
->in_session_id
= in_session_id
;
513 state
->in_flags
= in_flags
;
514 state
->in_security_mode
= in_security_mode
;
515 state
->in_previous_session_id
= in_previous_session_id
;
516 state
->in_security_buffer
= in_security_buffer
;
518 if (in_flags
& SMB2_SESSION_FLAG_BINDING
) {
519 if (smb2req
->sconn
->conn
->protocol
< PROTOCOL_SMB2_22
) {
520 tevent_req_nterror(req
, NT_STATUS_REQUEST_NOT_ACCEPTED
);
521 return tevent_req_post(req
, ev
);
525 * We do not support multi channel.
527 tevent_req_nterror(req
, NT_STATUS_NOT_SUPPORTED
);
528 return tevent_req_post(req
, ev
);
531 talloc_set_destructor(state
, smbd_smb2_session_setup_state_destructor
);
533 if (state
->in_session_id
== 0) {
534 /* create a new session */
535 status
= smbXsrv_session_create(state
->smb2req
->sconn
->conn
,
536 now
, &state
->session
);
537 if (tevent_req_nterror(req
, status
)) {
538 return tevent_req_post(req
, ev
);
541 status
= smb2srv_session_lookup(state
->smb2req
->sconn
->conn
,
542 state
->in_session_id
, now
,
544 if (NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_SESSION_EXPIRED
)) {
545 status
= NT_STATUS_OK
;
547 if (NT_STATUS_IS_OK(status
)) {
548 state
->session
->status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
549 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
550 TALLOC_FREE(state
->session
->gensec
);
552 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
553 tevent_req_nterror(req
, status
);
554 return tevent_req_post(req
, ev
);
558 status
= tag_state_session_ptr(state
);
559 if (tevent_req_nterror(req
, status
)) {
560 return tevent_req_post(req
, ev
);
563 if (state
->session
->gensec
== NULL
) {
564 status
= auth_generic_prepare(state
->session
,
565 state
->session
->connection
->remote_address
,
566 &state
->session
->gensec
);
567 if (tevent_req_nterror(req
, status
)) {
568 return tevent_req_post(req
, ev
);
571 gensec_want_feature(state
->session
->gensec
, GENSEC_FEATURE_SESSION_KEY
);
572 gensec_want_feature(state
->session
->gensec
, GENSEC_FEATURE_UNIX_TOKEN
);
574 status
= gensec_start_mech_by_oid(state
->session
->gensec
,
576 if (tevent_req_nterror(req
, status
)) {
577 return tevent_req_post(req
, ev
);
582 subreq
= gensec_update_send(state
, state
->ev
,
583 state
->session
->gensec
,
584 state
->in_security_buffer
);
586 if (tevent_req_nomem(subreq
, req
)) {
587 return tevent_req_post(req
, ev
);
589 tevent_req_set_callback(subreq
, smbd_smb2_session_setup_gensec_done
, req
);
594 static void smbd_smb2_session_setup_gensec_done(struct tevent_req
*subreq
)
596 struct tevent_req
*req
=
597 tevent_req_callback_data(subreq
,
599 struct smbd_smb2_session_setup_state
*state
=
601 struct smbd_smb2_session_setup_state
);
605 status
= gensec_update_recv(subreq
, state
,
606 &state
->out_security_buffer
);
609 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) &&
610 !NT_STATUS_IS_OK(status
)) {
611 tevent_req_nterror(req
, status
);
615 if (NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
616 state
->out_session_id
= state
->session
->global
->session_wire_id
;
617 /* we want to keep the session */
618 TALLOC_FREE(state
->pp_self_ref
);
619 tevent_req_nterror(req
, status
);
623 status
= gensec_session_info(state
->session
->gensec
,
624 state
->session
->global
,
625 &state
->session_info
);
626 if (tevent_req_nterror(req
, status
)) {
630 if ((state
->in_previous_session_id
!= 0) &&
631 (state
->session
->global
->session_wire_id
!=
632 state
->in_previous_session_id
))
634 subreq
= smb2srv_session_close_previous_send(state
, state
->ev
,
635 state
->session
->connection
,
637 state
->in_previous_session_id
,
638 state
->session
->global
->session_wire_id
);
639 if (tevent_req_nomem(subreq
, req
)) {
642 tevent_req_set_callback(subreq
,
643 smbd_smb2_session_setup_previous_done
,
648 if (state
->session
->global
->auth_session_info
!= NULL
) {
649 status
= smbd_smb2_reauth_generic_return(state
->session
,
652 &state
->out_session_flags
,
653 &state
->out_session_id
);
654 if (tevent_req_nterror(req
, status
)) {
657 /* we want to keep the session */
658 TALLOC_FREE(state
->pp_self_ref
);
659 tevent_req_done(req
);
663 status
= smbd_smb2_auth_generic_return(state
->session
,
665 state
->in_security_mode
,
667 &state
->out_session_flags
,
668 &state
->out_session_id
);
669 if (tevent_req_nterror(req
, status
)) {
673 /* we want to keep the session */
674 TALLOC_FREE(state
->pp_self_ref
);
675 tevent_req_done(req
);
679 static void smbd_smb2_session_setup_previous_done(struct tevent_req
*subreq
)
681 struct tevent_req
*req
=
682 tevent_req_callback_data(subreq
,
684 struct smbd_smb2_session_setup_state
*state
=
686 struct smbd_smb2_session_setup_state
);
689 status
= smb2srv_session_close_previous_recv(subreq
);
691 if (tevent_req_nterror(req
, status
)) {
695 if (state
->session
->global
->auth_session_info
!= NULL
) {
696 status
= smbd_smb2_reauth_generic_return(state
->session
,
699 &state
->out_session_flags
,
700 &state
->out_session_id
);
701 if (tevent_req_nterror(req
, status
)) {
704 /* we want to keep the session */
705 TALLOC_FREE(state
->pp_self_ref
);
706 tevent_req_done(req
);
710 status
= smbd_smb2_auth_generic_return(state
->session
,
712 state
->in_security_mode
,
714 &state
->out_session_flags
,
715 &state
->out_session_id
);
716 if (tevent_req_nterror(req
, status
)) {
720 /* we want to keep the session */
721 TALLOC_FREE(state
->pp_self_ref
);
722 tevent_req_done(req
);
726 static NTSTATUS
smbd_smb2_session_setup_recv(struct tevent_req
*req
,
727 uint16_t *out_session_flags
,
729 DATA_BLOB
*out_security_buffer
,
730 uint64_t *out_session_id
)
732 struct smbd_smb2_session_setup_state
*state
=
734 struct smbd_smb2_session_setup_state
);
737 if (tevent_req_is_nterror(req
, &status
)) {
738 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
739 tevent_req_received(req
);
740 return nt_status_squash(status
);
743 status
= NT_STATUS_OK
;
746 *out_session_flags
= state
->out_session_flags
;
747 *out_security_buffer
= state
->out_security_buffer
;
748 *out_session_id
= state
->out_session_id
;
750 talloc_steal(mem_ctx
, out_security_buffer
->data
);
751 tevent_req_received(req
);
755 static struct tevent_req
*smbd_smb2_logoff_send(TALLOC_CTX
*mem_ctx
,
756 struct tevent_context
*ev
,
757 struct smbd_smb2_request
*smb2req
);
758 static NTSTATUS
smbd_smb2_logoff_recv(struct tevent_req
*req
);
759 static void smbd_smb2_request_logoff_done(struct tevent_req
*subreq
);
761 NTSTATUS
smbd_smb2_request_process_logoff(struct smbd_smb2_request
*req
)
764 struct tevent_req
*subreq
= NULL
;
766 status
= smbd_smb2_request_verify_sizes(req
, 0x04);
767 if (!NT_STATUS_IS_OK(status
)) {
768 return smbd_smb2_request_error(req
, status
);
771 subreq
= smbd_smb2_logoff_send(req
, req
->sconn
->ev_ctx
, req
);
772 if (subreq
== NULL
) {
773 return smbd_smb2_request_error(req
, NT_STATUS_NO_MEMORY
);
775 tevent_req_set_callback(subreq
, smbd_smb2_request_logoff_done
, req
);
778 * Wait a long time before going async on this to allow
779 * requests we're waiting on to finish. Set timeout to 10 secs.
781 return smbd_smb2_request_pending_queue(req
, subreq
, 10000000);
784 static void smbd_smb2_request_logoff_done(struct tevent_req
*subreq
)
786 struct smbd_smb2_request
*smb2req
=
787 tevent_req_callback_data(subreq
,
788 struct smbd_smb2_request
);
793 status
= smbd_smb2_logoff_recv(subreq
);
795 if (!NT_STATUS_IS_OK(status
)) {
796 error
= smbd_smb2_request_error(smb2req
, status
);
797 if (!NT_STATUS_IS_OK(error
)) {
798 smbd_server_connection_terminate(smb2req
->sconn
,
805 outbody
= data_blob_talloc(smb2req
->out
.vector
, NULL
, 0x04);
806 if (outbody
.data
== NULL
) {
807 error
= smbd_smb2_request_error(smb2req
, NT_STATUS_NO_MEMORY
);
808 if (!NT_STATUS_IS_OK(error
)) {
809 smbd_server_connection_terminate(smb2req
->sconn
,
816 SSVAL(outbody
.data
, 0x00, 0x04); /* struct size */
817 SSVAL(outbody
.data
, 0x02, 0); /* reserved */
819 error
= smbd_smb2_request_done(smb2req
, outbody
, NULL
);
820 if (!NT_STATUS_IS_OK(error
)) {
821 smbd_server_connection_terminate(smb2req
->sconn
,
827 struct smbd_smb2_logout_state
{
828 struct smbd_smb2_request
*smb2req
;
829 struct tevent_queue
*wait_queue
;
832 static void smbd_smb2_logoff_wait_done(struct tevent_req
*subreq
);
834 static struct tevent_req
*smbd_smb2_logoff_send(TALLOC_CTX
*mem_ctx
,
835 struct tevent_context
*ev
,
836 struct smbd_smb2_request
*smb2req
)
838 struct tevent_req
*req
;
839 struct smbd_smb2_logout_state
*state
;
840 struct tevent_req
*subreq
;
841 struct smbd_smb2_request
*preq
;
843 req
= tevent_req_create(mem_ctx
, &state
,
844 struct smbd_smb2_logout_state
);
848 state
->smb2req
= smb2req
;
850 state
->wait_queue
= tevent_queue_create(state
, "logoff_wait_queue");
851 if (tevent_req_nomem(state
->wait_queue
, req
)) {
852 return tevent_req_post(req
, ev
);
856 * Make sure that no new request will be able to use this session.
858 smb2req
->session
->status
= NT_STATUS_USER_SESSION_DELETED
;
860 for (preq
= smb2req
->sconn
->smb2
.requests
; preq
!= NULL
; preq
= preq
->next
) {
861 if (preq
== smb2req
) {
862 /* Can't cancel current request. */
865 if (preq
->session
!= smb2req
->session
) {
866 /* Request on different session. */
871 * Never cancel anything in a compound
872 * request. Way too hard to deal with
875 if (!preq
->compound_related
&& preq
->subreq
!= NULL
) {
876 tevent_req_cancel(preq
->subreq
);
880 * Now wait until the request is finished.
882 * We don't set a callback, as we just want to block the
883 * wait queue and the talloc_free() of the request will
884 * remove the item from the wait queue.
886 subreq
= smbd_tevent_queue_wait_send(preq
, ev
, state
->wait_queue
);
887 if (tevent_req_nomem(subreq
, req
)) {
888 return tevent_req_post(req
, ev
);
893 * Now we add our own waiter to the end of the queue,
894 * this way we get notified when all pending requests are finished
895 * and send to the socket.
897 subreq
= smbd_tevent_queue_wait_send(state
, ev
, state
->wait_queue
);
898 if (tevent_req_nomem(subreq
, req
)) {
899 return tevent_req_post(req
, ev
);
901 tevent_req_set_callback(subreq
, smbd_smb2_logoff_wait_done
, req
);
906 static void smbd_smb2_logoff_wait_done(struct tevent_req
*subreq
)
908 struct tevent_req
*req
= tevent_req_callback_data(
909 subreq
, struct tevent_req
);
910 struct smbd_smb2_logout_state
*state
= tevent_req_data(
911 req
, struct smbd_smb2_logout_state
);
914 smbd_tevent_queue_wait_recv(subreq
);
918 * As we've been awoken, we may have changed
919 * uid in the meantime. Ensure we're still
920 * root (SMB2_OP_LOGOFF has .as_root = true).
922 change_to_root_user();
924 status
= smbXsrv_session_logoff(state
->smb2req
->session
);
925 if (tevent_req_nterror(req
, status
)) {
930 * we may need to sign the response, so we need to keep
931 * the session until the response is sent to the wire.
933 talloc_steal(state
->smb2req
, state
->smb2req
->session
);
935 tevent_req_done(req
);
938 static NTSTATUS
smbd_smb2_logoff_recv(struct tevent_req
*req
)
940 return tevent_req_simple_recv_ntstatus(req
);