lib: Remove idtree from samba_util.h
[bbaumbach/samba-autobuild/.git] / source3 / libsmb / cli_smb2_fnum.c
1 /*
2    Unix SMB/CIFS implementation.
3    smb2 lib
4    Copyright (C) Jeremy Allison 2013
5    Copyright (C) Volker Lendecke 2013
6    Copyright (C) Stefan Metzmacher 2013
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 /*
23  This code is a thin wrapper around the existing
24  cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c,
25  but allows the handles to be mapped to uint16_t fnums,
26  which are easier for smbclient to use.
27 */
28
29 #include "includes.h"
30 #include "client.h"
31 #include "async_smb.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "cli_smb2_fnum.h"
34 #include "trans2.h"
35 #include "clirap.h"
36 #include "../libcli/smb/smb2_create_blob.h"
37 #include "libsmb/proto.h"
38 #include "lib/util/tevent_ntstatus.h"
39 #include "../libcli/security/security.h"
40 #include "../librpc/gen_ndr/ndr_security.h"
41 #include "lib/util_ea.h"
42 #include "librpc/gen_ndr/ndr_ioctl.h"
43 #include "ntioctl.h"
44 #include "librpc/gen_ndr/ndr_quota.h"
45 #include "lib/util/string_wrappers.h"
46 #include "lib/util/idtree.h"
47
48 struct smb2_hnd {
49         uint64_t fid_persistent;
50         uint64_t fid_volatile;
51 };
52
53 /*
54  * Handle mapping code.
55  */
56
57 /***************************************************************
58  Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
59  Ensures handle is owned by cli struct.
60 ***************************************************************/
61
62 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
63                                 const struct smb2_hnd *ph,      /* In */
64                                 uint16_t *pfnum)                /* Out */
65 {
66         int ret;
67         struct idr_context *idp = cli->smb2.open_handles;
68         struct smb2_hnd *owned_h = talloc_memdup(cli,
69                                                 ph,
70                                                 sizeof(struct smb2_hnd));
71
72         if (owned_h == NULL) {
73                 return NT_STATUS_NO_MEMORY;
74         }
75
76         if (idp == NULL) {
77                 /* Lazy init */
78                 cli->smb2.open_handles = idr_init(cli);
79                 if (cli->smb2.open_handles == NULL) {
80                         TALLOC_FREE(owned_h);
81                         return NT_STATUS_NO_MEMORY;
82                 }
83                 idp = cli->smb2.open_handles;
84         }
85
86         ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
87         if (ret == -1) {
88                 TALLOC_FREE(owned_h);
89                 return NT_STATUS_NO_MEMORY;
90         }
91
92         *pfnum = (uint16_t)ret;
93         return NT_STATUS_OK;
94 }
95
96 /***************************************************************
97  Return the smb2_hnd pointer associated with the given fnum.
98 ***************************************************************/
99
100 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
101                                 uint16_t fnum,          /* In */
102                                 struct smb2_hnd **pph)  /* Out */
103 {
104         struct idr_context *idp = cli->smb2.open_handles;
105
106         if (idp == NULL) {
107                 return NT_STATUS_INVALID_PARAMETER;
108         }
109         *pph = (struct smb2_hnd *)idr_find(idp, fnum);
110         if (*pph == NULL) {
111                 return NT_STATUS_INVALID_HANDLE;
112         }
113         return NT_STATUS_OK;
114 }
115
116 /***************************************************************
117  Delete the fnum to smb2_hnd mapping. Zeros out handle on
118  successful return.
119 ***************************************************************/
120
121 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
122                                 struct smb2_hnd **pph,  /* In */
123                                 uint16_t fnum)                  /* In */
124 {
125         struct idr_context *idp = cli->smb2.open_handles;
126         struct smb2_hnd *ph;
127
128         if (idp == NULL) {
129                 return NT_STATUS_INVALID_PARAMETER;
130         }
131
132         ph = (struct smb2_hnd *)idr_find(idp, fnum);
133         if (ph != *pph) {
134                 return NT_STATUS_INVALID_PARAMETER;
135         }
136         idr_remove(idp, fnum);
137         TALLOC_FREE(*pph);
138         return NT_STATUS_OK;
139 }
140
141 /***************************************************************
142  Oplock mapping code.
143 ***************************************************************/
144
145 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
146 {
147         if (create_flags & REQUEST_BATCH_OPLOCK) {
148                 return SMB2_OPLOCK_LEVEL_BATCH;
149         } else if (create_flags & REQUEST_OPLOCK) {
150                 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
151         }
152
153         /* create_flags doesn't do a level2 request. */
154         return SMB2_OPLOCK_LEVEL_NONE;
155 }
156
157 /***************************************************************
158  If we're on a DFS share, ensure we convert to a full DFS path
159  if this hasn't already been done.
160 ***************************************************************/
161
162 static char *smb2_dfs_share_path(TALLOC_CTX *ctx,
163                                  struct cli_state *cli,
164                                  char *path)
165 {
166         bool is_dfs = smbXcli_conn_dfs_supported(cli->conn) &&
167                         smbXcli_tcon_is_dfs_share(cli->smb2.tcon);
168         bool is_already_dfs_path = false;
169
170         if (!is_dfs) {
171                 return path;
172         }
173         is_already_dfs_path = cli_dfs_is_already_full_path(cli, path);
174         if (is_already_dfs_path) {
175                 return path;
176         }
177         if (path[0] == '\0') {
178                 return talloc_asprintf(ctx,
179                                        "%s\\%s",
180                                         smbXcli_conn_remote_name(cli->conn),
181                                         cli->share);
182         }
183         while (*path == '\\') {
184                 path++;
185         }
186         return talloc_asprintf(ctx,
187                                "%s\\%s\\%s",
188                                smbXcli_conn_remote_name(cli->conn),
189                                cli->share,
190                                path);
191 }
192
193 /***************************************************************
194  Small wrapper that allows SMB2 create to return a uint16_t fnum.
195 ***************************************************************/
196
197 struct cli_smb2_create_fnum_state {
198         struct cli_state *cli;
199         struct smb2_create_blobs in_cblobs;
200         struct smb2_create_blobs out_cblobs;
201         struct smb_create_returns cr;
202         struct symlink_reparse_struct *symlink;
203         uint16_t fnum;
204         struct tevent_req *subreq;
205 };
206
207 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
208 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
209
210 struct tevent_req *cli_smb2_create_fnum_send(
211         TALLOC_CTX *mem_ctx,
212         struct tevent_context *ev,
213         struct cli_state *cli,
214         const char *fname_in,
215         uint32_t create_flags,
216         uint32_t impersonation_level,
217         uint32_t desired_access,
218         uint32_t file_attributes,
219         uint32_t share_access,
220         uint32_t create_disposition,
221         uint32_t create_options,
222         const struct smb2_create_blobs *in_cblobs)
223 {
224         struct tevent_req *req, *subreq;
225         struct cli_smb2_create_fnum_state *state;
226         char *fname = NULL;
227         size_t fname_len = 0;
228         bool have_twrp;
229         NTTIME ntt;
230         NTSTATUS status;
231
232         req = tevent_req_create(mem_ctx, &state,
233                                 struct cli_smb2_create_fnum_state);
234         if (req == NULL) {
235                 return NULL;
236         }
237         state->cli = cli;
238
239         fname = talloc_strdup(state, fname_in);
240         if (tevent_req_nomem(fname, req)) {
241                 return tevent_req_post(req, ev);
242         }
243
244         if (cli->backup_intent) {
245                 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
246         }
247
248         /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
249         have_twrp = clistr_smb2_extract_snapshot_token(fname, &ntt);
250         if (have_twrp) {
251                 status = smb2_create_blob_add(
252                         state,
253                         &state->in_cblobs,
254                         SMB2_CREATE_TAG_TWRP,
255                         (DATA_BLOB) {
256                                 .data = (uint8_t *)&ntt,
257                                 .length = sizeof(ntt),
258                         });
259                 if (tevent_req_nterror(req, status)) {
260                         return tevent_req_post(req, ev);
261                 }
262         }
263
264         if (in_cblobs != NULL) {
265                 uint32_t i;
266                 for (i=0; i<in_cblobs->num_blobs; i++) {
267                         struct smb2_create_blob *b = &in_cblobs->blobs[i];
268                         status = smb2_create_blob_add(
269                                 state, &state->in_cblobs, b->tag, b->data);
270                         if (!NT_STATUS_IS_OK(status)) {
271                                 tevent_req_nterror(req, status);
272                                 return tevent_req_post(req, ev);
273                         }
274                 }
275         }
276
277         fname = smb2_dfs_share_path(state, cli, fname);
278         if (tevent_req_nomem(fname, req)) {
279                 return tevent_req_post(req, ev);
280         }
281         fname_len = strlen(fname);
282
283         /* SMB2 is pickier about pathnames. Ensure it doesn't
284            start in a '\' */
285         if (*fname == '\\') {
286                 fname++;
287                 fname_len--;
288         }
289
290         /* Or end in a '\' */
291         if (fname_len > 0 && fname[fname_len-1] == '\\') {
292                 fname[fname_len-1] = '\0';
293         }
294
295         subreq = smb2cli_create_send(state, ev,
296                                      cli->conn,
297                                      cli->timeout,
298                                      cli->smb2.session,
299                                      cli->smb2.tcon,
300                                      fname,
301                                      flags_to_smb2_oplock(create_flags),
302                                      impersonation_level,
303                                      desired_access,
304                                      file_attributes,
305                                      share_access,
306                                      create_disposition,
307                                      create_options,
308                                      &state->in_cblobs);
309         if (tevent_req_nomem(subreq, req)) {
310                 return tevent_req_post(req, ev);
311         }
312         tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
313
314         state->subreq = subreq;
315         tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
316
317         return req;
318 }
319
320 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
321 {
322         struct tevent_req *req = tevent_req_callback_data(
323                 subreq, struct tevent_req);
324         struct cli_smb2_create_fnum_state *state = tevent_req_data(
325                 req, struct cli_smb2_create_fnum_state);
326         struct smb2_hnd h;
327         NTSTATUS status;
328
329         status = smb2cli_create_recv(
330                 subreq,
331                 &h.fid_persistent,
332                 &h.fid_volatile, &state->cr,
333                 state,
334                 &state->out_cblobs,
335                 &state->symlink);
336         TALLOC_FREE(subreq);
337         if (tevent_req_nterror(req, status)) {
338                 return;
339         }
340
341         status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
342         if (tevent_req_nterror(req, status)) {
343                 return;
344         }
345         tevent_req_done(req);
346 }
347
348 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
349 {
350         struct cli_smb2_create_fnum_state *state = tevent_req_data(
351                 req, struct cli_smb2_create_fnum_state);
352         return tevent_req_cancel(state->subreq);
353 }
354
355 NTSTATUS cli_smb2_create_fnum_recv(
356         struct tevent_req *req,
357         uint16_t *pfnum,
358         struct smb_create_returns *cr,
359         TALLOC_CTX *mem_ctx,
360         struct smb2_create_blobs *out_cblobs,
361         struct symlink_reparse_struct **symlink)
362 {
363         struct cli_smb2_create_fnum_state *state = tevent_req_data(
364                 req, struct cli_smb2_create_fnum_state);
365         NTSTATUS status;
366
367         if (tevent_req_is_nterror(req, &status)) {
368                 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) &&
369                     (symlink != NULL)) {
370                         *symlink = talloc_move(mem_ctx, &state->symlink);
371                 }
372                 state->cli->raw_status = status;
373                 return status;
374         }
375         if (pfnum != NULL) {
376                 *pfnum = state->fnum;
377         }
378         if (cr != NULL) {
379                 *cr = state->cr;
380         }
381         if (out_cblobs != NULL) {
382                 *out_cblobs = (struct smb2_create_blobs) {
383                         .num_blobs = state->out_cblobs.num_blobs,
384                         .blobs = talloc_move(
385                                 mem_ctx, &state->out_cblobs.blobs),
386                 };
387         }
388         state->cli->raw_status = NT_STATUS_OK;
389         return NT_STATUS_OK;
390 }
391
392 NTSTATUS cli_smb2_create_fnum(
393         struct cli_state *cli,
394         const char *fname,
395         uint32_t create_flags,
396         uint32_t impersonation_level,
397         uint32_t desired_access,
398         uint32_t file_attributes,
399         uint32_t share_access,
400         uint32_t create_disposition,
401         uint32_t create_options,
402         const struct smb2_create_blobs *in_cblobs,
403         uint16_t *pfid,
404         struct smb_create_returns *cr,
405         TALLOC_CTX *mem_ctx,
406         struct smb2_create_blobs *out_cblobs)
407 {
408         TALLOC_CTX *frame = talloc_stackframe();
409         struct tevent_context *ev;
410         struct tevent_req *req;
411         NTSTATUS status = NT_STATUS_NO_MEMORY;
412
413         if (smbXcli_conn_has_async_calls(cli->conn)) {
414                 /*
415                  * Can't use sync call while an async call is in flight
416                  */
417                 status = NT_STATUS_INVALID_PARAMETER;
418                 goto fail;
419         }
420         ev = samba_tevent_context_init(frame);
421         if (ev == NULL) {
422                 goto fail;
423         }
424         req = cli_smb2_create_fnum_send(
425                 frame,
426                 ev,
427                 cli,
428                 fname,
429                 create_flags,
430                 impersonation_level,
431                 desired_access,
432                 file_attributes,
433                 share_access,
434                 create_disposition,
435                 create_options,
436                 in_cblobs);
437         if (req == NULL) {
438                 goto fail;
439         }
440         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
441                 goto fail;
442         }
443         status = cli_smb2_create_fnum_recv(
444                 req, pfid, cr, mem_ctx, out_cblobs, NULL);
445  fail:
446         TALLOC_FREE(frame);
447         return status;
448 }
449
450 /***************************************************************
451  Small wrapper that allows SMB2 close to use a uint16_t fnum.
452 ***************************************************************/
453
454 struct cli_smb2_close_fnum_state {
455         struct cli_state *cli;
456         uint16_t fnum;
457         struct smb2_hnd *ph;
458 };
459
460 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
461
462 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
463                                             struct tevent_context *ev,
464                                             struct cli_state *cli,
465                                             uint16_t fnum)
466 {
467         struct tevent_req *req, *subreq;
468         struct cli_smb2_close_fnum_state *state;
469         NTSTATUS status;
470
471         req = tevent_req_create(mem_ctx, &state,
472                                 struct cli_smb2_close_fnum_state);
473         if (req == NULL) {
474                 return NULL;
475         }
476         state->cli = cli;
477         state->fnum = fnum;
478
479         status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
480         if (tevent_req_nterror(req, status)) {
481                 return tevent_req_post(req, ev);
482         }
483
484         subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
485                                     cli->smb2.session, cli->smb2.tcon,
486                                     0, state->ph->fid_persistent,
487                                     state->ph->fid_volatile);
488         if (tevent_req_nomem(subreq, req)) {
489                 return tevent_req_post(req, ev);
490         }
491         tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
492         return req;
493 }
494
495 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
496 {
497         struct tevent_req *req = tevent_req_callback_data(
498                 subreq, struct tevent_req);
499         struct cli_smb2_close_fnum_state *state = tevent_req_data(
500                 req, struct cli_smb2_close_fnum_state);
501         NTSTATUS status;
502
503         status = smb2cli_close_recv(subreq);
504         if (tevent_req_nterror(req, status)) {
505                 return;
506         }
507
508         /* Delete the fnum -> handle mapping. */
509         status = delete_smb2_handle_mapping(state->cli, &state->ph,
510                                             state->fnum);
511         if (tevent_req_nterror(req, status)) {
512                 return;
513         }
514         tevent_req_done(req);
515 }
516
517 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
518 {
519         struct cli_smb2_close_fnum_state *state = tevent_req_data(
520                 req, struct cli_smb2_close_fnum_state);
521         NTSTATUS status = NT_STATUS_OK;
522
523         if (tevent_req_is_nterror(req, &status)) {
524                 state->cli->raw_status = status;
525         }
526         tevent_req_received(req);
527         return status;
528 }
529
530 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
531 {
532         TALLOC_CTX *frame = talloc_stackframe();
533         struct tevent_context *ev;
534         struct tevent_req *req;
535         NTSTATUS status = NT_STATUS_NO_MEMORY;
536
537         if (smbXcli_conn_has_async_calls(cli->conn)) {
538                 /*
539                  * Can't use sync call while an async call is in flight
540                  */
541                 status = NT_STATUS_INVALID_PARAMETER;
542                 goto fail;
543         }
544         ev = samba_tevent_context_init(frame);
545         if (ev == NULL) {
546                 goto fail;
547         }
548         req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
549         if (req == NULL) {
550                 goto fail;
551         }
552         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
553                 goto fail;
554         }
555         status = cli_smb2_close_fnum_recv(req);
556  fail:
557         TALLOC_FREE(frame);
558         return status;
559 }
560
561 struct cli_smb2_set_info_fnum_state {
562         uint8_t dummy;
563 };
564
565 static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq);
566
567 struct tevent_req *cli_smb2_set_info_fnum_send(
568         TALLOC_CTX *mem_ctx,
569         struct tevent_context *ev,
570         struct cli_state *cli,
571         uint16_t fnum,
572         uint8_t in_info_type,
573         uint8_t in_info_class,
574         const DATA_BLOB *in_input_buffer,
575         uint32_t in_additional_info)
576 {
577         struct tevent_req *req = NULL, *subreq = NULL;
578         struct cli_smb2_set_info_fnum_state *state = NULL;
579         struct smb2_hnd *ph = NULL;
580         NTSTATUS status;
581
582         req = tevent_req_create(
583                 mem_ctx, &state, struct cli_smb2_set_info_fnum_state);
584         if (req == NULL) {
585                 return NULL;
586         }
587
588         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
589         if (tevent_req_nterror(req, status)) {
590                 return tevent_req_post(req, ev);
591         }
592
593         subreq = smb2cli_set_info_send(
594                 state,
595                 ev,
596                 cli->conn,
597                 cli->timeout,
598                 cli->smb2.session,
599                 cli->smb2.tcon,
600                 in_info_type,
601                 in_info_class,
602                 in_input_buffer,
603                 in_additional_info,
604                 ph->fid_persistent,
605                 ph->fid_volatile);
606         if (tevent_req_nomem(subreq, req)) {
607                 return tevent_req_post(req, ev);
608         }
609         tevent_req_set_callback(subreq, cli_smb2_set_info_fnum_done, req);
610         return req;
611 }
612
613 static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq)
614 {
615         NTSTATUS status = smb2cli_set_info_recv(subreq);
616         tevent_req_simple_finish_ntstatus(subreq, status);
617 }
618
619 NTSTATUS cli_smb2_set_info_fnum_recv(struct tevent_req *req)
620 {
621         return tevent_req_simple_recv_ntstatus(req);
622 }
623
624 NTSTATUS cli_smb2_set_info_fnum(
625         struct cli_state *cli,
626         uint16_t fnum,
627         uint8_t in_info_type,
628         uint8_t in_info_class,
629         const DATA_BLOB *in_input_buffer,
630         uint32_t in_additional_info)
631 {
632         TALLOC_CTX *frame = talloc_stackframe();
633         struct tevent_context *ev = NULL;
634         struct tevent_req *req = NULL;
635         NTSTATUS status = NT_STATUS_NO_MEMORY;
636         bool ok;
637
638         if (smbXcli_conn_has_async_calls(cli->conn)) {
639                 /*
640                  * Can't use sync call while an async call is in flight
641                  */
642                 status = NT_STATUS_INVALID_PARAMETER;
643                 goto fail;
644         }
645         ev = samba_tevent_context_init(frame);
646         if (ev == NULL) {
647                 goto fail;
648         }
649         req = cli_smb2_set_info_fnum_send(
650                 frame,
651                 ev,
652                 cli,
653                 fnum,
654                 in_info_type,
655                 in_info_class,
656                 in_input_buffer,
657                 in_additional_info);
658         if (req == NULL) {
659                 goto fail;
660         }
661         ok = tevent_req_poll_ntstatus(req, ev, &status);
662         if (!ok) {
663                 goto fail;
664         }
665         status = cli_smb2_set_info_fnum_recv(req);
666 fail:
667         TALLOC_FREE(frame);
668         return status;
669 }
670
671 struct cli_smb2_delete_on_close_state {
672         struct cli_state *cli;
673         uint8_t data[1];
674         DATA_BLOB inbuf;
675 };
676
677 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
678
679 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
680                                         struct tevent_context *ev,
681                                         struct cli_state *cli,
682                                         uint16_t fnum,
683                                         bool flag)
684 {
685         struct tevent_req *req = NULL;
686         struct cli_smb2_delete_on_close_state *state = NULL;
687         struct tevent_req *subreq = NULL;
688         uint8_t in_info_type;
689         uint8_t in_file_info_class;
690
691         req = tevent_req_create(mem_ctx, &state,
692                                 struct cli_smb2_delete_on_close_state);
693         if (req == NULL) {
694                 return NULL;
695         }
696         state->cli = cli;
697
698         /*
699          * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
700          * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
701          */
702         in_info_type = 1;
703         in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
704         /* Setup data array. */
705         SCVAL(&state->data[0], 0, flag ? 1 : 0);
706         state->inbuf.data = &state->data[0];
707         state->inbuf.length = 1;
708
709         subreq = cli_smb2_set_info_fnum_send(
710                 state,
711                 ev,
712                 cli,
713                 fnum,
714                 in_info_type,
715                 in_file_info_class,
716                 &state->inbuf,
717                 0);
718         if (tevent_req_nomem(subreq, req)) {
719                 return tevent_req_post(req, ev);
720         }
721         tevent_req_set_callback(subreq,
722                                 cli_smb2_delete_on_close_done,
723                                 req);
724         return req;
725 }
726
727 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
728 {
729         NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
730         tevent_req_simple_finish_ntstatus(subreq, status);
731 }
732
733 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
734 {
735         struct cli_smb2_delete_on_close_state *state =
736                 tevent_req_data(req,
737                 struct cli_smb2_delete_on_close_state);
738         NTSTATUS status;
739
740         if (tevent_req_is_nterror(req, &status)) {
741                 state->cli->raw_status = status;
742                 tevent_req_received(req);
743                 return status;
744         }
745
746         state->cli->raw_status = NT_STATUS_OK;
747         tevent_req_received(req);
748         return NT_STATUS_OK;
749 }
750
751 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
752 {
753         TALLOC_CTX *frame = talloc_stackframe();
754         struct tevent_context *ev;
755         struct tevent_req *req;
756         NTSTATUS status = NT_STATUS_NO_MEMORY;
757
758         if (smbXcli_conn_has_async_calls(cli->conn)) {
759                 /*
760                  * Can't use sync call while an async call is in flight
761                  */
762                 status = NT_STATUS_INVALID_PARAMETER;
763                 goto fail;
764         }
765         ev = samba_tevent_context_init(frame);
766         if (ev == NULL) {
767                 goto fail;
768         }
769         req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
770         if (req == NULL) {
771                 goto fail;
772         }
773         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
774                 goto fail;
775         }
776         status = cli_smb2_delete_on_close_recv(req);
777  fail:
778         TALLOC_FREE(frame);
779         return status;
780 }
781
782 struct cli_smb2_mkdir_state {
783         struct tevent_context *ev;
784         struct cli_state *cli;
785 };
786
787 static void cli_smb2_mkdir_opened(struct tevent_req *subreq);
788 static void cli_smb2_mkdir_closed(struct tevent_req *subreq);
789
790 struct tevent_req *cli_smb2_mkdir_send(
791         TALLOC_CTX *mem_ctx,
792         struct tevent_context *ev,
793         struct cli_state *cli,
794         const char *dname)
795 {
796         struct tevent_req *req = NULL, *subreq = NULL;
797         struct cli_smb2_mkdir_state *state = NULL;
798
799         req = tevent_req_create(
800                 mem_ctx, &state, struct cli_smb2_mkdir_state);
801         if (req == NULL) {
802                 return NULL;
803         }
804         state->ev = ev;
805         state->cli = cli;
806
807         /* Ensure this is a directory. */
808         subreq = cli_smb2_create_fnum_send(
809                 state,                             /* mem_ctx */
810                 ev,                                /* ev */
811                 cli,                               /* cli */
812                 dname,                             /* fname */
813                 0,                                 /* create_flags */
814                 SMB2_IMPERSONATION_IMPERSONATION,  /* impersonation_level */
815                 FILE_READ_ATTRIBUTES,              /* desired_access */
816                 FILE_ATTRIBUTE_DIRECTORY,          /* file_attributes */
817                 FILE_SHARE_READ|
818                 FILE_SHARE_WRITE,                  /* share_access */
819                 FILE_CREATE,                       /* create_disposition */
820                 FILE_DIRECTORY_FILE,               /* create_options */
821                 NULL);                             /* in_cblobs */
822         if (tevent_req_nomem(subreq, req)) {
823                 return tevent_req_post(req, ev);
824         }
825         tevent_req_set_callback(subreq, cli_smb2_mkdir_opened, req);
826         return req;
827 }
828
829 static void cli_smb2_mkdir_opened(struct tevent_req *subreq)
830 {
831         struct tevent_req *req = tevent_req_callback_data(
832                 subreq, struct tevent_req);
833         struct cli_smb2_mkdir_state *state = tevent_req_data(
834                 req, struct cli_smb2_mkdir_state);
835         NTSTATUS status;
836         uint16_t fnum = 0xffff;
837
838         status = cli_smb2_create_fnum_recv(
839                 subreq, &fnum, NULL, NULL, NULL, NULL);
840         TALLOC_FREE(subreq);
841         if (tevent_req_nterror(req, status)) {
842                 return;
843         }
844
845         subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
846         if (tevent_req_nomem(subreq, req)) {
847                 return;
848         }
849         tevent_req_set_callback(subreq, cli_smb2_mkdir_closed, req);
850 }
851
852 static void cli_smb2_mkdir_closed(struct tevent_req *subreq)
853 {
854         NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
855         tevent_req_simple_finish_ntstatus(subreq, status);
856 }
857
858 NTSTATUS cli_smb2_mkdir_recv(struct tevent_req *req)
859 {
860         return tevent_req_simple_recv_ntstatus(req);
861 }
862
863 struct cli_smb2_rmdir_state {
864         struct tevent_context *ev;
865         struct cli_state *cli;
866         const char *dname;
867         const struct smb2_create_blobs *in_cblobs;
868         uint16_t fnum;
869         NTSTATUS status;
870 };
871
872 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq);
873 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq);
874 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq);
875 static void cli_smb2_rmdir_closed(struct tevent_req *subreq);
876
877 struct tevent_req *cli_smb2_rmdir_send(
878         TALLOC_CTX *mem_ctx,
879         struct tevent_context *ev,
880         struct cli_state *cli,
881         const char *dname,
882         const struct smb2_create_blobs *in_cblobs)
883 {
884         struct tevent_req *req = NULL, *subreq = NULL;
885         struct cli_smb2_rmdir_state *state = NULL;
886
887         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_rmdir_state);
888         if (req == NULL) {
889                 return NULL;
890         }
891         state->ev = ev;
892         state->cli = cli;
893         state->dname = dname;
894         state->in_cblobs = in_cblobs;
895
896         subreq = cli_smb2_create_fnum_send(
897                 state,
898                 state->ev,
899                 state->cli,
900                 state->dname,
901                 0,                      /* create_flags */
902                 SMB2_IMPERSONATION_IMPERSONATION,
903                 DELETE_ACCESS,          /* desired_access */
904                 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
905                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
906                 FILE_OPEN,              /* create_disposition */
907                 FILE_DIRECTORY_FILE,    /* create_options */
908                 state->in_cblobs);      /* in_cblobs */
909         if (tevent_req_nomem(subreq, req)) {
910                 return tevent_req_post(req, ev);
911         }
912         tevent_req_set_callback(subreq, cli_smb2_rmdir_opened1, req);
913         return req;
914 }
915
916 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq)
917 {
918         struct tevent_req *req = tevent_req_callback_data(
919                 subreq, struct tevent_req);
920         struct cli_smb2_rmdir_state *state = tevent_req_data(
921                 req, struct cli_smb2_rmdir_state);
922         NTSTATUS status;
923
924         status = cli_smb2_create_fnum_recv(
925                 subreq, &state->fnum, NULL, NULL, NULL, NULL);
926         TALLOC_FREE(subreq);
927
928         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
929                 /*
930                  * Naive option to match our SMB1 code. Assume the
931                  * symlink path that tripped us up was the last
932                  * component and try again. Eventually we will have to
933                  * deal with the returned path unprocessed component. JRA.
934                  */
935                 subreq = cli_smb2_create_fnum_send(
936                         state,
937                         state->ev,
938                         state->cli,
939                         state->dname,
940                         0,                      /* create_flags */
941                         SMB2_IMPERSONATION_IMPERSONATION,
942                         DELETE_ACCESS,          /* desired_access */
943                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
944                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
945                         FILE_OPEN,              /* create_disposition */
946                         FILE_DIRECTORY_FILE|
947                         FILE_DELETE_ON_CLOSE|
948                         FILE_OPEN_REPARSE_POINT, /* create_options */
949                         state->in_cblobs);       /* in_cblobs */
950                 if (tevent_req_nomem(subreq, req)) {
951                         return;
952                 }
953                 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened2, req);
954                 return;
955         }
956
957         if (tevent_req_nterror(req, status)) {
958                 return;
959         }
960
961         subreq = cli_smb2_delete_on_close_send(
962                 state, state->ev, state->cli, state->fnum, true);
963         if (tevent_req_nomem(subreq, req)) {
964                 return;
965         }
966         tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
967 }
968
969 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq)
970 {
971         struct tevent_req *req = tevent_req_callback_data(
972                 subreq, struct tevent_req);
973         struct cli_smb2_rmdir_state *state = tevent_req_data(
974                 req, struct cli_smb2_rmdir_state);
975         NTSTATUS status;
976
977         status = cli_smb2_create_fnum_recv(
978                 subreq, &state->fnum, NULL, NULL, NULL, NULL);
979         TALLOC_FREE(subreq);
980         if (tevent_req_nterror(req, status)) {
981                 return;
982         }
983
984         subreq = cli_smb2_delete_on_close_send(
985                 state, state->ev, state->cli, state->fnum, true);
986         if (tevent_req_nomem(subreq, req)) {
987                 return;
988         }
989         tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
990 }
991
992 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq)
993 {
994         struct tevent_req *req = tevent_req_callback_data(
995                 subreq, struct tevent_req);
996         struct cli_smb2_rmdir_state *state = tevent_req_data(
997                 req, struct cli_smb2_rmdir_state);
998
999         state->status = cli_smb2_delete_on_close_recv(subreq);
1000         TALLOC_FREE(subreq);
1001
1002         /*
1003          * Close the fd even if the set_disp failed
1004          */
1005
1006         subreq = cli_smb2_close_fnum_send(
1007                 state, state->ev, state->cli, state->fnum);
1008         if (tevent_req_nomem(subreq, req)) {
1009                 return;
1010         }
1011         tevent_req_set_callback(subreq, cli_smb2_rmdir_closed, req);
1012 }
1013
1014 static void cli_smb2_rmdir_closed(struct tevent_req *subreq)
1015 {
1016         NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1017         tevent_req_simple_finish_ntstatus(subreq, status);
1018 }
1019
1020 NTSTATUS cli_smb2_rmdir_recv(struct tevent_req *req)
1021 {
1022         struct cli_smb2_rmdir_state *state = tevent_req_data(
1023                 req, struct cli_smb2_rmdir_state);
1024         NTSTATUS status;
1025
1026         if (tevent_req_is_nterror(req, &status)) {
1027                 return status;
1028         }
1029         return state->status;
1030 }
1031
1032 /***************************************************************
1033  Small wrapper that allows SMB2 to unlink a pathname.
1034 ***************************************************************/
1035
1036 struct cli_smb2_unlink_state {
1037         struct tevent_context *ev;
1038         struct cli_state *cli;
1039         const char *fname;
1040         const struct smb2_create_blobs *in_cblobs;
1041 };
1042
1043 static void cli_smb2_unlink_opened1(struct tevent_req *subreq);
1044 static void cli_smb2_unlink_opened2(struct tevent_req *subreq);
1045 static void cli_smb2_unlink_closed(struct tevent_req *subreq);
1046
1047 struct tevent_req *cli_smb2_unlink_send(
1048         TALLOC_CTX *mem_ctx,
1049         struct tevent_context *ev,
1050         struct cli_state *cli,
1051         const char *fname,
1052         const struct smb2_create_blobs *in_cblobs)
1053 {
1054         struct tevent_req *req = NULL, *subreq = NULL;
1055         struct cli_smb2_unlink_state *state = NULL;
1056
1057         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_unlink_state);
1058         if (req == NULL) {
1059                 return NULL;
1060         }
1061         state->ev = ev;
1062         state->cli = cli;
1063         state->fname = fname;
1064         state->in_cblobs = in_cblobs;
1065
1066         subreq = cli_smb2_create_fnum_send(
1067                 state,          /* mem_ctx */
1068                 state->ev,      /* tevent_context */
1069                 state->cli,     /* cli_struct */
1070                 state->fname,   /* filename */
1071                 0,                      /* create_flags */
1072                 SMB2_IMPERSONATION_IMPERSONATION,
1073                 DELETE_ACCESS,          /* desired_access */
1074                 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1075                 FILE_SHARE_READ|
1076                 FILE_SHARE_WRITE|
1077                 FILE_SHARE_DELETE, /* share_access */
1078                 FILE_OPEN,              /* create_disposition */
1079                 FILE_DELETE_ON_CLOSE,   /* create_options */
1080                 state->in_cblobs);      /* in_cblobs */
1081         if (tevent_req_nomem(subreq, req)) {
1082                 return tevent_req_post(req, ev);
1083         }
1084         tevent_req_set_callback(subreq, cli_smb2_unlink_opened1, req);
1085         return req;
1086 }
1087
1088 static void cli_smb2_unlink_opened1(struct tevent_req *subreq)
1089 {
1090         struct tevent_req *req = tevent_req_callback_data(
1091                 subreq, struct tevent_req);
1092         struct cli_smb2_unlink_state *state = tevent_req_data(
1093                 req, struct cli_smb2_unlink_state);
1094         uint16_t fnum = 0xffff;
1095         NTSTATUS status;
1096
1097         status = cli_smb2_create_fnum_recv(
1098                 subreq, &fnum, NULL, NULL, NULL, NULL);
1099         TALLOC_FREE(subreq);
1100
1101         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) ||
1102             NT_STATUS_EQUAL(status, NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED)) {
1103                 /*
1104                  * Naive option to match our SMB1 code. Assume the
1105                  * symlink path that tripped us up was the last
1106                  * component and try again. Eventually we will have to
1107                  * deal with the returned path unprocessed component. JRA.
1108                  */
1109                 subreq = cli_smb2_create_fnum_send(
1110                         state,          /* mem_ctx */
1111                         state->ev,      /* tevent_context */
1112                         state->cli,     /* cli_struct */
1113                         state->fname,   /* filename */
1114                         0,                      /* create_flags */
1115                         SMB2_IMPERSONATION_IMPERSONATION,
1116                         DELETE_ACCESS,          /* desired_access */
1117                         FILE_ATTRIBUTE_NORMAL, /* file attributes */
1118                         FILE_SHARE_READ|
1119                         FILE_SHARE_WRITE|
1120                         FILE_SHARE_DELETE, /* share_access */
1121                         FILE_OPEN,              /* create_disposition */
1122                         FILE_DELETE_ON_CLOSE|
1123                         FILE_OPEN_REPARSE_POINT, /* create_options */
1124                         state->in_cblobs);       /* in_cblobs */
1125                 if (tevent_req_nomem(subreq, req)) {
1126                         return;
1127                 }
1128                 tevent_req_set_callback(subreq, cli_smb2_unlink_opened2, req);
1129                 return;
1130         }
1131
1132         if (tevent_req_nterror(req, status)) {
1133                 return;
1134         }
1135
1136         subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1137         if (tevent_req_nomem(subreq, req)) {
1138                 return;
1139         }
1140         tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1141 }
1142
1143 static void cli_smb2_unlink_opened2(struct tevent_req *subreq)
1144 {
1145         struct tevent_req *req = tevent_req_callback_data(
1146                 subreq, struct tevent_req);
1147         struct cli_smb2_unlink_state *state = tevent_req_data(
1148                 req, struct cli_smb2_unlink_state);
1149         uint16_t fnum = 0xffff;
1150         NTSTATUS status;
1151
1152         status = cli_smb2_create_fnum_recv(
1153                 subreq, &fnum, NULL, NULL, NULL, NULL);
1154         TALLOC_FREE(subreq);
1155         if (tevent_req_nterror(req, status)) {
1156                 return;
1157         }
1158
1159         subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1160         if (tevent_req_nomem(subreq, req)) {
1161                 return;
1162         }
1163         tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1164 }
1165
1166 static void cli_smb2_unlink_closed(struct tevent_req *subreq)
1167 {
1168         NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1169         tevent_req_simple_finish_ntstatus(subreq, status);
1170 }
1171
1172 NTSTATUS cli_smb2_unlink_recv(struct tevent_req *req)
1173 {
1174         return tevent_req_simple_recv_ntstatus(req);
1175 }
1176
1177 static ssize_t sid_parse_wire(TALLOC_CTX *mem_ctx, const uint8_t *data,
1178                               struct dom_sid *sid, size_t num_rdata)
1179 {
1180         size_t sid_size;
1181         enum ndr_err_code ndr_err;
1182         DATA_BLOB in = data_blob_const(data, num_rdata);
1183
1184         ndr_err = ndr_pull_struct_blob(&in,
1185                                        mem_ctx,
1186                                        sid,
1187                                        (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
1188         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1189                 return 0;
1190         }
1191
1192         sid_size = ndr_size_dom_sid(sid, 0);
1193         if (sid_size > num_rdata) {
1194                 return 0;
1195         }
1196
1197         return sid_size;
1198 }
1199
1200 /***************************************************************
1201  Utility function to parse a SMB2_FIND_POSIX_INFORMATION reply.
1202 ***************************************************************/
1203
1204 static NTSTATUS parse_finfo_posix_info(const uint8_t *dir_data,
1205                                        uint32_t dir_data_length,
1206                                        struct file_info *finfo,
1207                                        uint32_t *next_offset)
1208 {
1209         size_t namelen = 0;
1210         size_t slen = 0, slen2 = 0;
1211         size_t ret = 0;
1212         uint32_t _next_offset = 0;
1213
1214         if (dir_data_length < 4) {
1215                 return NT_STATUS_INFO_LENGTH_MISMATCH;
1216         }
1217
1218         _next_offset = IVAL(dir_data, 0);
1219
1220         if (_next_offset > dir_data_length) {
1221                 return NT_STATUS_INFO_LENGTH_MISMATCH;
1222         }
1223
1224         if (_next_offset != 0) {
1225                 /* Ensure we only read what in this record. */
1226                 dir_data_length = _next_offset;
1227         }
1228
1229         if (dir_data_length < 92) {
1230                 return NT_STATUS_INFO_LENGTH_MISMATCH;
1231         }
1232
1233         finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
1234         finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
1235         finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
1236         finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
1237         finfo->allocated_size = PULL_LE_U64(dir_data, 40);
1238         finfo->size = PULL_LE_U64(dir_data, 48);
1239         finfo->mode = PULL_LE_U32(dir_data, 56);
1240         finfo->ino = PULL_LE_U64(dir_data, 60);
1241         finfo->st_ex_dev = PULL_LE_U32(dir_data, 68);
1242         finfo->st_ex_nlink = PULL_LE_U32(dir_data, 76);
1243         finfo->reparse_tag = PULL_LE_U32(dir_data, 80);
1244         finfo->st_ex_mode = wire_perms_to_unix(PULL_LE_U32(dir_data, 84));
1245
1246         slen = sid_parse_wire(finfo, dir_data+88, &finfo->owner_sid,
1247                               dir_data_length-88);
1248         if (slen == 0) {
1249                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1250         }
1251         slen2 = sid_parse_wire(finfo, dir_data+88+slen, &finfo->group_sid,
1252                                dir_data_length-88-slen);
1253         if (slen2 == 0) {
1254                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1255         }
1256         slen += slen2;
1257
1258         namelen = PULL_LE_U32(dir_data, 88+slen);
1259         ret = pull_string_talloc(finfo,
1260                                 dir_data,
1261                                 FLAGS2_UNICODE_STRINGS,
1262                                 &finfo->name,
1263                                 dir_data+92+slen,
1264                                 namelen,
1265                                 STR_UNICODE);
1266         if (ret == (size_t)-1) {
1267                 /* Bad conversion. */
1268                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1269         }
1270
1271         if (finfo->name == NULL) {
1272                 /* Bad conversion. */
1273                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1274         }
1275
1276         *next_offset = _next_offset;
1277         return NT_STATUS_OK;
1278 }
1279
1280 /***************************************************************
1281  Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1282 ***************************************************************/
1283
1284 static NTSTATUS parse_finfo_id_both_directory_info(const uint8_t *dir_data,
1285                                 uint32_t dir_data_length,
1286                                 struct file_info *finfo,
1287                                 uint32_t *next_offset)
1288 {
1289         size_t namelen = 0;
1290         size_t slen = 0;
1291         size_t ret = 0;
1292
1293         if (dir_data_length < 4) {
1294                 return NT_STATUS_INFO_LENGTH_MISMATCH;
1295         }
1296
1297         *next_offset = IVAL(dir_data, 0);
1298
1299         if (*next_offset > dir_data_length) {
1300                 return NT_STATUS_INFO_LENGTH_MISMATCH;
1301         }
1302
1303         if (*next_offset != 0) {
1304                 /* Ensure we only read what in this record. */
1305                 dir_data_length = *next_offset;
1306         }
1307
1308         if (dir_data_length < 105) {
1309                 return NT_STATUS_INFO_LENGTH_MISMATCH;
1310         }
1311
1312         finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
1313         finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
1314         finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
1315         finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
1316         finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
1317         finfo->allocated_size = IVAL2_TO_SMB_BIG_UINT(dir_data + 48, 0);
1318         finfo->attr = IVAL(dir_data + 56, 0);
1319         finfo->ino = IVAL2_TO_SMB_BIG_UINT(dir_data + 96, 0);
1320         namelen = IVAL(dir_data + 60,0);
1321         if (namelen > (dir_data_length - 104)) {
1322                 return NT_STATUS_INFO_LENGTH_MISMATCH;
1323         }
1324         slen = CVAL(dir_data + 68, 0);
1325         if (slen > 24) {
1326                 return NT_STATUS_INFO_LENGTH_MISMATCH;
1327         }
1328         ret = pull_string_talloc(finfo,
1329                                 dir_data,
1330                                 FLAGS2_UNICODE_STRINGS,
1331                                 &finfo->short_name,
1332                                 dir_data + 70,
1333                                 slen,
1334                                 STR_UNICODE);
1335         if (ret == (size_t)-1) {
1336                 /* Bad conversion. */
1337                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1338         }
1339
1340         ret = pull_string_talloc(finfo,
1341                                 dir_data,
1342                                 FLAGS2_UNICODE_STRINGS,
1343                                 &finfo->name,
1344                                 dir_data + 104,
1345                                 namelen,
1346                                 STR_UNICODE);
1347         if (ret == (size_t)-1) {
1348                 /* Bad conversion. */
1349                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1350         }
1351
1352         if (finfo->name == NULL) {
1353                 /* Bad conversion. */
1354                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1355         }
1356
1357         return NT_STATUS_OK;
1358 }
1359
1360 /*******************************************************************
1361  Given a filename - get its directory name
1362 ********************************************************************/
1363
1364 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
1365                                 const char *dir,
1366                                 char **parent,
1367                                 const char **name)
1368 {
1369         char *p;
1370         ptrdiff_t len;
1371
1372         p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
1373
1374         if (p == NULL) {
1375                 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
1376                         return false;
1377                 }
1378                 if (name) {
1379                         *name = dir;
1380                 }
1381                 return true;
1382         }
1383
1384         len = p-dir;
1385
1386         if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
1387                 return false;
1388         }
1389         (*parent)[len] = '\0';
1390
1391         if (name) {
1392                 *name = p+1;
1393         }
1394         return true;
1395 }
1396
1397 struct cli_smb2_list_dir_data {
1398         uint8_t *data;
1399         uint32_t length;
1400 };
1401
1402 struct cli_smb2_list_state {
1403         struct tevent_context *ev;
1404         struct cli_state *cli;
1405         const char *mask;
1406
1407         uint16_t fnum;
1408
1409         NTSTATUS status;
1410         struct cli_smb2_list_dir_data *response;
1411         uint32_t offset;
1412         unsigned int info_level;
1413 };
1414
1415 static void cli_smb2_list_opened(struct tevent_req *subreq);
1416 static void cli_smb2_list_done(struct tevent_req *subreq);
1417 static void cli_smb2_list_closed(struct tevent_req *subreq);
1418
1419 struct tevent_req *cli_smb2_list_send(
1420         TALLOC_CTX *mem_ctx,
1421         struct tevent_context *ev,
1422         struct cli_state *cli,
1423         const char *pathname,
1424         unsigned int info_level,
1425         bool posix)
1426 {
1427         struct tevent_req *req = NULL, *subreq = NULL;
1428         struct cli_smb2_list_state *state = NULL;
1429         char *parent = NULL;
1430         bool ok;
1431         struct smb2_create_blobs *in_cblobs = NULL;
1432
1433         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_list_state);
1434         if (req == NULL) {
1435                 return NULL;
1436         }
1437         state->ev = ev;
1438         state->cli = cli;
1439         state->status = NT_STATUS_OK;
1440         state->info_level = info_level;
1441
1442         ok = windows_parent_dirname(state, pathname, &parent, &state->mask);
1443         if (!ok) {
1444                 tevent_req_oom(req);
1445                 return tevent_req_post(req, ev);
1446         }
1447
1448         if (smbXcli_conn_have_posix(cli->conn) && posix) {
1449                 NTSTATUS status;
1450
1451                 /* The mode MUST be 0 when opening an existing file/dir, and
1452                  * will be ignored by the server.
1453                  */
1454                 uint8_t linear_mode[4] = { 0 };
1455                 DATA_BLOB blob = { .data=linear_mode,
1456                                    .length=sizeof(linear_mode) };
1457
1458                 in_cblobs = talloc_zero(mem_ctx, struct smb2_create_blobs);
1459                 if (in_cblobs == NULL) {
1460                         return NULL;
1461                 }
1462
1463                 status = smb2_create_blob_add(in_cblobs, in_cblobs,
1464                                               SMB2_CREATE_TAG_POSIX, blob);
1465                 if (!NT_STATUS_IS_OK(status)) {
1466                         tevent_req_nterror(req, status);
1467                         return tevent_req_post(req, ev);
1468                 }
1469         }
1470
1471         subreq = cli_smb2_create_fnum_send(
1472                 state,                                  /* mem_ctx */
1473                 ev,                                     /* ev */
1474                 cli,                                    /* cli */
1475                 parent,                                 /* fname */
1476                 0,                                      /* create_flags */
1477                 SMB2_IMPERSONATION_IMPERSONATION,       /* impersonation_level */
1478                 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,    /* desired_access */
1479                 FILE_ATTRIBUTE_DIRECTORY,               /* file_attributes */
1480                 FILE_SHARE_READ|FILE_SHARE_WRITE,       /* share_access */
1481                 FILE_OPEN,                              /* create_disposition */
1482                 FILE_DIRECTORY_FILE,                    /* create_options */
1483                 in_cblobs);                             /* in_cblobs */
1484         TALLOC_FREE(in_cblobs);
1485         if (tevent_req_nomem(subreq, req)) {
1486                 return tevent_req_post(req, ev);
1487         }
1488         tevent_req_set_callback(subreq, cli_smb2_list_opened, req);
1489         return req;
1490 }
1491
1492 static void cli_smb2_list_opened(struct tevent_req *subreq)
1493 {
1494         struct tevent_req *req = tevent_req_callback_data(
1495                 subreq, struct tevent_req);
1496         struct cli_smb2_list_state *state = tevent_req_data(
1497                 req, struct cli_smb2_list_state);
1498         NTSTATUS status;
1499
1500         status = cli_smb2_create_fnum_recv(
1501                 subreq, &state->fnum, NULL, NULL, NULL, NULL);
1502         TALLOC_FREE(subreq);
1503         if (tevent_req_nterror(req, status)) {
1504                 return;
1505         }
1506
1507         /*
1508          * Make our caller get back to us via cli_smb2_list_recv(),
1509          * triggering the smb2_query_directory_send()
1510          */
1511         tevent_req_defer_callback(req, state->ev);
1512         tevent_req_notify_callback(req);
1513 }
1514
1515 static void cli_smb2_list_done(struct tevent_req *subreq)
1516 {
1517         struct tevent_req *req = tevent_req_callback_data(
1518                 subreq, struct tevent_req);
1519         struct cli_smb2_list_state *state = tevent_req_data(
1520                 req, struct cli_smb2_list_state);
1521         struct cli_smb2_list_dir_data *response = NULL;
1522
1523         response = talloc(state, struct cli_smb2_list_dir_data);
1524         if (tevent_req_nomem(response, req)) {
1525                 return;
1526         }
1527
1528         state->status = smb2cli_query_directory_recv(
1529                 subreq, response, &response->data, &response->length);
1530         TALLOC_FREE(subreq);
1531
1532         if (NT_STATUS_IS_OK(state->status)) {
1533                 state->response = response;
1534                 state->offset = 0;
1535
1536                 tevent_req_defer_callback(req, state->ev);
1537                 tevent_req_notify_callback(req);
1538                 return;
1539         }
1540
1541         TALLOC_FREE(response);
1542
1543         subreq = cli_smb2_close_fnum_send(
1544                 state, state->ev, state->cli, state->fnum);
1545         if (tevent_req_nomem(subreq, req)) {
1546                 return;
1547         }
1548         tevent_req_set_callback(subreq, cli_smb2_list_closed, req);
1549 }
1550
1551 static void cli_smb2_list_closed(struct tevent_req *subreq)
1552 {
1553         NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1554         tevent_req_simple_finish_ntstatus(subreq, status);
1555 }
1556
1557 /*
1558  * Return the next finfo directory.
1559  *
1560  * This parses the blob returned from QUERY_DIRECTORY step by step. If
1561  * the blob ends, this triggers a fresh QUERY_DIRECTORY and returns
1562  * NT_STATUS_RETRY, which will then trigger the caller again when the
1563  * QUERY_DIRECTORY has returned with another buffer. This way we
1564  * guarantee that no asynchronous request is open after this call
1565  * returns an entry, so that other synchronous requests can be issued
1566  * on the same connection while the directoy listing proceeds.
1567  */
1568 NTSTATUS cli_smb2_list_recv(
1569         struct tevent_req *req,
1570         TALLOC_CTX *mem_ctx,
1571         struct file_info **pfinfo)
1572 {
1573         struct cli_smb2_list_state *state = tevent_req_data(
1574                 req, struct cli_smb2_list_state);
1575         struct cli_smb2_list_dir_data *response = NULL;
1576         struct file_info *finfo = NULL;
1577         NTSTATUS status;
1578         uint32_t next_offset = 0;
1579         bool in_progress;
1580
1581         in_progress = tevent_req_is_in_progress(req);
1582
1583         if (!in_progress) {
1584                 if (!tevent_req_is_nterror(req, &status)) {
1585                         status = NT_STATUS_NO_MORE_FILES;
1586                 }
1587                 goto fail;
1588         }
1589
1590         response = state->response;
1591         if (response == NULL) {
1592                 struct tevent_req *subreq = NULL;
1593                 struct cli_state *cli = state->cli;
1594                 struct smb2_hnd *ph = NULL;
1595                 uint32_t max_trans, max_avail_len;
1596                 bool ok;
1597
1598                 if (!NT_STATUS_IS_OK(state->status)) {
1599                         status = state->status;
1600                         goto fail;
1601                 }
1602
1603                 status = map_fnum_to_smb2_handle(cli, state->fnum, &ph);
1604                 if (!NT_STATUS_IS_OK(status)) {
1605                         goto fail;
1606                 }
1607
1608                 max_trans = smb2cli_conn_max_trans_size(cli->conn);
1609                 ok = smb2cli_conn_req_possible(cli->conn, &max_avail_len);
1610                 if (ok) {
1611                         max_trans = MIN(max_trans, max_avail_len);
1612                 }
1613
1614                 subreq = smb2cli_query_directory_send(
1615                         state,                          /* mem_ctx */
1616                         state->ev,                      /* ev */
1617                         cli->conn,                      /* conn */
1618                         cli->timeout,                   /* timeout_msec */
1619                         cli->smb2.session,              /* session */
1620                         cli->smb2.tcon,                 /* tcon */
1621                         state->info_level,              /* level */
1622                         0,                              /* flags */
1623                         0,                              /* file_index */
1624                         ph->fid_persistent,             /* fid_persistent */
1625                         ph->fid_volatile,               /* fid_volatile */
1626                         state->mask,                    /* mask */
1627                         max_trans);                     /* outbuf_len */
1628                 if (subreq == NULL) {
1629                         status = NT_STATUS_NO_MEMORY;
1630                         goto fail;
1631                 }
1632                 tevent_req_set_callback(subreq, cli_smb2_list_done, req);
1633                 return NT_STATUS_RETRY;
1634         }
1635
1636         SMB_ASSERT(response->length > state->offset);
1637
1638         finfo = talloc_zero(mem_ctx, struct file_info);
1639         if (finfo == NULL) {
1640                 status = NT_STATUS_NO_MEMORY;
1641                 goto fail;
1642         }
1643
1644         if (state->info_level == SMB2_FIND_POSIX_INFORMATION) {
1645                 status = parse_finfo_posix_info(
1646                         response->data + state->offset,
1647                         response->length - state->offset,
1648                         finfo,
1649                         &next_offset);
1650         } else {
1651                 status = parse_finfo_id_both_directory_info(
1652                         response->data + state->offset,
1653                         response->length - state->offset,
1654                         finfo,
1655                         &next_offset);
1656         }
1657         if (!NT_STATUS_IS_OK(status)) {
1658                 goto fail;
1659         }
1660
1661         status = is_bad_finfo_name(state->cli, finfo);
1662         if (!NT_STATUS_IS_OK(status)) {
1663                 goto fail;
1664         }
1665
1666         /*
1667          * parse_finfo_id_both_directory_info() checks for overflow,
1668          * no need to check again here.
1669          */
1670         state->offset += next_offset;
1671
1672         if (next_offset == 0) {
1673                 TALLOC_FREE(state->response);
1674         }
1675
1676         tevent_req_defer_callback(req, state->ev);
1677         tevent_req_notify_callback(req);
1678
1679         *pfinfo = finfo;
1680         return NT_STATUS_OK;
1681
1682 fail:
1683         TALLOC_FREE(finfo);
1684         tevent_req_received(req);
1685         return status;
1686 }
1687
1688 /***************************************************************
1689  Wrapper that allows SMB2 to query a path info (basic level).
1690  Synchronous only.
1691 ***************************************************************/
1692
1693 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1694                                 const char *name,
1695                                 SMB_STRUCT_STAT *sbuf,
1696                                 uint32_t *attributes)
1697 {
1698         NTSTATUS status;
1699         struct smb_create_returns cr;
1700         uint16_t fnum = 0xffff;
1701         size_t namelen = strlen(name);
1702
1703         if (smbXcli_conn_has_async_calls(cli->conn)) {
1704                 /*
1705                  * Can't use sync call while an async call is in flight
1706                  */
1707                 return NT_STATUS_INVALID_PARAMETER;
1708         }
1709
1710         /* SMB2 is pickier about pathnames. Ensure it doesn't
1711            end in a '\' */
1712         if (namelen > 0 && name[namelen-1] == '\\') {
1713                 char *modname = talloc_strndup(talloc_tos(), name, namelen-1);
1714                 if (modname == NULL) {
1715                         return NT_STATUS_NO_MEMORY;
1716                 }
1717                 name = modname;
1718         }
1719
1720         /* This is commonly used as a 'cd'. Try qpathinfo on
1721            a directory handle first. */
1722
1723         status = cli_smb2_create_fnum(cli,
1724                         name,
1725                         0,                      /* create_flags */
1726                         SMB2_IMPERSONATION_IMPERSONATION,
1727                         FILE_READ_ATTRIBUTES,   /* desired_access */
1728                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1729                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1730                         FILE_OPEN,              /* create_disposition */
1731                         FILE_DIRECTORY_FILE,    /* create_options */
1732                         NULL,
1733                         &fnum,
1734                         &cr,
1735                         NULL,
1736                         NULL);
1737
1738         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1739                 /* Maybe a file ? */
1740                 status = cli_smb2_create_fnum(cli,
1741                         name,
1742                         0,                      /* create_flags */
1743                         SMB2_IMPERSONATION_IMPERSONATION,
1744                         FILE_READ_ATTRIBUTES,           /* desired_access */
1745                         0, /* file attributes */
1746                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1747                         FILE_OPEN,              /* create_disposition */
1748                         0,      /* create_options */
1749                         NULL,
1750                         &fnum,
1751                         &cr,
1752                         NULL,
1753                         NULL);
1754         }
1755
1756         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1757                 /* Maybe a reparse point ? */
1758                 status = cli_smb2_create_fnum(cli,
1759                         name,
1760                         0,                      /* create_flags */
1761                         SMB2_IMPERSONATION_IMPERSONATION,
1762                         FILE_READ_ATTRIBUTES,           /* desired_access */
1763                         0, /* file attributes */
1764                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1765                         FILE_OPEN,              /* create_disposition */
1766                         FILE_OPEN_REPARSE_POINT, /* create_options */
1767                         NULL,
1768                         &fnum,
1769                         &cr,
1770                         NULL,
1771                         NULL);
1772         }
1773
1774         if (!NT_STATUS_IS_OK(status)) {
1775                 return status;
1776         }
1777
1778         status = cli_smb2_close_fnum(cli, fnum);
1779
1780         ZERO_STRUCTP(sbuf);
1781
1782         sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1783         sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1784         sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1785         sbuf->st_ex_size = cr.end_of_file;
1786         *attributes = cr.file_attributes;
1787
1788         return status;
1789 }
1790
1791 struct cli_smb2_query_info_fnum_state {
1792         DATA_BLOB outbuf;
1793 };
1794
1795 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq);
1796
1797 struct tevent_req *cli_smb2_query_info_fnum_send(
1798         TALLOC_CTX *mem_ctx,
1799         struct tevent_context *ev,
1800         struct cli_state *cli,
1801         uint16_t fnum,
1802         uint8_t in_info_type,
1803         uint8_t in_info_class,
1804         uint32_t in_max_output_length,
1805         const DATA_BLOB *in_input_buffer,
1806         uint32_t in_additional_info,
1807         uint32_t in_flags)
1808 {
1809         struct tevent_req *req = NULL, *subreq = NULL;
1810         struct cli_smb2_query_info_fnum_state *state = NULL;
1811         struct smb2_hnd *ph = NULL;
1812         NTSTATUS status;
1813
1814         req = tevent_req_create(
1815                 mem_ctx, &state, struct cli_smb2_query_info_fnum_state);
1816         if (req == NULL) {
1817                 return req;
1818         }
1819
1820         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1821         if (tevent_req_nterror(req, status)) {
1822                 return tevent_req_post(req, ev);
1823         }
1824
1825         subreq = smb2cli_query_info_send(
1826                 state,
1827                 ev,
1828                 cli->conn,
1829                 cli->timeout,
1830                 cli->smb2.session,
1831                 cli->smb2.tcon,
1832                 in_info_type,
1833                 in_info_class,
1834                 in_max_output_length,
1835                 in_input_buffer,
1836                 in_additional_info,
1837                 in_flags,
1838                 ph->fid_persistent,
1839                 ph->fid_volatile);
1840         if (tevent_req_nomem(subreq, req)) {
1841                 return tevent_req_post(req, ev);
1842         }
1843         tevent_req_set_callback(subreq, cli_smb2_query_info_fnum_done, req);
1844         return req;
1845 }
1846
1847 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq)
1848 {
1849         struct tevent_req *req = tevent_req_callback_data(
1850                 subreq, struct tevent_req);
1851         struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1852                 req, struct cli_smb2_query_info_fnum_state);
1853         DATA_BLOB outbuf;
1854         NTSTATUS status;
1855
1856         status = smb2cli_query_info_recv(subreq, state, &outbuf);
1857         TALLOC_FREE(subreq);
1858         if (tevent_req_nterror(req, status)) {
1859                 return;
1860         }
1861
1862         /*
1863          * We have to dup the memory here because outbuf.data is not
1864          * returned as a talloc object by smb2cli_query_info_recv.
1865          * It's a pointer into the received buffer.
1866          */
1867         state->outbuf = data_blob_dup_talloc(state, outbuf);
1868
1869         if ((outbuf.length != 0) &&
1870             tevent_req_nomem(state->outbuf.data, req)) {
1871                 return;
1872         }
1873         tevent_req_done(req);
1874 }
1875
1876 NTSTATUS cli_smb2_query_info_fnum_recv(
1877         struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *outbuf)
1878 {
1879         struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1880                 req, struct cli_smb2_query_info_fnum_state);
1881         NTSTATUS status;
1882
1883         if (tevent_req_is_nterror(req, &status)) {
1884                 return status;
1885         }
1886         *outbuf = (DATA_BLOB) {
1887                 .data = talloc_move(mem_ctx, &state->outbuf.data),
1888                 .length = state->outbuf.length,
1889         };
1890         return NT_STATUS_OK;
1891 }
1892
1893 NTSTATUS cli_smb2_query_info_fnum(
1894         struct cli_state *cli,
1895         uint16_t fnum,
1896         uint8_t in_info_type,
1897         uint8_t in_info_class,
1898         uint32_t in_max_output_length,
1899         const DATA_BLOB *in_input_buffer,
1900         uint32_t in_additional_info,
1901         uint32_t in_flags,
1902         TALLOC_CTX *mem_ctx,
1903         DATA_BLOB *outbuf)
1904 {
1905         TALLOC_CTX *frame = talloc_stackframe();
1906         struct tevent_context *ev = NULL;
1907         struct tevent_req *req = NULL;
1908         NTSTATUS status = NT_STATUS_NO_MEMORY;
1909         bool ok;
1910
1911         if (smbXcli_conn_has_async_calls(cli->conn)) {
1912                 /*
1913                  * Can't use sync call while an async call is in flight
1914                  */
1915                 status = NT_STATUS_INVALID_PARAMETER;
1916                 goto fail;
1917         }
1918         ev = samba_tevent_context_init(frame);
1919         if (ev == NULL) {
1920                 goto fail;
1921         }
1922         req = cli_smb2_query_info_fnum_send(
1923                 frame,
1924                 ev,
1925                 cli,
1926                 fnum,
1927                 in_info_type,
1928                 in_info_class,
1929                 in_max_output_length,
1930                 in_input_buffer,
1931                 in_additional_info,
1932                 in_flags);
1933         if (req == NULL) {
1934                 goto fail;
1935         }
1936         ok = tevent_req_poll_ntstatus(req, ev, &status);
1937         if (!ok) {
1938                 goto fail;
1939         }
1940         status = cli_smb2_query_info_fnum_recv(req, mem_ctx, outbuf);
1941 fail:
1942         TALLOC_FREE(frame);
1943         return status;
1944 }
1945
1946 /***************************************************************
1947  Helper function for pathname operations.
1948 ***************************************************************/
1949
1950 struct get_fnum_from_path_state {
1951         struct tevent_context *ev;
1952         struct cli_state *cli;
1953         const char *name;
1954         uint32_t desired_access;
1955         uint16_t fnum;
1956 };
1957
1958 static void get_fnum_from_path_opened_file(struct tevent_req *subreq);
1959 static void get_fnum_from_path_opened_reparse(struct tevent_req *subreq);
1960 static void get_fnum_from_path_opened_dir(struct tevent_req *subreq);
1961
1962 static struct tevent_req *get_fnum_from_path_send(
1963         TALLOC_CTX *mem_ctx,
1964         struct tevent_context *ev,
1965         struct cli_state *cli,
1966         const char *name,
1967         uint32_t desired_access)
1968 {
1969         struct tevent_req *req = NULL, *subreq = NULL;
1970         struct get_fnum_from_path_state *state = NULL;
1971         size_t namelen = strlen(name);
1972
1973         req = tevent_req_create(
1974                 mem_ctx, &state, struct get_fnum_from_path_state);
1975         if (req == NULL) {
1976                 return NULL;
1977         }
1978         state->ev = ev;
1979         state->cli = cli;
1980         state->name = name;
1981         state->desired_access = desired_access;
1982
1983         /*
1984          * SMB2 is pickier about pathnames. Ensure it doesn't end in a
1985          * '\'
1986          */
1987         if (namelen > 0 && name[namelen-1] == '\\') {
1988                 state->name = talloc_strndup(state, name, namelen-1);
1989                 if (tevent_req_nomem(state->name, req)) {
1990                         return tevent_req_post(req, ev);
1991                 }
1992         }
1993
1994         subreq = cli_smb2_create_fnum_send(
1995                 state,          /* mem_ctx, */
1996                 ev,             /* ev */
1997                 cli,            /* cli */
1998                 state->name,    /* fname */
1999                 0,              /* create_flags */
2000                 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level */
2001                 desired_access, /* desired_access */
2002                 0,              /* file_attributes */
2003                 FILE_SHARE_READ|
2004                 FILE_SHARE_WRITE|
2005                 FILE_SHARE_DELETE, /* share_access */
2006                 FILE_OPEN,      /* create_disposition */
2007                 0,              /* create_options */
2008                 NULL);          /* in_cblobs */
2009         if (tevent_req_nomem(subreq, req)) {
2010                 return tevent_req_post(req, ev);
2011         }
2012         tevent_req_set_callback(subreq, get_fnum_from_path_opened_file, req);
2013         return req;
2014 }
2015
2016 static void get_fnum_from_path_opened_file(struct tevent_req *subreq)
2017 {
2018         struct tevent_req *req = tevent_req_callback_data(
2019                 subreq, struct tevent_req);
2020         struct get_fnum_from_path_state *state = tevent_req_data(
2021                 req, struct get_fnum_from_path_state);
2022         NTSTATUS status;
2023
2024         status = cli_smb2_create_fnum_recv(
2025                 subreq, &state->fnum, NULL, NULL, NULL, NULL);
2026         TALLOC_FREE(subreq);
2027
2028         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
2029                 /*
2030                  * Naive option to match our SMB1 code. Assume the
2031                  * symlink path that tripped us up was the last
2032                  * component and try again. Eventually we will have to
2033                  * deal with the returned path unprocessed component. JRA.
2034                  */
2035                 subreq = cli_smb2_create_fnum_send(
2036                         state,          /* mem_ctx, */
2037                         state->ev,      /* ev */
2038                         state->cli,     /* cli */
2039                         state->name,    /* fname */
2040                         0,              /* create_flags */
2041                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation */
2042                         state->desired_access, /* desired_access */
2043                         0,              /* file_attributes */
2044                         FILE_SHARE_READ|
2045                         FILE_SHARE_WRITE|
2046                         FILE_SHARE_DELETE, /* share_access */
2047                         FILE_OPEN,      /* create_disposition */
2048                         FILE_OPEN_REPARSE_POINT, /* create_options */
2049                         NULL);          /* in_cblobs */
2050                 if (tevent_req_nomem(subreq, req)) {
2051                         return;
2052                 }
2053                 tevent_req_set_callback(
2054                         subreq, get_fnum_from_path_opened_reparse, req);
2055                 return;
2056         }
2057
2058         if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
2059                 subreq = cli_smb2_create_fnum_send(
2060                         state,          /* mem_ctx, */
2061                         state->ev,      /* ev */
2062                         state->cli,     /* cli */
2063                         state->name,    /* fname */
2064                         0,              /* create_flags */
2065                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation */
2066                         state->desired_access, /* desired_access */
2067                         0,              /* file_attributes */
2068                         FILE_SHARE_READ|
2069                         FILE_SHARE_WRITE|
2070                         FILE_SHARE_DELETE, /* share_access */
2071                         FILE_OPEN,      /* create_disposition */
2072                         FILE_DIRECTORY_FILE, /* create_options */
2073                         NULL);          /* in_cblobs */
2074                 if (tevent_req_nomem(subreq, req)) {
2075                         return;
2076                 }
2077                 tevent_req_set_callback(
2078                         subreq, get_fnum_from_path_opened_dir, req);
2079                 return;
2080         }
2081
2082         if (tevent_req_nterror(req, status)) {
2083                 return;
2084         }
2085         tevent_req_done(req);
2086 }
2087
2088 static void get_fnum_from_path_opened_reparse(struct tevent_req *subreq)
2089 {
2090         struct tevent_req *req = tevent_req_callback_data(
2091                 subreq, struct tevent_req);
2092         struct get_fnum_from_path_state *state = tevent_req_data(
2093                 req, struct get_fnum_from_path_state);
2094         NTSTATUS status = cli_smb2_create_fnum_recv(
2095                 subreq, &state->fnum, NULL, NULL, NULL, NULL);
2096         tevent_req_simple_finish_ntstatus(subreq, status);
2097 }
2098
2099 static void get_fnum_from_path_opened_dir(struct tevent_req *subreq)
2100 {
2101         /* Abstraction violation, but these two are just the same... */
2102         get_fnum_from_path_opened_reparse(subreq);
2103 }
2104
2105 static NTSTATUS get_fnum_from_path_recv(
2106         struct tevent_req *req, uint16_t *pfnum)
2107 {
2108         struct get_fnum_from_path_state *state = tevent_req_data(
2109                 req, struct get_fnum_from_path_state);
2110         NTSTATUS status = NT_STATUS_OK;
2111
2112         if (!tevent_req_is_nterror(req, &status)) {
2113                 *pfnum = state->fnum;
2114         }
2115         tevent_req_received(req);
2116         return status;
2117 }
2118
2119 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
2120                                 const char *name,
2121                                 uint32_t desired_access,
2122                                 uint16_t *pfnum)
2123 {
2124         TALLOC_CTX *frame = talloc_stackframe();
2125         struct tevent_context *ev = NULL;
2126         struct tevent_req *req = NULL;
2127         NTSTATUS status = NT_STATUS_NO_MEMORY;
2128
2129         if (smbXcli_conn_has_async_calls(cli->conn)) {
2130                 status = NT_STATUS_INVALID_PARAMETER;
2131                 goto fail;
2132         }
2133         ev = samba_tevent_context_init(frame);
2134         if (ev == NULL) {
2135                 goto fail;
2136         }
2137         req = get_fnum_from_path_send(frame, ev, cli, name, desired_access);
2138         if (req == NULL) {
2139                 goto fail;
2140         }
2141         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2142                 goto fail;
2143         }
2144         status = get_fnum_from_path_recv(req, pfnum);
2145  fail:
2146         TALLOC_FREE(frame);
2147         return status;
2148 }
2149
2150 /***************************************************************
2151  Wrapper that allows SMB2 to query a path info (ALTNAME level).
2152  Synchronous only.
2153 ***************************************************************/
2154
2155 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
2156                                 const char *name,
2157                                 fstring alt_name)
2158 {
2159         NTSTATUS status;
2160         DATA_BLOB outbuf = data_blob_null;
2161         uint16_t fnum = 0xffff;
2162         uint32_t altnamelen = 0;
2163         TALLOC_CTX *frame = talloc_stackframe();
2164
2165         if (smbXcli_conn_has_async_calls(cli->conn)) {
2166                 /*
2167                  * Can't use sync call while an async call is in flight
2168                  */
2169                 status = NT_STATUS_INVALID_PARAMETER;
2170                 goto fail;
2171         }
2172
2173         status = get_fnum_from_path(cli,
2174                                 name,
2175                                 FILE_READ_ATTRIBUTES,
2176                                 &fnum);
2177
2178         if (!NT_STATUS_IS_OK(status)) {
2179                 goto fail;
2180         }
2181
2182         status = cli_smb2_query_info_fnum(
2183                 cli,
2184                 fnum,
2185                 1, /* in_info_type */
2186                 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
2187                 0xFFFF, /* in_max_output_length */
2188                 NULL, /* in_input_buffer */
2189                 0, /* in_additional_info */
2190                 0, /* in_flags */
2191                 frame,
2192                 &outbuf);
2193
2194         if (!NT_STATUS_IS_OK(status)) {
2195                 goto fail;
2196         }
2197
2198         /* Parse the reply. */
2199         if (outbuf.length < 4) {
2200                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2201                 goto fail;
2202         }
2203
2204         altnamelen = IVAL(outbuf.data, 0);
2205         if (altnamelen > outbuf.length - 4) {
2206                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2207                 goto fail;
2208         }
2209
2210         if (altnamelen > 0) {
2211                 size_t ret = 0;
2212                 char *short_name = NULL;
2213                 ret = pull_string_talloc(frame,
2214                                 outbuf.data,
2215                                 FLAGS2_UNICODE_STRINGS,
2216                                 &short_name,
2217                                 outbuf.data + 4,
2218                                 altnamelen,
2219                                 STR_UNICODE);
2220                 if (ret == (size_t)-1) {
2221                         /* Bad conversion. */
2222                         status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2223                         goto fail;
2224                 }
2225
2226                 fstrcpy(alt_name, short_name);
2227         } else {
2228                 alt_name[0] = '\0';
2229         }
2230
2231         status = NT_STATUS_OK;
2232
2233   fail:
2234
2235         if (fnum != 0xffff) {
2236                 cli_smb2_close_fnum(cli, fnum);
2237         }
2238
2239         cli->raw_status = status;
2240
2241         TALLOC_FREE(frame);
2242         return status;
2243 }
2244
2245 /***************************************************************
2246  Wrapper that allows SMB2 to get pathname attributes.
2247  Synchronous only.
2248 ***************************************************************/
2249
2250 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
2251                         const char *name,
2252                         uint32_t *pattr,
2253                         off_t *size,
2254                         time_t *write_time)
2255 {
2256         NTSTATUS status;
2257         uint16_t fnum = 0xffff;
2258         struct timespec write_time_ts;
2259         TALLOC_CTX *frame = talloc_stackframe();
2260
2261         if (smbXcli_conn_has_async_calls(cli->conn)) {
2262                 /*
2263                  * Can't use sync call while an async call is in flight
2264                  */
2265                 status = NT_STATUS_INVALID_PARAMETER;
2266                 goto fail;
2267         }
2268
2269         status = get_fnum_from_path(cli,
2270                                 name,
2271                                 FILE_READ_ATTRIBUTES,
2272                                 &fnum);
2273
2274         if (!NT_STATUS_IS_OK(status)) {
2275                 goto fail;
2276         }
2277
2278         status = cli_qfileinfo_basic(
2279                 cli,
2280                 fnum,
2281                 pattr,
2282                 size,
2283                 NULL,           /* create_time */
2284                 NULL,           /* access_time */
2285                 &write_time_ts,
2286                 NULL,           /* change_time */
2287                 NULL);          /* ino */
2288         if (!NT_STATUS_IS_OK(status)) {
2289                 goto fail;
2290         }
2291         if (write_time != NULL) {
2292                 *write_time = write_time_ts.tv_sec;
2293         }
2294
2295   fail:
2296
2297         if (fnum != 0xffff) {
2298                 cli_smb2_close_fnum(cli, fnum);
2299         }
2300
2301         cli->raw_status = status;
2302
2303         TALLOC_FREE(frame);
2304         return status;
2305 }
2306
2307 /***************************************************************
2308  Wrapper that allows SMB2 to query a pathname info (basic level).
2309  Implement on top of cli_qfileinfo_basic().
2310  Synchronous only.
2311 ***************************************************************/
2312
2313 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
2314                         const char *name,
2315                         struct timespec *create_time,
2316                         struct timespec *access_time,
2317                         struct timespec *write_time,
2318                         struct timespec *change_time,
2319                         off_t *size,
2320                         uint32_t *pattr,
2321                         SMB_INO_T *ino)
2322 {
2323         NTSTATUS status;
2324         uint16_t fnum = 0xffff;
2325         TALLOC_CTX *frame = talloc_stackframe();
2326
2327         if (smbXcli_conn_has_async_calls(cli->conn)) {
2328                 /*
2329                  * Can't use sync call while an async call is in flight
2330                  */
2331                 status = NT_STATUS_INVALID_PARAMETER;
2332                 goto fail;
2333         }
2334
2335         status = get_fnum_from_path(cli,
2336                                         name,
2337                                         FILE_READ_ATTRIBUTES,
2338                                         &fnum);
2339
2340         if (!NT_STATUS_IS_OK(status)) {
2341                 goto fail;
2342         }
2343
2344         status = cli_qfileinfo_basic(
2345                 cli,
2346                 fnum,
2347                 pattr,
2348                 size,
2349                 create_time,
2350                 access_time,
2351                 write_time,
2352                 change_time,
2353                 ino);
2354
2355   fail:
2356
2357         if (fnum != 0xffff) {
2358                 cli_smb2_close_fnum(cli, fnum);
2359         }
2360
2361         cli->raw_status = status;
2362
2363         TALLOC_FREE(frame);
2364         return status;
2365 }
2366
2367 /***************************************************************
2368  Wrapper that allows SMB2 to query pathname streams.
2369  Synchronous only.
2370 ***************************************************************/
2371
2372 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
2373                                 const char *name,
2374                                 TALLOC_CTX *mem_ctx,
2375                                 unsigned int *pnum_streams,
2376                                 struct stream_struct **pstreams)
2377 {
2378         NTSTATUS status;
2379         uint16_t fnum = 0xffff;
2380         DATA_BLOB outbuf = data_blob_null;
2381         TALLOC_CTX *frame = talloc_stackframe();
2382
2383         if (smbXcli_conn_has_async_calls(cli->conn)) {
2384                 /*
2385                  * Can't use sync call while an async call is in flight
2386                  */
2387                 status = NT_STATUS_INVALID_PARAMETER;
2388                 goto fail;
2389         }
2390
2391         status = get_fnum_from_path(cli,
2392                                 name,
2393                                 FILE_READ_ATTRIBUTES,
2394                                 &fnum);
2395
2396         if (!NT_STATUS_IS_OK(status)) {
2397                 goto fail;
2398         }
2399
2400         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2401            level 22 (SMB2_FILE_STREAM_INFORMATION). */
2402
2403         status = cli_smb2_query_info_fnum(
2404                 cli,
2405                 fnum,
2406                 1, /* in_info_type */
2407                 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
2408                 0xFFFF, /* in_max_output_length */
2409                 NULL, /* in_input_buffer */
2410                 0, /* in_additional_info */
2411                 0, /* in_flags */
2412                 frame,
2413                 &outbuf);
2414
2415         if (!NT_STATUS_IS_OK(status)) {
2416                 goto fail;
2417         }
2418
2419         /* Parse the reply. */
2420         if (!parse_streams_blob(mem_ctx,
2421                                 outbuf.data,
2422                                 outbuf.length,
2423                                 pnum_streams,
2424                                 pstreams)) {
2425                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2426                 goto fail;
2427         }
2428
2429   fail:
2430
2431         if (fnum != 0xffff) {
2432                 cli_smb2_close_fnum(cli, fnum);
2433         }
2434
2435         cli->raw_status = status;
2436
2437         TALLOC_FREE(frame);
2438         return status;
2439 }
2440
2441 /***************************************************************
2442  Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2443  a pathname.
2444  Synchronous only.
2445 ***************************************************************/
2446
2447 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
2448                         const char *name,
2449                         uint8_t in_info_type,
2450                         uint8_t in_file_info_class,
2451                         const DATA_BLOB *p_in_data)
2452 {
2453         NTSTATUS status;
2454         uint16_t fnum = 0xffff;
2455         TALLOC_CTX *frame = talloc_stackframe();
2456
2457         if (smbXcli_conn_has_async_calls(cli->conn)) {
2458                 /*
2459                  * Can't use sync call while an async call is in flight
2460                  */
2461                 status = NT_STATUS_INVALID_PARAMETER;
2462                 goto fail;
2463         }
2464
2465         status = get_fnum_from_path(cli,
2466                                 name,
2467                                 FILE_WRITE_ATTRIBUTES,
2468                                 &fnum);
2469
2470         if (!NT_STATUS_IS_OK(status)) {
2471                 goto fail;
2472         }
2473
2474         status = cli_smb2_set_info_fnum(
2475                 cli,
2476                 fnum,
2477                 in_info_type,
2478                 in_file_info_class,
2479                 p_in_data,         /* in_input_buffer */
2480                 0);                /* in_additional_info */
2481   fail:
2482
2483         if (fnum != 0xffff) {
2484                 cli_smb2_close_fnum(cli, fnum);
2485         }
2486
2487         cli->raw_status = status;
2488
2489         TALLOC_FREE(frame);
2490         return status;
2491 }
2492
2493
2494 /***************************************************************
2495  Wrapper that allows SMB2 to set pathname attributes.
2496  Synchronous only.
2497 ***************************************************************/
2498
2499 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
2500                         const char *name,
2501                         uint32_t attr,
2502                         time_t mtime)
2503 {
2504         uint8_t inbuf_store[40];
2505         DATA_BLOB inbuf = data_blob_null;
2506
2507         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2508            level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2509
2510         inbuf.data = inbuf_store;
2511         inbuf.length = sizeof(inbuf_store);
2512         data_blob_clear(&inbuf);
2513
2514         /*
2515          * SMB1 uses attr == 0 to clear all attributes
2516          * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2517          * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2518          * request attribute change.
2519          *
2520          * SMB2 uses exactly the reverse. Unfortunately as the
2521          * cli_setatr() ABI is exposed inside libsmbclient,
2522          * we must make the SMB2 cli_smb2_setatr() call
2523          * export the same ABI as the SMB1 cli_setatr()
2524          * which calls it. This means reversing the sense
2525          * of the requested attr argument if it's zero
2526          * or FILE_ATTRIBUTE_NORMAL.
2527          *
2528          * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2529          */
2530
2531         if (attr == 0) {
2532                 attr = FILE_ATTRIBUTE_NORMAL;
2533         } else if (attr == FILE_ATTRIBUTE_NORMAL) {
2534                 attr = 0;
2535         }
2536
2537         SIVAL(inbuf.data, 32, attr);
2538         if (mtime != 0) {
2539                 put_long_date((char *)inbuf.data + 16,mtime);
2540         }
2541         /* Set all the other times to -1. */
2542         SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2543         SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
2544         SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
2545
2546         return cli_smb2_setpathinfo(cli,
2547                                 name,
2548                                 1, /* in_info_type */
2549                                 /* in_file_info_class */
2550                                 SMB_FILE_BASIC_INFORMATION - 1000,
2551                                 &inbuf);
2552 }
2553
2554
2555 /***************************************************************
2556  Wrapper that allows SMB2 to set file handle times.
2557  Synchronous only.
2558 ***************************************************************/
2559
2560 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
2561                         uint16_t fnum,
2562                         time_t change_time,
2563                         time_t access_time,
2564                         time_t write_time)
2565 {
2566         uint8_t inbuf_store[40];
2567         DATA_BLOB inbuf = data_blob_null;
2568
2569         if (smbXcli_conn_has_async_calls(cli->conn)) {
2570                 /*
2571                  * Can't use sync call while an async call is in flight
2572                  */
2573                 return NT_STATUS_INVALID_PARAMETER;
2574         }
2575
2576         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2577            level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2578
2579         inbuf.data = inbuf_store;
2580         inbuf.length = sizeof(inbuf_store);
2581         data_blob_clear(&inbuf);
2582
2583         SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2584         if (change_time != 0) {
2585                 put_long_date((char *)inbuf.data + 24, change_time);
2586         }
2587         if (access_time != 0) {
2588                 put_long_date((char *)inbuf.data + 8, access_time);
2589         }
2590         if (write_time != 0) {
2591                 put_long_date((char *)inbuf.data + 16, write_time);
2592         }
2593
2594         cli->raw_status = cli_smb2_set_info_fnum(
2595                 cli,
2596                 fnum,
2597                 1,              /* in_info_type */
2598                 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
2599                 &inbuf,            /* in_input_buffer */
2600                 0);                /* in_additional_info */
2601
2602         return cli->raw_status;
2603 }
2604
2605 /***************************************************************
2606  Wrapper that allows SMB2 to query disk attributes (size).
2607  Synchronous only.
2608 ***************************************************************/
2609
2610 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2611                           uint64_t *bsize, uint64_t *total, uint64_t *avail)
2612 {
2613         NTSTATUS status;
2614         uint16_t fnum = 0xffff;
2615         DATA_BLOB outbuf = data_blob_null;
2616         uint32_t sectors_per_unit = 0;
2617         uint32_t bytes_per_sector = 0;
2618         uint64_t total_size = 0;
2619         uint64_t size_free = 0;
2620         TALLOC_CTX *frame = talloc_stackframe();
2621
2622         if (smbXcli_conn_has_async_calls(cli->conn)) {
2623                 /*
2624                  * Can't use sync call while an async call is in flight
2625                  */
2626                 status = NT_STATUS_INVALID_PARAMETER;
2627                 goto fail;
2628         }
2629
2630         /* First open the top level directory. */
2631         status = cli_smb2_create_fnum(cli,
2632                         path,
2633                         0,                      /* create_flags */
2634                         SMB2_IMPERSONATION_IMPERSONATION,
2635                         FILE_READ_ATTRIBUTES,   /* desired_access */
2636                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2637                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2638                         FILE_OPEN,              /* create_disposition */
2639                         FILE_DIRECTORY_FILE,    /* create_options */
2640                         NULL,
2641                         &fnum,
2642                         NULL,
2643                         NULL,
2644                         NULL);
2645
2646         if (!NT_STATUS_IS_OK(status)) {
2647                 goto fail;
2648         }
2649
2650         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2651            level 3 (SMB_FS_SIZE_INFORMATION). */
2652
2653         status = cli_smb2_query_info_fnum(
2654                 cli,
2655                 fnum,
2656                 2, /* in_info_type */
2657                 3, /* in_file_info_class */
2658                 0xFFFF, /* in_max_output_length */
2659                 NULL, /* in_input_buffer */
2660                 0, /* in_additional_info */
2661                 0, /* in_flags */
2662                 frame,
2663                 &outbuf);
2664         if (!NT_STATUS_IS_OK(status)) {
2665                 goto fail;
2666         }
2667
2668         /* Parse the reply. */
2669         if (outbuf.length != 24) {
2670                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2671                 goto fail;
2672         }
2673
2674         total_size = BVAL(outbuf.data, 0);
2675         size_free = BVAL(outbuf.data, 8);
2676         sectors_per_unit = IVAL(outbuf.data, 16);
2677         bytes_per_sector = IVAL(outbuf.data, 20);
2678
2679         if (bsize) {
2680                 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2681         }
2682         if (total) {
2683                 *total = total_size;
2684         }
2685         if (avail) {
2686                 *avail = size_free;
2687         }
2688
2689         status = NT_STATUS_OK;
2690
2691   fail:
2692
2693         if (fnum != 0xffff) {
2694                 cli_smb2_close_fnum(cli, fnum);
2695         }
2696
2697         cli->raw_status = status;
2698
2699         TALLOC_FREE(frame);
2700         return status;
2701 }
2702
2703 /***************************************************************
2704  Wrapper that allows SMB2 to query file system sizes.
2705  Synchronous only.
2706 ***************************************************************/
2707
2708 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2709                                 uint64_t *total_allocation_units,
2710                                 uint64_t *caller_allocation_units,
2711                                 uint64_t *actual_allocation_units,
2712                                 uint64_t *sectors_per_allocation_unit,
2713                                 uint64_t *bytes_per_sector)
2714 {
2715         NTSTATUS status;
2716         uint16_t fnum = 0xffff;
2717         DATA_BLOB outbuf = data_blob_null;
2718         TALLOC_CTX *frame = talloc_stackframe();
2719
2720         if (smbXcli_conn_has_async_calls(cli->conn)) {
2721                 /*
2722                  * Can't use sync call while an async call is in flight
2723                  */
2724                 status = NT_STATUS_INVALID_PARAMETER;
2725                 goto fail;
2726         }
2727
2728         /* First open the top level directory. */
2729         status =
2730             cli_smb2_create_fnum(cli, "", 0,               /* create_flags */
2731                                  SMB2_IMPERSONATION_IMPERSONATION,
2732                                  FILE_READ_ATTRIBUTES,     /* desired_access */
2733                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2734                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
2735                                      FILE_SHARE_DELETE, /* share_access */
2736                                  FILE_OPEN,             /* create_disposition */
2737                                  FILE_DIRECTORY_FILE,   /* create_options */
2738                                  NULL,
2739                                  &fnum,
2740                                  NULL,
2741                                  NULL,
2742                                  NULL);
2743
2744         if (!NT_STATUS_IS_OK(status)) {
2745                 goto fail;
2746         }
2747
2748         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2749            level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2750
2751         status = cli_smb2_query_info_fnum(
2752                 cli,
2753                 fnum,
2754                 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2755                 SMB_FS_FULL_SIZE_INFORMATION - 1000, /* in_file_info_class */
2756                 0xFFFF, /* in_max_output_length */
2757                 NULL, /* in_input_buffer */
2758                 0, /* in_additional_info */
2759                 0, /* in_flags */
2760                 frame,
2761                 &outbuf);
2762         if (!NT_STATUS_IS_OK(status)) {
2763                 goto fail;
2764         }
2765
2766         if (outbuf.length < 32) {
2767                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2768                 goto fail;
2769         }
2770
2771         *total_allocation_units = BIG_UINT(outbuf.data, 0);
2772         *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2773         *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2774         *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2775         *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2776
2777 fail:
2778
2779         if (fnum != 0xffff) {
2780                 cli_smb2_close_fnum(cli, fnum);
2781         }
2782
2783         cli->raw_status = status;
2784
2785         TALLOC_FREE(frame);
2786         return status;
2787 }
2788
2789 /***************************************************************
2790  Wrapper that allows SMB2 to query file system attributes.
2791  Synchronous only.
2792 ***************************************************************/
2793
2794 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2795 {
2796         NTSTATUS status;
2797         uint16_t fnum = 0xffff;
2798         DATA_BLOB outbuf = data_blob_null;
2799         TALLOC_CTX *frame = talloc_stackframe();
2800
2801         if (smbXcli_conn_has_async_calls(cli->conn)) {
2802                 /*
2803                  * Can't use sync call while an async call is in flight
2804                  */
2805                 status = NT_STATUS_INVALID_PARAMETER;
2806                 goto fail;
2807         }
2808
2809         /* First open the top level directory. */
2810         status =
2811             cli_smb2_create_fnum(cli, "", 0,               /* create_flags */
2812                                  SMB2_IMPERSONATION_IMPERSONATION,
2813                                  FILE_READ_ATTRIBUTES,     /* desired_access */
2814                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2815                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
2816                                      FILE_SHARE_DELETE, /* share_access */
2817                                  FILE_OPEN,             /* create_disposition */
2818                                  FILE_DIRECTORY_FILE,   /* create_options */
2819                                  NULL,
2820                                  &fnum,
2821                                  NULL,
2822                                  NULL,
2823                                  NULL);
2824
2825         if (!NT_STATUS_IS_OK(status)) {
2826                 goto fail;
2827         }
2828
2829         status = cli_smb2_query_info_fnum(
2830                 cli,
2831                 fnum,
2832                 2, /* in_info_type */
2833                 5,                     /* in_file_info_class */
2834                 0xFFFF, /* in_max_output_length */
2835                 NULL,   /* in_input_buffer */
2836                 0,      /* in_additional_info */
2837                 0,      /* in_flags */
2838                 frame,
2839                 &outbuf);
2840         if (!NT_STATUS_IS_OK(status)) {
2841                 goto fail;
2842         }
2843
2844         if (outbuf.length < 12) {
2845                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2846                 goto fail;
2847         }
2848
2849         *fs_attr = IVAL(outbuf.data, 0);
2850
2851 fail:
2852
2853         if (fnum != 0xffff) {
2854                 cli_smb2_close_fnum(cli, fnum);
2855         }
2856
2857         cli->raw_status = status;
2858
2859         TALLOC_FREE(frame);
2860         return status;
2861 }
2862
2863 /***************************************************************
2864  Wrapper that allows SMB2 to query file system volume info.
2865  Synchronous only.
2866 ***************************************************************/
2867
2868 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2869                                 TALLOC_CTX *mem_ctx,
2870                                 char **_volume_name,
2871                                 uint32_t *pserial_number,
2872                                 time_t *pdate)
2873 {
2874         NTSTATUS status;
2875         uint16_t fnum = 0xffff;
2876         DATA_BLOB outbuf = data_blob_null;
2877         uint32_t nlen;
2878         char *volume_name = NULL;
2879         TALLOC_CTX *frame = talloc_stackframe();
2880
2881         if (smbXcli_conn_has_async_calls(cli->conn)) {
2882                 /*
2883                  * Can't use sync call while an async call is in flight
2884                  */
2885                 status = NT_STATUS_INVALID_PARAMETER;
2886                 goto fail;
2887         }
2888
2889         /* First open the top level directory. */
2890         status =
2891             cli_smb2_create_fnum(cli, "", 0,               /* create_flags */
2892                                  SMB2_IMPERSONATION_IMPERSONATION,
2893                                  FILE_READ_ATTRIBUTES,     /* desired_access */
2894                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2895                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
2896                                      FILE_SHARE_DELETE, /* share_access */
2897                                  FILE_OPEN,             /* create_disposition */
2898                                  FILE_DIRECTORY_FILE,   /* create_options */
2899                                  NULL,
2900                                  &fnum,
2901                                  NULL,
2902                                  NULL,
2903                                  NULL);
2904
2905         if (!NT_STATUS_IS_OK(status)) {
2906                 goto fail;
2907         }
2908
2909         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2910            level 1 (SMB_FS_VOLUME_INFORMATION). */
2911
2912         status = cli_smb2_query_info_fnum(
2913                 cli,
2914                 fnum,
2915                 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2916                 /* in_file_info_class */
2917                 SMB_FS_VOLUME_INFORMATION - 1000,
2918                 0xFFFF, /* in_max_output_length */
2919                 NULL, /* in_input_buffer */
2920                 0, /* in_additional_info */
2921                 0, /* in_flags */
2922                 frame,
2923                 &outbuf);
2924         if (!NT_STATUS_IS_OK(status)) {
2925                 goto fail;
2926         }
2927
2928         if (outbuf.length < 24) {
2929                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2930                 goto fail;
2931         }
2932
2933         if (pdate) {
2934                 struct timespec ts;
2935                 ts = interpret_long_date((char *)outbuf.data);
2936                 *pdate = ts.tv_sec;
2937         }
2938         if (pserial_number) {
2939                 *pserial_number = IVAL(outbuf.data,8);
2940         }
2941         nlen = IVAL(outbuf.data,12);
2942         if (nlen + 18 < 18) {
2943                 /* Integer wrap. */
2944                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2945                 goto fail;
2946         }
2947         /*
2948          * The next check is safe as we know outbuf.length >= 24
2949          * from above.
2950          */
2951         if (nlen > (outbuf.length - 18)) {
2952                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2953                 goto fail;
2954         }
2955
2956         pull_string_talloc(mem_ctx,
2957                            (const char *)outbuf.data,
2958                            0,
2959                            &volume_name,
2960                            outbuf.data + 18,
2961                            nlen,
2962                            STR_UNICODE);
2963         if (volume_name == NULL) {
2964                 status = map_nt_error_from_unix(errno);
2965                 goto fail;
2966         }
2967
2968         *_volume_name = volume_name;
2969
2970 fail:
2971
2972         if (fnum != 0xffff) {
2973                 cli_smb2_close_fnum(cli, fnum);
2974         }
2975
2976         cli->raw_status = status;
2977
2978         TALLOC_FREE(frame);
2979         return status;
2980 }
2981
2982 struct cli_smb2_mxac_state {
2983         struct tevent_context *ev;
2984         struct cli_state *cli;
2985         const char *fname;
2986         struct smb2_create_blobs in_cblobs;
2987         uint16_t fnum;
2988         NTSTATUS status;
2989         uint32_t mxac;
2990 };
2991
2992 static void cli_smb2_mxac_opened(struct tevent_req *subreq);
2993 static void cli_smb2_mxac_closed(struct tevent_req *subreq);
2994
2995 struct tevent_req *cli_smb2_query_mxac_send(TALLOC_CTX *mem_ctx,
2996                                             struct tevent_context *ev,
2997                                             struct cli_state *cli,
2998                                             const char *fname)
2999 {
3000         struct tevent_req *req = NULL, *subreq = NULL;
3001         struct cli_smb2_mxac_state *state = NULL;
3002         NTSTATUS status;
3003
3004         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_mxac_state);
3005         if (req == NULL) {
3006                 return NULL;
3007         }
3008         *state = (struct cli_smb2_mxac_state) {
3009                 .ev = ev,
3010                 .cli = cli,
3011                 .fname = fname,
3012         };
3013
3014         status = smb2_create_blob_add(state,
3015                                       &state->in_cblobs,
3016                                       SMB2_CREATE_TAG_MXAC,
3017                                       data_blob(NULL, 0));
3018         if (tevent_req_nterror(req, status)) {
3019                 return tevent_req_post(req, ev);
3020         }
3021
3022         subreq = cli_smb2_create_fnum_send(
3023                 state,
3024                 state->ev,
3025                 state->cli,
3026                 state->fname,
3027                 0,                      /* create_flags */
3028                 SMB2_IMPERSONATION_IMPERSONATION,
3029                 FILE_READ_ATTRIBUTES,
3030                 0,                      /* file attributes */
3031                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
3032                 FILE_OPEN,
3033                 0,                      /* create_options */
3034                 &state->in_cblobs);
3035         if (tevent_req_nomem(subreq, req)) {
3036                 return tevent_req_post(req, ev);
3037         }
3038         tevent_req_set_callback(subreq, cli_smb2_mxac_opened, req);
3039         return req;
3040 }
3041
3042 static void cli_smb2_mxac_opened(struct tevent_req *subreq)
3043 {
3044         struct tevent_req *req = tevent_req_callback_data(
3045                 subreq, struct tevent_req);
3046         struct cli_smb2_mxac_state *state = tevent_req_data(
3047                 req, struct cli_smb2_mxac_state);
3048         struct smb2_create_blobs out_cblobs = {0};
3049         struct smb2_create_blob *mxac_blob = NULL;
3050         NTSTATUS status;
3051
3052         status = cli_smb2_create_fnum_recv(
3053                 subreq, &state->fnum, NULL, state, &out_cblobs, NULL);
3054         TALLOC_FREE(subreq);
3055
3056         if (tevent_req_nterror(req, status)) {
3057                 return;
3058         }
3059
3060         mxac_blob = smb2_create_blob_find(&out_cblobs, SMB2_CREATE_TAG_MXAC);
3061         if (mxac_blob == NULL) {
3062                 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3063                 goto close;
3064         }
3065         if (mxac_blob->data.length != 8) {
3066                 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3067                 goto close;
3068         }
3069
3070         state->status = NT_STATUS(IVAL(mxac_blob->data.data, 0));
3071         state->mxac = IVAL(mxac_blob->data.data, 4);
3072
3073 close:
3074         subreq = cli_smb2_close_fnum_send(
3075                 state, state->ev, state->cli, state->fnum);
3076         if (tevent_req_nomem(subreq, req)) {
3077                 return;
3078         }
3079         tevent_req_set_callback(subreq, cli_smb2_mxac_closed, req);
3080
3081         return;
3082 }
3083
3084 static void cli_smb2_mxac_closed(struct tevent_req *subreq)
3085 {
3086         struct tevent_req *req = tevent_req_callback_data(
3087                 subreq, struct tevent_req);
3088         NTSTATUS status;
3089
3090         status = cli_smb2_close_fnum_recv(subreq);
3091         if (tevent_req_nterror(req, status)) {
3092                 return;
3093         }
3094
3095         tevent_req_done(req);
3096 }
3097
3098 NTSTATUS cli_smb2_query_mxac_recv(struct tevent_req *req, uint32_t *mxac)
3099 {
3100         struct cli_smb2_mxac_state *state = tevent_req_data(
3101                 req, struct cli_smb2_mxac_state);
3102         NTSTATUS status;
3103
3104         if (tevent_req_is_nterror(req, &status)) {
3105                 return status;
3106         }
3107
3108         if (!NT_STATUS_IS_OK(state->status)) {
3109                 return state->status;
3110         }
3111
3112         *mxac = state->mxac;
3113         return NT_STATUS_OK;
3114 }
3115
3116 NTSTATUS cli_smb2_query_mxac(struct cli_state *cli,
3117                              const char *fname,
3118                              uint32_t *_mxac)
3119 {
3120         TALLOC_CTX *frame = talloc_stackframe();
3121         struct tevent_context *ev = NULL;
3122         struct tevent_req *req = NULL;
3123         NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
3124         bool ok;
3125
3126         if (smbXcli_conn_has_async_calls(cli->conn)) {
3127                 /*
3128                  * Can't use sync call while an async call is in flight
3129                  */
3130                 status = NT_STATUS_INVALID_PARAMETER;
3131                 goto fail;
3132         }
3133
3134         ev = samba_tevent_context_init(frame);
3135         if (ev == NULL) {
3136                 goto fail;
3137         }
3138         req = cli_smb2_query_mxac_send(frame, ev, cli, fname);
3139         if (req == NULL) {
3140                 goto fail;
3141         }
3142         ok = tevent_req_poll_ntstatus(req, ev, &status);
3143         if (!ok) {
3144                 goto fail;
3145         }
3146         status = cli_smb2_query_mxac_recv(req, _mxac);
3147
3148 fail:
3149         cli->raw_status = status;
3150         TALLOC_FREE(frame);
3151         return status;
3152 }
3153
3154 struct cli_smb2_rename_fnum_state {
3155         DATA_BLOB inbuf;
3156 };
3157
3158 static void cli_smb2_rename_fnum_done(struct tevent_req *subreq);
3159
3160 static struct tevent_req *cli_smb2_rename_fnum_send(
3161         TALLOC_CTX *mem_ctx,
3162         struct tevent_context *ev,
3163         struct cli_state *cli,
3164         uint16_t fnum,
3165         const char *fname_dst,
3166         bool replace)
3167 {
3168         struct tevent_req *req = NULL, *subreq = NULL;
3169         struct cli_smb2_rename_fnum_state *state = NULL;
3170         size_t namelen = strlen(fname_dst);
3171         smb_ucs2_t *converted_str = NULL;
3172         size_t converted_size_bytes = 0;
3173         size_t inbuf_size;
3174         bool ok;
3175
3176         req = tevent_req_create(
3177                 mem_ctx, &state, struct cli_smb2_rename_fnum_state);
3178         if (req == NULL) {
3179                 return NULL;
3180         }
3181
3182         /*
3183          * SMB2 is pickier about pathnames. Ensure it doesn't start in
3184          * a '\'
3185          */
3186         if (*fname_dst == '\\') {
3187                 fname_dst++;
3188         }
3189
3190         /*
3191          * SMB2 is pickier about pathnames. Ensure it doesn't end in a
3192          * '\'
3193          */
3194         if (namelen > 0 && fname_dst[namelen-1] == '\\') {
3195                 fname_dst = talloc_strndup(state, fname_dst, namelen-1);
3196                 if (tevent_req_nomem(fname_dst, req)) {
3197                         return tevent_req_post(req, ev);
3198                 }
3199         }
3200
3201         ok = push_ucs2_talloc(
3202                 state, &converted_str, fname_dst, &converted_size_bytes);
3203         if (!ok) {
3204                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3205                 return tevent_req_post(req, ev);
3206         }
3207
3208         /*
3209          * W2K8 insists the dest name is not null terminated. Remove
3210          * the last 2 zero bytes and reduce the name length.
3211          */
3212         if (converted_size_bytes < 2) {
3213                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3214                 return tevent_req_post(req, ev);
3215         }
3216         converted_size_bytes -= 2;
3217
3218         inbuf_size = 20 + converted_size_bytes;
3219         if (inbuf_size < 20) {
3220                 /* Integer wrap check. */
3221                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3222                 return tevent_req_post(req, ev);
3223         }
3224
3225         /*
3226          * The Windows 10 SMB2 server has a minimum length
3227          * for a SMB2_FILE_RENAME_INFORMATION buffer of
3228          * 24 bytes. It returns NT_STATUS_INFO_LENGTH_MISMATCH
3229          * if the length is less. This isn't an alignment
3230          * issue as Windows client happily 2-byte align
3231          * for larget target name sizes. Also the Windows 10
3232          * SMB1 server doesn't have this restriction.
3233          *
3234          * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14403
3235          */
3236         inbuf_size = MAX(inbuf_size, 24);
3237
3238         state->inbuf = data_blob_talloc_zero(state, inbuf_size);
3239         if (tevent_req_nomem(state->inbuf.data, req)) {
3240                 return tevent_req_post(req, ev);
3241         }
3242
3243         if (replace) {
3244                 SCVAL(state->inbuf.data, 0, 1);
3245         }
3246
3247         SIVAL(state->inbuf.data, 16, converted_size_bytes);
3248         memcpy(state->inbuf.data + 20, converted_str, converted_size_bytes);
3249
3250         TALLOC_FREE(converted_str);
3251
3252         /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3253            level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3254
3255         subreq = cli_smb2_set_info_fnum_send(
3256                 state,          /* mem_ctx */
3257                 ev,             /* ev */
3258                 cli,            /* cli */
3259                 fnum,           /* fnum */
3260                 1,              /* in_info_type */
3261                 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
3262                 &state->inbuf,  /* in_input_buffer */
3263                 0);             /* in_additional_info */
3264         if (tevent_req_nomem(subreq, req)) {
3265                 return tevent_req_post(req, ev);
3266         }
3267         tevent_req_set_callback(subreq, cli_smb2_rename_fnum_done, req);
3268         return req;
3269 }
3270
3271 static void cli_smb2_rename_fnum_done(struct tevent_req *subreq)
3272 {
3273         NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
3274         tevent_req_simple_finish_ntstatus(subreq, status);
3275 }
3276
3277 static NTSTATUS cli_smb2_rename_fnum_recv(struct tevent_req *req)
3278 {
3279         return tevent_req_simple_recv_ntstatus(req);
3280 }
3281
3282 /***************************************************************
3283  Wrapper that allows SMB2 to rename a file.
3284 ***************************************************************/
3285
3286 struct cli_smb2_rename_state {
3287         struct tevent_context *ev;
3288         struct cli_state *cli;
3289         const char *fname_dst;
3290         bool replace;
3291         uint16_t fnum;
3292
3293         NTSTATUS rename_status;
3294 };
3295
3296 static void cli_smb2_rename_opened(struct tevent_req *subreq);
3297 static void cli_smb2_rename_renamed(struct tevent_req *subreq);
3298 static void cli_smb2_rename_closed(struct tevent_req *subreq);
3299
3300 struct tevent_req *cli_smb2_rename_send(
3301         TALLOC_CTX *mem_ctx,
3302         struct tevent_context *ev,
3303         struct cli_state *cli,
3304         const char *fname_src,
3305         const char *fname_dst,
3306         bool replace)
3307 {
3308         struct tevent_req *req = NULL, *subreq = NULL;
3309         struct cli_smb2_rename_state *state = NULL;
3310         NTSTATUS status;
3311
3312         req = tevent_req_create(
3313                 mem_ctx, &state, struct cli_smb2_rename_state);
3314         if (req == NULL) {
3315                 return NULL;
3316         }
3317
3318         /*
3319          * Strip a MSDFS path from fname_dst if we were given one.
3320          */
3321         status = cli_dfs_target_check(state,
3322                                 cli,
3323                                 fname_dst,
3324                                 &fname_dst);
3325         if (tevent_req_nterror(req, status)) {
3326                 return tevent_req_post(req, ev);
3327         }
3328
3329         state->ev = ev;
3330         state->cli = cli;
3331         state->fname_dst = fname_dst;
3332         state->replace = replace;
3333
3334         subreq = get_fnum_from_path_send(
3335                 state, ev, cli, fname_src, DELETE_ACCESS);
3336         if (tevent_req_nomem(subreq, req)) {
3337                 return tevent_req_post(req, ev);
3338         }
3339         tevent_req_set_callback(subreq, cli_smb2_rename_opened, req);
3340         return req;
3341 }
3342
3343 static void cli_smb2_rename_opened(struct tevent_req *subreq)
3344 {
3345         struct tevent_req *req = tevent_req_callback_data(
3346                 subreq, struct tevent_req);
3347         struct cli_smb2_rename_state *state = tevent_req_data(
3348                 req, struct cli_smb2_rename_state);
3349         NTSTATUS status;
3350
3351         status = get_fnum_from_path_recv(subreq, &state->fnum);
3352         TALLOC_FREE(subreq);
3353         if (tevent_req_nterror(req, status)) {
3354                 return;
3355         }
3356
3357         subreq = cli_smb2_rename_fnum_send(
3358                 state,
3359                 state->ev,
3360                 state->cli,
3361                 state->fnum,
3362                 state->fname_dst,
3363                 state->replace);
3364         if (tevent_req_nomem(subreq, req)) {
3365                 return;
3366         }
3367         tevent_req_set_callback(subreq, cli_smb2_rename_renamed, req);
3368 }
3369
3370 static void cli_smb2_rename_renamed(struct tevent_req *subreq)
3371 {
3372         struct tevent_req *req = tevent_req_callback_data(
3373                 subreq, struct tevent_req);
3374         struct cli_smb2_rename_state *state = tevent_req_data(
3375                 req, struct cli_smb2_rename_state);
3376
3377         state->rename_status = cli_smb2_rename_fnum_recv(subreq);
3378         TALLOC_FREE(subreq);
3379
3380         subreq = cli_smb2_close_fnum_send(
3381                 state, state->ev, state->cli, state->fnum);
3382         if (tevent_req_nomem(subreq, req)) {
3383                 return;
3384         }
3385         tevent_req_set_callback(subreq, cli_smb2_rename_closed, req);
3386 }
3387
3388 static void cli_smb2_rename_closed(struct tevent_req *subreq)
3389 {
3390         NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
3391         tevent_req_simple_finish_ntstatus(subreq, status);
3392 }
3393
3394 NTSTATUS cli_smb2_rename_recv(struct tevent_req *req)
3395 {
3396         struct cli_smb2_rename_state *state = tevent_req_data(
3397                 req, struct cli_smb2_rename_state);
3398         NTSTATUS status = NT_STATUS_OK;
3399
3400         if (!tevent_req_is_nterror(req, &status)) {
3401                 status = state->rename_status;
3402         }
3403         tevent_req_received(req);
3404         return status;
3405 }
3406
3407 /***************************************************************
3408  Wrapper that allows SMB2 to set an EA on a fnum.
3409  Synchronous only.
3410 ***************************************************************/
3411
3412 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
3413                         uint16_t fnum,
3414                         const char *ea_name,
3415                         const char *ea_val,
3416                         size_t ea_len)
3417 {
3418         NTSTATUS status;
3419         DATA_BLOB inbuf = data_blob_null;
3420         size_t bloblen = 0;
3421         char *ea_name_ascii = NULL;
3422         size_t namelen = 0;
3423         TALLOC_CTX *frame = talloc_stackframe();
3424
3425         if (smbXcli_conn_has_async_calls(cli->conn)) {
3426                 /*
3427                  * Can't use sync call while an async call is in flight
3428                  */
3429                 status = NT_STATUS_INVALID_PARAMETER;
3430                 goto fail;
3431         }
3432
3433         /* Marshall the SMB2 EA data. */
3434         if (ea_len > 0xFFFF) {
3435                 status = NT_STATUS_INVALID_PARAMETER;
3436                 goto fail;
3437         }
3438
3439         if (!push_ascii_talloc(frame,
3440                                 &ea_name_ascii,
3441                                 ea_name,
3442                                 &namelen)) {
3443                 status = NT_STATUS_INVALID_PARAMETER;
3444                 goto fail;
3445         }
3446
3447         if (namelen < 2 || namelen > 0xFF) {
3448                 status = NT_STATUS_INVALID_PARAMETER;
3449                 goto fail;
3450         }
3451
3452         bloblen = 8 + ea_len + namelen;
3453         /* Round up to a 4 byte boundary. */
3454         bloblen = ((bloblen + 3)&~3);
3455
3456         inbuf = data_blob_talloc_zero(frame, bloblen);
3457         if (inbuf.data == NULL) {
3458                 status = NT_STATUS_NO_MEMORY;
3459                 goto fail;
3460         }
3461         /* namelen doesn't include the NULL byte. */
3462         SCVAL(inbuf.data, 5, namelen - 1);
3463         SSVAL(inbuf.data, 6, ea_len);
3464         memcpy(inbuf.data + 8, ea_name_ascii, namelen);
3465         memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
3466
3467         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3468            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3469
3470         status = cli_smb2_set_info_fnum(
3471                 cli,
3472                 fnum,
3473                 1,              /* in_info_type */
3474                 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3475                 &inbuf,         /* in_input_buffer */
3476                 0);             /* in_additional_info */
3477
3478   fail:
3479
3480         cli->raw_status = status;
3481
3482         TALLOC_FREE(frame);
3483         return status;
3484 }
3485
3486 /***************************************************************
3487  Wrapper that allows SMB2 to set an EA on a pathname.
3488  Synchronous only.
3489 ***************************************************************/
3490
3491 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
3492                         const char *name,
3493                         const char *ea_name,
3494                         const char *ea_val,
3495                         size_t ea_len)
3496 {
3497         NTSTATUS status;
3498         uint16_t fnum = 0xffff;
3499
3500         if (smbXcli_conn_has_async_calls(cli->conn)) {
3501                 /*
3502                  * Can't use sync call while an async call is in flight
3503                  */
3504                 status = NT_STATUS_INVALID_PARAMETER;
3505                 goto fail;
3506         }
3507
3508         status = get_fnum_from_path(cli,
3509                                 name,
3510                                 FILE_WRITE_EA,
3511                                 &fnum);
3512
3513         if (!NT_STATUS_IS_OK(status)) {
3514                 goto fail;
3515         }
3516
3517         status = cli_set_ea_fnum(cli,
3518                                 fnum,
3519                                 ea_name,
3520                                 ea_val,
3521                                 ea_len);
3522         if (!NT_STATUS_IS_OK(status)) {
3523                 goto fail;
3524         }
3525
3526   fail:
3527
3528         if (fnum != 0xffff) {
3529                 cli_smb2_close_fnum(cli, fnum);
3530         }
3531
3532         cli->raw_status = status;
3533
3534         return status;
3535 }
3536
3537 /***************************************************************
3538  Wrapper that allows SMB2 to get an EA list on a pathname.
3539  Synchronous only.
3540 ***************************************************************/
3541
3542 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
3543                                 const char *name,
3544                                 TALLOC_CTX *ctx,
3545                                 size_t *pnum_eas,
3546                                 struct ea_struct **pea_array)
3547 {
3548         NTSTATUS status;
3549         uint16_t fnum = 0xffff;
3550         DATA_BLOB outbuf = data_blob_null;
3551         struct ea_list *ea_list = NULL;
3552         struct ea_list *eal = NULL;
3553         size_t ea_count = 0;
3554         TALLOC_CTX *frame = talloc_stackframe();
3555
3556         *pnum_eas = 0;
3557         *pea_array = NULL;
3558
3559         if (smbXcli_conn_has_async_calls(cli->conn)) {
3560                 /*
3561                  * Can't use sync call while an async call is in flight
3562                  */
3563                 status = NT_STATUS_INVALID_PARAMETER;
3564                 goto fail;
3565         }
3566
3567         status = get_fnum_from_path(cli,
3568                                 name,
3569                                 FILE_READ_EA,
3570                                 &fnum);
3571
3572         if (!NT_STATUS_IS_OK(status)) {
3573                 goto fail;
3574         }
3575
3576         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3577            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3578
3579         status = cli_smb2_query_info_fnum(
3580                 cli,
3581                 fnum,
3582                 1, /* in_info_type */
3583                 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3584                 0xFFFF, /* in_max_output_length */
3585                 NULL, /* in_input_buffer */
3586                 0, /* in_additional_info */
3587                 0, /* in_flags */
3588                 frame,
3589                 &outbuf);
3590
3591         if (!NT_STATUS_IS_OK(status)) {
3592                 goto fail;
3593         }
3594
3595         /* Parse the reply. */
3596         ea_list = read_nttrans_ea_list(ctx,
3597                                 (const char *)outbuf.data,
3598                                 outbuf.length);
3599         if (ea_list == NULL) {
3600                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3601                 goto fail;
3602         }
3603
3604         /* Convert to an array. */
3605         for (eal = ea_list; eal; eal = eal->next) {
3606                 ea_count++;
3607         }
3608
3609         if (ea_count) {
3610                 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
3611                 if (*pea_array == NULL) {
3612                         status = NT_STATUS_NO_MEMORY;
3613                         goto fail;
3614                 }
3615                 ea_count = 0;
3616                 for (eal = ea_list; eal; eal = eal->next) {
3617                         (*pea_array)[ea_count++] = eal->ea;
3618                 }
3619                 *pnum_eas = ea_count;
3620         }
3621
3622   fail:
3623
3624         if (fnum != 0xffff) {
3625                 cli_smb2_close_fnum(cli, fnum);
3626         }
3627
3628         cli->raw_status = status;
3629
3630         TALLOC_FREE(frame);
3631         return status;
3632 }
3633
3634 /***************************************************************
3635  Wrapper that allows SMB2 to get user quota.
3636  Synchronous only.
3637 ***************************************************************/
3638
3639 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
3640                                  int quota_fnum,
3641                                  SMB_NTQUOTA_STRUCT *pqt)
3642 {
3643         NTSTATUS status;
3644         DATA_BLOB inbuf = data_blob_null;
3645         DATA_BLOB info_blob = data_blob_null;
3646         DATA_BLOB outbuf = data_blob_null;
3647         TALLOC_CTX *frame = talloc_stackframe();
3648         unsigned sid_len;
3649         unsigned int offset;
3650         struct smb2_query_quota_info query = {0};
3651         struct file_get_quota_info info = {0};
3652         enum ndr_err_code err;
3653         struct ndr_push *ndr_push = NULL;
3654
3655         if (smbXcli_conn_has_async_calls(cli->conn)) {
3656                 /*
3657                  * Can't use sync call while an async call is in flight
3658                  */
3659                 status = NT_STATUS_INVALID_PARAMETER;
3660                 goto fail;
3661         }
3662
3663         sid_len = ndr_size_dom_sid(&pqt->sid, 0);
3664
3665         query.return_single = 1;
3666
3667         info.next_entry_offset = 0;
3668         info.sid_length = sid_len;
3669         info.sid = pqt->sid;
3670
3671         err = ndr_push_struct_blob(
3672                         &info_blob,
3673                         frame,
3674                         &info,
3675                         (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
3676
3677         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3678                 status = NT_STATUS_INTERNAL_ERROR;
3679                 goto fail;
3680         }
3681
3682         query.sid_list_length = info_blob.length;
3683         ndr_push = ndr_push_init_ctx(frame);
3684         if (!ndr_push) {
3685                 status = NT_STATUS_NO_MEMORY;
3686                 goto fail;
3687         }
3688
3689         err = ndr_push_smb2_query_quota_info(ndr_push,
3690                                              NDR_SCALARS | NDR_BUFFERS,
3691                                              &query);
3692
3693         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3694                 status = NT_STATUS_INTERNAL_ERROR;
3695                 goto fail;
3696         }
3697
3698         err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3699                                    info_blob.length);
3700
3701         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3702                 status = NT_STATUS_INTERNAL_ERROR;
3703                 goto fail;
3704         }
3705         inbuf.data = ndr_push->data;
3706         inbuf.length = ndr_push->offset;
3707
3708         status = cli_smb2_query_info_fnum(
3709                 cli,
3710                 quota_fnum,
3711                 4, /* in_info_type */
3712                 0,                     /* in_file_info_class */
3713                 0xFFFF, /* in_max_output_length */
3714                 &inbuf, /* in_input_buffer */
3715                 0,      /* in_additional_info */
3716                 0,      /* in_flags */
3717                 frame,
3718                 &outbuf);
3719
3720         if (!NT_STATUS_IS_OK(status)) {
3721                 goto fail;
3722         }
3723
3724         if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3725                                      pqt)) {
3726                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3727                 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3728         }
3729
3730 fail:
3731         cli->raw_status = status;
3732
3733         TALLOC_FREE(frame);
3734         return status;
3735 }
3736
3737 /***************************************************************
3738  Wrapper that allows SMB2 to list user quota.
3739  Synchronous only.
3740 ***************************************************************/
3741
3742 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3743                                        TALLOC_CTX *mem_ctx,
3744                                        int quota_fnum,
3745                                        SMB_NTQUOTA_LIST **pqt_list,
3746                                        bool first)
3747 {
3748         NTSTATUS status;
3749         DATA_BLOB inbuf = data_blob_null;
3750         DATA_BLOB outbuf = data_blob_null;
3751         TALLOC_CTX *frame = talloc_stackframe();
3752         struct smb2_query_quota_info info = {0};
3753         enum ndr_err_code err;
3754
3755         if (smbXcli_conn_has_async_calls(cli->conn)) {
3756                 /*
3757                  * Can't use sync call while an async call is in flight
3758                  */
3759                 status = NT_STATUS_INVALID_PARAMETER;
3760                 goto cleanup;
3761         }
3762
3763         info.restart_scan = first ? 1 : 0;
3764
3765         err = ndr_push_struct_blob(
3766                         &inbuf,
3767                         frame,
3768                         &info,
3769                         (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3770
3771         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3772                 status = NT_STATUS_INTERNAL_ERROR;
3773                 goto cleanup;
3774         }
3775
3776         status = cli_smb2_query_info_fnum(
3777                 cli,
3778                 quota_fnum,
3779                 4, /* in_info_type */
3780                 0, /* in_file_info_class */
3781                 0xFFFF, /* in_max_output_length */
3782                 &inbuf, /* in_input_buffer */
3783                 0,      /* in_additional_info */
3784                 0,      /* in_flags */
3785                 frame,
3786                 &outbuf);
3787
3788         /*
3789          * safeguard against panic from calling parse_user_quota_list with
3790          * NULL buffer
3791          */
3792         if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3793                 status = NT_STATUS_NO_MORE_ENTRIES;
3794         }
3795
3796         if (!NT_STATUS_IS_OK(status)) {
3797                 goto cleanup;
3798         }
3799
3800         status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3801                                        pqt_list);
3802
3803 cleanup:
3804         cli->raw_status = status;
3805
3806         TALLOC_FREE(frame);
3807         return status;
3808 }
3809
3810 /***************************************************************
3811  Wrapper that allows SMB2 to get file system quota.
3812  Synchronous only.
3813 ***************************************************************/
3814
3815 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3816                                     int quota_fnum,
3817                                     SMB_NTQUOTA_STRUCT *pqt)
3818 {
3819         NTSTATUS status;
3820         DATA_BLOB outbuf = data_blob_null;
3821         TALLOC_CTX *frame = talloc_stackframe();
3822
3823         if (smbXcli_conn_has_async_calls(cli->conn)) {
3824                 /*
3825                  * Can't use sync call while an async call is in flight
3826                  */
3827                 status = NT_STATUS_INVALID_PARAMETER;
3828                 goto cleanup;
3829         }
3830
3831         status = cli_smb2_query_info_fnum(
3832                 cli,
3833                 quota_fnum,
3834                 2,                                   /* in_info_type */
3835                 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3836                 0xFFFF,                      /* in_max_output_length */
3837                 NULL,                        /* in_input_buffer */
3838                 0,                                   /* in_additional_info */
3839                 0,                                   /* in_flags */
3840                 frame,
3841                 &outbuf);
3842
3843         if (!NT_STATUS_IS_OK(status)) {
3844                 goto cleanup;
3845         }
3846
3847         status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3848
3849 cleanup:
3850         cli->raw_status = status;
3851
3852         TALLOC_FREE(frame);
3853         return status;
3854 }
3855
3856 /***************************************************************
3857  Wrapper that allows SMB2 to set user quota.
3858  Synchronous only.
3859 ***************************************************************/
3860
3861 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3862                                  int quota_fnum,
3863                                  SMB_NTQUOTA_LIST *qtl)
3864 {
3865         NTSTATUS status;
3866         DATA_BLOB inbuf = data_blob_null;
3867         TALLOC_CTX *frame = talloc_stackframe();
3868
3869         if (smbXcli_conn_has_async_calls(cli->conn)) {
3870                 /*
3871                  * Can't use sync call while an async call is in flight
3872                  */
3873                 status = NT_STATUS_INVALID_PARAMETER;
3874                 goto cleanup;
3875         }
3876
3877         status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3878         if (!NT_STATUS_IS_OK(status)) {
3879                 goto cleanup;
3880         }
3881
3882         status = cli_smb2_set_info_fnum(
3883                 cli,
3884                 quota_fnum,
3885                 4,                        /* in_info_type */
3886                 0,                        /* in_file_info_class */
3887                 &inbuf,                   /* in_input_buffer */
3888                 0);                       /* in_additional_info */
3889 cleanup:
3890
3891         cli->raw_status = status;
3892
3893         TALLOC_FREE(frame);
3894
3895         return status;
3896 }
3897
3898 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3899                                     int quota_fnum,
3900                                     SMB_NTQUOTA_STRUCT *pqt)
3901 {
3902         NTSTATUS status;
3903         DATA_BLOB inbuf = data_blob_null;
3904         TALLOC_CTX *frame = talloc_stackframe();
3905
3906         if (smbXcli_conn_has_async_calls(cli->conn)) {
3907                 /*
3908                  * Can't use sync call while an async call is in flight
3909                  */
3910                 status = NT_STATUS_INVALID_PARAMETER;
3911                 goto cleanup;
3912         }
3913
3914         status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3915         if (!NT_STATUS_IS_OK(status)) {
3916                 goto cleanup;
3917         }
3918
3919         status = cli_smb2_set_info_fnum(
3920                 cli,
3921                 quota_fnum,
3922                 2,                           /* in_info_type */
3923                 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3924                 &inbuf,                      /* in_input_buffer */
3925                 0);                          /* in_additional_info */
3926 cleanup:
3927         cli->raw_status = status;
3928
3929         TALLOC_FREE(frame);
3930         return status;
3931 }
3932
3933 struct cli_smb2_read_state {
3934         struct tevent_context *ev;
3935         struct cli_state *cli;
3936         struct smb2_hnd *ph;
3937         uint64_t start_offset;
3938         uint32_t size;
3939         uint32_t received;
3940         uint8_t *buf;
3941 };
3942
3943 static void cli_smb2_read_done(struct tevent_req *subreq);
3944
3945 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3946                                 struct tevent_context *ev,
3947                                 struct cli_state *cli,
3948                                 uint16_t fnum,
3949                                 off_t offset,
3950                                 size_t size)
3951 {
3952         NTSTATUS status;
3953         struct tevent_req *req, *subreq;
3954         struct cli_smb2_read_state *state;
3955
3956         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3957         if (req == NULL) {
3958                 return NULL;
3959         }
3960         state->ev = ev;
3961         state->cli = cli;
3962         state->start_offset = (uint64_t)offset;
3963         state->size = (uint32_t)size;
3964         state->received = 0;
3965         state->buf = NULL;
3966
3967         status = map_fnum_to_smb2_handle(cli,
3968                                         fnum,
3969                                         &state->ph);
3970         if (tevent_req_nterror(req, status)) {
3971                 return tevent_req_post(req, ev);
3972         }
3973
3974         subreq = smb2cli_read_send(state,
3975                                 state->ev,
3976                                 state->cli->conn,
3977                                 state->cli->timeout,
3978                                 state->cli->smb2.session,
3979                                 state->cli->smb2.tcon,
3980                                 state->size,
3981                                 state->start_offset,
3982                                 state->ph->fid_persistent,
3983                                 state->ph->fid_volatile,
3984                                 0, /* minimum_count */
3985                                 0); /* remaining_bytes */
3986
3987         if (tevent_req_nomem(subreq, req)) {
3988                 return tevent_req_post(req, ev);
3989         }
3990         tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3991         return req;
3992 }
3993
3994 static void cli_smb2_read_done(struct tevent_req *subreq)
3995 {
3996         struct tevent_req *req = tevent_req_callback_data(
3997                 subreq, struct tevent_req);
3998         struct cli_smb2_read_state *state = tevent_req_data(
3999                 req, struct cli_smb2_read_state);
4000         NTSTATUS status;
4001
4002         status = smb2cli_read_recv(subreq, state,
4003                                    &state->buf, &state->received);
4004         if (tevent_req_nterror(req, status)) {
4005                 return;
4006         }
4007
4008         if (state->received > state->size) {
4009                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4010                 return;
4011         }
4012
4013         tevent_req_done(req);
4014 }
4015
4016 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
4017                                 ssize_t *received,
4018                                 uint8_t **rcvbuf)
4019 {
4020         NTSTATUS status;
4021         struct cli_smb2_read_state *state = tevent_req_data(
4022                                 req, struct cli_smb2_read_state);
4023
4024         if (tevent_req_is_nterror(req, &status)) {
4025                 state->cli->raw_status = status;
4026                 return status;
4027         }
4028         /*
4029          * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
4030          * better make sure that you copy it away before you talloc_free(req).
4031          * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
4032          */
4033         *received = (ssize_t)state->received;
4034         *rcvbuf = state->buf;
4035         state->cli->raw_status = NT_STATUS_OK;
4036         return NT_STATUS_OK;
4037 }
4038
4039 struct cli_smb2_write_state {
4040         struct tevent_context *ev;
4041         struct cli_state *cli;
4042         struct smb2_hnd *ph;
4043         uint32_t flags;
4044         const uint8_t *buf;
4045         uint64_t offset;
4046         uint32_t size;
4047         uint32_t written;
4048 };
4049
4050 static void cli_smb2_write_written(struct tevent_req *req);
4051
4052 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
4053                                         struct tevent_context *ev,
4054                                         struct cli_state *cli,
4055                                         uint16_t fnum,
4056                                         uint16_t mode,
4057                                         const uint8_t *buf,
4058                                         off_t offset,
4059                                         size_t size)
4060 {
4061         NTSTATUS status;
4062         struct tevent_req *req, *subreq = NULL;
4063         struct cli_smb2_write_state *state = NULL;
4064
4065         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
4066         if (req == NULL) {
4067                 return NULL;
4068         }
4069         state->ev = ev;
4070         state->cli = cli;
4071         /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4072         state->flags = (uint32_t)mode;
4073         state->buf = buf;
4074         state->offset = (uint64_t)offset;
4075         state->size = (uint32_t)size;
4076         state->written = 0;
4077
4078         status = map_fnum_to_smb2_handle(cli,
4079                                         fnum,
4080                                         &state->ph);
4081         if (tevent_req_nterror(req, status)) {
4082                 return tevent_req_post(req, ev);
4083         }
4084
4085         subreq = smb2cli_write_send(state,
4086                                 state->ev,
4087                                 state->cli->conn,
4088                                 state->cli->timeout,
4089                                 state->cli->smb2.session,
4090                                 state->cli->smb2.tcon,
4091                                 state->size,
4092                                 state->offset,
4093                                 state->ph->fid_persistent,
4094                                 state->ph->fid_volatile,
4095                                 0, /* remaining_bytes */
4096                                 state->flags, /* flags */
4097                                 state->buf);
4098
4099         if (tevent_req_nomem(subreq, req)) {
4100                 return tevent_req_post(req, ev);
4101         }
4102         tevent_req_set_callback(subreq, cli_smb2_write_written, req);
4103         return req;
4104 }
4105
4106 static void cli_smb2_write_written(struct tevent_req *subreq)
4107 {
4108         struct tevent_req *req = tevent_req_callback_data(
4109                 subreq, struct tevent_req);
4110         struct cli_smb2_write_state *state = tevent_req_data(
4111                 req, struct cli_smb2_write_state);
4112         NTSTATUS status;
4113         uint32_t written;
4114
4115         status = smb2cli_write_recv(subreq, &written);
4116         TALLOC_FREE(subreq);
4117         if (tevent_req_nterror(req, status)) {
4118                 return;
4119         }
4120
4121         state->written = written;
4122
4123         tevent_req_done(req);
4124 }
4125
4126 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
4127                              size_t *pwritten)
4128 {
4129         struct cli_smb2_write_state *state = tevent_req_data(
4130                 req, struct cli_smb2_write_state);
4131         NTSTATUS status;
4132
4133         if (tevent_req_is_nterror(req, &status)) {
4134                 state->cli->raw_status = status;
4135                 tevent_req_received(req);
4136                 return status;
4137         }
4138
4139         if (pwritten != NULL) {
4140                 *pwritten = (size_t)state->written;
4141         }
4142         state->cli->raw_status = NT_STATUS_OK;
4143         tevent_req_received(req);
4144         return NT_STATUS_OK;
4145 }
4146
4147 /***************************************************************
4148  Wrapper that allows SMB2 async write using an fnum.
4149  This is mostly cut-and-paste from Volker's code inside
4150  source3/libsmb/clireadwrite.c, adapted for SMB2.
4151
4152  Done this way so I can reuse all the logic inside cli_push()
4153  for free :-).
4154 ***************************************************************/
4155
4156 struct cli_smb2_writeall_state {
4157         struct tevent_context *ev;
4158         struct cli_state *cli;
4159         struct smb2_hnd *ph;
4160         uint32_t flags;
4161         const uint8_t *buf;
4162         uint64_t offset;
4163         uint32_t size;
4164         uint32_t written;
4165 };
4166
4167 static void cli_smb2_writeall_written(struct tevent_req *req);
4168
4169 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
4170                                         struct tevent_context *ev,
4171                                         struct cli_state *cli,
4172                                         uint16_t fnum,
4173                                         uint16_t mode,
4174                                         const uint8_t *buf,
4175                                         off_t offset,
4176                                         size_t size)
4177 {
4178         NTSTATUS status;
4179         struct tevent_req *req, *subreq = NULL;
4180         struct cli_smb2_writeall_state *state = NULL;
4181         uint32_t to_write;
4182         uint32_t max_size;
4183         bool ok;
4184
4185         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
4186         if (req == NULL) {
4187                 return NULL;
4188         }
4189         state->ev = ev;
4190         state->cli = cli;
4191         /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4192         state->flags = (uint32_t)mode;
4193         state->buf = buf;
4194         state->offset = (uint64_t)offset;
4195         state->size = (uint32_t)size;
4196         state->written = 0;
4197
4198         status = map_fnum_to_smb2_handle(cli,
4199                                         fnum,
4200                                         &state->ph);
4201         if (tevent_req_nterror(req, status)) {
4202                 return tevent_req_post(req, ev);
4203         }
4204
4205         to_write = state->size;
4206         max_size = smb2cli_conn_max_write_size(state->cli->conn);
4207         to_write = MIN(max_size, to_write);
4208         ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4209         if (ok) {
4210                 to_write = MIN(max_size, to_write);
4211         }
4212
4213         subreq = smb2cli_write_send(state,
4214                                 state->ev,
4215                                 state->cli->conn,
4216                                 state->cli->timeout,
4217                                 state->cli->smb2.session,
4218                                 state->cli->smb2.tcon,
4219                                 to_write,
4220                                 state->offset,
4221                                 state->ph->fid_persistent,
4222                                 state->ph->fid_volatile,
4223                                 0, /* remaining_bytes */
4224                                 state->flags, /* flags */
4225                                 state->buf + state->written);
4226
4227         if (tevent_req_nomem(subreq, req)) {
4228                 return tevent_req_post(req, ev);
4229         }
4230         tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4231         return req;
4232 }
4233
4234 static void cli_smb2_writeall_written(struct tevent_req *subreq)
4235 {
4236         struct tevent_req *req = tevent_req_callback_data(
4237                 subreq, struct tevent_req);
4238         struct cli_smb2_writeall_state *state = tevent_req_data(
4239                 req, struct cli_smb2_writeall_state);
4240         NTSTATUS status;
4241         uint32_t written, to_write;
4242         uint32_t max_size;
4243         bool ok;
4244
4245         status = smb2cli_write_recv(subreq, &written);
4246         TALLOC_FREE(subreq);
4247         if (tevent_req_nterror(req, status)) {
4248                 return;
4249         }
4250
4251         state->written += written;
4252
4253         if (state->written > state->size) {
4254                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4255                 return;
4256         }
4257
4258         to_write = state->size - state->written;
4259
4260         if (to_write == 0) {
4261                 tevent_req_done(req);
4262                 return;
4263         }
4264
4265         max_size = smb2cli_conn_max_write_size(state->cli->conn);
4266         to_write = MIN(max_size, to_write);
4267         ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4268         if (ok) {
4269                 to_write = MIN(max_size, to_write);
4270         }
4271
4272         subreq = smb2cli_write_send(state,
4273                                 state->ev,
4274                                 state->cli->conn,
4275                                 state->cli->timeout,
4276                                 state->cli->smb2.session,
4277                                 state->cli->smb2.tcon,
4278                                 to_write,
4279                                 state->offset + state->written,
4280                                 state->ph->fid_persistent,
4281                                 state->ph->fid_volatile,
4282                                 0, /* remaining_bytes */
4283                                 state->flags, /* flags */
4284                                 state->buf + state->written);
4285
4286         if (tevent_req_nomem(subreq, req)) {
4287                 return;
4288         }
4289         tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4290 }
4291
4292 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
4293                                 size_t *pwritten)
4294 {
4295         struct cli_smb2_writeall_state *state = tevent_req_data(
4296                 req, struct cli_smb2_writeall_state);
4297         NTSTATUS status;
4298
4299         if (tevent_req_is_nterror(req, &status)) {
4300                 state->cli->raw_status = status;
4301                 return status;
4302         }
4303         if (pwritten != NULL) {
4304                 *pwritten = (size_t)state->written;
4305         }
4306         state->cli->raw_status = NT_STATUS_OK;
4307         return NT_STATUS_OK;
4308 }
4309
4310 struct cli_smb2_splice_state {
4311         struct tevent_context *ev;
4312         struct cli_state *cli;
4313         struct smb2_hnd *src_ph;
4314         struct smb2_hnd *dst_ph;
4315         int (*splice_cb)(off_t n, void *priv);
4316         void *priv;
4317         off_t written;
4318         off_t size;
4319         off_t src_offset;
4320         off_t dst_offset;
4321         bool resized;
4322         struct req_resume_key_rsp resume_rsp;
4323         struct srv_copychunk_copy cc_copy;
4324 };
4325
4326 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4327                                       struct tevent_req *req);
4328
4329 static void cli_splice_copychunk_done(struct tevent_req *subreq)
4330 {
4331         struct tevent_req *req = tevent_req_callback_data(
4332                 subreq, struct tevent_req);
4333         struct cli_smb2_splice_state *state =
4334                 tevent_req_data(req,
4335                 struct cli_smb2_splice_state);
4336         struct smbXcli_conn *conn = state->cli->conn;
4337         DATA_BLOB out_input_buffer = data_blob_null;
4338         DATA_BLOB out_output_buffer = data_blob_null;
4339         struct srv_copychunk_rsp cc_copy_rsp;
4340         enum ndr_err_code ndr_ret;
4341         NTSTATUS status;
4342
4343         status = smb2cli_ioctl_recv(subreq, state,
4344                                     &out_input_buffer,
4345                                     &out_output_buffer);
4346         TALLOC_FREE(subreq);
4347         if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
4348              state->resized) && tevent_req_nterror(req, status)) {
4349                 return;
4350         }
4351
4352         ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
4353                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
4354         if (ndr_ret != NDR_ERR_SUCCESS) {
4355                 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4356                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4357                 return;
4358         }
4359
4360         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
4361                 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
4362                              cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
4363                 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
4364                      max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
4365                      tevent_req_nterror(req, status)) {
4366                         return;
4367                 }
4368
4369                 state->resized = true;
4370                 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
4371                 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
4372         } else {
4373                 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4374                     (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4375                     (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
4376                         tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4377                         return;
4378                 }
4379                 state->src_offset += cc_copy_rsp.total_bytes_written;
4380                 state->dst_offset += cc_copy_rsp.total_bytes_written;
4381                 state->written += cc_copy_rsp.total_bytes_written;
4382                 if (!state->splice_cb(state->written, state->priv)) {
4383                         tevent_req_nterror(req, NT_STATUS_CANCELLED);
4384                         return;
4385                 }
4386         }
4387
4388         cli_splice_copychunk_send(state, req);
4389 }
4390
4391 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4392                                       struct tevent_req *req)
4393 {
4394         struct tevent_req *subreq;
4395         enum ndr_err_code ndr_ret;
4396         struct smbXcli_conn *conn = state->cli->conn;
4397         struct srv_copychunk_copy *cc_copy = &state->cc_copy;
4398         off_t src_offset = state->src_offset;
4399         off_t dst_offset = state->dst_offset;
4400         uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
4401                                state->size - state->written);
4402         DATA_BLOB in_input_buffer = data_blob_null;
4403         DATA_BLOB in_output_buffer = data_blob_null;
4404
4405         if (state->size - state->written == 0) {
4406                 tevent_req_done(req);
4407                 return;
4408         }
4409
4410         cc_copy->chunk_count = 0;
4411         while (req_len) {
4412                 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
4413                 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
4414                 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
4415                                                                    smb2cli_conn_cc_chunk_len(conn));
4416                 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
4417                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4418                         return;
4419                 }
4420                 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
4421                 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
4422                     (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
4423                         tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4424                         return;
4425                 }
4426                 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4427                 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4428                 cc_copy->chunk_count++;
4429         }
4430
4431         ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
4432                                        (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
4433         if (ndr_ret != NDR_ERR_SUCCESS) {
4434                 DEBUG(0, ("failed to marshall copy chunk req\n"));
4435                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4436                 return;
4437         }
4438
4439         subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
4440                                state->cli->timeout,
4441                                state->cli->smb2.session,
4442                                state->cli->smb2.tcon,
4443                                state->dst_ph->fid_persistent, /* in_fid_persistent */
4444                                state->dst_ph->fid_volatile, /* in_fid_volatile */
4445                                FSCTL_SRV_COPYCHUNK_WRITE,
4446                                0, /* in_max_input_length */
4447                                &in_input_buffer,
4448                                12, /* in_max_output_length */
4449                                &in_output_buffer,
4450                                SMB2_IOCTL_FLAG_IS_FSCTL);
4451         if (tevent_req_nomem(subreq, req)) {
4452                 return;
4453         }
4454         tevent_req_set_callback(subreq,
4455                                 cli_splice_copychunk_done,
4456                                 req);
4457 }
4458
4459 static void cli_splice_key_done(struct tevent_req *subreq)
4460 {
4461         struct tevent_req *req = tevent_req_callback_data(
4462                 subreq, struct tevent_req);
4463         struct cli_smb2_splice_state *state =
4464                 tevent_req_data(req,
4465                 struct cli_smb2_splice_state);
4466         enum ndr_err_code ndr_ret;
4467         NTSTATUS status;
4468
4469         DATA_BLOB out_input_buffer = data_blob_null;
4470         DATA_BLOB out_output_buffer = data_blob_null;
4471
4472         status = smb2cli_ioctl_recv(subreq, state,
4473                                     &out_input_buffer,
4474                                     &out_output_buffer);
4475         TALLOC_FREE(subreq);
4476         if (tevent_req_nterror(req, status)) {
4477                 return;
4478         }
4479
4480         ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
4481                         state, &state->resume_rsp,
4482                         (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
4483         if (ndr_ret != NDR_ERR_SUCCESS) {
4484                 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4485                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4486                 return;
4487         }
4488
4489         memcpy(&state->cc_copy.source_key,
4490                &state->resume_rsp.resume_key,
4491                sizeof state->resume_rsp.resume_key);
4492
4493         cli_splice_copychunk_send(state, req);
4494 }
4495
4496 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
4497                                 struct tevent_context *ev,
4498                                 struct cli_state *cli,
4499                                 uint16_t src_fnum, uint16_t dst_fnum,
4500                                 off_t size, off_t src_offset, off_t dst_offset,
4501                                 int (*splice_cb)(off_t n, void *priv),
4502                                 void *priv)
4503 {
4504         struct tevent_req *req;
4505         struct tevent_req *subreq;
4506         struct cli_smb2_splice_state *state;
4507         NTSTATUS status;
4508         DATA_BLOB in_input_buffer = data_blob_null;
4509         DATA_BLOB in_output_buffer = data_blob_null;
4510
4511         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
4512         if (req == NULL) {
4513                 return NULL;
4514         }
4515         state->cli = cli;
4516         state->ev = ev;
4517         state->splice_cb = splice_cb;
4518         state->priv = priv;
4519         state->size = size;
4520         state->written = 0;
4521         state->src_offset = src_offset;
4522         state->dst_offset = dst_offset;
4523         state->cc_copy.chunks = talloc_array(state,
4524                                              struct srv_copychunk,
4525                                              smb2cli_conn_cc_max_chunks(cli->conn));
4526         if (state->cc_copy.chunks == NULL) {
4527                 return NULL;
4528         }
4529
4530         status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
4531         if (tevent_req_nterror(req, status))
4532                 return tevent_req_post(req, ev);
4533
4534         status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
4535         if (tevent_req_nterror(req, status))
4536                 return tevent_req_post(req, ev);
4537
4538         subreq = smb2cli_ioctl_send(state, ev, cli->conn,
4539                                cli->timeout,
4540                                cli->smb2.session,
4541                                cli->smb2.tcon,
4542                                state->src_ph->fid_persistent, /* in_fid_persistent */
4543                                state->src_ph->fid_volatile, /* in_fid_volatile */
4544                                FSCTL_SRV_REQUEST_RESUME_KEY,
4545                                0, /* in_max_input_length */
4546                                &in_input_buffer,
4547                                32, /* in_max_output_length */
4548                                &in_output_buffer,
4549                                SMB2_IOCTL_FLAG_IS_FSCTL);
4550         if (tevent_req_nomem(subreq, req)) {
4551                 return NULL;
4552         }
4553         tevent_req_set_callback(subreq,
4554                                 cli_splice_key_done,
4555                                 req);
4556
4557         return req;
4558 }
4559
4560 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
4561 {
4562         struct cli_smb2_splice_state *state = tevent_req_data(
4563                 req, struct cli_smb2_splice_state);
4564         NTSTATUS status;
4565
4566         if (tevent_req_is_nterror(req, &status)) {
4567                 state->cli->raw_status = status;
4568                 tevent_req_received(req);
4569                 return status;
4570         }
4571         if (written != NULL) {
4572                 *written = state->written;
4573         }
4574         state->cli->raw_status = NT_STATUS_OK;
4575         tevent_req_received(req);
4576         return NT_STATUS_OK;
4577 }
4578
4579 /***************************************************************
4580  SMB2 enum shadow copy data.
4581 ***************************************************************/
4582
4583 struct cli_smb2_shadow_copy_data_fnum_state {
4584         struct cli_state *cli;
4585         uint16_t fnum;
4586         struct smb2_hnd *ph;
4587         DATA_BLOB out_input_buffer;
4588         DATA_BLOB out_output_buffer;
4589 };
4590
4591 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
4592
4593 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
4594                                         TALLOC_CTX *mem_ctx,
4595                                         struct tevent_context *ev,
4596                                         struct cli_state *cli,
4597                                         uint16_t fnum,
4598                                         bool get_names)
4599 {
4600         struct tevent_req *req, *subreq;
4601         struct cli_smb2_shadow_copy_data_fnum_state *state;
4602         NTSTATUS status;
4603
4604         req = tevent_req_create(mem_ctx, &state,
4605                                 struct cli_smb2_shadow_copy_data_fnum_state);
4606         if (req == NULL) {
4607                 return NULL;
4608         }
4609
4610         state->cli = cli;
4611         state->fnum = fnum;
4612
4613         status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4614         if (tevent_req_nterror(req, status)) {
4615                 return tevent_req_post(req, ev);
4616         }
4617
4618         /*
4619          * TODO. Under SMB2 we should send a zero max_output_length
4620          * ioctl to get the required size, then send another ioctl
4621          * to get the data, but the current SMB1 implementation just
4622          * does one roundtrip with a 64K buffer size. Do the same
4623          * for now. JRA.
4624          */
4625
4626         subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4627                         state->cli->timeout,
4628                         state->cli->smb2.session,
4629                         state->cli->smb2.tcon,
4630                         state->ph->fid_persistent, /* in_fid_persistent */
4631                         state->ph->fid_volatile, /* in_fid_volatile */
4632                         FSCTL_GET_SHADOW_COPY_DATA,
4633                         0, /* in_max_input_length */
4634                         NULL, /* in_input_buffer */
4635                         get_names ?
4636                                 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
4637                         NULL, /* in_output_buffer */
4638                         SMB2_IOCTL_FLAG_IS_FSCTL);
4639
4640         if (tevent_req_nomem(subreq, req)) {
4641                 return tevent_req_post(req, ev);
4642         }
4643         tevent_req_set_callback(subreq,
4644                                 cli_smb2_shadow_copy_data_fnum_done,
4645                                 req);
4646
4647         return req;
4648 }
4649
4650 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4651 {
4652         struct tevent_req *req = tevent_req_callback_data(
4653                 subreq, struct tevent_req);
4654         struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4655                 req, struct cli_smb2_shadow_copy_data_fnum_state);
4656         NTSTATUS status;
4657
4658         status = smb2cli_ioctl_recv(subreq, state,
4659                                 &state->out_input_buffer,
4660                                 &state->out_output_buffer);
4661         tevent_req_simple_finish_ntstatus(subreq, status);
4662 }
4663
4664 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4665                                 TALLOC_CTX *mem_ctx,
4666                                 bool get_names,
4667                                 char ***pnames,
4668                                 int *pnum_names)
4669 {
4670         struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4671                 req, struct cli_smb2_shadow_copy_data_fnum_state);
4672         char **names = NULL;
4673         uint32_t num_names = 0;
4674         uint32_t num_names_returned = 0;
4675         uint32_t dlength = 0;
4676         uint32_t i;
4677         uint8_t *endp = NULL;
4678         NTSTATUS status;
4679
4680         if (tevent_req_is_nterror(req, &status)) {
4681                 return status;
4682         }
4683
4684         if (state->out_output_buffer.length < 16) {
4685                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4686         }
4687
4688         num_names = IVAL(state->out_output_buffer.data, 0);
4689         num_names_returned = IVAL(state->out_output_buffer.data, 4);
4690         dlength = IVAL(state->out_output_buffer.data, 8);
4691
4692         if (num_names > 0x7FFFFFFF) {
4693                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4694         }
4695
4696         if (get_names == false) {
4697                 *pnum_names = (int)num_names;
4698                 return NT_STATUS_OK;
4699         }
4700         if (num_names != num_names_returned) {
4701                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4702         }
4703         if (dlength + 12 < 12) {
4704                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4705         }
4706         /*
4707          * NB. The below is an allowable return if there are
4708          * more snapshots than the buffer size we told the
4709          * server we can receive. We currently don't support
4710          * this.
4711          */
4712         if (dlength + 12 > state->out_output_buffer.length) {
4713                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4714         }
4715         if (state->out_output_buffer.length +
4716                         (2 * sizeof(SHADOW_COPY_LABEL)) <
4717                                 state->out_output_buffer.length) {
4718                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4719         }
4720
4721         names = talloc_array(mem_ctx, char *, num_names_returned);
4722         if (names == NULL) {
4723                 return NT_STATUS_NO_MEMORY;
4724         }
4725
4726         endp = state->out_output_buffer.data +
4727                         state->out_output_buffer.length;
4728
4729         for (i=0; i<num_names_returned; i++) {
4730                 bool ret;
4731                 uint8_t *src;
4732                 size_t converted_size;
4733
4734                 src = state->out_output_buffer.data + 12 +
4735                         (i * 2 * sizeof(SHADOW_COPY_LABEL));
4736
4737                 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4738                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
4739                 }
4740                 ret = convert_string_talloc(
4741                         names, CH_UTF16LE, CH_UNIX,
4742                         src, 2 * sizeof(SHADOW_COPY_LABEL),
4743                         &names[i], &converted_size);
4744                 if (!ret) {
4745                         TALLOC_FREE(names);
4746                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
4747                 }
4748         }
4749         *pnum_names = num_names;
4750         *pnames = names;
4751         return NT_STATUS_OK;
4752 }
4753
4754 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4755                                 struct cli_state *cli,
4756                                 uint16_t fnum,
4757                                 bool get_names,
4758                                 char ***pnames,
4759                                 int *pnum_names)
4760 {
4761         TALLOC_CTX *frame = talloc_stackframe();
4762         struct tevent_context *ev;
4763         struct tevent_req *req;
4764         NTSTATUS status = NT_STATUS_NO_MEMORY;
4765
4766         if (smbXcli_conn_has_async_calls(cli->conn)) {
4767                 /*
4768                  * Can't use sync call while an async call is in flight
4769                  */
4770                 status = NT_STATUS_INVALID_PARAMETER;
4771                 goto fail;
4772         }
4773         ev = samba_tevent_context_init(frame);
4774         if (ev == NULL) {
4775                 goto fail;
4776         }
4777         req = cli_smb2_shadow_copy_data_fnum_send(frame,
4778                                         ev,
4779                                         cli,
4780                                         fnum,
4781                                         get_names);
4782         if (req == NULL) {
4783                 goto fail;
4784         }
4785         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4786                 goto fail;
4787         }
4788         status = cli_smb2_shadow_copy_data_fnum_recv(req,
4789                                                 mem_ctx,
4790                                                 get_names,
4791                                                 pnames,
4792                                                 pnum_names);
4793  fail:
4794         cli->raw_status = status;
4795
4796         TALLOC_FREE(frame);
4797         return status;
4798 }
4799
4800 /***************************************************************
4801  Wrapper that allows SMB2 to truncate a file.
4802  Synchronous only.
4803 ***************************************************************/
4804
4805 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4806                         uint16_t fnum,
4807                         uint64_t newsize)
4808 {
4809         NTSTATUS status;
4810         uint8_t buf[8] = {0};
4811         DATA_BLOB inbuf = { .data = buf, .length = sizeof(buf) };
4812         TALLOC_CTX *frame = talloc_stackframe();
4813
4814         if (smbXcli_conn_has_async_calls(cli->conn)) {
4815                 /*
4816                  * Can't use sync call while an async call is in flight
4817                  */
4818                 status = NT_STATUS_INVALID_PARAMETER;
4819                 goto fail;
4820         }
4821
4822         SBVAL(buf, 0, newsize);
4823
4824         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4825            level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4826
4827         status = cli_smb2_set_info_fnum(
4828                 cli,
4829                 fnum,
4830                 1, /* in_info_type */
4831                 SMB_FILE_END_OF_FILE_INFORMATION-1000, /* in_file_info_class */
4832                 &inbuf, /* in_input_buffer */
4833                 0);
4834
4835   fail:
4836
4837         cli->raw_status = status;
4838
4839         TALLOC_FREE(frame);
4840         return status;
4841 }
4842
4843 struct cli_smb2_notify_state {
4844         struct tevent_req *subreq;
4845         struct notify_change *changes;
4846         size_t num_changes;
4847 };
4848
4849 static void cli_smb2_notify_done(struct tevent_req *subreq);
4850 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4851
4852 struct tevent_req *cli_smb2_notify_send(
4853         TALLOC_CTX *mem_ctx,
4854         struct tevent_context *ev,
4855         struct cli_state *cli,
4856         uint16_t fnum,
4857         uint32_t buffer_size,
4858         uint32_t completion_filter,
4859         bool recursive)
4860 {
4861         struct tevent_req *req = NULL;
4862         struct cli_smb2_notify_state *state = NULL;
4863         struct smb2_hnd *ph = NULL;
4864         NTSTATUS status;
4865
4866         req = tevent_req_create(mem_ctx, &state,
4867                                 struct cli_smb2_notify_state);
4868         if (req == NULL) {
4869                 return NULL;
4870         }
4871
4872         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4873         if (tevent_req_nterror(req, status)) {
4874                 return tevent_req_post(req, ev);
4875         }
4876
4877         state->subreq = smb2cli_notify_send(
4878                 state,
4879                 ev,
4880                 cli->conn,
4881                 cli->timeout,
4882                 cli->smb2.session,
4883                 cli->smb2.tcon,
4884                 buffer_size,
4885                 ph->fid_persistent,
4886                 ph->fid_volatile,
4887                 completion_filter,
4888                 recursive);
4889         if (tevent_req_nomem(state->subreq, req)) {
4890                 return tevent_req_post(req, ev);
4891         }
4892         tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4893         tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4894         return req;
4895 }
4896
4897 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4898 {
4899         struct cli_smb2_notify_state *state = tevent_req_data(
4900                 req, struct cli_smb2_notify_state);
4901         bool ok;
4902
4903         ok = tevent_req_cancel(state->subreq);
4904         return ok;
4905 }
4906
4907 static void cli_smb2_notify_done(struct tevent_req *subreq)
4908 {
4909         struct tevent_req *req = tevent_req_callback_data(
4910                 subreq, struct tevent_req);
4911         struct cli_smb2_notify_state *state = tevent_req_data(
4912                 req, struct cli_smb2_notify_state);
4913         uint8_t *base;
4914         uint32_t len;
4915         uint32_t ofs;
4916         NTSTATUS status;
4917
4918         status = smb2cli_notify_recv(subreq, state, &base, &len);
4919         TALLOC_FREE(subreq);
4920
4921         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4922                 tevent_req_done(req);
4923                 return;
4924         }
4925         if (tevent_req_nterror(req, status)) {
4926                 return;
4927         }
4928
4929         ofs = 0;
4930
4931         while (len - ofs >= 12) {
4932                 struct notify_change *tmp;
4933                 struct notify_change *c;
4934                 uint32_t next_ofs = IVAL(base, ofs);
4935                 uint32_t file_name_length = IVAL(base, ofs+8);
4936                 size_t namelen;
4937                 bool ok;
4938
4939                 tmp = talloc_realloc(
4940                         state,
4941                         state->changes,
4942                         struct notify_change,
4943                         state->num_changes + 1);
4944                 if (tevent_req_nomem(tmp, req)) {
4945                         return;
4946                 }
4947                 state->changes = tmp;
4948                 c = &state->changes[state->num_changes];
4949                 state->num_changes += 1;
4950
4951                 if (smb_buffer_oob(len, ofs, next_ofs) ||
4952                     smb_buffer_oob(len, ofs+12, file_name_length)) {
4953                         tevent_req_nterror(
4954                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4955                         return;
4956                 }
4957
4958                 c->action = IVAL(base, ofs+4);
4959
4960                 ok = convert_string_talloc(
4961                         state->changes,
4962                         CH_UTF16LE,
4963                         CH_UNIX,
4964                         base + ofs + 12,
4965                         file_name_length,
4966                         &c->name,
4967                         &namelen);
4968                 if (!ok) {
4969                         tevent_req_nterror(
4970                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4971                         return;
4972                 }
4973
4974                 if (next_ofs == 0) {
4975                         break;
4976                 }
4977                 ofs += next_ofs;
4978         }
4979
4980         tevent_req_done(req);
4981 }
4982
4983 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
4984                               TALLOC_CTX *mem_ctx,
4985                               struct notify_change **pchanges,
4986                               uint32_t *pnum_changes)
4987 {
4988         struct cli_smb2_notify_state *state = tevent_req_data(
4989                 req, struct cli_smb2_notify_state);
4990         NTSTATUS status;
4991
4992         if (tevent_req_is_nterror(req, &status)) {
4993                 return status;
4994         }
4995         *pchanges = talloc_move(mem_ctx, &state->changes);
4996         *pnum_changes = state->num_changes;
4997         return NT_STATUS_OK;
4998 }
4999
5000 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
5001                          uint32_t buffer_size, uint32_t completion_filter,
5002                          bool recursive, TALLOC_CTX *mem_ctx,
5003                          struct notify_change **pchanges,
5004                          uint32_t *pnum_changes)
5005 {
5006         TALLOC_CTX *frame = talloc_stackframe();
5007         struct tevent_context *ev;
5008         struct tevent_req *req;
5009         NTSTATUS status = NT_STATUS_NO_MEMORY;
5010
5011         if (smbXcli_conn_has_async_calls(cli->conn)) {
5012                 /*
5013                  * Can't use sync call while an async call is in flight
5014                  */
5015                 status = NT_STATUS_INVALID_PARAMETER;
5016                 goto fail;
5017         }
5018         ev = samba_tevent_context_init(frame);
5019         if (ev == NULL) {
5020                 goto fail;
5021         }
5022         req = cli_smb2_notify_send(
5023                 frame,
5024                 ev,
5025                 cli,
5026                 fnum,
5027                 buffer_size,
5028                 completion_filter,
5029                 recursive);
5030         if (req == NULL) {
5031                 goto fail;
5032         }
5033         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5034                 goto fail;
5035         }
5036         status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
5037 fail:
5038         TALLOC_FREE(frame);
5039         return status;
5040 }
5041
5042 struct cli_smb2_fsctl_state {
5043         DATA_BLOB out;
5044 };
5045
5046 static void cli_smb2_fsctl_done(struct tevent_req *subreq);
5047
5048 struct tevent_req *cli_smb2_fsctl_send(
5049         TALLOC_CTX *mem_ctx,
5050         struct tevent_context *ev,
5051         struct cli_state *cli,
5052         uint16_t fnum,
5053         uint32_t ctl_code,
5054         const DATA_BLOB *in,
5055         uint32_t max_out)
5056 {
5057         struct tevent_req *req = NULL, *subreq = NULL;
5058         struct cli_smb2_fsctl_state *state = NULL;
5059         struct smb2_hnd *ph = NULL;
5060         NTSTATUS status;
5061
5062         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_fsctl_state);
5063         if (req == NULL) {
5064                 return NULL;
5065         }
5066
5067         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
5068         if (tevent_req_nterror(req, status)) {
5069                 return tevent_req_post(req, ev);
5070         }
5071
5072         subreq = smb2cli_ioctl_send(
5073                 state,
5074                 ev,
5075                 cli->conn,
5076                 cli->timeout,
5077                 cli->smb2.session,
5078                 cli->smb2.tcon,
5079                 ph->fid_persistent,
5080                 ph->fid_volatile,
5081                 ctl_code,
5082                 0, /* in_max_input_length */
5083                 in,
5084                 max_out,
5085                 NULL,
5086                 SMB2_IOCTL_FLAG_IS_FSCTL);
5087
5088         if (tevent_req_nomem(subreq, req)) {
5089                 return tevent_req_post(req, ev);
5090         }
5091         tevent_req_set_callback(subreq, cli_smb2_fsctl_done, req);
5092         return req;
5093 }
5094
5095 static void cli_smb2_fsctl_done(struct tevent_req *subreq)
5096 {
5097         struct tevent_req *req = tevent_req_callback_data(
5098                 subreq, struct tevent_req);
5099         struct cli_smb2_fsctl_state *state = tevent_req_data(
5100                 req, struct cli_smb2_fsctl_state);
5101         NTSTATUS status;
5102
5103         status = smb2cli_ioctl_recv(subreq, state, NULL, &state->out);
5104         tevent_req_simple_finish_ntstatus(subreq, status);
5105 }
5106
5107 NTSTATUS cli_smb2_fsctl_recv(
5108         struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *out)
5109 {
5110         struct cli_smb2_fsctl_state *state = tevent_req_data(
5111                 req, struct cli_smb2_fsctl_state);
5112         NTSTATUS status = NT_STATUS_OK;
5113
5114         if (tevent_req_is_nterror(req, &status)) {
5115                 tevent_req_received(req);
5116                 return status;
5117         }
5118
5119         if (state->out.length == 0) {
5120                 *out = (DATA_BLOB) { .data = NULL, };
5121         } else {
5122                 /*
5123                  * Can't use talloc_move() here, the outblobs from
5124                  * smb2cli_ioctl_recv() are not standalone talloc
5125                  * objects but just peek into the larger buffers
5126                  * received, hanging off "state".
5127                  */
5128                 *out = data_blob_talloc(
5129                         mem_ctx, state->out.data, state->out.length);
5130                 if (out->data == NULL) {
5131                         status = NT_STATUS_NO_MEMORY;
5132                 }
5133         }
5134
5135         tevent_req_received(req);
5136         return NT_STATUS_OK;
5137 }