smbd: Make find_share_mode_lease() static
[kai/samba-autobuild/.git] / source3 / smbd / smb2_tcon.c
1 /*
2    Unix SMB/CIFS implementation.
3    Core SMB2 server
4
5    Copyright (C) Stefan Metzmacher 2009
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "smbd/smbd.h"
23 #include "smbd/globals.h"
24 #include "../libcli/smb/smb_common.h"
25 #include "../libcli/security/security.h"
26 #include "auth.h"
27 #include "lib/param/loadparm.h"
28 #include "../lib/util/tevent_ntstatus.h"
29
30 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_SMB2
32
33 static struct tevent_req *smbd_smb2_tree_connect_send(TALLOC_CTX *mem_ctx,
34                                         struct tevent_context *ev,
35                                         struct smbd_smb2_request *smb2req,
36                                         const char *in_path);
37 static NTSTATUS smbd_smb2_tree_connect_recv(struct tevent_req *req,
38                                             uint8_t *out_share_type,
39                                             uint32_t *out_share_flags,
40                                             uint32_t *out_capabilities,
41                                             uint32_t *out_maximal_access,
42                                             uint32_t *out_tree_id,
43                                             bool *disconnect);
44
45 static void smbd_smb2_request_tcon_done(struct tevent_req *subreq);
46
47 NTSTATUS smbd_smb2_request_process_tcon(struct smbd_smb2_request *req)
48 {
49         const uint8_t *inbody;
50         uint16_t in_path_offset;
51         uint16_t in_path_length;
52         DATA_BLOB in_path_buffer;
53         char *in_path_string;
54         size_t in_path_string_size;
55         NTSTATUS status;
56         bool ok;
57         struct tevent_req *subreq;
58
59         status = smbd_smb2_request_verify_sizes(req, 0x09);
60         if (!NT_STATUS_IS_OK(status)) {
61                 return smbd_smb2_request_error(req, status);
62         }
63         inbody = SMBD_SMB2_IN_BODY_PTR(req);
64
65         in_path_offset = SVAL(inbody, 0x04);
66         in_path_length = SVAL(inbody, 0x06);
67
68         if (in_path_offset != (SMB2_HDR_BODY + SMBD_SMB2_IN_BODY_LEN(req))) {
69                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
70         }
71
72         if (in_path_length > SMBD_SMB2_IN_DYN_LEN(req)) {
73                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
74         }
75
76         in_path_buffer.data = SMBD_SMB2_IN_DYN_PTR(req);
77         in_path_buffer.length = in_path_length;
78
79         ok = convert_string_talloc(req, CH_UTF16, CH_UNIX,
80                                    in_path_buffer.data,
81                                    in_path_buffer.length,
82                                    &in_path_string,
83                                    &in_path_string_size);
84         if (!ok) {
85                 return smbd_smb2_request_error(req, NT_STATUS_ILLEGAL_CHARACTER);
86         }
87
88         if (in_path_buffer.length == 0) {
89                 in_path_string_size = 0;
90         }
91
92         if (strlen(in_path_string) != in_path_string_size) {
93                 return smbd_smb2_request_error(req, NT_STATUS_BAD_NETWORK_NAME);
94         }
95
96         subreq = smbd_smb2_tree_connect_send(req,
97                                              req->sconn->ev_ctx,
98                                              req,
99                                              in_path_string);
100         if (subreq == NULL) {
101                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
102         }
103         tevent_req_set_callback(subreq, smbd_smb2_request_tcon_done, req);
104
105         /*
106          * Avoid sending a STATUS_PENDING message, it's very likely
107          * the client won't expect that.
108          */
109         return smbd_smb2_request_pending_queue(req, subreq, 0);
110 }
111
112 static void smbd_smb2_request_tcon_done(struct tevent_req *subreq)
113 {
114         struct smbd_smb2_request *req =
115                 tevent_req_callback_data(subreq,
116                 struct smbd_smb2_request);
117         uint8_t *outhdr;
118         DATA_BLOB outbody;
119         uint8_t out_share_type = 0;
120         uint32_t out_share_flags = 0;
121         uint32_t out_capabilities = 0;
122         uint32_t out_maximal_access = 0;
123         uint32_t out_tree_id = 0;
124         bool disconnect = false;
125         NTSTATUS status;
126         NTSTATUS error;
127
128         status = smbd_smb2_tree_connect_recv(subreq,
129                                              &out_share_type,
130                                              &out_share_flags,
131                                              &out_capabilities,
132                                              &out_maximal_access,
133                                              &out_tree_id,
134                                              &disconnect);
135         TALLOC_FREE(subreq);
136         if (!NT_STATUS_IS_OK(status)) {
137                 if (disconnect) {
138                         smbd_server_connection_terminate(req->xconn,
139                                                          nt_errstr(status));
140                         return;
141                 }
142                 error = smbd_smb2_request_error(req, status);
143                 if (!NT_STATUS_IS_OK(error)) {
144                         smbd_server_connection_terminate(req->xconn,
145                                                          nt_errstr(error));
146                         return;
147                 }
148                 return;
149         }
150
151         outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
152
153         outbody = smbd_smb2_generate_outbody(req, 0x10);
154         if (outbody.data == NULL) {
155                 error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
156                 if (!NT_STATUS_IS_OK(error)) {
157                         smbd_server_connection_terminate(req->xconn,
158                                                          nt_errstr(error));
159                         return;
160                 }
161                 return;
162         }
163
164         SIVAL(outhdr, SMB2_HDR_TID, out_tree_id);
165
166         SSVAL(outbody.data, 0x00, 0x10);        /* struct size */
167         SCVAL(outbody.data, 0x02,
168               out_share_type);                  /* share type */
169         SCVAL(outbody.data, 0x03, 0);           /* reserved */
170         SIVAL(outbody.data, 0x04,
171               out_share_flags);                 /* share flags */
172         SIVAL(outbody.data, 0x08,
173               out_capabilities);                /* capabilities */
174         SIVAL(outbody.data, 0x0C,
175               out_maximal_access);              /* maximal access */
176
177         error = smbd_smb2_request_done(req, outbody, NULL);
178         if (!NT_STATUS_IS_OK(error)) {
179                 smbd_server_connection_terminate(req->xconn,
180                                                  nt_errstr(error));
181                 return;
182         }
183 }
184
185 static NTSTATUS smbd_smb2_tree_connect(struct smbd_smb2_request *req,
186                                        const char *in_path,
187                                        uint8_t *out_share_type,
188                                        uint32_t *out_share_flags,
189                                        uint32_t *out_capabilities,
190                                        uint32_t *out_maximal_access,
191                                        uint32_t *out_tree_id,
192                                        bool *disconnect)
193 {
194         struct smbXsrv_connection *conn = req->xconn;
195         const char *share = in_path;
196         char *service = NULL;
197         int snum = -1;
198         struct smbXsrv_tcon *tcon;
199         NTTIME now = timeval_to_nttime(&req->request_time);
200         connection_struct *compat_conn = NULL;
201         struct user_struct *compat_vuser = req->session->compat;
202         NTSTATUS status;
203         bool encryption_desired = req->session->global->encryption_flags & SMBXSRV_ENCRYPTION_DESIRED;
204         bool encryption_required = req->session->global->encryption_flags & SMBXSRV_ENCRYPTION_REQUIRED;
205         bool guest_session = false;
206         bool require_signed_tcon = false;
207
208         *disconnect = false;
209
210         if (strncmp(share, "\\\\", 2) == 0) {
211                 const char *p = strchr(share+2, '\\');
212                 if (p) {
213                         share = p + 1;
214                 }
215         }
216
217         DEBUG(10,("smbd_smb2_tree_connect: path[%s] share[%s]\n",
218                   in_path, share));
219
220         if (security_session_user_level(compat_vuser->session_info, NULL) < SECURITY_USER) {
221                 guest_session = true;
222         }
223
224         if (conn->protocol >= PROTOCOL_SMB3_11 && !guest_session) {
225                 require_signed_tcon = true;
226         }
227
228         if (require_signed_tcon && !req->do_encryption && !req->do_signing) {
229                 DEBUG(1, ("smbd_smb2_tree_connect: reject request to share "
230                           "[%s] as '%s\\%s' without encryption or signing. "
231                           "Disconnecting.\n",
232                           share,
233                           req->session->global->auth_session_info->info->domain_name,
234                           req->session->global->auth_session_info->info->account_name));
235                 *disconnect = true;
236                 return NT_STATUS_ACCESS_DENIED;
237         }
238
239         service = talloc_strdup(talloc_tos(), share);
240         if(!service) {
241                 return NT_STATUS_NO_MEMORY;
242         }
243
244         if (!strlower_m(service)) {
245                 DEBUG(2, ("strlower_m %s failed\n", service));
246                 return NT_STATUS_INVALID_PARAMETER;
247         }
248
249         /* TODO: do more things... */
250         if (strequal(service,HOMES_NAME)) {
251                 if (compat_vuser->homes_snum == -1) {
252                         DEBUG(2, ("[homes] share not available for "
253                                 "user %s because it was not found "
254                                 "or created at session setup "
255                                 "time\n",
256                                 compat_vuser->session_info->unix_info->unix_name));
257                         return NT_STATUS_BAD_NETWORK_NAME;
258                 }
259                 snum = compat_vuser->homes_snum;
260         } else if ((compat_vuser->homes_snum != -1)
261                    && strequal(service,
262                         lp_servicename(talloc_tos(), compat_vuser->homes_snum))) {
263                 snum = compat_vuser->homes_snum;
264         } else {
265                 snum = find_service(talloc_tos(), service, &service);
266                 if (!service) {
267                         return NT_STATUS_NO_MEMORY;
268                 }
269         }
270
271         if (snum < 0) {
272                 DEBUG(3,("smbd_smb2_tree_connect: couldn't find service %s\n",
273                          service));
274                 return NT_STATUS_BAD_NETWORK_NAME;
275         }
276
277         /* Handle non-DFS clients attempting connections to msdfs proxy */
278         if (lp_host_msdfs()) {
279                 char *proxy = lp_msdfs_proxy(talloc_tos(), snum);
280
281                 if ((proxy != NULL) && (*proxy != '\0')) {
282                         DBG_NOTICE("refusing connection to dfs proxy share "
283                                    "'%s' (pointing to %s)\n",
284                                    service,
285                                    proxy);
286                         TALLOC_FREE(proxy);
287                         return NT_STATUS_BAD_NETWORK_NAME;
288                 }
289                 TALLOC_FREE(proxy);
290         }
291
292         if ((lp_smb_encrypt(snum) >= SMB_SIGNING_DESIRED) &&
293             (conn->smb2.server.cipher != 0))
294         {
295                 encryption_desired = true;
296         }
297
298         if (lp_smb_encrypt(snum) == SMB_SIGNING_REQUIRED) {
299                 encryption_desired = true;
300                 encryption_required = true;
301         }
302
303         if (guest_session && encryption_required) {
304                 DEBUG(1,("reject guest as encryption is required for service %s\n",
305                          service));
306                 return NT_STATUS_ACCESS_DENIED;
307         }
308
309         if (conn->smb2.server.cipher == 0) {
310                 if (encryption_required) {
311                         DEBUG(1,("reject tcon with dialect[0x%04X] "
312                                  "as encryption is required for service %s\n",
313                                  conn->smb2.server.dialect, service));
314                         return NT_STATUS_ACCESS_DENIED;
315                 }
316         }
317
318         /* create a new tcon as child of the session */
319         status = smb2srv_tcon_create(req->session, now, &tcon);
320         if (!NT_STATUS_IS_OK(status)) {
321                 return status;
322         }
323
324         if (encryption_desired) {
325                 tcon->global->encryption_flags |= SMBXSRV_ENCRYPTION_DESIRED;
326         }
327         if (encryption_required) {
328                 tcon->global->encryption_flags |= SMBXSRV_ENCRYPTION_REQUIRED;
329         }
330
331         compat_conn = make_connection_smb2(req,
332                                         tcon, snum,
333                                         req->session->compat,
334                                         "???",
335                                         &status);
336         if (compat_conn == NULL) {
337                 TALLOC_FREE(tcon);
338                 return status;
339         }
340
341         tcon->global->share_name = lp_servicename(tcon->global,
342                                                   SNUM(compat_conn));
343         if (tcon->global->share_name == NULL) {
344                 conn_free(compat_conn);
345                 TALLOC_FREE(tcon);
346                 return NT_STATUS_NO_MEMORY;
347         }
348         tcon->global->session_global_id =
349                 req->session->global->session_global_id;
350
351         tcon->compat = talloc_move(tcon, &compat_conn);
352
353         tcon->status = NT_STATUS_OK;
354
355         status = smbXsrv_tcon_update(tcon);
356         if (!NT_STATUS_IS_OK(status)) {
357                 TALLOC_FREE(tcon);
358                 return status;
359         }
360
361         if (IS_PRINT(tcon->compat)) {
362                 *out_share_type = SMB2_SHARE_TYPE_PRINT;
363         } else if (IS_IPC(tcon->compat)) {
364                 *out_share_type = SMB2_SHARE_TYPE_PIPE;
365         } else {
366                 *out_share_type = SMB2_SHARE_TYPE_DISK;
367         }
368
369         *out_share_flags = 0;
370
371         if (lp_msdfs_root(SNUM(tcon->compat)) && lp_host_msdfs()) {
372                 *out_share_flags |= (SMB2_SHAREFLAG_DFS|SMB2_SHAREFLAG_DFS_ROOT);
373                 *out_capabilities = SMB2_SHARE_CAP_DFS;
374         } else {
375                 *out_capabilities = 0;
376         }
377
378         switch(lp_csc_policy(SNUM(tcon->compat))) {
379         case CSC_POLICY_MANUAL:
380                 break;
381         case CSC_POLICY_DOCUMENTS:
382                 *out_share_flags |= SMB2_SHAREFLAG_AUTO_CACHING;
383                 break;
384         case CSC_POLICY_PROGRAMS:
385                 *out_share_flags |= SMB2_SHAREFLAG_VDO_CACHING;
386                 break;
387         case CSC_POLICY_DISABLE:
388                 *out_share_flags |= SMB2_SHAREFLAG_NO_CACHING;
389                 break;
390         default:
391                 break;
392         }
393
394         if (lp_hide_unreadable(SNUM(tcon->compat)) ||
395             lp_hide_unwriteable_files(SNUM(tcon->compat))) {
396                 *out_share_flags |= SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM;
397         }
398
399         if (encryption_desired) {
400                 *out_share_flags |= SMB2_SHAREFLAG_ENCRYPT_DATA;
401         }
402
403         *out_maximal_access = tcon->compat->share_access;
404
405         *out_tree_id = tcon->global->tcon_wire_id;
406         req->last_tid = tcon->global->tcon_wire_id;
407
408         return NT_STATUS_OK;
409 }
410
411 struct smbd_smb2_tree_connect_state {
412         const char *in_path;
413         uint8_t out_share_type;
414         uint32_t out_share_flags;
415         uint32_t out_capabilities;
416         uint32_t out_maximal_access;
417         uint32_t out_tree_id;
418         bool disconnect;
419 };
420
421 static struct tevent_req *smbd_smb2_tree_connect_send(TALLOC_CTX *mem_ctx,
422                                         struct tevent_context *ev,
423                                         struct smbd_smb2_request *smb2req,
424                                         const char *in_path)
425 {
426         struct tevent_req *req;
427         struct smbd_smb2_tree_connect_state *state;
428         NTSTATUS status;
429
430         req = tevent_req_create(mem_ctx, &state,
431                                 struct smbd_smb2_tree_connect_state);
432         if (req == NULL) {
433                 return NULL;
434         }
435         state->in_path = in_path;
436
437         status = smbd_smb2_tree_connect(smb2req,
438                                         state->in_path,
439                                         &state->out_share_type,
440                                         &state->out_share_flags,
441                                         &state->out_capabilities,
442                                         &state->out_maximal_access,
443                                         &state->out_tree_id,
444                                         &state->disconnect);
445         if (tevent_req_nterror(req, status)) {
446                 return tevent_req_post(req, ev);
447         }
448
449         tevent_req_done(req);
450         return tevent_req_post(req, ev);
451 }
452
453 static NTSTATUS smbd_smb2_tree_connect_recv(struct tevent_req *req,
454                                             uint8_t *out_share_type,
455                                             uint32_t *out_share_flags,
456                                             uint32_t *out_capabilities,
457                                             uint32_t *out_maximal_access,
458                                             uint32_t *out_tree_id,
459                                             bool *disconnect)
460 {
461         struct smbd_smb2_tree_connect_state *state =
462                 tevent_req_data(req,
463                 struct smbd_smb2_tree_connect_state);
464         NTSTATUS status;
465
466         if (tevent_req_is_nterror(req, &status)) {
467                 tevent_req_received(req);
468                 return status;
469         }
470
471         *out_share_type = state->out_share_type;
472         *out_share_flags = state->out_share_flags;
473         *out_capabilities = state->out_capabilities;
474         *out_maximal_access = state->out_maximal_access;
475         *out_tree_id = state->out_tree_id;
476         *disconnect = state->disconnect;
477
478         tevent_req_received(req);
479         return NT_STATUS_OK;
480 }
481
482 static struct tevent_req *smbd_smb2_tdis_send(TALLOC_CTX *mem_ctx,
483                                         struct tevent_context *ev,
484                                         struct smbd_smb2_request *smb2req);
485 static NTSTATUS smbd_smb2_tdis_recv(struct tevent_req *req);
486 static void smbd_smb2_request_tdis_done(struct tevent_req *subreq);
487
488 NTSTATUS smbd_smb2_request_process_tdis(struct smbd_smb2_request *req)
489 {
490         NTSTATUS status;
491         struct tevent_req *subreq = NULL;
492
493         status = smbd_smb2_request_verify_sizes(req, 0x04);
494         if (!NT_STATUS_IS_OK(status)) {
495                 return smbd_smb2_request_error(req, status);
496         }
497
498         subreq = smbd_smb2_tdis_send(req, req->sconn->ev_ctx, req);
499         if (subreq == NULL) {
500                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
501         }
502         tevent_req_set_callback(subreq, smbd_smb2_request_tdis_done, req);
503
504         /*
505          * Avoid sending a STATUS_PENDING message, it's very likely
506          * the client won't expect that.
507          */
508         return smbd_smb2_request_pending_queue(req, subreq, 0);
509 }
510
511 static void smbd_smb2_request_tdis_done(struct tevent_req *subreq)
512 {
513         struct smbd_smb2_request *smb2req =
514                 tevent_req_callback_data(subreq,
515                 struct smbd_smb2_request);
516         DATA_BLOB outbody;
517         NTSTATUS status;
518         NTSTATUS error;
519
520         status = smbd_smb2_tdis_recv(subreq);
521         TALLOC_FREE(subreq);
522         if (!NT_STATUS_IS_OK(status)) {
523                 error = smbd_smb2_request_error(smb2req, status);
524                 if (!NT_STATUS_IS_OK(error)) {
525                         smbd_server_connection_terminate(smb2req->xconn,
526                                                         nt_errstr(error));
527                         return;
528                 }
529                 return;
530         }
531
532         outbody = smbd_smb2_generate_outbody(smb2req, 0x04);
533         if (outbody.data == NULL) {
534                 error = smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
535                 if (!NT_STATUS_IS_OK(error)) {
536                         smbd_server_connection_terminate(smb2req->xconn,
537                                                         nt_errstr(error));
538                         return;
539                 }
540                 return;
541         }
542
543         SSVAL(outbody.data, 0x00, 0x04);        /* struct size */
544         SSVAL(outbody.data, 0x02, 0);           /* reserved */
545
546         error = smbd_smb2_request_done(smb2req, outbody, NULL);
547         if (!NT_STATUS_IS_OK(error)) {
548                 smbd_server_connection_terminate(smb2req->xconn,
549                                                 nt_errstr(error));
550                 return;
551         }
552 }
553
554 struct smbd_smb2_tdis_state {
555         struct smbd_smb2_request *smb2req;
556         struct tevent_queue *wait_queue;
557 };
558
559 static void smbd_smb2_tdis_wait_done(struct tevent_req *subreq);
560
561 static struct tevent_req *smbd_smb2_tdis_send(TALLOC_CTX *mem_ctx,
562                                         struct tevent_context *ev,
563                                         struct smbd_smb2_request *smb2req)
564 {
565         struct tevent_req *req;
566         struct smbd_smb2_tdis_state *state;
567         struct tevent_req *subreq;
568         struct smbXsrv_connection *xconn = NULL;
569
570         req = tevent_req_create(mem_ctx, &state,
571                         struct smbd_smb2_tdis_state);
572         if (req == NULL) {
573                 return NULL;
574         }
575         state->smb2req = smb2req;
576
577         state->wait_queue = tevent_queue_create(state, "tdis_wait_queue");
578         if (tevent_req_nomem(state->wait_queue, req)) {
579                 return tevent_req_post(req, ev);
580         }
581
582         /*
583          * Make sure that no new request will be able to use this tcon.
584          */
585         smb2req->tcon->status = NT_STATUS_NETWORK_NAME_DELETED;
586
587         xconn = smb2req->xconn->client->connections;
588         for (; xconn != NULL; xconn = xconn->next) {
589                 struct smbd_smb2_request *preq;
590
591                 for (preq = xconn->smb2.requests; preq != NULL; preq = preq->next) {
592                         if (preq == smb2req) {
593                                 /* Can't cancel current request. */
594                                 continue;
595                         }
596                         if (preq->tcon != smb2req->tcon) {
597                                 /* Request on different tcon. */
598                                 continue;
599                         }
600
601                         /*
602                          * Never cancel anything in a compound
603                          * request. Way too hard to deal with
604                          * the result.
605                          */
606                         if (!preq->compound_related && preq->subreq != NULL) {
607                                 tevent_req_cancel(preq->subreq);
608                         }
609
610                         /*
611                          * Now wait until the request is finished.
612                          *
613                          * We don't set a callback, as we just want to block the
614                          * wait queue and the talloc_free() of the request will
615                          * remove the item from the wait queue.
616                          */
617                         subreq = tevent_queue_wait_send(preq, ev, state->wait_queue);
618                         if (tevent_req_nomem(subreq, req)) {
619                                 return tevent_req_post(req, ev);
620                         }
621                 }
622         }
623
624         /*
625          * Now we add our own waiter to the end of the queue,
626          * this way we get notified when all pending requests are finished
627          * and send to the socket.
628          */
629         subreq = tevent_queue_wait_send(state, ev, state->wait_queue);
630         if (tevent_req_nomem(subreq, req)) {
631                 return tevent_req_post(req, ev);
632         }
633         tevent_req_set_callback(subreq, smbd_smb2_tdis_wait_done, req);
634
635         return req;
636 }
637
638 static void smbd_smb2_tdis_wait_done(struct tevent_req *subreq)
639 {
640         struct tevent_req *req = tevent_req_callback_data(
641                 subreq, struct tevent_req);
642         struct smbd_smb2_tdis_state *state = tevent_req_data(
643                 req, struct smbd_smb2_tdis_state);
644         NTSTATUS status;
645
646         tevent_queue_wait_recv(subreq);
647         TALLOC_FREE(subreq);
648
649         /*
650          * As we've been awoken, we may have changed
651          * uid in the meantime. Ensure we're still
652          * root (SMB2_OP_TDIS has .as_root = true).
653          */
654         change_to_root_user();
655
656         status = smbXsrv_tcon_disconnect(state->smb2req->tcon,
657                                          state->smb2req->tcon->compat->vuid);
658         if (tevent_req_nterror(req, status)) {
659                 return;
660         }
661
662         /* We did tear down the tcon. */
663         TALLOC_FREE(state->smb2req->tcon);
664         tevent_req_done(req);
665 }
666
667 static NTSTATUS smbd_smb2_tdis_recv(struct tevent_req *req)
668 {
669         return tevent_req_simple_recv_ntstatus(req);
670 }