s3:smb2_sesssetup: make use of smb2srv_session_close_previous_send/recv
[samba.git] / source3 / smbd / smb2_sesssetup.c
1 /*
2    Unix SMB/CIFS implementation.
3    Core SMB2 server
4
5    Copyright (C) Stefan Metzmacher 2009
6    Copyright (C) Jeremy Allison 2010
7
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.
12
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.
17
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/>.
20 */
21
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"
31
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);
45
46 static void smbd_smb2_request_sesssetup_done(struct tevent_req *subreq);
47
48 NTSTATUS smbd_smb2_request_process_sesssetup(struct smbd_smb2_request *smb2req)
49 {
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;
62
63         status = smbd_smb2_request_verify_sizes(smb2req, 0x19);
64         if (!NT_STATUS_IS_OK(status)) {
65                 return smbd_smb2_request_error(smb2req, status);
66         }
67         inhdr = (const uint8_t *)smb2req->in.vector[i+0].iov_base;
68         inbody = (const uint8_t *)smb2req->in.vector[i+1].iov_base;
69
70         in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
71
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);
79
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);
82         }
83
84         if (in_security_length > smb2req->in.vector[i+2].iov_len) {
85                 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
86         }
87
88         in_security_buffer.data = (uint8_t *)smb2req->in.vector[i+2].iov_base;
89         in_security_buffer.length = in_security_length;
90
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);
101         }
102         tevent_req_set_callback(subreq, smbd_smb2_request_sesssetup_done, smb2req);
103
104         return smbd_smb2_request_pending_queue(smb2req, subreq, 500);
105 }
106
107 static void smbd_smb2_request_sesssetup_done(struct tevent_req *subreq)
108 {
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 */
122
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;
137                 }
138                 return;
139         }
140
141         out_security_offset = SMB2_HDR_BODY + 0x08;
142
143         outhdr = (uint8_t *)smb2req->out.vector[i].iov_base;
144
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;
152                 }
153                 return;
154         }
155
156         SBVAL(outhdr, SMB2_HDR_SESSION_ID, out_session_id);
157
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 */
165
166         outdyn = out_security_buffer;
167
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;
174         }
175 }
176
177 static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
178                                         struct smbd_smb2_request *smb2req,
179                                         uint8_t in_security_mode,
180                                         struct auth_session_info *session_info,
181                                         uint16_t *out_session_flags,
182                                         uint64_t *out_session_id)
183 {
184         NTSTATUS status;
185         bool guest = false;
186         uint8_t session_key[16];
187         struct smbXsrv_session *x = session;
188         struct smbXsrv_connection *conn = session->connection;
189
190         if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
191             lp_server_signing() == SMB_SIGNING_REQUIRED) {
192                 x->global->signing_required = true;
193         }
194
195         if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
196                 /* we map anonymous to guest internally */
197                 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
198                 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
199                 /* force no signing */
200                 x->global->signing_required = false;
201                 guest = true;
202         }
203
204         ZERO_STRUCT(session_key);
205         memcpy(session_key, session_info->session_key.data,
206                MIN(session_info->session_key.length, sizeof(session_key)));
207
208         x->global->signing_key = data_blob_talloc(x->global,
209                                                   session_key,
210                                                   sizeof(session_key));
211         if (x->global->signing_key.data == NULL) {
212                 ZERO_STRUCT(session_key);
213                 TALLOC_FREE(session);
214                 return NT_STATUS_NO_MEMORY;
215         }
216
217         if (conn->protocol >= PROTOCOL_SMB2_24) {
218                 const DATA_BLOB label = data_blob_string_const_null("SMB2AESCMAC");
219                 const DATA_BLOB context = data_blob_string_const_null("SmbSign");
220
221                 smb2_key_derivation(session_key, sizeof(session_key),
222                                     label.data, label.length,
223                                     context.data, context.length,
224                                     x->global->signing_key.data);
225         }
226
227         x->global->application_key = data_blob_dup_talloc(x->global,
228                                                 x->global->signing_key);
229         if (x->global->application_key.data == NULL) {
230                 ZERO_STRUCT(session_key);
231                 TALLOC_FREE(session);
232                 return NT_STATUS_NO_MEMORY;
233         }
234
235         if (conn->protocol >= PROTOCOL_SMB2_24) {
236                 const DATA_BLOB label = data_blob_string_const_null("SMB2APP");
237                 const DATA_BLOB context = data_blob_string_const_null("SmbRpc");
238
239                 smb2_key_derivation(session_key, sizeof(session_key),
240                                     label.data, label.length,
241                                     context.data, context.length,
242                                     x->global->application_key.data);
243         }
244         ZERO_STRUCT(session_key);
245
246         x->global->channels[0].signing_key = data_blob_dup_talloc(x->global->channels,
247                                                 x->global->signing_key);
248         if (x->global->channels[0].signing_key.data == NULL) {
249                 TALLOC_FREE(session);
250                 return NT_STATUS_NO_MEMORY;
251         }
252
253         data_blob_clear_free(&session_info->session_key);
254         session_info->session_key = data_blob_dup_talloc(session_info,
255                                                 x->global->application_key);
256         if (session_info->session_key.data == NULL) {
257                 TALLOC_FREE(session);
258                 return NT_STATUS_NO_MEMORY;
259         }
260
261         session->compat = talloc_zero(session, struct user_struct);
262         if (session->compat == NULL) {
263                 TALLOC_FREE(session);
264                 return NT_STATUS_NO_MEMORY;
265         }
266         session->compat->session = session;
267         session->compat->homes_snum = -1;
268         session->compat->session_info = session_info;
269         session->compat->session_keystr = NULL;
270         session->compat->vuid = session->global->session_wire_id;
271         DLIST_ADD(smb2req->sconn->users, session->compat);
272         smb2req->sconn->num_users++;
273
274         if (security_session_user_level(session_info, NULL) >= SECURITY_USER) {
275                 session->compat->homes_snum =
276                         register_homes_share(session_info->unix_info->unix_name);
277         }
278
279         if (!session_claim(smb2req->sconn, session->compat)) {
280                 DEBUG(1, ("smb2: Failed to claim session "
281                         "for vuid=%llu\n",
282                         (unsigned long long)session->compat->vuid));
283                 TALLOC_FREE(session);
284                 return NT_STATUS_LOGON_FAILURE;
285         }
286
287         set_current_user_info(session_info->unix_info->sanitized_username,
288                               session_info->unix_info->unix_name,
289                               session_info->info->domain_name);
290
291         reload_services(smb2req->sconn, conn_snum_used, true);
292
293         session->status = NT_STATUS_OK;
294         session->global->auth_session_info = session_info;
295         session->global->auth_session_info_seqnum += 1;
296         session->global->channels[0].auth_session_info_seqnum =
297                 session->global->auth_session_info_seqnum;
298         session->global->expiration_time = gensec_expire_time(session->gensec);
299
300         status = smbXsrv_session_update(session);
301         if (!NT_STATUS_IS_OK(status)) {
302                 DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n",
303                           (unsigned long long)session->compat->vuid,
304                           nt_errstr(status)));
305                 TALLOC_FREE(session);
306                 return NT_STATUS_LOGON_FAILURE;
307         }
308
309         /*
310          * we attach the session to the request
311          * so that the response can be signed
312          */
313         smb2req->session = session;
314         if (!guest) {
315                 smb2req->do_signing = true;
316         }
317
318         global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
319
320         *out_session_id = session->global->session_wire_id;
321
322         return NT_STATUS_OK;
323 }
324
325 static NTSTATUS smbd_smb2_reauth_generic_return(struct smbXsrv_session *session,
326                                         struct smbd_smb2_request *smb2req,
327                                         struct auth_session_info *session_info,
328                                         uint16_t *out_session_flags,
329                                         uint64_t *out_session_id)
330 {
331         NTSTATUS status;
332         struct smbXsrv_session *x = session;
333         struct smbXsrv_connection *conn = session->connection;
334
335         data_blob_clear_free(&session_info->session_key);
336         session_info->session_key = data_blob_dup_talloc(session_info,
337                                                 x->global->application_key);
338         if (session_info->session_key.data == NULL) {
339                 TALLOC_FREE(session);
340                 return NT_STATUS_NO_MEMORY;
341         }
342
343         session->compat->session_info = session_info;
344         session->compat->vuid = session->global->session_wire_id;
345
346         session->compat->homes_snum =
347                         register_homes_share(session_info->unix_info->unix_name);
348
349         set_current_user_info(session_info->unix_info->sanitized_username,
350                               session_info->unix_info->unix_name,
351                               session_info->info->domain_name);
352
353         reload_services(smb2req->sconn, conn_snum_used, true);
354
355         session->status = NT_STATUS_OK;
356         TALLOC_FREE(session->global->auth_session_info);
357         session->global->auth_session_info = session_info;
358         session->global->auth_session_info_seqnum += 1;
359         session->global->channels[0].auth_session_info_seqnum =
360                 session->global->auth_session_info_seqnum;
361         session->global->expiration_time = gensec_expire_time(session->gensec);
362
363         status = smbXsrv_session_update(session);
364         if (!NT_STATUS_IS_OK(status)) {
365                 DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n",
366                           (unsigned long long)session->compat->vuid,
367                           nt_errstr(status)));
368                 TALLOC_FREE(session);
369                 return NT_STATUS_LOGON_FAILURE;
370         }
371
372         conn_clear_vuid_caches(conn->sconn, session->compat->vuid);
373
374         /*
375          * we attach the session to the request
376          * so that the response can be signed
377          */
378         smb2req->session = session;
379         smb2req->do_signing = true;
380
381         global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
382
383         *out_session_id = session->global->session_wire_id;
384
385         return NT_STATUS_OK;
386 }
387
388 struct smbd_smb2_session_setup_state {
389         struct tevent_context *ev;
390         struct smbd_smb2_request *smb2req;
391         uint64_t in_session_id;
392         uint8_t in_flags;
393         uint8_t in_security_mode;
394         uint64_t in_previous_session_id;
395         DATA_BLOB in_security_buffer;
396         struct smbXsrv_session *session;
397         struct auth_session_info *session_info;
398         uint16_t out_session_flags;
399         DATA_BLOB out_security_buffer;
400         uint64_t out_session_id;
401 };
402
403 static int smbd_smb2_session_setup_state_destructor(struct smbd_smb2_session_setup_state *state)
404 {
405         /*
406          * if state->session is not NULL,
407          * we remove the session on failure
408          */
409         TALLOC_FREE(state->session);
410         return 0;
411 }
412
413 static void smbd_smb2_session_setup_gensec_done(struct tevent_req *subreq);
414 static void smbd_smb2_session_setup_previous_done(struct tevent_req *subreq);
415
416 static struct tevent_req *smbd_smb2_session_setup_send(TALLOC_CTX *mem_ctx,
417                                         struct tevent_context *ev,
418                                         struct smbd_smb2_request *smb2req,
419                                         uint64_t in_session_id,
420                                         uint8_t in_flags,
421                                         uint8_t in_security_mode,
422                                         uint64_t in_previous_session_id,
423                                         DATA_BLOB in_security_buffer)
424 {
425         struct tevent_req *req;
426         struct smbd_smb2_session_setup_state *state;
427         NTSTATUS status;
428         NTTIME now = timeval_to_nttime(&smb2req->request_time);
429         struct tevent_req *subreq;
430
431         req = tevent_req_create(mem_ctx, &state,
432                                 struct smbd_smb2_session_setup_state);
433         if (req == NULL) {
434                 return NULL;
435         }
436         state->ev = ev;
437         state->smb2req = smb2req;
438         state->in_session_id = in_session_id;
439         state->in_flags = in_flags;
440         state->in_security_mode = in_security_mode;
441         state->in_previous_session_id = in_previous_session_id;
442         state->in_security_buffer = in_security_buffer;
443
444         talloc_set_destructor(state, smbd_smb2_session_setup_state_destructor);
445
446         if (state->in_session_id == 0) {
447                 /* create a new session */
448                 status = smbXsrv_session_create(state->smb2req->sconn->conn,
449                                                 now, &state->session);
450                 if (tevent_req_nterror(req, status)) {
451                         return tevent_req_post(req, ev);
452                 }
453         } else {
454                 status = smb2srv_session_lookup(state->smb2req->sconn->conn,
455                                                 state->in_session_id, now,
456                                                 &state->session);
457                 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
458                         status = NT_STATUS_OK;
459                 }
460                 if (NT_STATUS_IS_OK(status)) {
461                         state->session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
462                         status = NT_STATUS_MORE_PROCESSING_REQUIRED;
463                         TALLOC_FREE(state->session->gensec);
464                 }
465                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
466                         tevent_req_nterror(req, status);
467                         return tevent_req_post(req, ev);
468                 }
469         }
470
471         if (state->session->gensec == NULL) {
472                 status = auth_generic_prepare(state->session,
473                                               state->session->connection->remote_address,
474                                               &state->session->gensec);
475                 if (tevent_req_nterror(req, status)) {
476                         return tevent_req_post(req, ev);
477                 }
478
479                 gensec_want_feature(state->session->gensec, GENSEC_FEATURE_SESSION_KEY);
480                 gensec_want_feature(state->session->gensec, GENSEC_FEATURE_UNIX_TOKEN);
481
482                 status = gensec_start_mech_by_oid(state->session->gensec,
483                                                   GENSEC_OID_SPNEGO);
484                 if (tevent_req_nterror(req, status)) {
485                         return tevent_req_post(req, ev);
486                 }
487         }
488
489         become_root();
490         subreq = gensec_update_send(state, state->ev,
491                                     state->session->gensec,
492                                     state->in_security_buffer);
493         unbecome_root();
494         if (tevent_req_nomem(subreq, req)) {
495                 return tevent_req_post(req, ev);
496         }
497         tevent_req_set_callback(subreq, smbd_smb2_session_setup_gensec_done, req);
498
499         return req;
500 }
501
502 static void smbd_smb2_session_setup_gensec_done(struct tevent_req *subreq)
503 {
504         struct tevent_req *req =
505                 tevent_req_callback_data(subreq,
506                 struct tevent_req);
507         struct smbd_smb2_session_setup_state *state =
508                 tevent_req_data(req,
509                 struct smbd_smb2_session_setup_state);
510         NTSTATUS status;
511
512         become_root();
513         status = gensec_update_recv(subreq, state,
514                                     &state->out_security_buffer);
515         unbecome_root();
516         TALLOC_FREE(subreq);
517         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
518             !NT_STATUS_IS_OK(status)) {
519                 tevent_req_nterror(req, status);
520                 return;
521         }
522
523         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
524                 state->out_session_id = state->session->global->session_wire_id;
525                 /* we want to keep the session */
526                 state->session = NULL;
527                 tevent_req_nterror(req, status);
528                 return;
529         }
530
531         status = gensec_session_info(state->session->gensec,
532                                      state->session->global,
533                                      &state->session_info);
534         if (tevent_req_nterror(req, status)) {
535                 return;
536         }
537
538         if ((state->in_previous_session_id != 0) &&
539              (state->session->global->session_wire_id !=
540               state->in_previous_session_id))
541         {
542                 subreq = smb2srv_session_close_previous_send(state, state->ev,
543                                                 state->session->connection,
544                                                 state->session_info,
545                                                 state->in_previous_session_id,
546                                                 state->session->global->session_wire_id);
547                 if (tevent_req_nomem(subreq, req)) {
548                         return;
549                 }
550                 tevent_req_set_callback(subreq,
551                                         smbd_smb2_session_setup_previous_done,
552                                         req);
553                 return;
554         }
555
556         if (state->session->global->auth_session_info != NULL) {
557                 status = smbd_smb2_reauth_generic_return(state->session,
558                                                          state->smb2req,
559                                                          state->session_info,
560                                                          &state->out_session_flags,
561                                                          &state->out_session_id);
562                 if (tevent_req_nterror(req, status)) {
563                         return;
564                 }
565                 /* we want to keep the session */
566                 state->session = NULL;
567                 tevent_req_done(req);
568                 return;
569         }
570
571         status = smbd_smb2_auth_generic_return(state->session,
572                                                state->smb2req,
573                                                state->in_security_mode,
574                                                state->session_info,
575                                                &state->out_session_flags,
576                                                &state->out_session_id);
577         if (tevent_req_nterror(req, status)) {
578                 return;
579         }
580
581         /* we want to keep the session */
582         state->session = NULL;
583         tevent_req_done(req);
584         return;
585 }
586
587 static void smbd_smb2_session_setup_previous_done(struct tevent_req *subreq)
588 {
589         struct tevent_req *req =
590                 tevent_req_callback_data(subreq,
591                 struct tevent_req);
592         struct smbd_smb2_session_setup_state *state =
593                 tevent_req_data(req,
594                 struct smbd_smb2_session_setup_state);
595         NTSTATUS status;
596
597         status = smb2srv_session_close_previous_recv(subreq);
598         TALLOC_FREE(subreq);
599         if (tevent_req_nterror(req, status)) {
600                 return;
601         }
602
603         if (state->session->global->auth_session_info != NULL) {
604                 status = smbd_smb2_reauth_generic_return(state->session,
605                                                          state->smb2req,
606                                                          state->session_info,
607                                                          &state->out_session_flags,
608                                                          &state->out_session_id);
609                 if (tevent_req_nterror(req, status)) {
610                         return;
611                 }
612                 /* we want to keep the session */
613                 state->session = NULL;
614                 tevent_req_done(req);
615                 return;
616         }
617
618         status = smbd_smb2_auth_generic_return(state->session,
619                                                state->smb2req,
620                                                state->in_security_mode,
621                                                state->session_info,
622                                                &state->out_session_flags,
623                                                &state->out_session_id);
624         if (tevent_req_nterror(req, status)) {
625                 return;
626         }
627
628         /* we want to keep the session */
629         state->session = NULL;
630         tevent_req_done(req);
631         return;
632 }
633
634 static NTSTATUS smbd_smb2_session_setup_recv(struct tevent_req *req,
635                                         uint16_t *out_session_flags,
636                                         TALLOC_CTX *mem_ctx,
637                                         DATA_BLOB *out_security_buffer,
638                                         uint64_t *out_session_id)
639 {
640         struct smbd_smb2_session_setup_state *state =
641                 tevent_req_data(req,
642                 struct smbd_smb2_session_setup_state);
643         NTSTATUS status;
644
645         if (tevent_req_is_nterror(req, &status)) {
646                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
647                         tevent_req_received(req);
648                         return nt_status_squash(status);
649                 }
650         } else {
651                 status = NT_STATUS_OK;
652         }
653
654         *out_session_flags = state->out_session_flags;
655         *out_security_buffer = state->out_security_buffer;
656         *out_session_id = state->out_session_id;
657
658         talloc_steal(mem_ctx, out_security_buffer->data);
659         tevent_req_received(req);
660         return status;
661 }
662
663 NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req)
664 {
665         NTSTATUS status;
666         DATA_BLOB outbody;
667
668         status = smbd_smb2_request_verify_sizes(req, 0x04);
669         if (!NT_STATUS_IS_OK(status)) {
670                 return smbd_smb2_request_error(req, status);
671         }
672
673         /*
674          * TODO: cancel all outstanding requests on the session
675          */
676         status = smbXsrv_session_logoff(req->session);
677         if (!NT_STATUS_IS_OK(status)) {
678                 DEBUG(0, ("smbd_smb2_request_process_logoff: "
679                           "smbXsrv_session_logoff() failed: %s\n",
680                           nt_errstr(status)));
681                 /*
682                  * If we hit this case, there is something completely
683                  * wrong, so we better disconnect the transport connection.
684                  */
685                 return status;
686         }
687
688         /*
689          * we may need to sign the response, so we need to keep
690          * the session until the response is sent to the wire.
691          */
692         talloc_steal(req, req->session);
693
694         outbody = data_blob_talloc(req->out.vector, NULL, 0x04);
695         if (outbody.data == NULL) {
696                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
697         }
698
699         SSVAL(outbody.data, 0x00, 0x04);        /* struct size */
700         SSVAL(outbody.data, 0x02, 0);           /* reserved */
701
702         return smbd_smb2_request_done(req, outbody, NULL);
703 }