pyldb: avoid segfault when adding an element with no name
[nivanova/samba-autobuild/.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 #include "lib/crypto/sha512.h"
32 #include "lib/crypto/aes.h"
33 #include "lib/crypto/aes_ccm_128.h"
34 #include "lib/crypto/aes_gcm_128.h"
35
36 #undef DBGC_CLASS
37 #define DBGC_CLASS DBGC_SMB2
38
39 static struct tevent_req *smbd_smb2_session_setup_wrap_send(TALLOC_CTX *mem_ctx,
40                                         struct tevent_context *ev,
41                                         struct smbd_smb2_request *smb2req,
42                                         uint64_t in_session_id,
43                                         uint8_t in_flags,
44                                         uint8_t in_security_mode,
45                                         uint64_t in_previous_session_id,
46                                         DATA_BLOB in_security_buffer);
47 static NTSTATUS smbd_smb2_session_setup_wrap_recv(struct tevent_req *req,
48                                         uint16_t *out_session_flags,
49                                         TALLOC_CTX *mem_ctx,
50                                         DATA_BLOB *out_security_buffer,
51                                         uint64_t *out_session_id);
52
53 static void smbd_smb2_request_sesssetup_done(struct tevent_req *subreq);
54
55 NTSTATUS smbd_smb2_request_process_sesssetup(struct smbd_smb2_request *smb2req)
56 {
57         const uint8_t *inhdr;
58         const uint8_t *inbody;
59         uint64_t in_session_id;
60         uint8_t in_flags;
61         uint8_t in_security_mode;
62         uint64_t in_previous_session_id;
63         uint16_t in_security_offset;
64         uint16_t in_security_length;
65         DATA_BLOB in_security_buffer;
66         NTSTATUS status;
67         struct tevent_req *subreq;
68
69         status = smbd_smb2_request_verify_sizes(smb2req, 0x19);
70         if (!NT_STATUS_IS_OK(status)) {
71                 return smbd_smb2_request_error(smb2req, status);
72         }
73         inhdr = SMBD_SMB2_IN_HDR_PTR(smb2req);
74         inbody = SMBD_SMB2_IN_BODY_PTR(smb2req);
75
76         in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
77
78         in_flags = CVAL(inbody, 0x02);
79         in_security_mode = CVAL(inbody, 0x03);
80         /* Capabilities = IVAL(inbody, 0x04) */
81         /* Channel = IVAL(inbody, 0x08) */
82         in_security_offset = SVAL(inbody, 0x0C);
83         in_security_length = SVAL(inbody, 0x0E);
84         in_previous_session_id = BVAL(inbody, 0x10);
85
86         if (in_security_offset != (SMB2_HDR_BODY + SMBD_SMB2_IN_BODY_LEN(smb2req))) {
87                 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
88         }
89
90         if (in_security_length > SMBD_SMB2_IN_DYN_LEN(smb2req)) {
91                 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
92         }
93
94         in_security_buffer.data = SMBD_SMB2_IN_DYN_PTR(smb2req);
95         in_security_buffer.length = in_security_length;
96
97         subreq = smbd_smb2_session_setup_wrap_send(smb2req,
98                                                    smb2req->sconn->ev_ctx,
99                                                    smb2req,
100                                                    in_session_id,
101                                                    in_flags,
102                                                    in_security_mode,
103                                                    in_previous_session_id,
104                                                    in_security_buffer);
105         if (subreq == NULL) {
106                 return smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
107         }
108         tevent_req_set_callback(subreq, smbd_smb2_request_sesssetup_done, smb2req);
109
110         /*
111          * Avoid sending a STATUS_PENDING message, which
112          * matches a Windows Server and avoids problems with
113          * MacOS clients.
114          *
115          * Even after 90 seconds a Windows Server doesn't return
116          * STATUS_PENDING if using NTLMSSP against a non reachable
117          * trusted domain.
118          */
119         return smbd_smb2_request_pending_queue(smb2req, subreq, 0);
120 }
121
122 static void smbd_smb2_request_sesssetup_done(struct tevent_req *subreq)
123 {
124         struct smbd_smb2_request *smb2req =
125                 tevent_req_callback_data(subreq,
126                 struct smbd_smb2_request);
127         uint8_t *outhdr;
128         DATA_BLOB outbody;
129         DATA_BLOB outdyn;
130         uint16_t out_session_flags = 0;
131         uint64_t out_session_id = 0;
132         uint16_t out_security_offset;
133         DATA_BLOB out_security_buffer = data_blob_null;
134         NTSTATUS status;
135         NTSTATUS error; /* transport error */
136
137         status = smbd_smb2_session_setup_wrap_recv(subreq,
138                                                    &out_session_flags,
139                                                    smb2req,
140                                                    &out_security_buffer,
141                                                    &out_session_id);
142         TALLOC_FREE(subreq);
143         if (!NT_STATUS_IS_OK(status) &&
144             !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
145                 status = nt_status_squash(status);
146                 error = smbd_smb2_request_error(smb2req, status);
147                 if (!NT_STATUS_IS_OK(error)) {
148                         smbd_server_connection_terminate(smb2req->xconn,
149                                                          nt_errstr(error));
150                         return;
151                 }
152                 return;
153         }
154
155         out_security_offset = SMB2_HDR_BODY + 0x08;
156
157         outhdr = SMBD_SMB2_OUT_HDR_PTR(smb2req);
158
159         outbody = smbd_smb2_generate_outbody(smb2req, 0x08);
160         if (outbody.data == NULL) {
161                 error = smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
162                 if (!NT_STATUS_IS_OK(error)) {
163                         smbd_server_connection_terminate(smb2req->xconn,
164                                                          nt_errstr(error));
165                         return;
166                 }
167                 return;
168         }
169
170         SBVAL(outhdr, SMB2_HDR_SESSION_ID, out_session_id);
171
172         SSVAL(outbody.data, 0x00, 0x08 + 1);    /* struct size */
173         SSVAL(outbody.data, 0x02,
174               out_session_flags);               /* session flags */
175         SSVAL(outbody.data, 0x04,
176               out_security_offset);             /* security buffer offset */
177         SSVAL(outbody.data, 0x06,
178               out_security_buffer.length);      /* security buffer length */
179
180         outdyn = out_security_buffer;
181
182         error = smbd_smb2_request_done_ex(smb2req, status, outbody, &outdyn,
183                                            __location__);
184         if (!NT_STATUS_IS_OK(error)) {
185                 smbd_server_connection_terminate(smb2req->xconn,
186                                                  nt_errstr(error));
187                 return;
188         }
189 }
190
191 static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
192                                         struct smbXsrv_session_auth0 **_auth,
193                                         struct smbd_smb2_request *smb2req,
194                                         uint8_t in_security_mode,
195                                         struct auth_session_info *session_info,
196                                         uint16_t *out_session_flags,
197                                         uint64_t *out_session_id)
198 {
199         NTSTATUS status;
200         bool guest = false;
201         uint8_t session_key[16];
202         struct smbXsrv_session *x = session;
203         struct smbXsrv_session_auth0 *auth = *_auth;
204         struct smbXsrv_connection *xconn = smb2req->xconn;
205         size_t i;
206         struct _derivation {
207                 DATA_BLOB label;
208                 DATA_BLOB context;
209         };
210         struct {
211                 struct _derivation signing;
212                 struct _derivation encryption;
213                 struct _derivation decryption;
214                 struct _derivation application;
215         } derivation = { };
216
217         *_auth = NULL;
218
219         if (xconn->protocol >= PROTOCOL_SMB3_10) {
220                 struct smbXsrv_preauth *preauth;
221                 struct _derivation *d;
222                 DATA_BLOB p;
223                 struct hc_sha512state sctx;
224
225                 preauth = talloc_move(smb2req, &auth->preauth);
226
227                 samba_SHA512_Init(&sctx);
228                 samba_SHA512_Update(&sctx, preauth->sha512_value,
229                                     sizeof(preauth->sha512_value));
230                 for (i = 1; i < smb2req->in.vector_count; i++) {
231                         samba_SHA512_Update(&sctx,
232                                             smb2req->in.vector[i].iov_base,
233                                             smb2req->in.vector[i].iov_len);
234                 }
235                 samba_SHA512_Final(preauth->sha512_value, &sctx);
236
237                 p = data_blob_const(preauth->sha512_value,
238                                     sizeof(preauth->sha512_value));
239
240                 d = &derivation.signing;
241                 d->label = data_blob_string_const_null("SMBSigningKey");
242                 d->context = p;
243
244                 d = &derivation.decryption;
245                 d->label = data_blob_string_const_null("SMBC2SCipherKey");
246                 d->context = p;
247
248                 d = &derivation.encryption;
249                 d->label = data_blob_string_const_null("SMBS2CCipherKey");
250                 d->context = p;
251
252                 d = &derivation.application;
253                 d->label = data_blob_string_const_null("SMBAppKey");
254                 d->context = p;
255
256         } else if (xconn->protocol >= PROTOCOL_SMB2_24) {
257                 struct _derivation *d;
258
259                 d = &derivation.signing;
260                 d->label = data_blob_string_const_null("SMB2AESCMAC");
261                 d->context = data_blob_string_const_null("SmbSign");
262
263                 d = &derivation.decryption;
264                 d->label = data_blob_string_const_null("SMB2AESCCM");
265                 d->context = data_blob_string_const_null("ServerIn ");
266
267                 d = &derivation.encryption;
268                 d->label = data_blob_string_const_null("SMB2AESCCM");
269                 d->context = data_blob_string_const_null("ServerOut");
270
271                 d = &derivation.application;
272                 d->label = data_blob_string_const_null("SMB2APP");
273                 d->context = data_blob_string_const_null("SmbRpc");
274         }
275
276         if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
277             (xconn->smb2.server.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED))
278         {
279                 x->global->signing_flags = SMBXSRV_SIGNING_REQUIRED;
280         }
281
282         if ((lp_smb_encrypt(-1) >= SMB_SIGNING_DESIRED) &&
283             (xconn->smb2.client.capabilities & SMB2_CAP_ENCRYPTION)) {
284                 x->global->encryption_flags = SMBXSRV_ENCRYPTION_DESIRED;
285         }
286
287         if (lp_smb_encrypt(-1) == SMB_SIGNING_REQUIRED) {
288                 x->global->encryption_flags = SMBXSRV_ENCRYPTION_REQUIRED |
289                         SMBXSRV_ENCRYPTION_DESIRED;
290         }
291
292         if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
293                 if (security_session_user_level(session_info, NULL) == SECURITY_GUEST) {
294                         *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
295                 }
296                 /* force no signing */
297                 x->global->signing_flags &= ~SMBXSRV_SIGNING_REQUIRED;
298                 /* we map anonymous to guest internally */
299                 guest = true;
300         }
301
302         if (guest && (x->global->encryption_flags & SMBXSRV_ENCRYPTION_REQUIRED)) {
303                 DEBUG(1,("reject guest session as encryption is required\n"));
304                 return NT_STATUS_ACCESS_DENIED;
305         }
306
307         if (xconn->smb2.server.cipher == 0) {
308                 if (x->global->encryption_flags & SMBXSRV_ENCRYPTION_REQUIRED) {
309                         DEBUG(1,("reject session with dialect[0x%04X] "
310                                  "as encryption is required\n",
311                                  xconn->smb2.server.dialect));
312                         return NT_STATUS_ACCESS_DENIED;
313                 }
314         } else {
315                 x->global->channels[0].encryption_cipher = xconn->smb2.server.cipher;
316         }
317
318         if (x->global->encryption_flags & SMBXSRV_ENCRYPTION_DESIRED) {
319                 *out_session_flags |= SMB2_SESSION_FLAG_ENCRYPT_DATA;
320         }
321
322         ZERO_STRUCT(session_key);
323         memcpy(session_key, session_info->session_key.data,
324                MIN(session_info->session_key.length, sizeof(session_key)));
325
326         x->global->signing_key = data_blob_talloc(x->global,
327                                                   session_key,
328                                                   sizeof(session_key));
329         if (x->global->signing_key.data == NULL) {
330                 ZERO_STRUCT(session_key);
331                 return NT_STATUS_NO_MEMORY;
332         }
333
334         if (xconn->protocol >= PROTOCOL_SMB2_24) {
335                 struct _derivation *d = &derivation.signing;
336
337                 smb2_key_derivation(session_key, sizeof(session_key),
338                                     d->label.data, d->label.length,
339                                     d->context.data, d->context.length,
340                                     x->global->signing_key.data);
341         }
342
343         if (xconn->protocol >= PROTOCOL_SMB2_24) {
344                 struct _derivation *d = &derivation.decryption;
345
346                 x->global->decryption_key = data_blob_talloc(x->global,
347                                                              session_key,
348                                                              sizeof(session_key));
349                 if (x->global->decryption_key.data == NULL) {
350                         ZERO_STRUCT(session_key);
351                         return NT_STATUS_NO_MEMORY;
352                 }
353
354                 smb2_key_derivation(session_key, sizeof(session_key),
355                                     d->label.data, d->label.length,
356                                     d->context.data, d->context.length,
357                                     x->global->decryption_key.data);
358         }
359
360         if (xconn->protocol >= PROTOCOL_SMB2_24) {
361                 struct _derivation *d = &derivation.encryption;
362                 size_t nonce_size;
363
364                 x->global->encryption_key = data_blob_talloc(x->global,
365                                                              session_key,
366                                                              sizeof(session_key));
367                 if (x->global->encryption_key.data == NULL) {
368                         ZERO_STRUCT(session_key);
369                         return NT_STATUS_NO_MEMORY;
370                 }
371
372                 smb2_key_derivation(session_key, sizeof(session_key),
373                                     d->label.data, d->label.length,
374                                     d->context.data, d->context.length,
375                                     x->global->encryption_key.data);
376
377                 /*
378                  * CCM and GCM algorithms must never have their
379                  * nonce wrap, or the security of the whole
380                  * communication and the keys is destroyed.
381                  * We must drop the connection once we have
382                  * transfered too much data.
383                  *
384                  * NOTE: We assume nonces greater than 8 bytes.
385                  */
386                 generate_random_buffer((uint8_t *)&x->nonce_high_random,
387                                        sizeof(x->nonce_high_random));
388                 switch (xconn->smb2.server.cipher) {
389                 case SMB2_ENCRYPTION_AES128_CCM:
390                         nonce_size = AES_CCM_128_NONCE_SIZE;
391                         break;
392                 case SMB2_ENCRYPTION_AES128_GCM:
393                         nonce_size = AES_GCM_128_IV_SIZE;
394                         break;
395                 default:
396                         nonce_size = 0;
397                         break;
398                 }
399                 x->nonce_high_max = SMB2_NONCE_HIGH_MAX(nonce_size);
400                 x->nonce_high = 0;
401                 x->nonce_low = 0;
402         }
403
404         x->global->application_key = data_blob_dup_talloc(x->global,
405                                                 x->global->signing_key);
406         if (x->global->application_key.data == NULL) {
407                 ZERO_STRUCT(session_key);
408                 return NT_STATUS_NO_MEMORY;
409         }
410
411         if (xconn->protocol >= PROTOCOL_SMB2_24) {
412                 struct _derivation *d = &derivation.application;
413
414                 smb2_key_derivation(session_key, sizeof(session_key),
415                                     d->label.data, d->label.length,
416                                     d->context.data, d->context.length,
417                                     x->global->application_key.data);
418         }
419
420         if (xconn->protocol >= PROTOCOL_SMB3_00 && lp_debug_encryption()) {
421                 DEBUG(0, ("debug encryption: dumping generated session keys\n"));
422                 DEBUGADD(0, ("Session Id    "));
423                 dump_data(0, (uint8_t*)&session->global->session_wire_id,
424                           sizeof(session->global->session_wire_id));
425                 DEBUGADD(0, ("Session Key   "));
426                 dump_data(0, session_key, sizeof(session_key));
427                 DEBUGADD(0, ("Signing Key   "));
428                 dump_data(0, x->global->signing_key.data,
429                           x->global->signing_key.length);
430                 DEBUGADD(0, ("App Key       "));
431                 dump_data(0, x->global->application_key.data,
432                           x->global->application_key.length);
433
434                 /* In server code, ServerIn is the decryption key */
435
436                 DEBUGADD(0, ("ServerIn Key  "));
437                 dump_data(0, x->global->decryption_key.data,
438                           x->global->decryption_key.length);
439                 DEBUGADD(0, ("ServerOut Key "));
440                 dump_data(0, x->global->encryption_key.data,
441                           x->global->encryption_key.length);
442         }
443
444         ZERO_STRUCT(session_key);
445
446         x->global->channels[0].signing_key = data_blob_dup_talloc(x->global->channels,
447                                                 x->global->signing_key);
448         if (x->global->channels[0].signing_key.data == NULL) {
449                 return NT_STATUS_NO_MEMORY;
450         }
451
452         data_blob_clear_free(&session_info->session_key);
453         session_info->session_key = data_blob_dup_talloc(session_info,
454                                                 x->global->application_key);
455         if (session_info->session_key.data == NULL) {
456                 return NT_STATUS_NO_MEMORY;
457         }
458
459         session->compat = talloc_zero(session, struct user_struct);
460         if (session->compat == NULL) {
461                 return NT_STATUS_NO_MEMORY;
462         }
463         session->compat->session = session;
464         session->compat->homes_snum = -1;
465         session->compat->session_info = session_info;
466         session->compat->session_keystr = NULL;
467         session->compat->vuid = session->global->session_wire_id;
468         DLIST_ADD(smb2req->sconn->users, session->compat);
469         smb2req->sconn->num_users++;
470
471         if (security_session_user_level(session_info, NULL) >= SECURITY_USER) {
472                 session->compat->homes_snum =
473                         register_homes_share(session_info->unix_info->unix_name);
474         }
475
476         set_current_user_info(session_info->unix_info->sanitized_username,
477                               session_info->unix_info->unix_name,
478                               session_info->info->domain_name);
479
480         reload_services(smb2req->sconn, conn_snum_used, true);
481
482         session->status = NT_STATUS_OK;
483         session->global->auth_session_info = talloc_move(session->global,
484                                                          &session_info);
485         session->global->auth_session_info_seqnum += 1;
486         for (i=0; i < session->global->num_channels; i++) {
487                 struct smbXsrv_channel_global0 *_c =
488                         &session->global->channels[i];
489
490                 _c->auth_session_info_seqnum =
491                         session->global->auth_session_info_seqnum;
492         }
493         session->global->auth_time = timeval_to_nttime(&smb2req->request_time);
494         session->global->expiration_time = gensec_expire_time(auth->gensec);
495
496         if (!session_claim(session)) {
497                 DEBUG(1, ("smb2: Failed to claim session "
498                         "for vuid=%llu\n",
499                         (unsigned long long)session->compat->vuid));
500                 return NT_STATUS_LOGON_FAILURE;
501         }
502
503         TALLOC_FREE(auth);
504         status = smbXsrv_session_update(session);
505         if (!NT_STATUS_IS_OK(status)) {
506                 DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n",
507                           (unsigned long long)session->compat->vuid,
508                           nt_errstr(status)));
509                 return NT_STATUS_LOGON_FAILURE;
510         }
511
512         /*
513          * we attach the session to the request
514          * so that the response can be signed
515          */
516         if (!guest) {
517                 smb2req->do_signing = true;
518         }
519
520         global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
521
522         *out_session_id = session->global->session_wire_id;
523         smb2req->last_session_id = session->global->session_wire_id;
524
525         return NT_STATUS_OK;
526 }
527
528 static NTSTATUS smbd_smb2_reauth_generic_return(struct smbXsrv_session *session,
529                                         struct smbXsrv_session_auth0 **_auth,
530                                         struct smbd_smb2_request *smb2req,
531                                         struct auth_session_info *session_info,
532                                         uint16_t *out_session_flags,
533                                         uint64_t *out_session_id)
534 {
535         NTSTATUS status;
536         struct smbXsrv_session *x = session;
537         struct smbXsrv_session_auth0 *auth = *_auth;
538         struct smbXsrv_connection *xconn = smb2req->xconn;
539         size_t i;
540
541         *_auth = NULL;
542
543         data_blob_clear_free(&session_info->session_key);
544         session_info->session_key = data_blob_dup_talloc(session_info,
545                                                 x->global->application_key);
546         if (session_info->session_key.data == NULL) {
547                 return NT_STATUS_NO_MEMORY;
548         }
549
550         session->compat->session_info = session_info;
551         session->compat->vuid = session->global->session_wire_id;
552
553         session->compat->homes_snum =
554                         register_homes_share(session_info->unix_info->unix_name);
555
556         set_current_user_info(session_info->unix_info->sanitized_username,
557                               session_info->unix_info->unix_name,
558                               session_info->info->domain_name);
559
560         reload_services(smb2req->sconn, conn_snum_used, true);
561
562         if (security_session_user_level(session_info, NULL) >= SECURITY_USER) {
563                 smb2req->do_signing = true;
564         }
565
566         session->status = NT_STATUS_OK;
567         TALLOC_FREE(session->global->auth_session_info);
568         session->global->auth_session_info = talloc_move(session->global,
569                                                          &session_info);
570         session->global->auth_session_info_seqnum += 1;
571         for (i=0; i < session->global->num_channels; i++) {
572                 struct smbXsrv_channel_global0 *_c =
573                         &session->global->channels[i];
574
575                 _c->auth_session_info_seqnum =
576                         session->global->auth_session_info_seqnum;
577         }
578         session->global->auth_time = timeval_to_nttime(&smb2req->request_time);
579         session->global->expiration_time = gensec_expire_time(auth->gensec);
580
581         TALLOC_FREE(auth);
582         status = smbXsrv_session_update(session);
583         if (!NT_STATUS_IS_OK(status)) {
584                 DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n",
585                           (unsigned long long)session->compat->vuid,
586                           nt_errstr(status)));
587                 return NT_STATUS_LOGON_FAILURE;
588         }
589
590         conn_clear_vuid_caches(xconn->client->sconn, session->compat->vuid);
591
592         *out_session_id = session->global->session_wire_id;
593
594         return NT_STATUS_OK;
595 }
596
597 static NTSTATUS smbd_smb2_bind_auth_return(struct smbXsrv_session *session,
598                                            struct smbXsrv_session_auth0 **_auth,
599                                            struct smbd_smb2_request *smb2req,
600                                            struct auth_session_info *session_info,
601                                            uint16_t *out_session_flags,
602                                            uint64_t *out_session_id)
603 {
604         NTSTATUS status;
605         struct smbXsrv_session *x = session;
606         struct smbXsrv_session_auth0 *auth = *_auth;
607         struct smbXsrv_connection *xconn = smb2req->xconn;
608         struct smbXsrv_channel_global0 *c = NULL;
609         uint8_t session_key[16];
610         size_t i;
611         struct _derivation {
612                 DATA_BLOB label;
613                 DATA_BLOB context;
614         };
615         struct {
616                 struct _derivation signing;
617         } derivation = { };
618         bool ok;
619
620         *_auth = NULL;
621
622         if (xconn->protocol >= PROTOCOL_SMB3_10) {
623                 struct smbXsrv_preauth *preauth;
624                 struct _derivation *d;
625                 DATA_BLOB p;
626                 struct hc_sha512state sctx;
627
628                 preauth = talloc_move(smb2req, &auth->preauth);
629
630                 samba_SHA512_Init(&sctx);
631                 samba_SHA512_Update(&sctx, preauth->sha512_value,
632                                     sizeof(preauth->sha512_value));
633                 for (i = 1; i < smb2req->in.vector_count; i++) {
634                         samba_SHA512_Update(&sctx,
635                                             smb2req->in.vector[i].iov_base,
636                                             smb2req->in.vector[i].iov_len);
637                 }
638                 samba_SHA512_Final(preauth->sha512_value, &sctx);
639
640                 p = data_blob_const(preauth->sha512_value,
641                                     sizeof(preauth->sha512_value));
642
643                 d = &derivation.signing;
644                 d->label = data_blob_string_const_null("SMBSigningKey");
645                 d->context = p;
646
647         } else if (xconn->protocol >= PROTOCOL_SMB2_24) {
648                 struct _derivation *d;
649
650                 d = &derivation.signing;
651                 d->label = data_blob_string_const_null("SMB2AESCMAC");
652                 d->context = data_blob_string_const_null("SmbSign");
653         }
654
655         status = smbXsrv_session_find_channel(session, xconn, &c);
656         if (!NT_STATUS_IS_OK(status)) {
657                 return status;
658         }
659
660         ok = security_token_is_sid(session_info->security_token,
661                         &x->global->auth_session_info->security_token->sids[0]);
662         if (!ok) {
663                 return NT_STATUS_NOT_SUPPORTED;
664         }
665
666         if (session_info->session_key.length == 0) {
667                 /* See [MS-SMB2] 3.3.5.2.4 for the return code. */
668                 return NT_STATUS_NOT_SUPPORTED;
669         }
670
671         ZERO_STRUCT(session_key);
672         memcpy(session_key, session_info->session_key.data,
673                MIN(session_info->session_key.length, sizeof(session_key)));
674
675         c->signing_key = data_blob_talloc(x->global,
676                                           session_key,
677                                           sizeof(session_key));
678         if (c->signing_key.data == NULL) {
679                 ZERO_STRUCT(session_key);
680                 return NT_STATUS_NO_MEMORY;
681         }
682
683         if (xconn->protocol >= PROTOCOL_SMB2_24) {
684                 struct _derivation *d = &derivation.signing;
685
686                 smb2_key_derivation(session_key, sizeof(session_key),
687                                     d->label.data, d->label.length,
688                                     d->context.data, d->context.length,
689                                     c->signing_key.data);
690         }
691         ZERO_STRUCT(session_key);
692
693         TALLOC_FREE(auth);
694         status = smbXsrv_session_update(session);
695         if (!NT_STATUS_IS_OK(status)) {
696                 DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n",
697                           (unsigned long long)session->compat->vuid,
698                           nt_errstr(status)));
699                 return NT_STATUS_LOGON_FAILURE;
700         }
701
702         *out_session_id = session->global->session_wire_id;
703
704         return NT_STATUS_OK;
705 }
706
707 struct smbd_smb2_session_setup_state {
708         struct tevent_context *ev;
709         struct smbd_smb2_request *smb2req;
710         uint64_t in_session_id;
711         uint8_t in_flags;
712         uint8_t in_security_mode;
713         uint64_t in_previous_session_id;
714         DATA_BLOB in_security_buffer;
715         struct smbXsrv_session *session;
716         struct smbXsrv_session_auth0 *auth;
717         struct auth_session_info *session_info;
718         uint16_t out_session_flags;
719         DATA_BLOB out_security_buffer;
720         uint64_t out_session_id;
721 };
722
723 static void smbd_smb2_session_setup_gensec_done(struct tevent_req *subreq);
724 static void smbd_smb2_session_setup_previous_done(struct tevent_req *subreq);
725 static void smbd_smb2_session_setup_auth_return(struct tevent_req *req);
726
727 static struct tevent_req *smbd_smb2_session_setup_send(TALLOC_CTX *mem_ctx,
728                                         struct tevent_context *ev,
729                                         struct smbd_smb2_request *smb2req,
730                                         uint64_t in_session_id,
731                                         uint8_t in_flags,
732                                         uint8_t in_security_mode,
733                                         uint64_t in_previous_session_id,
734                                         DATA_BLOB in_security_buffer)
735 {
736         struct tevent_req *req;
737         struct smbd_smb2_session_setup_state *state;
738         NTSTATUS status;
739         NTTIME now = timeval_to_nttime(&smb2req->request_time);
740         struct tevent_req *subreq;
741         struct smbXsrv_channel_global0 *c = NULL;
742         enum security_user_level seclvl;
743
744         req = tevent_req_create(mem_ctx, &state,
745                                 struct smbd_smb2_session_setup_state);
746         if (req == NULL) {
747                 return NULL;
748         }
749         state->ev = ev;
750         state->smb2req = smb2req;
751         state->in_session_id = in_session_id;
752         state->in_flags = in_flags;
753         state->in_security_mode = in_security_mode;
754         state->in_previous_session_id = in_previous_session_id;
755         state->in_security_buffer = in_security_buffer;
756
757         if (in_flags & SMB2_SESSION_FLAG_BINDING) {
758                 if (smb2req->xconn->protocol < PROTOCOL_SMB2_22) {
759                         tevent_req_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED);
760                         return tevent_req_post(req, ev);
761                 }
762
763                 if (!smb2req->xconn->client->server_multi_channel_enabled) {
764                         tevent_req_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED);
765                         return tevent_req_post(req, ev);
766                 }
767
768                 if (in_session_id == 0) {
769                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
770                         return tevent_req_post(req, ev);
771                 }
772
773                 if (smb2req->session == NULL) {
774                         tevent_req_nterror(req, NT_STATUS_USER_SESSION_DELETED);
775                         return tevent_req_post(req, ev);
776                 }
777
778                 if (!smb2req->do_signing) {
779                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
780                         return tevent_req_post(req, ev);
781                 }
782
783                 status = smbXsrv_session_find_channel(smb2req->session,
784                                                       smb2req->xconn,
785                                                       &c);
786                 if (NT_STATUS_IS_OK(status)) {
787                         if (c->signing_key.length == 0) {
788                                 goto auth;
789                         }
790                         tevent_req_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED);
791                         return tevent_req_post(req, ev);
792                 }
793
794                 /*
795                  * OLD: 3.00 NEW 3.02 => INVALID_PARAMETER
796                  * OLD: 3.02 NEW 3.00 => INVALID_PARAMETER
797                  * OLD: 2.10 NEW 3.02 => ACCESS_DENIED
798                  * OLD: 3.02 NEW 2.10 => ACCESS_DENIED
799                  */
800                 if (smb2req->session->global->connection_dialect
801                     < SMB2_DIALECT_REVISION_222)
802                 {
803                         tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
804                         return tevent_req_post(req, ev);
805                 }
806                 if (smb2req->xconn->smb2.server.dialect
807                     < SMB2_DIALECT_REVISION_222)
808                 {
809                         tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
810                         return tevent_req_post(req, ev);
811                 }
812                 if (smb2req->session->global->connection_dialect
813                     != smb2req->xconn->smb2.server.dialect)
814                 {
815                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
816                         return tevent_req_post(req, ev);
817                 }
818
819                 seclvl = security_session_user_level(
820                                 smb2req->session->global->auth_session_info,
821                                 NULL);
822                 if (seclvl < SECURITY_USER) {
823                         tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
824                         return tevent_req_post(req, ev);
825                 }
826
827                 status = smbXsrv_session_add_channel(smb2req->session,
828                                                      smb2req->xconn,
829                                                      &c);
830                 if (!NT_STATUS_IS_OK(status)) {
831                         tevent_req_nterror(req, status);
832                         return tevent_req_post(req, ev);
833                 }
834
835                 status = smbXsrv_session_update(smb2req->session);
836                 if (!NT_STATUS_IS_OK(status)) {
837                         tevent_req_nterror(req, status);
838                         return tevent_req_post(req, ev);
839                 }
840         }
841
842 auth:
843
844         if (state->in_session_id == 0) {
845                 /* create a new session */
846                 status = smbXsrv_session_create(state->smb2req->xconn,
847                                                 now, &state->session);
848                 if (tevent_req_nterror(req, status)) {
849                         return tevent_req_post(req, ev);
850                 }
851                 smb2req->session = state->session;
852         } else {
853                 if (smb2req->session == NULL) {
854                         tevent_req_nterror(req, NT_STATUS_USER_SESSION_DELETED);
855                         return tevent_req_post(req, ev);
856                 }
857
858                 state->session = smb2req->session;
859                 status = state->session->status;
860                 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
861                         status = NT_STATUS_OK;
862                 }
863                 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
864                         status = NT_STATUS_OK;
865                 }
866                 if (tevent_req_nterror(req, status)) {
867                         return tevent_req_post(req, ev);
868                 }
869                 if (!(in_flags & SMB2_SESSION_FLAG_BINDING)) {
870                         state->session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
871                 }
872         }
873
874         status = smbXsrv_session_find_channel(smb2req->session,
875                                               smb2req->xconn, &c);
876         if (!NT_STATUS_IS_OK(status)) {
877                 tevent_req_nterror(req, status);
878                 return tevent_req_post(req, ev);
879         }
880
881         status = smbXsrv_session_find_auth(state->session, smb2req->xconn,
882                                            now, &state->auth);
883         if (!NT_STATUS_IS_OK(status)) {
884                 status = smbXsrv_session_create_auth(state->session,
885                                                      smb2req->xconn, now,
886                                                      in_flags, in_security_mode,
887                                                      &state->auth);
888                 if (tevent_req_nterror(req, status)) {
889                         return tevent_req_post(req, ev);
890                 }
891         }
892
893         if (state->auth->gensec == NULL) {
894                 status = auth_generic_prepare(state->auth,
895                                               state->smb2req->xconn->remote_address,
896                                               state->smb2req->xconn->local_address,
897                                               "SMB2",
898                                               &state->auth->gensec);
899                 if (tevent_req_nterror(req, status)) {
900                         return tevent_req_post(req, ev);
901                 }
902
903                 gensec_want_feature(state->auth->gensec, GENSEC_FEATURE_SESSION_KEY);
904                 gensec_want_feature(state->auth->gensec, GENSEC_FEATURE_UNIX_TOKEN);
905                 gensec_want_feature(state->auth->gensec, GENSEC_FEATURE_SMB_TRANSPORT);
906
907                 status = gensec_start_mech_by_oid(state->auth->gensec,
908                                                   GENSEC_OID_SPNEGO);
909                 if (tevent_req_nterror(req, status)) {
910                         return tevent_req_post(req, ev);
911                 }
912         }
913
914         status = smbXsrv_session_update(state->session);
915         if (tevent_req_nterror(req, status)) {
916                 return tevent_req_post(req, ev);
917         }
918
919         become_root();
920         subreq = gensec_update_send(state, state->ev,
921                                     state->auth->gensec,
922                                     state->in_security_buffer);
923         unbecome_root();
924         if (tevent_req_nomem(subreq, req)) {
925                 return tevent_req_post(req, ev);
926         }
927         tevent_req_set_callback(subreq, smbd_smb2_session_setup_gensec_done, req);
928
929         return req;
930 }
931
932 static void smbd_smb2_session_setup_gensec_done(struct tevent_req *subreq)
933 {
934         struct tevent_req *req =
935                 tevent_req_callback_data(subreq,
936                 struct tevent_req);
937         struct smbd_smb2_session_setup_state *state =
938                 tevent_req_data(req,
939                 struct smbd_smb2_session_setup_state);
940         NTSTATUS status;
941
942         become_root();
943         status = gensec_update_recv(subreq, state,
944                                     &state->out_security_buffer);
945         unbecome_root();
946         TALLOC_FREE(subreq);
947         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
948             !NT_STATUS_IS_OK(status)) {
949                 tevent_req_nterror(req, status);
950                 return;
951         }
952
953         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
954                 state->out_session_id = state->session->global->session_wire_id;
955                 state->smb2req->preauth = state->auth->preauth;
956                 tevent_req_nterror(req, status);
957                 return;
958         }
959
960         status = gensec_session_info(state->auth->gensec,
961                                      state,
962                                      &state->session_info);
963         if (tevent_req_nterror(req, status)) {
964                 return;
965         }
966
967         if ((state->in_previous_session_id != 0) &&
968              (state->session->global->session_wire_id !=
969               state->in_previous_session_id))
970         {
971                 subreq = smb2srv_session_close_previous_send(state, state->ev,
972                                                 state->smb2req->xconn,
973                                                 state->session_info,
974                                                 state->in_previous_session_id,
975                                                 state->session->global->session_wire_id);
976                 if (tevent_req_nomem(subreq, req)) {
977                         return;
978                 }
979                 tevent_req_set_callback(subreq,
980                                         smbd_smb2_session_setup_previous_done,
981                                         req);
982                 return;
983         }
984
985         smbd_smb2_session_setup_auth_return(req);
986 }
987
988 static void smbd_smb2_session_setup_previous_done(struct tevent_req *subreq)
989 {
990         struct tevent_req *req =
991                 tevent_req_callback_data(subreq,
992                 struct tevent_req);
993         NTSTATUS status;
994
995         status = smb2srv_session_close_previous_recv(subreq);
996         TALLOC_FREE(subreq);
997         if (tevent_req_nterror(req, status)) {
998                 return;
999         }
1000
1001         smbd_smb2_session_setup_auth_return(req);
1002 }
1003
1004 static void smbd_smb2_session_setup_auth_return(struct tevent_req *req)
1005 {
1006         struct smbd_smb2_session_setup_state *state =
1007                 tevent_req_data(req,
1008                 struct smbd_smb2_session_setup_state);
1009         NTSTATUS status;
1010
1011         if (state->in_flags & SMB2_SESSION_FLAG_BINDING) {
1012                 status = smbd_smb2_bind_auth_return(state->session,
1013                                                     &state->auth,
1014                                                     state->smb2req,
1015                                                     state->session_info,
1016                                                     &state->out_session_flags,
1017                                                     &state->out_session_id);
1018                 if (tevent_req_nterror(req, status)) {
1019                         return;
1020                 }
1021                 tevent_req_done(req);
1022                 return;
1023         }
1024
1025         if (state->session->global->auth_session_info != NULL) {
1026                 status = smbd_smb2_reauth_generic_return(state->session,
1027                                                          &state->auth,
1028                                                          state->smb2req,
1029                                                          state->session_info,
1030                                                          &state->out_session_flags,
1031                                                          &state->out_session_id);
1032                 if (tevent_req_nterror(req, status)) {
1033                         return;
1034                 }
1035                 tevent_req_done(req);
1036                 return;
1037         }
1038
1039         status = smbd_smb2_auth_generic_return(state->session,
1040                                                &state->auth,
1041                                                state->smb2req,
1042                                                state->in_security_mode,
1043                                                state->session_info,
1044                                                &state->out_session_flags,
1045                                                &state->out_session_id);
1046         if (tevent_req_nterror(req, status)) {
1047                 return;
1048         }
1049
1050         tevent_req_done(req);
1051         return;
1052 }
1053
1054 static NTSTATUS smbd_smb2_session_setup_recv(struct tevent_req *req,
1055                                         uint16_t *out_session_flags,
1056                                         TALLOC_CTX *mem_ctx,
1057                                         DATA_BLOB *out_security_buffer,
1058                                         uint64_t *out_session_id)
1059 {
1060         struct smbd_smb2_session_setup_state *state =
1061                 tevent_req_data(req,
1062                 struct smbd_smb2_session_setup_state);
1063         NTSTATUS status;
1064
1065         if (tevent_req_is_nterror(req, &status)) {
1066                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1067                         tevent_req_received(req);
1068                         return nt_status_squash(status);
1069                 }
1070         } else {
1071                 status = NT_STATUS_OK;
1072         }
1073
1074         *out_session_flags = state->out_session_flags;
1075         *out_security_buffer = state->out_security_buffer;
1076         *out_session_id = state->out_session_id;
1077
1078         talloc_steal(mem_ctx, out_security_buffer->data);
1079         tevent_req_received(req);
1080         return status;
1081 }
1082
1083 struct smbd_smb2_session_setup_wrap_state {
1084         struct tevent_context *ev;
1085         struct smbd_smb2_request *smb2req;
1086         uint64_t in_session_id;
1087         uint8_t in_flags;
1088         uint8_t in_security_mode;
1089         uint64_t in_previous_session_id;
1090         DATA_BLOB in_security_buffer;
1091         uint16_t out_session_flags;
1092         DATA_BLOB out_security_buffer;
1093         uint64_t out_session_id;
1094         NTSTATUS error;
1095 };
1096
1097 static void smbd_smb2_session_setup_wrap_setup_done(struct tevent_req *subreq);
1098 static void smbd_smb2_session_setup_wrap_shutdown_done(struct tevent_req *subreq);
1099
1100 static struct tevent_req *smbd_smb2_session_setup_wrap_send(TALLOC_CTX *mem_ctx,
1101                                         struct tevent_context *ev,
1102                                         struct smbd_smb2_request *smb2req,
1103                                         uint64_t in_session_id,
1104                                         uint8_t in_flags,
1105                                         uint8_t in_security_mode,
1106                                         uint64_t in_previous_session_id,
1107                                         DATA_BLOB in_security_buffer)
1108 {
1109         struct tevent_req *req;
1110         struct smbd_smb2_session_setup_wrap_state *state;
1111         struct tevent_req *subreq;
1112
1113         req = tevent_req_create(mem_ctx, &state,
1114                                 struct smbd_smb2_session_setup_wrap_state);
1115         if (req == NULL) {
1116                 return NULL;
1117         }
1118         state->ev = ev;
1119         state->smb2req = smb2req;
1120         state->in_session_id = in_session_id;
1121         state->in_flags = in_flags;
1122         state->in_security_mode = in_security_mode;
1123         state->in_previous_session_id = in_previous_session_id;
1124         state->in_security_buffer = in_security_buffer;
1125
1126         subreq = smbd_smb2_session_setup_send(state, state->ev,
1127                                               state->smb2req,
1128                                               state->in_session_id,
1129                                               state->in_flags,
1130                                               state->in_security_mode,
1131                                               state->in_previous_session_id,
1132                                               state->in_security_buffer);
1133         if (tevent_req_nomem(subreq, req)) {
1134                 return tevent_req_post(req, ev);
1135         }
1136         tevent_req_set_callback(subreq,
1137                                 smbd_smb2_session_setup_wrap_setup_done, req);
1138
1139         return req;
1140 }
1141
1142 static void smbd_smb2_session_setup_wrap_setup_done(struct tevent_req *subreq)
1143 {
1144         struct tevent_req *req =
1145                 tevent_req_callback_data(subreq,
1146                 struct tevent_req);
1147         struct smbd_smb2_session_setup_wrap_state *state =
1148                 tevent_req_data(req,
1149                 struct smbd_smb2_session_setup_wrap_state);
1150         NTSTATUS status;
1151
1152         status = smbd_smb2_session_setup_recv(subreq,
1153                                               &state->out_session_flags,
1154                                               state,
1155                                               &state->out_security_buffer,
1156                                               &state->out_session_id);
1157         TALLOC_FREE(subreq);
1158         if (NT_STATUS_IS_OK(status)) {
1159                 tevent_req_done(req);
1160                 return;
1161         }
1162         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1163                 tevent_req_nterror(req, status);
1164                 return;
1165         }
1166
1167         if (state->smb2req->session == NULL) {
1168                 tevent_req_nterror(req, status);
1169                 return;
1170         }
1171
1172         state->error = status;
1173
1174         subreq = smb2srv_session_shutdown_send(state, state->ev,
1175                                                state->smb2req->session,
1176                                                state->smb2req);
1177         if (tevent_req_nomem(subreq, req)) {
1178                 return;
1179         }
1180         tevent_req_set_callback(subreq,
1181                                 smbd_smb2_session_setup_wrap_shutdown_done,
1182                                 req);
1183 }
1184
1185 static void smbd_smb2_session_setup_wrap_shutdown_done(struct tevent_req *subreq)
1186 {
1187         struct tevent_req *req =
1188                 tevent_req_callback_data(subreq,
1189                 struct tevent_req);
1190         struct smbd_smb2_session_setup_wrap_state *state =
1191                 tevent_req_data(req,
1192                 struct smbd_smb2_session_setup_wrap_state);
1193         NTSTATUS status;
1194
1195         status = smb2srv_session_shutdown_recv(subreq);
1196         TALLOC_FREE(subreq);
1197         if (tevent_req_nterror(req, status)) {
1198                 return;
1199         }
1200
1201         /*
1202          * we may need to sign the response, so we need to keep
1203          * the session until the response is sent to the wire.
1204          */
1205         talloc_steal(state->smb2req, state->smb2req->session);
1206
1207         tevent_req_nterror(req, state->error);
1208 }
1209
1210 static NTSTATUS smbd_smb2_session_setup_wrap_recv(struct tevent_req *req,
1211                                         uint16_t *out_session_flags,
1212                                         TALLOC_CTX *mem_ctx,
1213                                         DATA_BLOB *out_security_buffer,
1214                                         uint64_t *out_session_id)
1215 {
1216         struct smbd_smb2_session_setup_wrap_state *state =
1217                 tevent_req_data(req,
1218                 struct smbd_smb2_session_setup_wrap_state);
1219         NTSTATUS status;
1220
1221         if (tevent_req_is_nterror(req, &status)) {
1222                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1223                         tevent_req_received(req);
1224                         return nt_status_squash(status);
1225                 }
1226         } else {
1227                 status = NT_STATUS_OK;
1228         }
1229
1230         *out_session_flags = state->out_session_flags;
1231         *out_security_buffer = state->out_security_buffer;
1232         *out_session_id = state->out_session_id;
1233
1234         talloc_steal(mem_ctx, out_security_buffer->data);
1235         tevent_req_received(req);
1236         return status;
1237 }
1238
1239 static struct tevent_req *smbd_smb2_logoff_send(TALLOC_CTX *mem_ctx,
1240                                         struct tevent_context *ev,
1241                                         struct smbd_smb2_request *smb2req);
1242 static NTSTATUS smbd_smb2_logoff_recv(struct tevent_req *req);
1243 static void smbd_smb2_request_logoff_done(struct tevent_req *subreq);
1244
1245 NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req)
1246 {
1247         NTSTATUS status;
1248         struct tevent_req *subreq = NULL;
1249
1250         status = smbd_smb2_request_verify_sizes(req, 0x04);
1251         if (!NT_STATUS_IS_OK(status)) {
1252                 return smbd_smb2_request_error(req, status);
1253         }
1254
1255         subreq = smbd_smb2_logoff_send(req, req->sconn->ev_ctx, req);
1256         if (subreq == NULL) {
1257                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
1258         }
1259         tevent_req_set_callback(subreq, smbd_smb2_request_logoff_done, req);
1260
1261         /*
1262          * Avoid sending a STATUS_PENDING message, it's very likely
1263          * the client won't expect that.
1264          */
1265         return smbd_smb2_request_pending_queue(req, subreq, 0);
1266 }
1267
1268 static void smbd_smb2_request_logoff_done(struct tevent_req *subreq)
1269 {
1270         struct smbd_smb2_request *smb2req =
1271                 tevent_req_callback_data(subreq,
1272                 struct smbd_smb2_request);
1273         DATA_BLOB outbody;
1274         NTSTATUS status;
1275         NTSTATUS error;
1276
1277         status = smbd_smb2_logoff_recv(subreq);
1278         TALLOC_FREE(subreq);
1279         if (!NT_STATUS_IS_OK(status)) {
1280                 error = smbd_smb2_request_error(smb2req, status);
1281                 if (!NT_STATUS_IS_OK(error)) {
1282                         smbd_server_connection_terminate(smb2req->xconn,
1283                                                         nt_errstr(error));
1284                         return;
1285                 }
1286                 return;
1287         }
1288
1289         outbody = smbd_smb2_generate_outbody(smb2req, 0x04);
1290         if (outbody.data == NULL) {
1291                 error = smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
1292                 if (!NT_STATUS_IS_OK(error)) {
1293                         smbd_server_connection_terminate(smb2req->xconn,
1294                                                         nt_errstr(error));
1295                         return;
1296                 }
1297                 return;
1298         }
1299
1300         SSVAL(outbody.data, 0x00, 0x04);        /* struct size */
1301         SSVAL(outbody.data, 0x02, 0);           /* reserved */
1302
1303         error = smbd_smb2_request_done(smb2req, outbody, NULL);
1304         if (!NT_STATUS_IS_OK(error)) {
1305                 smbd_server_connection_terminate(smb2req->xconn,
1306                                                 nt_errstr(error));
1307                 return;
1308         }
1309 }
1310
1311 struct smbd_smb2_logoff_state {
1312         struct smbd_smb2_request *smb2req;
1313 };
1314
1315 static void smbd_smb2_logoff_shutdown_done(struct tevent_req *subreq);
1316
1317 static struct tevent_req *smbd_smb2_logoff_send(TALLOC_CTX *mem_ctx,
1318                                         struct tevent_context *ev,
1319                                         struct smbd_smb2_request *smb2req)
1320 {
1321         struct tevent_req *req;
1322         struct smbd_smb2_logoff_state *state;
1323         struct tevent_req *subreq;
1324
1325         req = tevent_req_create(mem_ctx, &state,
1326                         struct smbd_smb2_logoff_state);
1327         if (req == NULL) {
1328                 return NULL;
1329         }
1330         state->smb2req = smb2req;
1331
1332         subreq = smb2srv_session_shutdown_send(state, ev,
1333                                                smb2req->session,
1334                                                smb2req);
1335         if (tevent_req_nomem(subreq, req)) {
1336                 return tevent_req_post(req, ev);
1337         }
1338         tevent_req_set_callback(subreq, smbd_smb2_logoff_shutdown_done, req);
1339
1340         return req;
1341 }
1342
1343 static void smbd_smb2_logoff_shutdown_done(struct tevent_req *subreq)
1344 {
1345         struct tevent_req *req = tevent_req_callback_data(
1346                 subreq, struct tevent_req);
1347         struct smbd_smb2_logoff_state *state = tevent_req_data(
1348                 req, struct smbd_smb2_logoff_state);
1349         NTSTATUS status;
1350         bool ok;
1351         const struct GUID *client_guid =
1352                 &state->smb2req->session->client->connections->smb2.client.guid;
1353
1354         status = smb2srv_session_shutdown_recv(subreq);
1355         if (tevent_req_nterror(req, status)) {
1356                 return;
1357         }
1358         TALLOC_FREE(subreq);
1359
1360         if (!GUID_all_zero(client_guid)) {
1361                 ok = remote_arch_cache_delete(client_guid);
1362                 if (!ok) {
1363                         /* Most likely not an error, but not in cache */
1364                         DBG_DEBUG("Deletion from remote arch cache failed\n");
1365                 }
1366         }
1367
1368         /*
1369          * As we've been awoken, we may have changed
1370          * uid in the meantime. Ensure we're still
1371          * root (SMB2_OP_LOGOFF has .as_root = true).
1372          */
1373         change_to_root_user();
1374
1375         status = smbXsrv_session_logoff(state->smb2req->session);
1376         if (tevent_req_nterror(req, status)) {
1377                 return;
1378         }
1379
1380         /*
1381          * we may need to sign the response, so we need to keep
1382          * the session until the response is sent to the wire.
1383          */
1384         talloc_steal(state->smb2req, state->smb2req->session);
1385
1386         tevent_req_done(req);
1387 }
1388
1389 static NTSTATUS smbd_smb2_logoff_recv(struct tevent_req *req)
1390 {
1391         return tevent_req_simple_recv_ntstatus(req);
1392 }