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