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