Add two flags to allow for handling of Extended Signatures (Session Key Protection...
[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         if (in_flags & SMB2_SESSION_FLAG_BINDING) {
445                 if (smb2req->sconn->conn->protocol < PROTOCOL_SMB2_22) {
446                         tevent_req_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED);
447                         return tevent_req_post(req, ev);
448                 }
449
450                 /*
451                  * We do not support multi channel.
452                  */
453                 tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
454                 return tevent_req_post(req, ev);
455         }
456
457         talloc_set_destructor(state, smbd_smb2_session_setup_state_destructor);
458
459         if (state->in_session_id == 0) {
460                 /* create a new session */
461                 status = smbXsrv_session_create(state->smb2req->sconn->conn,
462                                                 now, &state->session);
463                 if (tevent_req_nterror(req, status)) {
464                         return tevent_req_post(req, ev);
465                 }
466         } else {
467                 status = smb2srv_session_lookup(state->smb2req->sconn->conn,
468                                                 state->in_session_id, now,
469                                                 &state->session);
470                 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
471                         status = NT_STATUS_OK;
472                 }
473                 if (NT_STATUS_IS_OK(status)) {
474                         state->session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
475                         status = NT_STATUS_MORE_PROCESSING_REQUIRED;
476                         TALLOC_FREE(state->session->gensec);
477                 }
478                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
479                         tevent_req_nterror(req, status);
480                         return tevent_req_post(req, ev);
481                 }
482         }
483
484         if (state->session->gensec == NULL) {
485                 status = auth_generic_prepare(state->session,
486                                               state->session->connection->remote_address,
487                                               &state->session->gensec);
488                 if (tevent_req_nterror(req, status)) {
489                         return tevent_req_post(req, ev);
490                 }
491
492                 gensec_want_feature(state->session->gensec, GENSEC_FEATURE_SESSION_KEY);
493                 gensec_want_feature(state->session->gensec, GENSEC_FEATURE_UNIX_TOKEN);
494
495                 status = gensec_start_mech_by_oid(state->session->gensec,
496                                                   GENSEC_OID_SPNEGO);
497                 if (tevent_req_nterror(req, status)) {
498                         return tevent_req_post(req, ev);
499                 }
500         }
501
502         become_root();
503         subreq = gensec_update_send(state, state->ev,
504                                     state->session->gensec,
505                                     state->in_security_buffer);
506         unbecome_root();
507         if (tevent_req_nomem(subreq, req)) {
508                 return tevent_req_post(req, ev);
509         }
510         tevent_req_set_callback(subreq, smbd_smb2_session_setup_gensec_done, req);
511
512         return req;
513 }
514
515 static void smbd_smb2_session_setup_gensec_done(struct tevent_req *subreq)
516 {
517         struct tevent_req *req =
518                 tevent_req_callback_data(subreq,
519                 struct tevent_req);
520         struct smbd_smb2_session_setup_state *state =
521                 tevent_req_data(req,
522                 struct smbd_smb2_session_setup_state);
523         NTSTATUS status;
524
525         become_root();
526         status = gensec_update_recv(subreq, state,
527                                     &state->out_security_buffer);
528         unbecome_root();
529         TALLOC_FREE(subreq);
530         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
531             !NT_STATUS_IS_OK(status)) {
532                 tevent_req_nterror(req, status);
533                 return;
534         }
535
536         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
537                 state->out_session_id = state->session->global->session_wire_id;
538                 /* we want to keep the session */
539                 state->session = NULL;
540                 tevent_req_nterror(req, status);
541                 return;
542         }
543
544         status = gensec_session_info(state->session->gensec,
545                                      state->session->global,
546                                      &state->session_info);
547         if (tevent_req_nterror(req, status)) {
548                 return;
549         }
550
551         if ((state->in_previous_session_id != 0) &&
552              (state->session->global->session_wire_id !=
553               state->in_previous_session_id))
554         {
555                 subreq = smb2srv_session_close_previous_send(state, state->ev,
556                                                 state->session->connection,
557                                                 state->session_info,
558                                                 state->in_previous_session_id,
559                                                 state->session->global->session_wire_id);
560                 if (tevent_req_nomem(subreq, req)) {
561                         return;
562                 }
563                 tevent_req_set_callback(subreq,
564                                         smbd_smb2_session_setup_previous_done,
565                                         req);
566                 return;
567         }
568
569         if (state->session->global->auth_session_info != NULL) {
570                 status = smbd_smb2_reauth_generic_return(state->session,
571                                                          state->smb2req,
572                                                          state->session_info,
573                                                          &state->out_session_flags,
574                                                          &state->out_session_id);
575                 if (tevent_req_nterror(req, status)) {
576                         return;
577                 }
578                 /* we want to keep the session */
579                 state->session = NULL;
580                 tevent_req_done(req);
581                 return;
582         }
583
584         status = smbd_smb2_auth_generic_return(state->session,
585                                                state->smb2req,
586                                                state->in_security_mode,
587                                                state->session_info,
588                                                &state->out_session_flags,
589                                                &state->out_session_id);
590         if (tevent_req_nterror(req, status)) {
591                 return;
592         }
593
594         /* we want to keep the session */
595         state->session = NULL;
596         tevent_req_done(req);
597         return;
598 }
599
600 static void smbd_smb2_session_setup_previous_done(struct tevent_req *subreq)
601 {
602         struct tevent_req *req =
603                 tevent_req_callback_data(subreq,
604                 struct tevent_req);
605         struct smbd_smb2_session_setup_state *state =
606                 tevent_req_data(req,
607                 struct smbd_smb2_session_setup_state);
608         NTSTATUS status;
609
610         status = smb2srv_session_close_previous_recv(subreq);
611         TALLOC_FREE(subreq);
612         if (tevent_req_nterror(req, status)) {
613                 return;
614         }
615
616         if (state->session->global->auth_session_info != NULL) {
617                 status = smbd_smb2_reauth_generic_return(state->session,
618                                                          state->smb2req,
619                                                          state->session_info,
620                                                          &state->out_session_flags,
621                                                          &state->out_session_id);
622                 if (tevent_req_nterror(req, status)) {
623                         return;
624                 }
625                 /* we want to keep the session */
626                 state->session = NULL;
627                 tevent_req_done(req);
628                 return;
629         }
630
631         status = smbd_smb2_auth_generic_return(state->session,
632                                                state->smb2req,
633                                                state->in_security_mode,
634                                                state->session_info,
635                                                &state->out_session_flags,
636                                                &state->out_session_id);
637         if (tevent_req_nterror(req, status)) {
638                 return;
639         }
640
641         /* we want to keep the session */
642         state->session = NULL;
643         tevent_req_done(req);
644         return;
645 }
646
647 static NTSTATUS smbd_smb2_session_setup_recv(struct tevent_req *req,
648                                         uint16_t *out_session_flags,
649                                         TALLOC_CTX *mem_ctx,
650                                         DATA_BLOB *out_security_buffer,
651                                         uint64_t *out_session_id)
652 {
653         struct smbd_smb2_session_setup_state *state =
654                 tevent_req_data(req,
655                 struct smbd_smb2_session_setup_state);
656         NTSTATUS status;
657
658         if (tevent_req_is_nterror(req, &status)) {
659                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
660                         tevent_req_received(req);
661                         return nt_status_squash(status);
662                 }
663         } else {
664                 status = NT_STATUS_OK;
665         }
666
667         *out_session_flags = state->out_session_flags;
668         *out_security_buffer = state->out_security_buffer;
669         *out_session_id = state->out_session_id;
670
671         talloc_steal(mem_ctx, out_security_buffer->data);
672         tevent_req_received(req);
673         return status;
674 }
675
676 NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req)
677 {
678         NTSTATUS status;
679         DATA_BLOB outbody;
680
681         status = smbd_smb2_request_verify_sizes(req, 0x04);
682         if (!NT_STATUS_IS_OK(status)) {
683                 return smbd_smb2_request_error(req, status);
684         }
685
686         /*
687          * TODO: cancel all outstanding requests on the session
688          */
689         status = smbXsrv_session_logoff(req->session);
690         if (!NT_STATUS_IS_OK(status)) {
691                 DEBUG(0, ("smbd_smb2_request_process_logoff: "
692                           "smbXsrv_session_logoff() failed: %s\n",
693                           nt_errstr(status)));
694                 /*
695                  * If we hit this case, there is something completely
696                  * wrong, so we better disconnect the transport connection.
697                  */
698                 return status;
699         }
700
701         /*
702          * we may need to sign the response, so we need to keep
703          * the session until the response is sent to the wire.
704          */
705         talloc_steal(req, req->session);
706
707         outbody = data_blob_talloc(req->out.vector, NULL, 0x04);
708         if (outbody.data == NULL) {
709                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
710         }
711
712         SSVAL(outbody.data, 0x00, 0x04);        /* struct size */
713         SSVAL(outbody.data, 0x02, 0);           /* reserved */
714
715         return smbd_smb2_request_done(req, outbody, NULL);
716 }