2092fc550480d611f3c219fd43fba0adc56d9df1
[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->mode = 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         bool posix)
1458 {
1459         struct tevent_req *req = NULL, *subreq = NULL;
1460         struct cli_smb2_list_state *state = NULL;
1461         char *parent = NULL;
1462         bool ok;
1463         struct smb2_create_blobs *in_cblobs = NULL;
1464
1465         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_list_state);
1466         if (req == NULL) {
1467                 return NULL;
1468         }
1469         state->ev = ev;
1470         state->cli = cli;
1471         state->status = NT_STATUS_OK;
1472         state->info_level = info_level;
1473
1474         ok = windows_parent_dirname(state, pathname, &parent, &state->mask);
1475         if (!ok) {
1476                 tevent_req_oom(req);
1477                 return tevent_req_post(req, ev);
1478         }
1479
1480         if (smbXcli_conn_have_posix(cli->conn) && posix) {
1481                 NTSTATUS status;
1482
1483                 /* The mode MUST be 0 when opening an existing file/dir, and
1484                  * will be ignored by the server.
1485                  */
1486                 uint8_t linear_mode[4] = { 0 };
1487                 DATA_BLOB blob = { .data=linear_mode,
1488                                    .length=sizeof(linear_mode) };
1489
1490                 in_cblobs = talloc_zero(mem_ctx, struct smb2_create_blobs);
1491                 if (in_cblobs == NULL) {
1492                         return NULL;
1493                 }
1494
1495                 status = smb2_create_blob_add(in_cblobs, in_cblobs,
1496                                               SMB2_CREATE_TAG_POSIX, blob);
1497                 if (tevent_req_nterror(req, status)) {
1498                         tevent_req_nterror(req, status);
1499                         return tevent_req_post(req, ev);
1500                 }
1501         }
1502
1503         subreq = cli_smb2_create_fnum_send(
1504                 state,                                  /* mem_ctx */
1505                 ev,                                     /* ev */
1506                 cli,                                    /* cli */
1507                 parent,                                 /* fname */
1508                 (struct cli_smb2_create_flags){0},      /* create_flags */
1509                 SMB2_IMPERSONATION_IMPERSONATION,       /* impersonation_level */
1510                 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,    /* desired_access */
1511                 FILE_ATTRIBUTE_DIRECTORY,               /* file_attributes */
1512                 FILE_SHARE_READ|FILE_SHARE_WRITE,       /* share_access */
1513                 FILE_OPEN,                              /* create_disposition */
1514                 FILE_DIRECTORY_FILE,                    /* create_options */
1515                 in_cblobs);                             /* in_cblobs */
1516         TALLOC_FREE(in_cblobs);
1517         if (tevent_req_nomem(subreq, req)) {
1518                 return tevent_req_post(req, ev);
1519         }
1520         tevent_req_set_callback(subreq, cli_smb2_list_opened, req);
1521         return req;
1522 }
1523
1524 static void cli_smb2_list_opened(struct tevent_req *subreq)
1525 {
1526         struct tevent_req *req = tevent_req_callback_data(
1527                 subreq, struct tevent_req);
1528         struct cli_smb2_list_state *state = tevent_req_data(
1529                 req, struct cli_smb2_list_state);
1530         NTSTATUS status;
1531
1532         status = cli_smb2_create_fnum_recv(
1533                 subreq, &state->fnum, NULL, NULL, NULL, NULL);
1534         TALLOC_FREE(subreq);
1535         if (tevent_req_nterror(req, status)) {
1536                 return;
1537         }
1538
1539         /*
1540          * Make our caller get back to us via cli_smb2_list_recv(),
1541          * triggering the smb2_query_directory_send()
1542          */
1543         tevent_req_defer_callback(req, state->ev);
1544         tevent_req_notify_callback(req);
1545 }
1546
1547 static void cli_smb2_list_done(struct tevent_req *subreq)
1548 {
1549         struct tevent_req *req = tevent_req_callback_data(
1550                 subreq, struct tevent_req);
1551         struct cli_smb2_list_state *state = tevent_req_data(
1552                 req, struct cli_smb2_list_state);
1553         struct cli_smb2_list_dir_data *response = NULL;
1554
1555         response = talloc(state, struct cli_smb2_list_dir_data);
1556         if (tevent_req_nomem(response, req)) {
1557                 return;
1558         }
1559
1560         state->status = smb2cli_query_directory_recv(
1561                 subreq, response, &response->data, &response->length);
1562         TALLOC_FREE(subreq);
1563
1564         if (NT_STATUS_IS_OK(state->status)) {
1565                 state->response = response;
1566                 state->offset = 0;
1567
1568                 tevent_req_defer_callback(req, state->ev);
1569                 tevent_req_notify_callback(req);
1570                 return;
1571         }
1572
1573         TALLOC_FREE(response);
1574
1575         subreq = cli_smb2_close_fnum_send(state,
1576                                           state->ev,
1577                                           state->cli,
1578                                           state->fnum,
1579                                           0);
1580         if (tevent_req_nomem(subreq, req)) {
1581                 return;
1582         }
1583         tevent_req_set_callback(subreq, cli_smb2_list_closed, req);
1584 }
1585
1586 static void cli_smb2_list_closed(struct tevent_req *subreq)
1587 {
1588         NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1589         tevent_req_simple_finish_ntstatus(subreq, status);
1590 }
1591
1592 /*
1593  * Return the next finfo directory.
1594  *
1595  * This parses the blob returned from QUERY_DIRECTORY step by step. If
1596  * the blob ends, this triggers a fresh QUERY_DIRECTORY and returns
1597  * NT_STATUS_RETRY, which will then trigger the caller again when the
1598  * QUERY_DIRECTORY has returned with another buffer. This way we
1599  * guarantee that no asynchronous request is open after this call
1600  * returns an entry, so that other synchronous requests can be issued
1601  * on the same connection while the directory listing proceeds.
1602  */
1603 NTSTATUS cli_smb2_list_recv(
1604         struct tevent_req *req,
1605         TALLOC_CTX *mem_ctx,
1606         struct file_info **pfinfo)
1607 {
1608         struct cli_smb2_list_state *state = tevent_req_data(
1609                 req, struct cli_smb2_list_state);
1610         struct cli_smb2_list_dir_data *response = NULL;
1611         struct file_info *finfo = NULL;
1612         NTSTATUS status;
1613         uint32_t next_offset = 0;
1614         bool in_progress;
1615
1616         in_progress = tevent_req_is_in_progress(req);
1617
1618         if (!in_progress) {
1619                 if (!tevent_req_is_nterror(req, &status)) {
1620                         status = NT_STATUS_NO_MORE_FILES;
1621                 }
1622                 goto fail;
1623         }
1624
1625         response = state->response;
1626         if (response == NULL) {
1627                 struct tevent_req *subreq = NULL;
1628                 struct cli_state *cli = state->cli;
1629                 struct smb2_hnd *ph = NULL;
1630                 uint32_t max_trans, max_avail_len;
1631                 bool ok;
1632
1633                 if (!NT_STATUS_IS_OK(state->status)) {
1634                         status = state->status;
1635                         goto fail;
1636                 }
1637
1638                 status = map_fnum_to_smb2_handle(cli, state->fnum, &ph);
1639                 if (!NT_STATUS_IS_OK(status)) {
1640                         goto fail;
1641                 }
1642
1643                 max_trans = smb2cli_conn_max_trans_size(cli->conn);
1644                 ok = smb2cli_conn_req_possible(cli->conn, &max_avail_len);
1645                 if (ok) {
1646                         max_trans = MIN(max_trans, max_avail_len);
1647                 }
1648
1649                 subreq = smb2cli_query_directory_send(
1650                         state,                          /* mem_ctx */
1651                         state->ev,                      /* ev */
1652                         cli->conn,                      /* conn */
1653                         cli->timeout,                   /* timeout_msec */
1654                         cli->smb2.session,              /* session */
1655                         cli->smb2.tcon,                 /* tcon */
1656                         state->info_level,              /* level */
1657                         0,                              /* flags */
1658                         0,                              /* file_index */
1659                         ph->fid_persistent,             /* fid_persistent */
1660                         ph->fid_volatile,               /* fid_volatile */
1661                         state->mask,                    /* mask */
1662                         max_trans);                     /* outbuf_len */
1663                 if (subreq == NULL) {
1664                         status = NT_STATUS_NO_MEMORY;
1665                         goto fail;
1666                 }
1667                 tevent_req_set_callback(subreq, cli_smb2_list_done, req);
1668                 return NT_STATUS_RETRY;
1669         }
1670
1671         SMB_ASSERT(response->length > state->offset);
1672
1673         finfo = talloc_zero(mem_ctx, struct file_info);
1674         if (finfo == NULL) {
1675                 status = NT_STATUS_NO_MEMORY;
1676                 goto fail;
1677         }
1678
1679         if (state->info_level == SMB2_FIND_POSIX_INFORMATION) {
1680                 status = parse_finfo_posix_info(
1681                         response->data + state->offset,
1682                         response->length - state->offset,
1683                         finfo,
1684                         &next_offset);
1685         } else {
1686                 status = parse_finfo_id_both_directory_info(
1687                         response->data + state->offset,
1688                         response->length - state->offset,
1689                         finfo,
1690                         &next_offset);
1691         }
1692         if (!NT_STATUS_IS_OK(status)) {
1693                 goto fail;
1694         }
1695
1696         status = is_bad_finfo_name(state->cli, finfo);
1697         if (!NT_STATUS_IS_OK(status)) {
1698                 goto fail;
1699         }
1700
1701         /*
1702          * parse_finfo_id_both_directory_info() checks for overflow,
1703          * no need to check again here.
1704          */
1705         state->offset += next_offset;
1706
1707         if (next_offset == 0) {
1708                 TALLOC_FREE(state->response);
1709         }
1710
1711         tevent_req_defer_callback(req, state->ev);
1712         tevent_req_notify_callback(req);
1713
1714         *pfinfo = finfo;
1715         return NT_STATUS_OK;
1716
1717 fail:
1718         TALLOC_FREE(finfo);
1719         tevent_req_received(req);
1720         return status;
1721 }
1722
1723 /***************************************************************
1724  Wrapper that allows SMB2 to query a path info (basic level).
1725  Synchronous only.
1726 ***************************************************************/
1727
1728 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1729                                 const char *name,
1730                                 SMB_STRUCT_STAT *sbuf,
1731                                 uint32_t *attributes)
1732 {
1733         NTSTATUS status;
1734         struct smb_create_returns cr;
1735         uint16_t fnum = 0xffff;
1736         size_t namelen = strlen(name);
1737
1738         if (smbXcli_conn_has_async_calls(cli->conn)) {
1739                 /*
1740                  * Can't use sync call while an async call is in flight
1741                  */
1742                 return NT_STATUS_INVALID_PARAMETER;
1743         }
1744
1745         /* SMB2 is pickier about pathnames. Ensure it doesn't
1746            end in a '\' */
1747         if (namelen > 0 && name[namelen-1] == '\\') {
1748                 char *modname = talloc_strndup(talloc_tos(), name, namelen-1);
1749                 if (modname == NULL) {
1750                         return NT_STATUS_NO_MEMORY;
1751                 }
1752                 name = modname;
1753         }
1754
1755         /* This is commonly used as a 'cd'. Try qpathinfo on
1756            a directory handle first. */
1757
1758         status = cli_smb2_create_fnum(cli,
1759                         name,
1760                         (struct cli_smb2_create_flags){0},
1761                         SMB2_IMPERSONATION_IMPERSONATION,
1762                         FILE_READ_ATTRIBUTES,   /* desired_access */
1763                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1764                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1765                         FILE_OPEN,              /* create_disposition */
1766                         FILE_DIRECTORY_FILE,    /* create_options */
1767                         NULL,
1768                         &fnum,
1769                         &cr,
1770                         NULL,
1771                         NULL);
1772
1773         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1774                 /* Maybe a file ? */
1775                 status = cli_smb2_create_fnum(cli,
1776                         name,
1777                         (struct cli_smb2_create_flags){0},
1778                         SMB2_IMPERSONATION_IMPERSONATION,
1779                         FILE_READ_ATTRIBUTES,           /* desired_access */
1780                         0, /* file attributes */
1781                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1782                         FILE_OPEN,              /* create_disposition */
1783                         0,      /* create_options */
1784                         NULL,
1785                         &fnum,
1786                         &cr,
1787                         NULL,
1788                         NULL);
1789         }
1790
1791         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1792                 /* Maybe a reparse point ? */
1793                 status = cli_smb2_create_fnum(cli,
1794                         name,
1795                         (struct cli_smb2_create_flags){0},
1796                         SMB2_IMPERSONATION_IMPERSONATION,
1797                         FILE_READ_ATTRIBUTES,           /* desired_access */
1798                         0, /* file attributes */
1799                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1800                         FILE_OPEN,              /* create_disposition */
1801                         FILE_OPEN_REPARSE_POINT, /* create_options */
1802                         NULL,
1803                         &fnum,
1804                         &cr,
1805                         NULL,
1806                         NULL);
1807         }
1808
1809         if (!NT_STATUS_IS_OK(status)) {
1810                 return status;
1811         }
1812
1813         status = cli_smb2_close_fnum(cli, fnum);
1814
1815         ZERO_STRUCTP(sbuf);
1816
1817         sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1818         sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1819         sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1820         sbuf->st_ex_size = cr.end_of_file;
1821         *attributes = cr.file_attributes;
1822
1823         return status;
1824 }
1825
1826 struct cli_smb2_query_info_fnum_state {
1827         DATA_BLOB outbuf;
1828 };
1829
1830 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq);
1831
1832 struct tevent_req *cli_smb2_query_info_fnum_send(
1833         TALLOC_CTX *mem_ctx,
1834         struct tevent_context *ev,
1835         struct cli_state *cli,
1836         uint16_t fnum,
1837         uint8_t in_info_type,
1838         uint8_t in_info_class,
1839         uint32_t in_max_output_length,
1840         const DATA_BLOB *in_input_buffer,
1841         uint32_t in_additional_info,
1842         uint32_t in_flags)
1843 {
1844         struct tevent_req *req = NULL, *subreq = NULL;
1845         struct cli_smb2_query_info_fnum_state *state = NULL;
1846         struct smb2_hnd *ph = NULL;
1847         NTSTATUS status;
1848
1849         req = tevent_req_create(
1850                 mem_ctx, &state, struct cli_smb2_query_info_fnum_state);
1851         if (req == NULL) {
1852                 return req;
1853         }
1854
1855         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1856         if (tevent_req_nterror(req, status)) {
1857                 return tevent_req_post(req, ev);
1858         }
1859
1860         subreq = smb2cli_query_info_send(
1861                 state,
1862                 ev,
1863                 cli->conn,
1864                 cli->timeout,
1865                 cli->smb2.session,
1866                 cli->smb2.tcon,
1867                 in_info_type,
1868                 in_info_class,
1869                 in_max_output_length,
1870                 in_input_buffer,
1871                 in_additional_info,
1872                 in_flags,
1873                 ph->fid_persistent,
1874                 ph->fid_volatile);
1875         if (tevent_req_nomem(subreq, req)) {
1876                 return tevent_req_post(req, ev);
1877         }
1878         tevent_req_set_callback(subreq, cli_smb2_query_info_fnum_done, req);
1879         return req;
1880 }
1881
1882 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq)
1883 {
1884         struct tevent_req *req = tevent_req_callback_data(
1885                 subreq, struct tevent_req);
1886         struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1887                 req, struct cli_smb2_query_info_fnum_state);
1888         DATA_BLOB outbuf;
1889         NTSTATUS status;
1890
1891         status = smb2cli_query_info_recv(subreq, state, &outbuf);
1892         TALLOC_FREE(subreq);
1893         if (tevent_req_nterror(req, status)) {
1894                 return;
1895         }
1896
1897         /*
1898          * We have to dup the memory here because outbuf.data is not
1899          * returned as a talloc object by smb2cli_query_info_recv.
1900          * It's a pointer into the received buffer.
1901          */
1902         state->outbuf = data_blob_dup_talloc(state, outbuf);
1903
1904         if ((outbuf.length != 0) &&
1905             tevent_req_nomem(state->outbuf.data, req)) {
1906                 return;
1907         }
1908         tevent_req_done(req);
1909 }
1910
1911 NTSTATUS cli_smb2_query_info_fnum_recv(
1912         struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *outbuf)
1913 {
1914         struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1915                 req, struct cli_smb2_query_info_fnum_state);
1916         NTSTATUS status;
1917
1918         if (tevent_req_is_nterror(req, &status)) {
1919                 return status;
1920         }
1921         *outbuf = (DATA_BLOB) {
1922                 .data = talloc_move(mem_ctx, &state->outbuf.data),
1923                 .length = state->outbuf.length,
1924         };
1925         return NT_STATUS_OK;
1926 }
1927
1928 NTSTATUS cli_smb2_query_info_fnum(
1929         struct cli_state *cli,
1930         uint16_t fnum,
1931         uint8_t in_info_type,
1932         uint8_t in_info_class,
1933         uint32_t in_max_output_length,
1934         const DATA_BLOB *in_input_buffer,
1935         uint32_t in_additional_info,
1936         uint32_t in_flags,
1937         TALLOC_CTX *mem_ctx,
1938         DATA_BLOB *outbuf)
1939 {
1940         TALLOC_CTX *frame = talloc_stackframe();
1941         struct tevent_context *ev = NULL;
1942         struct tevent_req *req = NULL;
1943         NTSTATUS status = NT_STATUS_NO_MEMORY;
1944         bool ok;
1945
1946         if (smbXcli_conn_has_async_calls(cli->conn)) {
1947                 /*
1948                  * Can't use sync call while an async call is in flight
1949                  */
1950                 status = NT_STATUS_INVALID_PARAMETER;
1951                 goto fail;
1952         }
1953         ev = samba_tevent_context_init(frame);
1954         if (ev == NULL) {
1955                 goto fail;
1956         }
1957         req = cli_smb2_query_info_fnum_send(
1958                 frame,
1959                 ev,
1960                 cli,
1961                 fnum,
1962                 in_info_type,
1963                 in_info_class,
1964                 in_max_output_length,
1965                 in_input_buffer,
1966                 in_additional_info,
1967                 in_flags);
1968         if (req == NULL) {
1969                 goto fail;
1970         }
1971         ok = tevent_req_poll_ntstatus(req, ev, &status);
1972         if (!ok) {
1973                 goto fail;
1974         }
1975         status = cli_smb2_query_info_fnum_recv(req, mem_ctx, outbuf);
1976 fail:
1977         TALLOC_FREE(frame);
1978         return status;
1979 }
1980
1981 /***************************************************************
1982  Helper function for pathname operations.
1983 ***************************************************************/
1984
1985 struct get_fnum_from_path_state {
1986         struct tevent_context *ev;
1987         struct cli_state *cli;
1988         const char *name;
1989         uint32_t desired_access;
1990         uint16_t fnum;
1991 };
1992
1993 static void get_fnum_from_path_opened_file(struct tevent_req *subreq);
1994 static void get_fnum_from_path_opened_reparse(struct tevent_req *subreq);
1995 static void get_fnum_from_path_opened_dir(struct tevent_req *subreq);
1996
1997 static struct tevent_req *get_fnum_from_path_send(
1998         TALLOC_CTX *mem_ctx,
1999         struct tevent_context *ev,
2000         struct cli_state *cli,
2001         const char *name,
2002         uint32_t desired_access)
2003 {
2004         struct tevent_req *req = NULL, *subreq = NULL;
2005         struct get_fnum_from_path_state *state = NULL;
2006         size_t namelen = strlen(name);
2007
2008         req = tevent_req_create(
2009                 mem_ctx, &state, struct get_fnum_from_path_state);
2010         if (req == NULL) {
2011                 return NULL;
2012         }
2013         state->ev = ev;
2014         state->cli = cli;
2015         state->name = name;
2016         state->desired_access = desired_access;
2017
2018         /*
2019          * SMB2 is pickier about pathnames. Ensure it doesn't end in a
2020          * '\'
2021          */
2022         if (namelen > 0 && name[namelen-1] == '\\') {
2023                 state->name = talloc_strndup(state, name, namelen-1);
2024                 if (tevent_req_nomem(state->name, req)) {
2025                         return tevent_req_post(req, ev);
2026                 }
2027         }
2028
2029         subreq = cli_smb2_create_fnum_send(
2030                 state,          /* mem_ctx, */
2031                 ev,             /* ev */
2032                 cli,            /* cli */
2033                 state->name,    /* fname */
2034                 (struct cli_smb2_create_flags){0}, /* create_flags */
2035                 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level */
2036                 desired_access, /* desired_access */
2037                 0,              /* file_attributes */
2038                 FILE_SHARE_READ|
2039                 FILE_SHARE_WRITE|
2040                 FILE_SHARE_DELETE, /* share_access */
2041                 FILE_OPEN,      /* create_disposition */
2042                 0,              /* create_options */
2043                 NULL);          /* in_cblobs */
2044         if (tevent_req_nomem(subreq, req)) {
2045                 return tevent_req_post(req, ev);
2046         }
2047         tevent_req_set_callback(subreq, get_fnum_from_path_opened_file, req);
2048         return req;
2049 }
2050
2051 static void get_fnum_from_path_opened_file(struct tevent_req *subreq)
2052 {
2053         struct tevent_req *req = tevent_req_callback_data(
2054                 subreq, struct tevent_req);
2055         struct get_fnum_from_path_state *state = tevent_req_data(
2056                 req, struct get_fnum_from_path_state);
2057         NTSTATUS status;
2058
2059         status = cli_smb2_create_fnum_recv(
2060                 subreq, &state->fnum, NULL, NULL, NULL, NULL);
2061         TALLOC_FREE(subreq);
2062
2063         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) ||
2064             NT_STATUS_EQUAL(status, NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED)) {
2065                 /*
2066                  * Naive option to match our SMB1 code. Assume the
2067                  * symlink path that tripped us up was the last
2068                  * component and try again. Eventually we will have to
2069                  * deal with the returned path unprocessed component. JRA.
2070                  */
2071                 subreq = cli_smb2_create_fnum_send(
2072                         state,          /* mem_ctx, */
2073                         state->ev,      /* ev */
2074                         state->cli,     /* cli */
2075                         state->name,    /* fname */
2076                         (struct cli_smb2_create_flags){0}, /* create_flags */
2077                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation */
2078                         state->desired_access, /* desired_access */
2079                         0,              /* file_attributes */
2080                         FILE_SHARE_READ|
2081                         FILE_SHARE_WRITE|
2082                         FILE_SHARE_DELETE, /* share_access */
2083                         FILE_OPEN,      /* create_disposition */
2084                         FILE_OPEN_REPARSE_POINT, /* create_options */
2085                         NULL);          /* in_cblobs */
2086                 if (tevent_req_nomem(subreq, req)) {
2087                         return;
2088                 }
2089                 tevent_req_set_callback(
2090                         subreq, get_fnum_from_path_opened_reparse, req);
2091                 return;
2092         }
2093
2094         if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
2095                 subreq = cli_smb2_create_fnum_send(
2096                         state,          /* mem_ctx, */
2097                         state->ev,      /* ev */
2098                         state->cli,     /* cli */
2099                         state->name,    /* fname */
2100                         (struct cli_smb2_create_flags){0}, /* create_flags */
2101                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation */
2102                         state->desired_access, /* desired_access */
2103                         0,              /* file_attributes */
2104                         FILE_SHARE_READ|
2105                         FILE_SHARE_WRITE|
2106                         FILE_SHARE_DELETE, /* share_access */
2107                         FILE_OPEN,      /* create_disposition */
2108                         FILE_DIRECTORY_FILE, /* create_options */
2109                         NULL);          /* in_cblobs */
2110                 if (tevent_req_nomem(subreq, req)) {
2111                         return;
2112                 }
2113                 tevent_req_set_callback(
2114                         subreq, get_fnum_from_path_opened_dir, req);
2115                 return;
2116         }
2117
2118         if (tevent_req_nterror(req, status)) {
2119                 return;
2120         }
2121         tevent_req_done(req);
2122 }
2123
2124 static void get_fnum_from_path_opened_reparse(struct tevent_req *subreq)
2125 {
2126         struct tevent_req *req = tevent_req_callback_data(
2127                 subreq, struct tevent_req);
2128         struct get_fnum_from_path_state *state = tevent_req_data(
2129                 req, struct get_fnum_from_path_state);
2130         NTSTATUS status = cli_smb2_create_fnum_recv(
2131                 subreq, &state->fnum, NULL, NULL, NULL, NULL);
2132         tevent_req_simple_finish_ntstatus(subreq, status);
2133 }
2134
2135 static void get_fnum_from_path_opened_dir(struct tevent_req *subreq)
2136 {
2137         /* Abstraction violation, but these two are just the same... */
2138         get_fnum_from_path_opened_reparse(subreq);
2139 }
2140
2141 static NTSTATUS get_fnum_from_path_recv(
2142         struct tevent_req *req, uint16_t *pfnum)
2143 {
2144         struct get_fnum_from_path_state *state = tevent_req_data(
2145                 req, struct get_fnum_from_path_state);
2146         NTSTATUS status = NT_STATUS_OK;
2147
2148         if (!tevent_req_is_nterror(req, &status)) {
2149                 *pfnum = state->fnum;
2150         }
2151         tevent_req_received(req);
2152         return status;
2153 }
2154
2155 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
2156                                 const char *name,
2157                                 uint32_t desired_access,
2158                                 uint16_t *pfnum)
2159 {
2160         TALLOC_CTX *frame = talloc_stackframe();
2161         struct tevent_context *ev = NULL;
2162         struct tevent_req *req = NULL;
2163         NTSTATUS status = NT_STATUS_NO_MEMORY;
2164
2165         if (smbXcli_conn_has_async_calls(cli->conn)) {
2166                 status = NT_STATUS_INVALID_PARAMETER;
2167                 goto fail;
2168         }
2169         ev = samba_tevent_context_init(frame);
2170         if (ev == NULL) {
2171                 goto fail;
2172         }
2173         req = get_fnum_from_path_send(frame, ev, cli, name, desired_access);
2174         if (req == NULL) {
2175                 goto fail;
2176         }
2177         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2178                 goto fail;
2179         }
2180         status = get_fnum_from_path_recv(req, pfnum);
2181  fail:
2182         TALLOC_FREE(frame);
2183         return status;
2184 }
2185
2186 struct cli_smb2_qpathinfo_state {
2187         struct tevent_context *ev;
2188         struct cli_state *cli;
2189         const char *fname;
2190         uint16_t fnum;
2191         uint16_t level;
2192         uint32_t min_rdata;
2193         uint32_t max_rdata;
2194
2195         NTSTATUS status;
2196         DATA_BLOB out;
2197 };
2198
2199 static void cli_smb2_qpathinfo_opened(struct tevent_req *subreq);
2200 static void cli_smb2_qpathinfo_done(struct tevent_req *subreq);
2201 static void cli_smb2_qpathinfo_closed(struct tevent_req *subreq);
2202
2203 struct tevent_req *cli_smb2_qpathinfo_send(TALLOC_CTX *mem_ctx,
2204                                            struct tevent_context *ev,
2205                                            struct cli_state *cli,
2206                                            const char *fname,
2207                                            uint16_t level,
2208                                            uint32_t min_rdata,
2209                                            uint32_t max_rdata)
2210 {
2211         struct tevent_req *req = NULL, *subreq = NULL;
2212         struct cli_smb2_qpathinfo_state *state = NULL;
2213
2214         req = tevent_req_create(mem_ctx,
2215                                 &state,
2216                                 struct cli_smb2_qpathinfo_state);
2217         if (req == NULL) {
2218                 return NULL;
2219         }
2220         state->ev = ev;
2221         state->cli = cli;
2222         state->level = level;
2223         state->min_rdata = min_rdata;
2224         state->max_rdata = max_rdata;
2225
2226         subreq = get_fnum_from_path_send(state,
2227                                          ev,
2228                                          cli,
2229                                          fname,
2230                                          FILE_READ_ATTRIBUTES);
2231         if (tevent_req_nomem(subreq, req)) {
2232                 return tevent_req_post(req, ev);
2233         }
2234         tevent_req_set_callback(subreq, cli_smb2_qpathinfo_opened, req);
2235         return req;
2236 }
2237
2238 static void cli_smb2_qpathinfo_opened(struct tevent_req *subreq)
2239 {
2240         struct tevent_req *req =
2241                 tevent_req_callback_data(subreq, struct tevent_req);
2242         struct cli_smb2_qpathinfo_state *state =
2243                 tevent_req_data(req, struct cli_smb2_qpathinfo_state);
2244         NTSTATUS status;
2245
2246         status = get_fnum_from_path_recv(subreq, &state->fnum);
2247         TALLOC_FREE(subreq);
2248         if (tevent_req_nterror(req, status)) {
2249                 return;
2250         }
2251
2252         subreq = cli_smb2_query_info_fnum_send(state,
2253                                                state->ev,
2254                                                state->cli,
2255                                                state->fnum,
2256                                                1, /* in_info_type */
2257                                                state->level,
2258                                                state->max_rdata,
2259                                                NULL, /* in_input_buffer */
2260                                                0,    /* in_additional_info */
2261                                                0);   /* in_flags */
2262         if (tevent_req_nomem(subreq, req)) {
2263                 return;
2264         }
2265         tevent_req_set_callback(subreq, cli_smb2_qpathinfo_done, req);
2266 }
2267
2268 static void cli_smb2_qpathinfo_done(struct tevent_req *subreq)
2269 {
2270         struct tevent_req *req =
2271                 tevent_req_callback_data(subreq, struct tevent_req);
2272         struct cli_smb2_qpathinfo_state *state =
2273                 tevent_req_data(req, struct cli_smb2_qpathinfo_state);
2274
2275         state->status =
2276                 cli_smb2_query_info_fnum_recv(subreq, state, &state->out);
2277         TALLOC_FREE(subreq);
2278
2279         if (NT_STATUS_IS_OK(state->status) &&
2280             (state->out.length < state->min_rdata)) {
2281                 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2282         }
2283
2284         subreq = cli_smb2_close_fnum_send(state,
2285                                           state->ev,
2286                                           state->cli,
2287                                           state->fnum,
2288                                           0);
2289         if (tevent_req_nomem(subreq, req)) {
2290                 return;
2291         }
2292         tevent_req_set_callback(subreq, cli_smb2_qpathinfo_closed, req);
2293 }
2294
2295 static void cli_smb2_qpathinfo_closed(struct tevent_req *subreq)
2296 {
2297         struct tevent_req *req =
2298                 tevent_req_callback_data(subreq, struct tevent_req);
2299         struct cli_smb2_qpathinfo_state *state =
2300                 tevent_req_data(req, struct cli_smb2_qpathinfo_state);
2301         NTSTATUS status;
2302
2303         status = cli_smb2_close_fnum_recv(subreq);
2304         TALLOC_FREE(subreq);
2305         if (tevent_req_nterror(req, status)) {
2306                 return;
2307         }
2308         if (tevent_req_nterror(req, state->status)) {
2309                 return;
2310         }
2311         tevent_req_done(req);
2312 }
2313
2314 NTSTATUS cli_smb2_qpathinfo_recv(struct tevent_req *req,
2315                                  TALLOC_CTX *mem_ctx,
2316                                  uint8_t **rdata,
2317                                  uint32_t *num_rdata)
2318 {
2319         struct cli_smb2_qpathinfo_state *state =
2320                 tevent_req_data(req, struct cli_smb2_qpathinfo_state);
2321         NTSTATUS status;
2322
2323         if (tevent_req_is_nterror(req, &status)) {
2324                 return status;
2325         }
2326
2327         *rdata = talloc_move(mem_ctx, &state->out.data);
2328         *num_rdata = state->out.length;
2329         tevent_req_received(req);
2330         return NT_STATUS_OK;
2331 }
2332
2333 /***************************************************************
2334  Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2335  a pathname.
2336  Synchronous only.
2337 ***************************************************************/
2338
2339 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
2340                         const char *name,
2341                         uint8_t in_info_type,
2342                         uint8_t in_file_info_class,
2343                         const DATA_BLOB *p_in_data)
2344 {
2345         NTSTATUS status;
2346         uint16_t fnum = 0xffff;
2347         TALLOC_CTX *frame = talloc_stackframe();
2348
2349         if (smbXcli_conn_has_async_calls(cli->conn)) {
2350                 /*
2351                  * Can't use sync call while an async call is in flight
2352                  */
2353                 status = NT_STATUS_INVALID_PARAMETER;
2354                 goto fail;
2355         }
2356
2357         status = get_fnum_from_path(cli,
2358                                 name,
2359                                 FILE_WRITE_ATTRIBUTES,
2360                                 &fnum);
2361
2362         if (!NT_STATUS_IS_OK(status)) {
2363                 goto fail;
2364         }
2365
2366         status = cli_smb2_set_info_fnum(
2367                 cli,
2368                 fnum,
2369                 in_info_type,
2370                 in_file_info_class,
2371                 p_in_data,         /* in_input_buffer */
2372                 0);                /* in_additional_info */
2373   fail:
2374
2375         if (fnum != 0xffff) {
2376                 cli_smb2_close_fnum(cli, fnum);
2377         }
2378
2379         cli->raw_status = status;
2380
2381         TALLOC_FREE(frame);
2382         return status;
2383 }
2384
2385
2386 /***************************************************************
2387  Wrapper that allows SMB2 to set pathname attributes.
2388  Synchronous only.
2389 ***************************************************************/
2390
2391 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
2392                         const char *name,
2393                         uint32_t attr,
2394                         time_t mtime)
2395 {
2396         uint8_t inbuf_store[40];
2397         DATA_BLOB inbuf = data_blob_null;
2398
2399         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2400            level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2401
2402         inbuf.data = inbuf_store;
2403         inbuf.length = sizeof(inbuf_store);
2404         data_blob_clear(&inbuf);
2405
2406         /*
2407          * SMB1 uses attr == 0 to clear all attributes
2408          * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2409          * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2410          * request attribute change.
2411          *
2412          * SMB2 uses exactly the reverse. Unfortunately as the
2413          * cli_setatr() ABI is exposed inside libsmbclient,
2414          * we must make the SMB2 cli_smb2_setatr() call
2415          * export the same ABI as the SMB1 cli_setatr()
2416          * which calls it. This means reversing the sense
2417          * of the requested attr argument if it's zero
2418          * or FILE_ATTRIBUTE_NORMAL.
2419          *
2420          * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2421          */
2422
2423         if (attr == 0) {
2424                 attr = FILE_ATTRIBUTE_NORMAL;
2425         } else if (attr == FILE_ATTRIBUTE_NORMAL) {
2426                 attr = 0;
2427         }
2428
2429         SIVAL(inbuf.data, 32, attr);
2430         if (mtime != 0) {
2431                 put_long_date((char *)inbuf.data + 16,mtime);
2432         }
2433         /* Set all the other times to -1. */
2434         SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2435         SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
2436         SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
2437
2438         return cli_smb2_setpathinfo(cli,
2439                                 name,
2440                                 1, /* in_info_type */
2441                                 /* in_file_info_class */
2442                                 SMB_FILE_BASIC_INFORMATION - 1000,
2443                                 &inbuf);
2444 }
2445
2446
2447 /***************************************************************
2448  Wrapper that allows SMB2 to set file handle times.
2449  Synchronous only.
2450 ***************************************************************/
2451
2452 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
2453                         uint16_t fnum,
2454                         time_t change_time,
2455                         time_t access_time,
2456                         time_t write_time)
2457 {
2458         uint8_t inbuf_store[40];
2459         DATA_BLOB inbuf = data_blob_null;
2460         NTSTATUS status;
2461
2462         if (smbXcli_conn_has_async_calls(cli->conn)) {
2463                 /*
2464                  * Can't use sync call while an async call is in flight
2465                  */
2466                 return NT_STATUS_INVALID_PARAMETER;
2467         }
2468
2469         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2470            level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2471
2472         inbuf.data = inbuf_store;
2473         inbuf.length = sizeof(inbuf_store);
2474         data_blob_clear(&inbuf);
2475
2476         SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2477         if (change_time != 0) {
2478                 put_long_date((char *)inbuf.data + 24, change_time);
2479         }
2480         if (access_time != 0) {
2481                 put_long_date((char *)inbuf.data + 8, access_time);
2482         }
2483         if (write_time != 0) {
2484                 put_long_date((char *)inbuf.data + 16, write_time);
2485         }
2486
2487         status = cli_smb2_set_info_fnum(cli,
2488                                         fnum,
2489                                         1, /* in_info_type */
2490                                         SMB_FILE_BASIC_INFORMATION -
2491                                                 1000, /* in_file_info_class */
2492                                         &inbuf,       /* in_input_buffer */
2493                                         0);           /* in_additional_info */
2494         cli->raw_status = status;
2495         return status;
2496 }
2497
2498 /***************************************************************
2499  Wrapper that allows SMB2 to query disk attributes (size).
2500  Synchronous only.
2501 ***************************************************************/
2502
2503 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2504                           uint64_t *bsize, uint64_t *total, uint64_t *avail)
2505 {
2506         NTSTATUS status;
2507         uint16_t fnum = 0xffff;
2508         DATA_BLOB outbuf = data_blob_null;
2509         uint32_t sectors_per_unit = 0;
2510         uint32_t bytes_per_sector = 0;
2511         uint64_t total_size = 0;
2512         uint64_t size_free = 0;
2513         TALLOC_CTX *frame = talloc_stackframe();
2514
2515         if (smbXcli_conn_has_async_calls(cli->conn)) {
2516                 /*
2517                  * Can't use sync call while an async call is in flight
2518                  */
2519                 status = NT_STATUS_INVALID_PARAMETER;
2520                 goto fail;
2521         }
2522
2523         /* First open the top level directory. */
2524         status = cli_smb2_create_fnum(cli,
2525                         path,
2526                         (struct cli_smb2_create_flags){0},
2527                         SMB2_IMPERSONATION_IMPERSONATION,
2528                         FILE_READ_ATTRIBUTES,   /* desired_access */
2529                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2530                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2531                         FILE_OPEN,              /* create_disposition */
2532                         FILE_DIRECTORY_FILE,    /* create_options */
2533                         NULL,
2534                         &fnum,
2535                         NULL,
2536                         NULL,
2537                         NULL);
2538
2539         if (!NT_STATUS_IS_OK(status)) {
2540                 goto fail;
2541         }
2542
2543         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2544            level 3 (SMB_FS_SIZE_INFORMATION). */
2545
2546         status = cli_smb2_query_info_fnum(
2547                 cli,
2548                 fnum,
2549                 2, /* in_info_type */
2550                 3, /* in_file_info_class */
2551                 0xFFFF, /* in_max_output_length */
2552                 NULL, /* in_input_buffer */
2553                 0, /* in_additional_info */
2554                 0, /* in_flags */
2555                 frame,
2556                 &outbuf);
2557         if (!NT_STATUS_IS_OK(status)) {
2558                 goto fail;
2559         }
2560
2561         /* Parse the reply. */
2562         if (outbuf.length != 24) {
2563                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2564                 goto fail;
2565         }
2566
2567         total_size = BVAL(outbuf.data, 0);
2568         size_free = BVAL(outbuf.data, 8);
2569         sectors_per_unit = IVAL(outbuf.data, 16);
2570         bytes_per_sector = IVAL(outbuf.data, 20);
2571
2572         if (bsize) {
2573                 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2574         }
2575         if (total) {
2576                 *total = total_size;
2577         }
2578         if (avail) {
2579                 *avail = size_free;
2580         }
2581
2582         status = NT_STATUS_OK;
2583
2584   fail:
2585
2586         if (fnum != 0xffff) {
2587                 cli_smb2_close_fnum(cli, fnum);
2588         }
2589
2590         cli->raw_status = status;
2591
2592         TALLOC_FREE(frame);
2593         return status;
2594 }
2595
2596 /***************************************************************
2597  Wrapper that allows SMB2 to query file system sizes.
2598  Synchronous only.
2599 ***************************************************************/
2600
2601 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2602                                 uint64_t *total_allocation_units,
2603                                 uint64_t *caller_allocation_units,
2604                                 uint64_t *actual_allocation_units,
2605                                 uint64_t *sectors_per_allocation_unit,
2606                                 uint64_t *bytes_per_sector)
2607 {
2608         NTSTATUS status;
2609         uint16_t fnum = 0xffff;
2610         DATA_BLOB outbuf = data_blob_null;
2611         TALLOC_CTX *frame = talloc_stackframe();
2612
2613         if (smbXcli_conn_has_async_calls(cli->conn)) {
2614                 /*
2615                  * Can't use sync call while an async call is in flight
2616                  */
2617                 status = NT_STATUS_INVALID_PARAMETER;
2618                 goto fail;
2619         }
2620
2621         /* First open the top level directory. */
2622         status =
2623             cli_smb2_create_fnum(cli, "",
2624                                  (struct cli_smb2_create_flags){0},
2625                                  SMB2_IMPERSONATION_IMPERSONATION,
2626                                  FILE_READ_ATTRIBUTES,     /* desired_access */
2627                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2628                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
2629                                      FILE_SHARE_DELETE, /* share_access */
2630                                  FILE_OPEN,             /* create_disposition */
2631                                  FILE_DIRECTORY_FILE,   /* create_options */
2632                                  NULL,
2633                                  &fnum,
2634                                  NULL,
2635                                  NULL,
2636                                  NULL);
2637
2638         if (!NT_STATUS_IS_OK(status)) {
2639                 goto fail;
2640         }
2641
2642         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2643            level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2644
2645         status = cli_smb2_query_info_fnum(
2646                 cli,
2647                 fnum,
2648                 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2649                 SMB_FS_FULL_SIZE_INFORMATION - 1000, /* in_file_info_class */
2650                 0xFFFF, /* in_max_output_length */
2651                 NULL, /* in_input_buffer */
2652                 0, /* in_additional_info */
2653                 0, /* in_flags */
2654                 frame,
2655                 &outbuf);
2656         if (!NT_STATUS_IS_OK(status)) {
2657                 goto fail;
2658         }
2659
2660         if (outbuf.length < 32) {
2661                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2662                 goto fail;
2663         }
2664
2665         *total_allocation_units = BIG_UINT(outbuf.data, 0);
2666         *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2667         *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2668         *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2669         *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2670
2671 fail:
2672
2673         if (fnum != 0xffff) {
2674                 cli_smb2_close_fnum(cli, fnum);
2675         }
2676
2677         cli->raw_status = status;
2678
2679         TALLOC_FREE(frame);
2680         return status;
2681 }
2682
2683 /***************************************************************
2684  Wrapper that allows SMB2 to query file system attributes.
2685  Synchronous only.
2686 ***************************************************************/
2687
2688 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2689 {
2690         NTSTATUS status;
2691         uint16_t fnum = 0xffff;
2692         DATA_BLOB outbuf = data_blob_null;
2693         TALLOC_CTX *frame = talloc_stackframe();
2694
2695         if (smbXcli_conn_has_async_calls(cli->conn)) {
2696                 /*
2697                  * Can't use sync call while an async call is in flight
2698                  */
2699                 status = NT_STATUS_INVALID_PARAMETER;
2700                 goto fail;
2701         }
2702
2703         /* First open the top level directory. */
2704         status =
2705             cli_smb2_create_fnum(cli, "",
2706                                  (struct cli_smb2_create_flags){0},
2707                                  SMB2_IMPERSONATION_IMPERSONATION,
2708                                  FILE_READ_ATTRIBUTES,     /* desired_access */
2709                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2710                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
2711                                      FILE_SHARE_DELETE, /* share_access */
2712                                  FILE_OPEN,             /* create_disposition */
2713                                  FILE_DIRECTORY_FILE,   /* create_options */
2714                                  NULL,
2715                                  &fnum,
2716                                  NULL,
2717                                  NULL,
2718                                  NULL);
2719
2720         if (!NT_STATUS_IS_OK(status)) {
2721                 goto fail;
2722         }
2723
2724         status = cli_smb2_query_info_fnum(
2725                 cli,
2726                 fnum,
2727                 2, /* in_info_type */
2728                 5,                     /* in_file_info_class */
2729                 0xFFFF, /* in_max_output_length */
2730                 NULL,   /* in_input_buffer */
2731                 0,      /* in_additional_info */
2732                 0,      /* in_flags */
2733                 frame,
2734                 &outbuf);
2735         if (!NT_STATUS_IS_OK(status)) {
2736                 goto fail;
2737         }
2738
2739         if (outbuf.length < 12) {
2740                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2741                 goto fail;
2742         }
2743
2744         *fs_attr = IVAL(outbuf.data, 0);
2745
2746 fail:
2747
2748         if (fnum != 0xffff) {
2749                 cli_smb2_close_fnum(cli, fnum);
2750         }
2751
2752         cli->raw_status = status;
2753
2754         TALLOC_FREE(frame);
2755         return status;
2756 }
2757
2758 /***************************************************************
2759  Wrapper that allows SMB2 to query file system volume info.
2760  Synchronous only.
2761 ***************************************************************/
2762
2763 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2764                                 TALLOC_CTX *mem_ctx,
2765                                 char **_volume_name,
2766                                 uint32_t *pserial_number,
2767                                 time_t *pdate)
2768 {
2769         NTSTATUS status;
2770         uint16_t fnum = 0xffff;
2771         DATA_BLOB outbuf = data_blob_null;
2772         uint32_t nlen;
2773         char *volume_name = NULL;
2774         TALLOC_CTX *frame = talloc_stackframe();
2775
2776         if (smbXcli_conn_has_async_calls(cli->conn)) {
2777                 /*
2778                  * Can't use sync call while an async call is in flight
2779                  */
2780                 status = NT_STATUS_INVALID_PARAMETER;
2781                 goto fail;
2782         }
2783
2784         /* First open the top level directory. */
2785         status =
2786             cli_smb2_create_fnum(cli, "",
2787                                  (struct cli_smb2_create_flags){0},
2788                                  SMB2_IMPERSONATION_IMPERSONATION,
2789                                  FILE_READ_ATTRIBUTES,     /* desired_access */
2790                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2791                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
2792                                      FILE_SHARE_DELETE, /* share_access */
2793                                  FILE_OPEN,             /* create_disposition */
2794                                  FILE_DIRECTORY_FILE,   /* create_options */
2795                                  NULL,
2796                                  &fnum,
2797                                  NULL,
2798                                  NULL,
2799                                  NULL);
2800
2801         if (!NT_STATUS_IS_OK(status)) {
2802                 goto fail;
2803         }
2804
2805         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2806            level 1 (SMB_FS_VOLUME_INFORMATION). */
2807
2808         status = cli_smb2_query_info_fnum(
2809                 cli,
2810                 fnum,
2811                 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2812                 /* in_file_info_class */
2813                 SMB_FS_VOLUME_INFORMATION - 1000,
2814                 0xFFFF, /* in_max_output_length */
2815                 NULL, /* in_input_buffer */
2816                 0, /* in_additional_info */
2817                 0, /* in_flags */
2818                 frame,
2819                 &outbuf);
2820         if (!NT_STATUS_IS_OK(status)) {
2821                 goto fail;
2822         }
2823
2824         if (outbuf.length < 24) {
2825                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2826                 goto fail;
2827         }
2828
2829         if (pdate) {
2830                 struct timespec ts;
2831                 ts = interpret_long_date(BVAL(outbuf.data, 0));
2832                 *pdate = ts.tv_sec;
2833         }
2834         if (pserial_number) {
2835                 *pserial_number = IVAL(outbuf.data,8);
2836         }
2837         nlen = IVAL(outbuf.data,12);
2838         if (nlen + 18 < 18) {
2839                 /* Integer wrap. */
2840                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2841                 goto fail;
2842         }
2843         /*
2844          * The next check is safe as we know outbuf.length >= 24
2845          * from above.
2846          */
2847         if (nlen > (outbuf.length - 18)) {
2848                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2849                 goto fail;
2850         }
2851
2852         pull_string_talloc(mem_ctx,
2853                            (const char *)outbuf.data,
2854                            0,
2855                            &volume_name,
2856                            outbuf.data + 18,
2857                            nlen,
2858                            STR_UNICODE);
2859         if (volume_name == NULL) {
2860                 status = map_nt_error_from_unix(errno);
2861                 goto fail;
2862         }
2863
2864         *_volume_name = volume_name;
2865
2866 fail:
2867
2868         if (fnum != 0xffff) {
2869                 cli_smb2_close_fnum(cli, fnum);
2870         }
2871
2872         cli->raw_status = status;
2873
2874         TALLOC_FREE(frame);
2875         return status;
2876 }
2877
2878 struct cli_smb2_mxac_state {
2879         struct tevent_context *ev;
2880         struct cli_state *cli;
2881         const char *fname;
2882         struct smb2_create_blobs in_cblobs;
2883         uint16_t fnum;
2884         NTSTATUS status;
2885         uint32_t mxac;
2886 };
2887
2888 static void cli_smb2_mxac_opened(struct tevent_req *subreq);
2889 static void cli_smb2_mxac_closed(struct tevent_req *subreq);
2890
2891 struct tevent_req *cli_smb2_query_mxac_send(TALLOC_CTX *mem_ctx,
2892                                             struct tevent_context *ev,
2893                                             struct cli_state *cli,
2894                                             const char *fname)
2895 {
2896         struct tevent_req *req = NULL, *subreq = NULL;
2897         struct cli_smb2_mxac_state *state = NULL;
2898         NTSTATUS status;
2899
2900         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_mxac_state);
2901         if (req == NULL) {
2902                 return NULL;
2903         }
2904         *state = (struct cli_smb2_mxac_state) {
2905                 .ev = ev,
2906                 .cli = cli,
2907                 .fname = fname,
2908         };
2909
2910         status = smb2_create_blob_add(state,
2911                                       &state->in_cblobs,
2912                                       SMB2_CREATE_TAG_MXAC,
2913                                       data_blob(NULL, 0));
2914         if (tevent_req_nterror(req, status)) {
2915                 return tevent_req_post(req, ev);
2916         }
2917
2918         subreq = cli_smb2_create_fnum_send(
2919                 state,
2920                 state->ev,
2921                 state->cli,
2922                 state->fname,
2923                 (struct cli_smb2_create_flags){0},
2924                 SMB2_IMPERSONATION_IMPERSONATION,
2925                 FILE_READ_ATTRIBUTES,
2926                 0,                      /* file attributes */
2927                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
2928                 FILE_OPEN,
2929                 0,                      /* create_options */
2930                 &state->in_cblobs);
2931         if (tevent_req_nomem(subreq, req)) {
2932                 return tevent_req_post(req, ev);
2933         }
2934         tevent_req_set_callback(subreq, cli_smb2_mxac_opened, req);
2935         return req;
2936 }
2937
2938 static void cli_smb2_mxac_opened(struct tevent_req *subreq)
2939 {
2940         struct tevent_req *req = tevent_req_callback_data(
2941                 subreq, struct tevent_req);
2942         struct cli_smb2_mxac_state *state = tevent_req_data(
2943                 req, struct cli_smb2_mxac_state);
2944         struct smb2_create_blobs out_cblobs = {0};
2945         struct smb2_create_blob *mxac_blob = NULL;
2946         NTSTATUS status;
2947
2948         status = cli_smb2_create_fnum_recv(
2949                 subreq, &state->fnum, NULL, state, &out_cblobs, NULL);
2950         TALLOC_FREE(subreq);
2951
2952         if (tevent_req_nterror(req, status)) {
2953                 return;
2954         }
2955
2956         mxac_blob = smb2_create_blob_find(&out_cblobs, SMB2_CREATE_TAG_MXAC);
2957         if (mxac_blob == NULL) {
2958                 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2959                 goto close;
2960         }
2961         if (mxac_blob->data.length != 8) {
2962                 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2963                 goto close;
2964         }
2965
2966         state->status = NT_STATUS(IVAL(mxac_blob->data.data, 0));
2967         state->mxac = IVAL(mxac_blob->data.data, 4);
2968
2969 close:
2970         subreq = cli_smb2_close_fnum_send(state,
2971                                           state->ev,
2972                                           state->cli,
2973                                           state->fnum,
2974                                           0);
2975         if (tevent_req_nomem(subreq, req)) {
2976                 return;
2977         }
2978         tevent_req_set_callback(subreq, cli_smb2_mxac_closed, req);
2979
2980         return;
2981 }
2982
2983 static void cli_smb2_mxac_closed(struct tevent_req *subreq)
2984 {
2985         struct tevent_req *req = tevent_req_callback_data(
2986                 subreq, struct tevent_req);
2987         NTSTATUS status;
2988
2989         status = cli_smb2_close_fnum_recv(subreq);
2990         if (tevent_req_nterror(req, status)) {
2991                 return;
2992         }
2993
2994         tevent_req_done(req);
2995 }
2996
2997 NTSTATUS cli_smb2_query_mxac_recv(struct tevent_req *req, uint32_t *mxac)
2998 {
2999         struct cli_smb2_mxac_state *state = tevent_req_data(
3000                 req, struct cli_smb2_mxac_state);
3001         NTSTATUS status;
3002
3003         if (tevent_req_is_nterror(req, &status)) {
3004                 return status;
3005         }
3006
3007         if (!NT_STATUS_IS_OK(state->status)) {
3008                 return state->status;
3009         }
3010
3011         *mxac = state->mxac;
3012         return NT_STATUS_OK;
3013 }
3014
3015 NTSTATUS cli_smb2_query_mxac(struct cli_state *cli,
3016                              const char *fname,
3017                              uint32_t *_mxac)
3018 {
3019         TALLOC_CTX *frame = talloc_stackframe();
3020         struct tevent_context *ev = NULL;
3021         struct tevent_req *req = NULL;
3022         NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
3023         bool ok;
3024
3025         if (smbXcli_conn_has_async_calls(cli->conn)) {
3026                 /*
3027                  * Can't use sync call while an async call is in flight
3028                  */
3029                 status = NT_STATUS_INVALID_PARAMETER;
3030                 goto fail;
3031         }
3032
3033         ev = samba_tevent_context_init(frame);
3034         if (ev == NULL) {
3035                 goto fail;
3036         }
3037         req = cli_smb2_query_mxac_send(frame, ev, cli, fname);
3038         if (req == NULL) {
3039                 goto fail;
3040         }
3041         ok = tevent_req_poll_ntstatus(req, ev, &status);
3042         if (!ok) {
3043                 goto fail;
3044         }
3045         status = cli_smb2_query_mxac_recv(req, _mxac);
3046
3047 fail:
3048         cli->raw_status = status;
3049         TALLOC_FREE(frame);
3050         return status;
3051 }
3052
3053 struct cli_smb2_rename_fnum_state {
3054         DATA_BLOB inbuf;
3055 };
3056
3057 static void cli_smb2_rename_fnum_done(struct tevent_req *subreq);
3058
3059 static struct tevent_req *cli_smb2_rename_fnum_send(
3060         TALLOC_CTX *mem_ctx,
3061         struct tevent_context *ev,
3062         struct cli_state *cli,
3063         uint16_t fnum,
3064         const char *fname_dst,
3065         bool replace)
3066 {
3067         struct tevent_req *req = NULL, *subreq = NULL;
3068         struct cli_smb2_rename_fnum_state *state = NULL;
3069         size_t namelen = strlen(fname_dst);
3070         smb_ucs2_t *converted_str = NULL;
3071         size_t converted_size_bytes = 0;
3072         size_t inbuf_size;
3073         bool ok;
3074
3075         req = tevent_req_create(
3076                 mem_ctx, &state, struct cli_smb2_rename_fnum_state);
3077         if (req == NULL) {
3078                 return NULL;
3079         }
3080
3081         /*
3082          * SMB2 is pickier about pathnames. Ensure it doesn't start in
3083          * a '\'
3084          */
3085         if (*fname_dst == '\\') {
3086                 fname_dst++;
3087         }
3088
3089         /*
3090          * SMB2 is pickier about pathnames. Ensure it doesn't end in a
3091          * '\'
3092          */
3093         if (namelen > 0 && fname_dst[namelen-1] == '\\') {
3094                 fname_dst = talloc_strndup(state, fname_dst, namelen-1);
3095                 if (tevent_req_nomem(fname_dst, req)) {
3096                         return tevent_req_post(req, ev);
3097                 }
3098         }
3099
3100         ok = push_ucs2_talloc(
3101                 state, &converted_str, fname_dst, &converted_size_bytes);
3102         if (!ok) {
3103                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3104                 return tevent_req_post(req, ev);
3105         }
3106
3107         /*
3108          * W2K8 insists the dest name is not null terminated. Remove
3109          * the last 2 zero bytes and reduce the name length.
3110          */
3111         if (converted_size_bytes < 2) {
3112                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3113                 return tevent_req_post(req, ev);
3114         }
3115         converted_size_bytes -= 2;
3116
3117         inbuf_size = 20 + converted_size_bytes;
3118         if (inbuf_size < 20) {
3119                 /* Integer wrap check. */
3120                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3121                 return tevent_req_post(req, ev);
3122         }
3123
3124         /*
3125          * The Windows 10 SMB2 server has a minimum length
3126          * for a SMB2_FILE_RENAME_INFORMATION buffer of
3127          * 24 bytes. It returns NT_STATUS_INFO_LENGTH_MISMATCH
3128          * if the length is less. This isn't an alignment
3129          * issue as Windows client accepts happily 2-byte align
3130          * for larger target name sizes. Also the Windows 10
3131          * SMB1 server doesn't have this restriction.
3132          *
3133          * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14403
3134          */
3135         inbuf_size = MAX(inbuf_size, 24);
3136
3137         state->inbuf = data_blob_talloc_zero(state, inbuf_size);
3138         if (tevent_req_nomem(state->inbuf.data, req)) {
3139                 return tevent_req_post(req, ev);
3140         }
3141
3142         if (replace) {
3143                 SCVAL(state->inbuf.data, 0, 1);
3144         }
3145
3146         SIVAL(state->inbuf.data, 16, converted_size_bytes);
3147         memcpy(state->inbuf.data + 20, converted_str, converted_size_bytes);
3148
3149         TALLOC_FREE(converted_str);
3150
3151         /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3152            level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3153
3154         subreq = cli_smb2_set_info_fnum_send(
3155                 state,          /* mem_ctx */
3156                 ev,             /* ev */
3157                 cli,            /* cli */
3158                 fnum,           /* fnum */
3159                 1,              /* in_info_type */
3160                 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
3161                 &state->inbuf,  /* in_input_buffer */
3162                 0);             /* in_additional_info */
3163         if (tevent_req_nomem(subreq, req)) {
3164                 return tevent_req_post(req, ev);
3165         }
3166         tevent_req_set_callback(subreq, cli_smb2_rename_fnum_done, req);
3167         return req;
3168 }
3169
3170 static void cli_smb2_rename_fnum_done(struct tevent_req *subreq)
3171 {
3172         NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
3173         tevent_req_simple_finish_ntstatus(subreq, status);
3174 }
3175
3176 static NTSTATUS cli_smb2_rename_fnum_recv(struct tevent_req *req)
3177 {
3178         return tevent_req_simple_recv_ntstatus(req);
3179 }
3180
3181 /***************************************************************
3182  Wrapper that allows SMB2 to rename a file.
3183 ***************************************************************/
3184
3185 struct cli_smb2_rename_state {
3186         struct tevent_context *ev;
3187         struct cli_state *cli;
3188         const char *fname_dst;
3189         bool replace;
3190         uint16_t fnum;
3191
3192         NTSTATUS rename_status;
3193 };
3194
3195 static void cli_smb2_rename_opened(struct tevent_req *subreq);
3196 static void cli_smb2_rename_renamed(struct tevent_req *subreq);
3197 static void cli_smb2_rename_closed(struct tevent_req *subreq);
3198
3199 struct tevent_req *cli_smb2_rename_send(
3200         TALLOC_CTX *mem_ctx,
3201         struct tevent_context *ev,
3202         struct cli_state *cli,
3203         const char *fname_src,
3204         const char *fname_dst,
3205         bool replace)
3206 {
3207         struct tevent_req *req = NULL, *subreq = NULL;
3208         struct cli_smb2_rename_state *state = NULL;
3209         NTSTATUS status;
3210
3211         req = tevent_req_create(
3212                 mem_ctx, &state, struct cli_smb2_rename_state);
3213         if (req == NULL) {
3214                 return NULL;
3215         }
3216
3217         /*
3218          * Strip a MSDFS path from fname_dst if we were given one.
3219          */
3220         status = cli_dfs_target_check(state,
3221                                 cli,
3222                                 fname_dst,
3223                                 &fname_dst);
3224         if (tevent_req_nterror(req, status)) {
3225                 return tevent_req_post(req, ev);
3226         }
3227
3228         state->ev = ev;
3229         state->cli = cli;
3230         state->fname_dst = fname_dst;
3231         state->replace = replace;
3232
3233         subreq = get_fnum_from_path_send(
3234                 state, ev, cli, fname_src, DELETE_ACCESS);
3235         if (tevent_req_nomem(subreq, req)) {
3236                 return tevent_req_post(req, ev);
3237         }
3238         tevent_req_set_callback(subreq, cli_smb2_rename_opened, req);
3239         return req;
3240 }
3241
3242 static void cli_smb2_rename_opened(struct tevent_req *subreq)
3243 {
3244         struct tevent_req *req = tevent_req_callback_data(
3245                 subreq, struct tevent_req);
3246         struct cli_smb2_rename_state *state = tevent_req_data(
3247                 req, struct cli_smb2_rename_state);
3248         NTSTATUS status;
3249
3250         status = get_fnum_from_path_recv(subreq, &state->fnum);
3251         TALLOC_FREE(subreq);
3252         if (tevent_req_nterror(req, status)) {
3253                 return;
3254         }
3255
3256         subreq = cli_smb2_rename_fnum_send(
3257                 state,
3258                 state->ev,
3259                 state->cli,
3260                 state->fnum,
3261                 state->fname_dst,
3262                 state->replace);
3263         if (tevent_req_nomem(subreq, req)) {
3264                 return;
3265         }
3266         tevent_req_set_callback(subreq, cli_smb2_rename_renamed, req);
3267 }
3268
3269 static void cli_smb2_rename_renamed(struct tevent_req *subreq)
3270 {
3271         struct tevent_req *req = tevent_req_callback_data(
3272                 subreq, struct tevent_req);
3273         struct cli_smb2_rename_state *state = tevent_req_data(
3274                 req, struct cli_smb2_rename_state);
3275
3276         state->rename_status = cli_smb2_rename_fnum_recv(subreq);
3277         TALLOC_FREE(subreq);
3278
3279         subreq = cli_smb2_close_fnum_send(state,
3280                                           state->ev,
3281                                           state->cli,
3282                                           state->fnum,
3283                                           0);
3284         if (tevent_req_nomem(subreq, req)) {
3285                 return;
3286         }
3287         tevent_req_set_callback(subreq, cli_smb2_rename_closed, req);
3288 }
3289
3290 static void cli_smb2_rename_closed(struct tevent_req *subreq)
3291 {
3292         NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
3293         tevent_req_simple_finish_ntstatus(subreq, status);
3294 }
3295
3296 NTSTATUS cli_smb2_rename_recv(struct tevent_req *req)
3297 {
3298         struct cli_smb2_rename_state *state = tevent_req_data(
3299                 req, struct cli_smb2_rename_state);
3300         NTSTATUS status = NT_STATUS_OK;
3301
3302         if (!tevent_req_is_nterror(req, &status)) {
3303                 status = state->rename_status;
3304         }
3305         tevent_req_received(req);
3306         return status;
3307 }
3308
3309 /***************************************************************
3310  Wrapper that allows SMB2 to set an EA on a fnum.
3311  Synchronous only.
3312 ***************************************************************/
3313
3314 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
3315                         uint16_t fnum,
3316                         const char *ea_name,
3317                         const char *ea_val,
3318                         size_t ea_len)
3319 {
3320         NTSTATUS status;
3321         DATA_BLOB inbuf = data_blob_null;
3322         size_t bloblen = 0;
3323         char *ea_name_ascii = NULL;
3324         size_t namelen = 0;
3325         TALLOC_CTX *frame = talloc_stackframe();
3326
3327         if (smbXcli_conn_has_async_calls(cli->conn)) {
3328                 /*
3329                  * Can't use sync call while an async call is in flight
3330                  */
3331                 status = NT_STATUS_INVALID_PARAMETER;
3332                 goto fail;
3333         }
3334
3335         /* Marshall the SMB2 EA data. */
3336         if (ea_len > 0xFFFF) {
3337                 status = NT_STATUS_INVALID_PARAMETER;
3338                 goto fail;
3339         }
3340
3341         if (!push_ascii_talloc(frame,
3342                                 &ea_name_ascii,
3343                                 ea_name,
3344                                 &namelen)) {
3345                 status = NT_STATUS_INVALID_PARAMETER;
3346                 goto fail;
3347         }
3348
3349         if (namelen < 2 || namelen > 0xFF) {
3350                 status = NT_STATUS_INVALID_PARAMETER;
3351                 goto fail;
3352         }
3353
3354         bloblen = 8 + ea_len + namelen;
3355         /* Round up to a 4 byte boundary. */
3356         bloblen = ((bloblen + 3)&~3);
3357
3358         inbuf = data_blob_talloc_zero(frame, bloblen);
3359         if (inbuf.data == NULL) {
3360                 status = NT_STATUS_NO_MEMORY;
3361                 goto fail;
3362         }
3363         /* namelen doesn't include the NULL byte. */
3364         SCVAL(inbuf.data, 5, namelen - 1);
3365         SSVAL(inbuf.data, 6, ea_len);
3366         memcpy(inbuf.data + 8, ea_name_ascii, namelen);
3367         memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
3368
3369         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3370            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3371
3372         status = cli_smb2_set_info_fnum(
3373                 cli,
3374                 fnum,
3375                 1,              /* in_info_type */
3376                 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3377                 &inbuf,         /* in_input_buffer */
3378                 0);             /* in_additional_info */
3379
3380   fail:
3381
3382         cli->raw_status = status;
3383
3384         TALLOC_FREE(frame);
3385         return status;
3386 }
3387
3388 /***************************************************************
3389  Wrapper that allows SMB2 to set an EA on a pathname.
3390  Synchronous only.
3391 ***************************************************************/
3392
3393 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
3394                         const char *name,
3395                         const char *ea_name,
3396                         const char *ea_val,
3397                         size_t ea_len)
3398 {
3399         NTSTATUS status;
3400         uint16_t fnum = 0xffff;
3401
3402         if (smbXcli_conn_has_async_calls(cli->conn)) {
3403                 /*
3404                  * Can't use sync call while an async call is in flight
3405                  */
3406                 status = NT_STATUS_INVALID_PARAMETER;
3407                 goto fail;
3408         }
3409
3410         status = get_fnum_from_path(cli,
3411                                 name,
3412                                 FILE_WRITE_EA,
3413                                 &fnum);
3414
3415         if (!NT_STATUS_IS_OK(status)) {
3416                 goto fail;
3417         }
3418
3419         status = cli_set_ea_fnum(cli,
3420                                 fnum,
3421                                 ea_name,
3422                                 ea_val,
3423                                 ea_len);
3424         if (!NT_STATUS_IS_OK(status)) {
3425                 goto fail;
3426         }
3427
3428   fail:
3429
3430         if (fnum != 0xffff) {
3431                 cli_smb2_close_fnum(cli, fnum);
3432         }
3433
3434         cli->raw_status = status;
3435
3436         return status;
3437 }
3438
3439 /***************************************************************
3440  Wrapper that allows SMB2 to get an EA list on a pathname.
3441  Synchronous only.
3442 ***************************************************************/
3443
3444 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
3445                                 const char *name,
3446                                 TALLOC_CTX *ctx,
3447                                 size_t *pnum_eas,
3448                                 struct ea_struct **pea_array)
3449 {
3450         NTSTATUS status;
3451         uint16_t fnum = 0xffff;
3452         DATA_BLOB outbuf = data_blob_null;
3453         struct ea_list *ea_list = NULL;
3454         struct ea_list *eal = NULL;
3455         size_t ea_count = 0;
3456         TALLOC_CTX *frame = talloc_stackframe();
3457
3458         *pnum_eas = 0;
3459         *pea_array = NULL;
3460
3461         if (smbXcli_conn_has_async_calls(cli->conn)) {
3462                 /*
3463                  * Can't use sync call while an async call is in flight
3464                  */
3465                 status = NT_STATUS_INVALID_PARAMETER;
3466                 goto fail;
3467         }
3468
3469         status = get_fnum_from_path(cli,
3470                                 name,
3471                                 FILE_READ_EA,
3472                                 &fnum);
3473
3474         if (!NT_STATUS_IS_OK(status)) {
3475                 goto fail;
3476         }
3477
3478         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3479            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3480
3481         status = cli_smb2_query_info_fnum(
3482                 cli,
3483                 fnum,
3484                 1, /* in_info_type */
3485                 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3486                 0xFFFF, /* in_max_output_length */
3487                 NULL, /* in_input_buffer */
3488                 0, /* in_additional_info */
3489                 0, /* in_flags */
3490                 frame,
3491                 &outbuf);
3492
3493         if (!NT_STATUS_IS_OK(status)) {
3494                 goto fail;
3495         }
3496
3497         /* Parse the reply. */
3498         ea_list = read_nttrans_ea_list(ctx,
3499                                 (const char *)outbuf.data,
3500                                 outbuf.length);
3501         if (ea_list == NULL) {
3502                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3503                 goto fail;
3504         }
3505
3506         /* Convert to an array. */
3507         for (eal = ea_list; eal; eal = eal->next) {
3508                 ea_count++;
3509         }
3510
3511         if (ea_count) {
3512                 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
3513                 if (*pea_array == NULL) {
3514                         status = NT_STATUS_NO_MEMORY;
3515                         goto fail;
3516                 }
3517                 ea_count = 0;
3518                 for (eal = ea_list; eal; eal = eal->next) {
3519                         (*pea_array)[ea_count++] = eal->ea;
3520                 }
3521                 *pnum_eas = ea_count;
3522         }
3523
3524   fail:
3525
3526         if (fnum != 0xffff) {
3527                 cli_smb2_close_fnum(cli, fnum);
3528         }
3529
3530         cli->raw_status = status;
3531
3532         TALLOC_FREE(frame);
3533         return status;
3534 }
3535
3536 /***************************************************************
3537  Wrapper that allows SMB2 to get user quota.
3538  Synchronous only.
3539 ***************************************************************/
3540
3541 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
3542                                  int quota_fnum,
3543                                  SMB_NTQUOTA_STRUCT *pqt)
3544 {
3545         NTSTATUS status;
3546         DATA_BLOB inbuf = data_blob_null;
3547         DATA_BLOB info_blob = data_blob_null;
3548         DATA_BLOB outbuf = data_blob_null;
3549         TALLOC_CTX *frame = talloc_stackframe();
3550         unsigned sid_len;
3551         unsigned int offset;
3552         struct smb2_query_quota_info query = {0};
3553         struct file_get_quota_info info = {0};
3554         enum ndr_err_code err;
3555         struct ndr_push *ndr_push = NULL;
3556
3557         if (smbXcli_conn_has_async_calls(cli->conn)) {
3558                 /*
3559                  * Can't use sync call while an async call is in flight
3560                  */
3561                 status = NT_STATUS_INVALID_PARAMETER;
3562                 goto fail;
3563         }
3564
3565         sid_len = ndr_size_dom_sid(&pqt->sid, 0);
3566
3567         query.return_single = 1;
3568
3569         info.next_entry_offset = 0;
3570         info.sid_length = sid_len;
3571         info.sid = pqt->sid;
3572
3573         err = ndr_push_struct_blob(
3574                         &info_blob,
3575                         frame,
3576                         &info,
3577                         (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
3578
3579         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3580                 status = NT_STATUS_INTERNAL_ERROR;
3581                 goto fail;
3582         }
3583
3584         query.sid_list_length = info_blob.length;
3585         ndr_push = ndr_push_init_ctx(frame);
3586         if (!ndr_push) {
3587                 status = NT_STATUS_NO_MEMORY;
3588                 goto fail;
3589         }
3590
3591         err = ndr_push_smb2_query_quota_info(ndr_push,
3592                                              NDR_SCALARS | NDR_BUFFERS,
3593                                              &query);
3594
3595         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3596                 status = NT_STATUS_INTERNAL_ERROR;
3597                 goto fail;
3598         }
3599
3600         err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3601                                    info_blob.length);
3602
3603         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3604                 status = NT_STATUS_INTERNAL_ERROR;
3605                 goto fail;
3606         }
3607         inbuf.data = ndr_push->data;
3608         inbuf.length = ndr_push->offset;
3609
3610         status = cli_smb2_query_info_fnum(
3611                 cli,
3612                 quota_fnum,
3613                 4, /* in_info_type */
3614                 0,                     /* in_file_info_class */
3615                 0xFFFF, /* in_max_output_length */
3616                 &inbuf, /* in_input_buffer */
3617                 0,      /* in_additional_info */
3618                 0,      /* in_flags */
3619                 frame,
3620                 &outbuf);
3621
3622         if (!NT_STATUS_IS_OK(status)) {
3623                 goto fail;
3624         }
3625
3626         if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3627                                      pqt)) {
3628                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3629                 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3630         }
3631
3632 fail:
3633         cli->raw_status = status;
3634
3635         TALLOC_FREE(frame);
3636         return status;
3637 }
3638
3639 /***************************************************************
3640  Wrapper that allows SMB2 to list user quota.
3641  Synchronous only.
3642 ***************************************************************/
3643
3644 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3645                                        TALLOC_CTX *mem_ctx,
3646                                        int quota_fnum,
3647                                        SMB_NTQUOTA_LIST **pqt_list,
3648                                        bool first)
3649 {
3650         NTSTATUS status;
3651         DATA_BLOB inbuf = data_blob_null;
3652         DATA_BLOB outbuf = data_blob_null;
3653         TALLOC_CTX *frame = talloc_stackframe();
3654         struct smb2_query_quota_info info = {0};
3655         enum ndr_err_code err;
3656
3657         if (smbXcli_conn_has_async_calls(cli->conn)) {
3658                 /*
3659                  * Can't use sync call while an async call is in flight
3660                  */
3661                 status = NT_STATUS_INVALID_PARAMETER;
3662                 goto cleanup;
3663         }
3664
3665         info.restart_scan = first ? 1 : 0;
3666
3667         err = ndr_push_struct_blob(
3668                         &inbuf,
3669                         frame,
3670                         &info,
3671                         (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3672
3673         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3674                 status = NT_STATUS_INTERNAL_ERROR;
3675                 goto cleanup;
3676         }
3677
3678         status = cli_smb2_query_info_fnum(
3679                 cli,
3680                 quota_fnum,
3681                 4, /* in_info_type */
3682                 0, /* in_file_info_class */
3683                 0xFFFF, /* in_max_output_length */
3684                 &inbuf, /* in_input_buffer */
3685                 0,      /* in_additional_info */
3686                 0,      /* in_flags */
3687                 frame,
3688                 &outbuf);
3689
3690         /*
3691          * safeguard against panic from calling parse_user_quota_list with
3692          * NULL buffer
3693          */
3694         if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3695                 status = NT_STATUS_NO_MORE_ENTRIES;
3696         }
3697
3698         if (!NT_STATUS_IS_OK(status)) {
3699                 goto cleanup;
3700         }
3701
3702         status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3703                                        pqt_list);
3704
3705 cleanup:
3706         cli->raw_status = status;
3707
3708         TALLOC_FREE(frame);
3709         return status;
3710 }
3711
3712 /***************************************************************
3713  Wrapper that allows SMB2 to get file system quota.
3714  Synchronous only.
3715 ***************************************************************/
3716
3717 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3718                                     int quota_fnum,
3719                                     SMB_NTQUOTA_STRUCT *pqt)
3720 {
3721         NTSTATUS status;
3722         DATA_BLOB outbuf = data_blob_null;
3723         TALLOC_CTX *frame = talloc_stackframe();
3724
3725         if (smbXcli_conn_has_async_calls(cli->conn)) {
3726                 /*
3727                  * Can't use sync call while an async call is in flight
3728                  */
3729                 status = NT_STATUS_INVALID_PARAMETER;
3730                 goto cleanup;
3731         }
3732
3733         status = cli_smb2_query_info_fnum(
3734                 cli,
3735                 quota_fnum,
3736                 2,                                   /* in_info_type */
3737                 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3738                 0xFFFF,                      /* in_max_output_length */
3739                 NULL,                        /* in_input_buffer */
3740                 0,                                   /* in_additional_info */
3741                 0,                                   /* in_flags */
3742                 frame,
3743                 &outbuf);
3744
3745         if (!NT_STATUS_IS_OK(status)) {
3746                 goto cleanup;
3747         }
3748
3749         status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3750
3751 cleanup:
3752         cli->raw_status = status;
3753
3754         TALLOC_FREE(frame);
3755         return status;
3756 }
3757
3758 /***************************************************************
3759  Wrapper that allows SMB2 to set user quota.
3760  Synchronous only.
3761 ***************************************************************/
3762
3763 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3764                                  int quota_fnum,
3765                                  SMB_NTQUOTA_LIST *qtl)
3766 {
3767         NTSTATUS status;
3768         DATA_BLOB inbuf = data_blob_null;
3769         TALLOC_CTX *frame = talloc_stackframe();
3770
3771         if (smbXcli_conn_has_async_calls(cli->conn)) {
3772                 /*
3773                  * Can't use sync call while an async call is in flight
3774                  */
3775                 status = NT_STATUS_INVALID_PARAMETER;
3776                 goto cleanup;
3777         }
3778
3779         status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3780         if (!NT_STATUS_IS_OK(status)) {
3781                 goto cleanup;
3782         }
3783
3784         status = cli_smb2_set_info_fnum(
3785                 cli,
3786                 quota_fnum,
3787                 4,                        /* in_info_type */
3788                 0,                        /* in_file_info_class */
3789                 &inbuf,                   /* in_input_buffer */
3790                 0);                       /* in_additional_info */
3791 cleanup:
3792
3793         cli->raw_status = status;
3794
3795         TALLOC_FREE(frame);
3796
3797         return status;
3798 }
3799
3800 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3801                                     int quota_fnum,
3802                                     SMB_NTQUOTA_STRUCT *pqt)
3803 {
3804         NTSTATUS status;
3805         DATA_BLOB inbuf = data_blob_null;
3806         TALLOC_CTX *frame = talloc_stackframe();
3807
3808         if (smbXcli_conn_has_async_calls(cli->conn)) {
3809                 /*
3810                  * Can't use sync call while an async call is in flight
3811                  */
3812                 status = NT_STATUS_INVALID_PARAMETER;
3813                 goto cleanup;
3814         }
3815
3816         status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3817         if (!NT_STATUS_IS_OK(status)) {
3818                 goto cleanup;
3819         }
3820
3821         status = cli_smb2_set_info_fnum(
3822                 cli,
3823                 quota_fnum,
3824                 2,                           /* in_info_type */
3825                 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3826                 &inbuf,                      /* in_input_buffer */
3827                 0);                          /* in_additional_info */
3828 cleanup:
3829         cli->raw_status = status;
3830
3831         TALLOC_FREE(frame);
3832         return status;
3833 }
3834
3835 struct cli_smb2_read_state {
3836         struct tevent_context *ev;
3837         struct cli_state *cli;
3838         struct smb2_hnd *ph;
3839         uint64_t start_offset;
3840         uint32_t size;
3841         uint32_t received;
3842         uint8_t *buf;
3843 };
3844
3845 static void cli_smb2_read_done(struct tevent_req *subreq);
3846
3847 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3848                                 struct tevent_context *ev,
3849                                 struct cli_state *cli,
3850                                 uint16_t fnum,
3851                                 off_t offset,
3852                                 size_t size)
3853 {
3854         NTSTATUS status;
3855         struct tevent_req *req, *subreq;
3856         struct cli_smb2_read_state *state;
3857
3858         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3859         if (req == NULL) {
3860                 return NULL;
3861         }
3862         state->ev = ev;
3863         state->cli = cli;
3864         state->start_offset = (uint64_t)offset;
3865         state->size = (uint32_t)size;
3866         state->received = 0;
3867         state->buf = NULL;
3868
3869         status = map_fnum_to_smb2_handle(cli,
3870                                         fnum,
3871                                         &state->ph);
3872         if (tevent_req_nterror(req, status)) {
3873                 return tevent_req_post(req, ev);
3874         }
3875
3876         subreq = smb2cli_read_send(state,
3877                                 state->ev,
3878                                 state->cli->conn,
3879                                 state->cli->timeout,
3880                                 state->cli->smb2.session,
3881                                 state->cli->smb2.tcon,
3882                                 state->size,
3883                                 state->start_offset,
3884                                 state->ph->fid_persistent,
3885                                 state->ph->fid_volatile,
3886                                 0, /* minimum_count */
3887                                 0); /* remaining_bytes */
3888
3889         if (tevent_req_nomem(subreq, req)) {
3890                 return tevent_req_post(req, ev);
3891         }
3892         tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3893         return req;
3894 }
3895
3896 static void cli_smb2_read_done(struct tevent_req *subreq)
3897 {
3898         struct tevent_req *req = tevent_req_callback_data(
3899                 subreq, struct tevent_req);
3900         struct cli_smb2_read_state *state = tevent_req_data(
3901                 req, struct cli_smb2_read_state);
3902         NTSTATUS status;
3903
3904         status = smb2cli_read_recv(subreq, state,
3905                                    &state->buf, &state->received);
3906         if (tevent_req_nterror(req, status)) {
3907                 return;
3908         }
3909
3910         if (state->received > state->size) {
3911                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3912                 return;
3913         }
3914
3915         tevent_req_done(req);
3916 }
3917
3918 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
3919                                 ssize_t *received,
3920                                 uint8_t **rcvbuf)
3921 {
3922         NTSTATUS status;
3923         struct cli_smb2_read_state *state = tevent_req_data(
3924                                 req, struct cli_smb2_read_state);
3925
3926         if (tevent_req_is_nterror(req, &status)) {
3927                 state->cli->raw_status = status;
3928                 return status;
3929         }
3930         /*
3931          * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3932          * better make sure that you copy it away before you talloc_free(req).
3933          * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3934          */
3935         *received = (ssize_t)state->received;
3936         *rcvbuf = state->buf;
3937         state->cli->raw_status = NT_STATUS_OK;
3938         return NT_STATUS_OK;
3939 }
3940
3941 struct cli_smb2_write_state {
3942         struct tevent_context *ev;
3943         struct cli_state *cli;
3944         struct smb2_hnd *ph;
3945         uint32_t flags;
3946         const uint8_t *buf;
3947         uint64_t offset;
3948         uint32_t size;
3949         uint32_t written;
3950 };
3951
3952 static void cli_smb2_write_written(struct tevent_req *req);
3953
3954 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
3955                                         struct tevent_context *ev,
3956                                         struct cli_state *cli,
3957                                         uint16_t fnum,
3958                                         uint16_t mode,
3959                                         const uint8_t *buf,
3960                                         off_t offset,
3961                                         size_t size)
3962 {
3963         NTSTATUS status;
3964         struct tevent_req *req, *subreq = NULL;
3965         struct cli_smb2_write_state *state = NULL;
3966
3967         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
3968         if (req == NULL) {
3969                 return NULL;
3970         }
3971         state->ev = ev;
3972         state->cli = cli;
3973         /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3974         state->flags = (uint32_t)mode;
3975         state->buf = buf;
3976         state->offset = (uint64_t)offset;
3977         state->size = (uint32_t)size;
3978         state->written = 0;
3979
3980         status = map_fnum_to_smb2_handle(cli,
3981                                         fnum,
3982                                         &state->ph);
3983         if (tevent_req_nterror(req, status)) {
3984                 return tevent_req_post(req, ev);
3985         }
3986
3987         subreq = smb2cli_write_send(state,
3988                                 state->ev,
3989                                 state->cli->conn,
3990                                 state->cli->timeout,
3991                                 state->cli->smb2.session,
3992                                 state->cli->smb2.tcon,
3993                                 state->size,
3994                                 state->offset,
3995                                 state->ph->fid_persistent,
3996                                 state->ph->fid_volatile,
3997                                 0, /* remaining_bytes */
3998                                 state->flags, /* flags */
3999                                 state->buf);
4000
4001         if (tevent_req_nomem(subreq, req)) {
4002                 return tevent_req_post(req, ev);
4003         }
4004         tevent_req_set_callback(subreq, cli_smb2_write_written, req);
4005         return req;
4006 }
4007
4008 static void cli_smb2_write_written(struct tevent_req *subreq)
4009 {
4010         struct tevent_req *req = tevent_req_callback_data(
4011                 subreq, struct tevent_req);
4012         struct cli_smb2_write_state *state = tevent_req_data(
4013                 req, struct cli_smb2_write_state);
4014         NTSTATUS status;
4015         uint32_t written;
4016
4017         status = smb2cli_write_recv(subreq, &written);
4018         TALLOC_FREE(subreq);
4019         if (tevent_req_nterror(req, status)) {
4020                 return;
4021         }
4022
4023         state->written = written;
4024
4025         tevent_req_done(req);
4026 }
4027
4028 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
4029                              size_t *pwritten)
4030 {
4031         struct cli_smb2_write_state *state = tevent_req_data(
4032                 req, struct cli_smb2_write_state);
4033         NTSTATUS status;
4034
4035         if (tevent_req_is_nterror(req, &status)) {
4036                 state->cli->raw_status = status;
4037                 tevent_req_received(req);
4038                 return status;
4039         }
4040
4041         if (pwritten != NULL) {
4042                 *pwritten = (size_t)state->written;
4043         }
4044         state->cli->raw_status = NT_STATUS_OK;
4045         tevent_req_received(req);
4046         return NT_STATUS_OK;
4047 }
4048
4049 /***************************************************************
4050  Wrapper that allows SMB2 async write using an fnum.
4051  This is mostly cut-and-paste from Volker's code inside
4052  source3/libsmb/clireadwrite.c, adapted for SMB2.
4053
4054  Done this way so I can reuse all the logic inside cli_push()
4055  for free :-).
4056 ***************************************************************/
4057
4058 struct cli_smb2_writeall_state {
4059         struct tevent_context *ev;
4060         struct cli_state *cli;
4061         struct smb2_hnd *ph;
4062         uint32_t flags;
4063         const uint8_t *buf;
4064         uint64_t offset;
4065         uint32_t size;
4066         uint32_t written;
4067 };
4068
4069 static void cli_smb2_writeall_written(struct tevent_req *req);
4070
4071 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
4072                                         struct tevent_context *ev,
4073                                         struct cli_state *cli,
4074                                         uint16_t fnum,
4075                                         uint16_t mode,
4076                                         const uint8_t *buf,
4077                                         off_t offset,
4078                                         size_t size)
4079 {
4080         NTSTATUS status;
4081         struct tevent_req *req, *subreq = NULL;
4082         struct cli_smb2_writeall_state *state = NULL;
4083         uint32_t to_write;
4084         uint32_t max_size;
4085         bool ok;
4086
4087         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
4088         if (req == NULL) {
4089                 return NULL;
4090         }
4091         state->ev = ev;
4092         state->cli = cli;
4093         /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4094         state->flags = (uint32_t)mode;
4095         state->buf = buf;
4096         state->offset = (uint64_t)offset;
4097         state->size = (uint32_t)size;
4098         state->written = 0;
4099
4100         status = map_fnum_to_smb2_handle(cli,
4101                                         fnum,
4102                                         &state->ph);
4103         if (tevent_req_nterror(req, status)) {
4104                 return tevent_req_post(req, ev);
4105         }
4106
4107         to_write = state->size;
4108         max_size = smb2cli_conn_max_write_size(state->cli->conn);
4109         to_write = MIN(max_size, to_write);
4110         ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4111         if (ok) {
4112                 to_write = MIN(max_size, to_write);
4113         }
4114
4115         subreq = smb2cli_write_send(state,
4116                                 state->ev,
4117                                 state->cli->conn,
4118                                 state->cli->timeout,
4119                                 state->cli->smb2.session,
4120                                 state->cli->smb2.tcon,
4121                                 to_write,
4122                                 state->offset,
4123                                 state->ph->fid_persistent,
4124                                 state->ph->fid_volatile,
4125                                 0, /* remaining_bytes */
4126                                 state->flags, /* flags */
4127                                 state->buf + state->written);
4128
4129         if (tevent_req_nomem(subreq, req)) {
4130                 return tevent_req_post(req, ev);
4131         }
4132         tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4133         return req;
4134 }
4135
4136 static void cli_smb2_writeall_written(struct tevent_req *subreq)
4137 {
4138         struct tevent_req *req = tevent_req_callback_data(
4139                 subreq, struct tevent_req);
4140         struct cli_smb2_writeall_state *state = tevent_req_data(
4141                 req, struct cli_smb2_writeall_state);
4142         NTSTATUS status;
4143         uint32_t written, to_write;
4144         uint32_t max_size;
4145         bool ok;
4146
4147         status = smb2cli_write_recv(subreq, &written);
4148         TALLOC_FREE(subreq);
4149         if (tevent_req_nterror(req, status)) {
4150                 return;
4151         }
4152
4153         state->written += written;
4154
4155         if (state->written > state->size) {
4156                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4157                 return;
4158         }
4159
4160         to_write = state->size - state->written;
4161
4162         if (to_write == 0) {
4163                 tevent_req_done(req);
4164                 return;
4165         }
4166
4167         max_size = smb2cli_conn_max_write_size(state->cli->conn);
4168         to_write = MIN(max_size, to_write);
4169         ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4170         if (ok) {
4171                 to_write = MIN(max_size, to_write);
4172         }
4173
4174         subreq = smb2cli_write_send(state,
4175                                 state->ev,
4176                                 state->cli->conn,
4177                                 state->cli->timeout,
4178                                 state->cli->smb2.session,
4179                                 state->cli->smb2.tcon,
4180                                 to_write,
4181                                 state->offset + state->written,
4182                                 state->ph->fid_persistent,
4183                                 state->ph->fid_volatile,
4184                                 0, /* remaining_bytes */
4185                                 state->flags, /* flags */
4186                                 state->buf + state->written);
4187
4188         if (tevent_req_nomem(subreq, req)) {
4189                 return;
4190         }
4191         tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4192 }
4193
4194 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
4195                                 size_t *pwritten)
4196 {
4197         struct cli_smb2_writeall_state *state = tevent_req_data(
4198                 req, struct cli_smb2_writeall_state);
4199         NTSTATUS status;
4200
4201         if (tevent_req_is_nterror(req, &status)) {
4202                 state->cli->raw_status = status;
4203                 return status;
4204         }
4205         if (pwritten != NULL) {
4206                 *pwritten = (size_t)state->written;
4207         }
4208         state->cli->raw_status = NT_STATUS_OK;
4209         return NT_STATUS_OK;
4210 }
4211
4212 struct cli_smb2_splice_state {
4213         struct tevent_context *ev;
4214         struct cli_state *cli;
4215         struct smb2_hnd *src_ph;
4216         struct smb2_hnd *dst_ph;
4217         int (*splice_cb)(off_t n, void *priv);
4218         void *priv;
4219         off_t written;
4220         off_t size;
4221         off_t src_offset;
4222         off_t dst_offset;
4223         bool resized;
4224         struct req_resume_key_rsp resume_rsp;
4225         struct srv_copychunk_copy cc_copy;
4226 };
4227
4228 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4229                                       struct tevent_req *req);
4230
4231 static void cli_splice_copychunk_done(struct tevent_req *subreq)
4232 {
4233         struct tevent_req *req = tevent_req_callback_data(
4234                 subreq, struct tevent_req);
4235         struct cli_smb2_splice_state *state =
4236                 tevent_req_data(req,
4237                 struct cli_smb2_splice_state);
4238         struct smbXcli_conn *conn = state->cli->conn;
4239         DATA_BLOB out_input_buffer = data_blob_null;
4240         DATA_BLOB out_output_buffer = data_blob_null;
4241         struct srv_copychunk_rsp cc_copy_rsp;
4242         enum ndr_err_code ndr_ret;
4243         NTSTATUS status;
4244
4245         status = smb2cli_ioctl_recv(subreq, state,
4246                                     &out_input_buffer,
4247                                     &out_output_buffer);
4248         TALLOC_FREE(subreq);
4249         if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
4250              state->resized) && tevent_req_nterror(req, status)) {
4251                 return;
4252         }
4253
4254         ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
4255                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
4256         if (ndr_ret != NDR_ERR_SUCCESS) {
4257                 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4258                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4259                 return;
4260         }
4261
4262         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
4263                 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
4264                              cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
4265                 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
4266                      max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
4267                      tevent_req_nterror(req, status)) {
4268                         return;
4269                 }
4270
4271                 state->resized = true;
4272                 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
4273                 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
4274         } else {
4275                 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4276                     (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4277                     (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
4278                         tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4279                         return;
4280                 }
4281                 state->src_offset += cc_copy_rsp.total_bytes_written;
4282                 state->dst_offset += cc_copy_rsp.total_bytes_written;
4283                 state->written += cc_copy_rsp.total_bytes_written;
4284                 if (!state->splice_cb(state->written, state->priv)) {
4285                         tevent_req_nterror(req, NT_STATUS_CANCELLED);
4286                         return;
4287                 }
4288         }
4289
4290         cli_splice_copychunk_send(state, req);
4291 }
4292
4293 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4294                                       struct tevent_req *req)
4295 {
4296         struct tevent_req *subreq;
4297         enum ndr_err_code ndr_ret;
4298         struct smbXcli_conn *conn = state->cli->conn;
4299         struct srv_copychunk_copy *cc_copy = &state->cc_copy;
4300         off_t src_offset = state->src_offset;
4301         off_t dst_offset = state->dst_offset;
4302         uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
4303                                state->size - state->written);
4304         DATA_BLOB in_input_buffer = data_blob_null;
4305         DATA_BLOB in_output_buffer = data_blob_null;
4306
4307         if (state->size - state->written == 0) {
4308                 tevent_req_done(req);
4309                 return;
4310         }
4311
4312         cc_copy->chunk_count = 0;
4313         while (req_len) {
4314                 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
4315                 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
4316                 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
4317                                                                    smb2cli_conn_cc_chunk_len(conn));
4318                 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
4319                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4320                         return;
4321                 }
4322                 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
4323                 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
4324                     (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
4325                         tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4326                         return;
4327                 }
4328                 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4329                 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4330                 cc_copy->chunk_count++;
4331         }
4332
4333         ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
4334                                        (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
4335         if (ndr_ret != NDR_ERR_SUCCESS) {
4336                 DEBUG(0, ("failed to marshall copy chunk req\n"));
4337                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4338                 return;
4339         }
4340
4341         subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
4342                                state->cli->timeout,
4343                                state->cli->smb2.session,
4344                                state->cli->smb2.tcon,
4345                                state->dst_ph->fid_persistent, /* in_fid_persistent */
4346                                state->dst_ph->fid_volatile, /* in_fid_volatile */
4347                                FSCTL_SRV_COPYCHUNK_WRITE,
4348                                0, /* in_max_input_length */
4349                                &in_input_buffer,
4350                                12, /* in_max_output_length */
4351                                &in_output_buffer,
4352                                SMB2_IOCTL_FLAG_IS_FSCTL);
4353         if (tevent_req_nomem(subreq, req)) {
4354                 return;
4355         }
4356         tevent_req_set_callback(subreq,
4357                                 cli_splice_copychunk_done,
4358                                 req);
4359 }
4360
4361 static void cli_splice_key_done(struct tevent_req *subreq)
4362 {
4363         struct tevent_req *req = tevent_req_callback_data(
4364                 subreq, struct tevent_req);
4365         struct cli_smb2_splice_state *state =
4366                 tevent_req_data(req,
4367                 struct cli_smb2_splice_state);
4368         enum ndr_err_code ndr_ret;
4369         NTSTATUS status;
4370
4371         DATA_BLOB out_input_buffer = data_blob_null;
4372         DATA_BLOB out_output_buffer = data_blob_null;
4373
4374         status = smb2cli_ioctl_recv(subreq, state,
4375                                     &out_input_buffer,
4376                                     &out_output_buffer);
4377         TALLOC_FREE(subreq);
4378         if (tevent_req_nterror(req, status)) {
4379                 return;
4380         }
4381
4382         ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
4383                         state, &state->resume_rsp,
4384                         (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
4385         if (ndr_ret != NDR_ERR_SUCCESS) {
4386                 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4387                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4388                 return;
4389         }
4390
4391         memcpy(&state->cc_copy.source_key,
4392                &state->resume_rsp.resume_key,
4393                sizeof state->resume_rsp.resume_key);
4394
4395         cli_splice_copychunk_send(state, req);
4396 }
4397
4398 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
4399                                 struct tevent_context *ev,
4400                                 struct cli_state *cli,
4401                                 uint16_t src_fnum, uint16_t dst_fnum,
4402                                 off_t size, off_t src_offset, off_t dst_offset,
4403                                 int (*splice_cb)(off_t n, void *priv),
4404                                 void *priv)
4405 {
4406         struct tevent_req *req;
4407         struct tevent_req *subreq;
4408         struct cli_smb2_splice_state *state;
4409         NTSTATUS status;
4410         DATA_BLOB in_input_buffer = data_blob_null;
4411         DATA_BLOB in_output_buffer = data_blob_null;
4412
4413         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
4414         if (req == NULL) {
4415                 return NULL;
4416         }
4417         state->cli = cli;
4418         state->ev = ev;
4419         state->splice_cb = splice_cb;
4420         state->priv = priv;
4421         state->size = size;
4422         state->written = 0;
4423         state->src_offset = src_offset;
4424         state->dst_offset = dst_offset;
4425         state->cc_copy.chunks = talloc_array(state,
4426                                              struct srv_copychunk,
4427                                              smb2cli_conn_cc_max_chunks(cli->conn));
4428         if (state->cc_copy.chunks == NULL) {
4429                 return NULL;
4430         }
4431
4432         status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
4433         if (tevent_req_nterror(req, status))
4434                 return tevent_req_post(req, ev);
4435
4436         status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
4437         if (tevent_req_nterror(req, status))
4438                 return tevent_req_post(req, ev);
4439
4440         subreq = smb2cli_ioctl_send(state, ev, cli->conn,
4441                                cli->timeout,
4442                                cli->smb2.session,
4443                                cli->smb2.tcon,
4444                                state->src_ph->fid_persistent, /* in_fid_persistent */
4445                                state->src_ph->fid_volatile, /* in_fid_volatile */
4446                                FSCTL_SRV_REQUEST_RESUME_KEY,
4447                                0, /* in_max_input_length */
4448                                &in_input_buffer,
4449                                32, /* in_max_output_length */
4450                                &in_output_buffer,
4451                                SMB2_IOCTL_FLAG_IS_FSCTL);
4452         if (tevent_req_nomem(subreq, req)) {
4453                 return NULL;
4454         }
4455         tevent_req_set_callback(subreq,
4456                                 cli_splice_key_done,
4457                                 req);
4458
4459         return req;
4460 }
4461
4462 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
4463 {
4464         struct cli_smb2_splice_state *state = tevent_req_data(
4465                 req, struct cli_smb2_splice_state);
4466         NTSTATUS status;
4467
4468         if (tevent_req_is_nterror(req, &status)) {
4469                 state->cli->raw_status = status;
4470                 tevent_req_received(req);
4471                 return status;
4472         }
4473         if (written != NULL) {
4474                 *written = state->written;
4475         }
4476         state->cli->raw_status = NT_STATUS_OK;
4477         tevent_req_received(req);
4478         return NT_STATUS_OK;
4479 }
4480
4481 /***************************************************************
4482  SMB2 enum shadow copy data.
4483 ***************************************************************/
4484
4485 struct cli_smb2_shadow_copy_data_fnum_state {
4486         struct cli_state *cli;
4487         uint16_t fnum;
4488         struct smb2_hnd *ph;
4489         DATA_BLOB out_input_buffer;
4490         DATA_BLOB out_output_buffer;
4491 };
4492
4493 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
4494
4495 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
4496                                         TALLOC_CTX *mem_ctx,
4497                                         struct tevent_context *ev,
4498                                         struct cli_state *cli,
4499                                         uint16_t fnum,
4500                                         bool get_names)
4501 {
4502         struct tevent_req *req, *subreq;
4503         struct cli_smb2_shadow_copy_data_fnum_state *state;
4504         NTSTATUS status;
4505
4506         req = tevent_req_create(mem_ctx, &state,
4507                                 struct cli_smb2_shadow_copy_data_fnum_state);
4508         if (req == NULL) {
4509                 return NULL;
4510         }
4511
4512         state->cli = cli;
4513         state->fnum = fnum;
4514
4515         status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4516         if (tevent_req_nterror(req, status)) {
4517                 return tevent_req_post(req, ev);
4518         }
4519
4520         /*
4521          * TODO. Under SMB2 we should send a zero max_output_length
4522          * ioctl to get the required size, then send another ioctl
4523          * to get the data, but the current SMB1 implementation just
4524          * does one roundtrip with a 64K buffer size. Do the same
4525          * for now. JRA.
4526          */
4527
4528         subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4529                         state->cli->timeout,
4530                         state->cli->smb2.session,
4531                         state->cli->smb2.tcon,
4532                         state->ph->fid_persistent, /* in_fid_persistent */
4533                         state->ph->fid_volatile, /* in_fid_volatile */
4534                         FSCTL_GET_SHADOW_COPY_DATA,
4535                         0, /* in_max_input_length */
4536                         NULL, /* in_input_buffer */
4537                         get_names ?
4538                                 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
4539                         NULL, /* in_output_buffer */
4540                         SMB2_IOCTL_FLAG_IS_FSCTL);
4541
4542         if (tevent_req_nomem(subreq, req)) {
4543                 return tevent_req_post(req, ev);
4544         }
4545         tevent_req_set_callback(subreq,
4546                                 cli_smb2_shadow_copy_data_fnum_done,
4547                                 req);
4548
4549         return req;
4550 }
4551
4552 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4553 {
4554         struct tevent_req *req = tevent_req_callback_data(
4555                 subreq, struct tevent_req);
4556         struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4557                 req, struct cli_smb2_shadow_copy_data_fnum_state);
4558         NTSTATUS status;
4559
4560         status = smb2cli_ioctl_recv(subreq, state,
4561                                 &state->out_input_buffer,
4562                                 &state->out_output_buffer);
4563         tevent_req_simple_finish_ntstatus(subreq, status);
4564 }
4565
4566 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4567                                 TALLOC_CTX *mem_ctx,
4568                                 bool get_names,
4569                                 char ***pnames,
4570                                 int *pnum_names)
4571 {
4572         struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4573                 req, struct cli_smb2_shadow_copy_data_fnum_state);
4574         char **names = NULL;
4575         uint32_t num_names = 0;
4576         uint32_t num_names_returned = 0;
4577         uint32_t dlength = 0;
4578         uint32_t i;
4579         uint8_t *endp = NULL;
4580         NTSTATUS status;
4581
4582         if (tevent_req_is_nterror(req, &status)) {
4583                 return status;
4584         }
4585
4586         if (state->out_output_buffer.length < 16) {
4587                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4588         }
4589
4590         num_names = IVAL(state->out_output_buffer.data, 0);
4591         num_names_returned = IVAL(state->out_output_buffer.data, 4);
4592         dlength = IVAL(state->out_output_buffer.data, 8);
4593
4594         if (num_names > 0x7FFFFFFF) {
4595                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4596         }
4597
4598         if (get_names == false) {
4599                 *pnum_names = (int)num_names;
4600                 return NT_STATUS_OK;
4601         }
4602         if (num_names != num_names_returned) {
4603                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4604         }
4605         if (dlength + 12 < 12) {
4606                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4607         }
4608         /*
4609          * NB. The below is an allowable return if there are
4610          * more snapshots than the buffer size we told the
4611          * server we can receive. We currently don't support
4612          * this.
4613          */
4614         if (dlength + 12 > state->out_output_buffer.length) {
4615                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4616         }
4617         if (state->out_output_buffer.length +
4618                         (2 * sizeof(SHADOW_COPY_LABEL)) <
4619                                 state->out_output_buffer.length) {
4620                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4621         }
4622
4623         names = talloc_array(mem_ctx, char *, num_names_returned);
4624         if (names == NULL) {
4625                 return NT_STATUS_NO_MEMORY;
4626         }
4627
4628         endp = state->out_output_buffer.data +
4629                         state->out_output_buffer.length;
4630
4631         for (i=0; i<num_names_returned; i++) {
4632                 bool ret;
4633                 uint8_t *src;
4634                 size_t converted_size;
4635
4636                 src = state->out_output_buffer.data + 12 +
4637                         (i * 2 * sizeof(SHADOW_COPY_LABEL));
4638
4639                 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4640                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
4641                 }
4642                 ret = convert_string_talloc(
4643                         names, CH_UTF16LE, CH_UNIX,
4644                         src, 2 * sizeof(SHADOW_COPY_LABEL),
4645                         &names[i], &converted_size);
4646                 if (!ret) {
4647                         TALLOC_FREE(names);
4648                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
4649                 }
4650         }
4651         *pnum_names = num_names;
4652         *pnames = names;
4653         return NT_STATUS_OK;
4654 }
4655
4656 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4657                                 struct cli_state *cli,
4658                                 uint16_t fnum,
4659                                 bool get_names,
4660                                 char ***pnames,
4661                                 int *pnum_names)
4662 {
4663         TALLOC_CTX *frame = talloc_stackframe();
4664         struct tevent_context *ev;
4665         struct tevent_req *req;
4666         NTSTATUS status = NT_STATUS_NO_MEMORY;
4667
4668         if (smbXcli_conn_has_async_calls(cli->conn)) {
4669                 /*
4670                  * Can't use sync call while an async call is in flight
4671                  */
4672                 status = NT_STATUS_INVALID_PARAMETER;
4673                 goto fail;
4674         }
4675         ev = samba_tevent_context_init(frame);
4676         if (ev == NULL) {
4677                 goto fail;
4678         }
4679         req = cli_smb2_shadow_copy_data_fnum_send(frame,
4680                                         ev,
4681                                         cli,
4682                                         fnum,
4683                                         get_names);
4684         if (req == NULL) {
4685                 goto fail;
4686         }
4687         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4688                 goto fail;
4689         }
4690         status = cli_smb2_shadow_copy_data_fnum_recv(req,
4691                                                 mem_ctx,
4692                                                 get_names,
4693                                                 pnames,
4694                                                 pnum_names);
4695  fail:
4696         cli->raw_status = status;
4697
4698         TALLOC_FREE(frame);
4699         return status;
4700 }
4701
4702 /***************************************************************
4703  Wrapper that allows SMB2 to truncate a file.
4704  Synchronous only.
4705 ***************************************************************/
4706
4707 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4708                         uint16_t fnum,
4709                         uint64_t newsize)
4710 {
4711         NTSTATUS status;
4712         uint8_t buf[8] = {0};
4713         DATA_BLOB inbuf = { .data = buf, .length = sizeof(buf) };
4714         TALLOC_CTX *frame = talloc_stackframe();
4715
4716         if (smbXcli_conn_has_async_calls(cli->conn)) {
4717                 /*
4718                  * Can't use sync call while an async call is in flight
4719                  */
4720                 status = NT_STATUS_INVALID_PARAMETER;
4721                 goto fail;
4722         }
4723
4724         SBVAL(buf, 0, newsize);
4725
4726         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4727            level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4728
4729         status = cli_smb2_set_info_fnum(
4730                 cli,
4731                 fnum,
4732                 1, /* in_info_type */
4733                 SMB_FILE_END_OF_FILE_INFORMATION-1000, /* in_file_info_class */
4734                 &inbuf, /* in_input_buffer */
4735                 0);
4736
4737   fail:
4738
4739         cli->raw_status = status;
4740
4741         TALLOC_FREE(frame);
4742         return status;
4743 }
4744
4745 struct cli_smb2_notify_state {
4746         struct tevent_req *subreq;
4747         struct notify_change *changes;
4748         size_t num_changes;
4749 };
4750
4751 static void cli_smb2_notify_done(struct tevent_req *subreq);
4752 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4753
4754 struct tevent_req *cli_smb2_notify_send(
4755         TALLOC_CTX *mem_ctx,
4756         struct tevent_context *ev,
4757         struct cli_state *cli,
4758         uint16_t fnum,
4759         uint32_t buffer_size,
4760         uint32_t completion_filter,
4761         bool recursive)
4762 {
4763         struct tevent_req *req = NULL;
4764         struct cli_smb2_notify_state *state = NULL;
4765         struct smb2_hnd *ph = NULL;
4766         NTSTATUS status;
4767
4768         req = tevent_req_create(mem_ctx, &state,
4769                                 struct cli_smb2_notify_state);
4770         if (req == NULL) {
4771                 return NULL;
4772         }
4773
4774         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4775         if (tevent_req_nterror(req, status)) {
4776                 return tevent_req_post(req, ev);
4777         }
4778
4779         state->subreq = smb2cli_notify_send(
4780                 state,
4781                 ev,
4782                 cli->conn,
4783                 cli->timeout,
4784                 cli->smb2.session,
4785                 cli->smb2.tcon,
4786                 buffer_size,
4787                 ph->fid_persistent,
4788                 ph->fid_volatile,
4789                 completion_filter,
4790                 recursive);
4791         if (tevent_req_nomem(state->subreq, req)) {
4792                 return tevent_req_post(req, ev);
4793         }
4794         tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4795         tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4796         return req;
4797 }
4798
4799 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4800 {
4801         struct cli_smb2_notify_state *state = tevent_req_data(
4802                 req, struct cli_smb2_notify_state);
4803         bool ok;
4804
4805         ok = tevent_req_cancel(state->subreq);
4806         return ok;
4807 }
4808
4809 static void cli_smb2_notify_done(struct tevent_req *subreq)
4810 {
4811         struct tevent_req *req = tevent_req_callback_data(
4812                 subreq, struct tevent_req);
4813         struct cli_smb2_notify_state *state = tevent_req_data(
4814                 req, struct cli_smb2_notify_state);
4815         uint8_t *base;
4816         uint32_t len;
4817         uint32_t ofs;
4818         NTSTATUS status;
4819
4820         status = smb2cli_notify_recv(subreq, state, &base, &len);
4821         TALLOC_FREE(subreq);
4822
4823         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4824                 tevent_req_done(req);
4825                 return;
4826         }
4827         if (tevent_req_nterror(req, status)) {
4828                 return;
4829         }
4830
4831         ofs = 0;
4832
4833         while (len - ofs >= 12) {
4834                 struct notify_change *tmp;
4835                 struct notify_change *c;
4836                 uint32_t next_ofs = IVAL(base, ofs);
4837                 uint32_t file_name_length = IVAL(base, ofs+8);
4838                 size_t namelen;
4839                 bool ok;
4840
4841                 tmp = talloc_realloc(
4842                         state,
4843                         state->changes,
4844                         struct notify_change,
4845                         state->num_changes + 1);
4846                 if (tevent_req_nomem(tmp, req)) {
4847                         return;
4848                 }
4849                 state->changes = tmp;
4850                 c = &state->changes[state->num_changes];
4851                 state->num_changes += 1;
4852
4853                 if (smb_buffer_oob(len, ofs, next_ofs) ||
4854                     smb_buffer_oob(len, ofs+12, file_name_length)) {
4855                         tevent_req_nterror(
4856                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4857                         return;
4858                 }
4859
4860                 c->action = IVAL(base, ofs+4);
4861
4862                 ok = convert_string_talloc(
4863                         state->changes,
4864                         CH_UTF16LE,
4865                         CH_UNIX,
4866                         base + ofs + 12,
4867                         file_name_length,
4868                         &c->name,
4869                         &namelen);
4870                 if (!ok) {
4871                         tevent_req_nterror(
4872                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4873                         return;
4874                 }
4875
4876                 if (next_ofs == 0) {
4877                         break;
4878                 }
4879                 ofs += next_ofs;
4880         }
4881
4882         tevent_req_done(req);
4883 }
4884
4885 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
4886                               TALLOC_CTX *mem_ctx,
4887                               struct notify_change **pchanges,
4888                               uint32_t *pnum_changes)
4889 {
4890         struct cli_smb2_notify_state *state = tevent_req_data(
4891                 req, struct cli_smb2_notify_state);
4892         NTSTATUS status;
4893
4894         if (tevent_req_is_nterror(req, &status)) {
4895                 return status;
4896         }
4897         *pchanges = talloc_move(mem_ctx, &state->changes);
4898         *pnum_changes = state->num_changes;
4899         return NT_STATUS_OK;
4900 }
4901
4902 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
4903                          uint32_t buffer_size, uint32_t completion_filter,
4904                          bool recursive, TALLOC_CTX *mem_ctx,
4905                          struct notify_change **pchanges,
4906                          uint32_t *pnum_changes)
4907 {
4908         TALLOC_CTX *frame = talloc_stackframe();
4909         struct tevent_context *ev;
4910         struct tevent_req *req;
4911         NTSTATUS status = NT_STATUS_NO_MEMORY;
4912
4913         if (smbXcli_conn_has_async_calls(cli->conn)) {
4914                 /*
4915                  * Can't use sync call while an async call is in flight
4916                  */
4917                 status = NT_STATUS_INVALID_PARAMETER;
4918                 goto fail;
4919         }
4920         ev = samba_tevent_context_init(frame);
4921         if (ev == NULL) {
4922                 goto fail;
4923         }
4924         req = cli_smb2_notify_send(
4925                 frame,
4926                 ev,
4927                 cli,
4928                 fnum,
4929                 buffer_size,
4930                 completion_filter,
4931                 recursive);
4932         if (req == NULL) {
4933                 goto fail;
4934         }
4935         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4936                 goto fail;
4937         }
4938         status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
4939 fail:
4940         TALLOC_FREE(frame);
4941         return status;
4942 }
4943
4944 struct cli_smb2_fsctl_state {
4945         DATA_BLOB out;
4946 };
4947
4948 static void cli_smb2_fsctl_done(struct tevent_req *subreq);
4949
4950 struct tevent_req *cli_smb2_fsctl_send(
4951         TALLOC_CTX *mem_ctx,
4952         struct tevent_context *ev,
4953         struct cli_state *cli,
4954         uint16_t fnum,
4955         uint32_t ctl_code,
4956         const DATA_BLOB *in,
4957         uint32_t max_out)
4958 {
4959         struct tevent_req *req = NULL, *subreq = NULL;
4960         struct cli_smb2_fsctl_state *state = NULL;
4961         struct smb2_hnd *ph = NULL;
4962         NTSTATUS status;
4963
4964         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_fsctl_state);
4965         if (req == NULL) {
4966                 return NULL;
4967         }
4968
4969         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4970         if (tevent_req_nterror(req, status)) {
4971                 return tevent_req_post(req, ev);
4972         }
4973
4974         subreq = smb2cli_ioctl_send(
4975                 state,
4976                 ev,
4977                 cli->conn,
4978                 cli->timeout,
4979                 cli->smb2.session,
4980                 cli->smb2.tcon,
4981                 ph->fid_persistent,
4982                 ph->fid_volatile,
4983                 ctl_code,
4984                 0, /* in_max_input_length */
4985                 in,
4986                 max_out,
4987                 NULL,
4988                 SMB2_IOCTL_FLAG_IS_FSCTL);
4989
4990         if (tevent_req_nomem(subreq, req)) {
4991                 return tevent_req_post(req, ev);
4992         }
4993         tevent_req_set_callback(subreq, cli_smb2_fsctl_done, req);
4994         return req;
4995 }
4996
4997 static void cli_smb2_fsctl_done(struct tevent_req *subreq)
4998 {
4999         struct tevent_req *req = tevent_req_callback_data(
5000                 subreq, struct tevent_req);
5001         struct cli_smb2_fsctl_state *state = tevent_req_data(
5002                 req, struct cli_smb2_fsctl_state);
5003         NTSTATUS status;
5004
5005         status = smb2cli_ioctl_recv(subreq, state, NULL, &state->out);
5006         tevent_req_simple_finish_ntstatus(subreq, status);
5007 }
5008
5009 NTSTATUS cli_smb2_fsctl_recv(
5010         struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *out)
5011 {
5012         struct cli_smb2_fsctl_state *state = tevent_req_data(
5013                 req, struct cli_smb2_fsctl_state);
5014         NTSTATUS status = NT_STATUS_OK;
5015
5016         if (tevent_req_is_nterror(req, &status)) {
5017                 tevent_req_received(req);
5018                 return status;
5019         }
5020
5021         if (state->out.length == 0) {
5022                 *out = (DATA_BLOB) { .data = NULL, };
5023         } else {
5024                 /*
5025                  * Can't use talloc_move() here, the outblobs from
5026                  * smb2cli_ioctl_recv() are not standalone talloc
5027                  * objects but just peek into the larger buffers
5028                  * received, hanging off "state".
5029                  */
5030                 *out = data_blob_talloc(
5031                         mem_ctx, state->out.data, state->out.length);
5032                 if (out->data == NULL) {
5033                         status = NT_STATUS_NO_MEMORY;
5034                 }
5035         }
5036
5037         tevent_req_received(req);
5038         return NT_STATUS_OK;
5039 }