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