libsmb: Pass NTTIME to interpret_long_date()
[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(BVAL(dir_data, 8));
1234         finfo->atime_ts = interpret_long_date(BVAL(dir_data, 16));
1235         finfo->mtime_ts = interpret_long_date(BVAL(dir_data, 24));
1236         finfo->ctime_ts = interpret_long_date(BVAL(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(BVAL(dir_data, 8));
1313         finfo->atime_ts = interpret_long_date(BVAL(dir_data, 16));
1314         finfo->mtime_ts = interpret_long_date(BVAL(dir_data, 24));
1315         finfo->ctime_ts = interpret_long_date(BVAL(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 (tevent_req_nterror(req, 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 set SMB_FILE_BASIC_INFORMATION on
2394  a pathname.
2395  Synchronous only.
2396 ***************************************************************/
2397
2398 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
2399                         const char *name,
2400                         uint8_t in_info_type,
2401                         uint8_t in_file_info_class,
2402                         const DATA_BLOB *p_in_data)
2403 {
2404         NTSTATUS status;
2405         uint16_t fnum = 0xffff;
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_WRITE_ATTRIBUTES,
2419                                 &fnum);
2420
2421         if (!NT_STATUS_IS_OK(status)) {
2422                 goto fail;
2423         }
2424
2425         status = cli_smb2_set_info_fnum(
2426                 cli,
2427                 fnum,
2428                 in_info_type,
2429                 in_file_info_class,
2430                 p_in_data,         /* in_input_buffer */
2431                 0);                /* in_additional_info */
2432   fail:
2433
2434         if (fnum != 0xffff) {
2435                 cli_smb2_close_fnum(cli, fnum);
2436         }
2437
2438         cli->raw_status = status;
2439
2440         TALLOC_FREE(frame);
2441         return status;
2442 }
2443
2444
2445 /***************************************************************
2446  Wrapper that allows SMB2 to set pathname attributes.
2447  Synchronous only.
2448 ***************************************************************/
2449
2450 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
2451                         const char *name,
2452                         uint32_t attr,
2453                         time_t mtime)
2454 {
2455         uint8_t inbuf_store[40];
2456         DATA_BLOB inbuf = data_blob_null;
2457
2458         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2459            level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2460
2461         inbuf.data = inbuf_store;
2462         inbuf.length = sizeof(inbuf_store);
2463         data_blob_clear(&inbuf);
2464
2465         /*
2466          * SMB1 uses attr == 0 to clear all attributes
2467          * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2468          * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2469          * request attribute change.
2470          *
2471          * SMB2 uses exactly the reverse. Unfortunately as the
2472          * cli_setatr() ABI is exposed inside libsmbclient,
2473          * we must make the SMB2 cli_smb2_setatr() call
2474          * export the same ABI as the SMB1 cli_setatr()
2475          * which calls it. This means reversing the sense
2476          * of the requested attr argument if it's zero
2477          * or FILE_ATTRIBUTE_NORMAL.
2478          *
2479          * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2480          */
2481
2482         if (attr == 0) {
2483                 attr = FILE_ATTRIBUTE_NORMAL;
2484         } else if (attr == FILE_ATTRIBUTE_NORMAL) {
2485                 attr = 0;
2486         }
2487
2488         SIVAL(inbuf.data, 32, attr);
2489         if (mtime != 0) {
2490                 put_long_date((char *)inbuf.data + 16,mtime);
2491         }
2492         /* Set all the other times to -1. */
2493         SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2494         SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
2495         SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
2496
2497         return cli_smb2_setpathinfo(cli,
2498                                 name,
2499                                 1, /* in_info_type */
2500                                 /* in_file_info_class */
2501                                 SMB_FILE_BASIC_INFORMATION - 1000,
2502                                 &inbuf);
2503 }
2504
2505
2506 /***************************************************************
2507  Wrapper that allows SMB2 to set file handle times.
2508  Synchronous only.
2509 ***************************************************************/
2510
2511 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
2512                         uint16_t fnum,
2513                         time_t change_time,
2514                         time_t access_time,
2515                         time_t write_time)
2516 {
2517         uint8_t inbuf_store[40];
2518         DATA_BLOB inbuf = data_blob_null;
2519         NTSTATUS status;
2520
2521         if (smbXcli_conn_has_async_calls(cli->conn)) {
2522                 /*
2523                  * Can't use sync call while an async call is in flight
2524                  */
2525                 return NT_STATUS_INVALID_PARAMETER;
2526         }
2527
2528         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2529            level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2530
2531         inbuf.data = inbuf_store;
2532         inbuf.length = sizeof(inbuf_store);
2533         data_blob_clear(&inbuf);
2534
2535         SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2536         if (change_time != 0) {
2537                 put_long_date((char *)inbuf.data + 24, change_time);
2538         }
2539         if (access_time != 0) {
2540                 put_long_date((char *)inbuf.data + 8, access_time);
2541         }
2542         if (write_time != 0) {
2543                 put_long_date((char *)inbuf.data + 16, write_time);
2544         }
2545
2546         status = cli_smb2_set_info_fnum(cli,
2547                                         fnum,
2548                                         1, /* in_info_type */
2549                                         SMB_FILE_BASIC_INFORMATION -
2550                                                 1000, /* in_file_info_class */
2551                                         &inbuf,       /* in_input_buffer */
2552                                         0);           /* in_additional_info */
2553         cli->raw_status = status;
2554         return status;
2555 }
2556
2557 /***************************************************************
2558  Wrapper that allows SMB2 to query disk attributes (size).
2559  Synchronous only.
2560 ***************************************************************/
2561
2562 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2563                           uint64_t *bsize, uint64_t *total, uint64_t *avail)
2564 {
2565         NTSTATUS status;
2566         uint16_t fnum = 0xffff;
2567         DATA_BLOB outbuf = data_blob_null;
2568         uint32_t sectors_per_unit = 0;
2569         uint32_t bytes_per_sector = 0;
2570         uint64_t total_size = 0;
2571         uint64_t size_free = 0;
2572         TALLOC_CTX *frame = talloc_stackframe();
2573
2574         if (smbXcli_conn_has_async_calls(cli->conn)) {
2575                 /*
2576                  * Can't use sync call while an async call is in flight
2577                  */
2578                 status = NT_STATUS_INVALID_PARAMETER;
2579                 goto fail;
2580         }
2581
2582         /* First open the top level directory. */
2583         status = cli_smb2_create_fnum(cli,
2584                         path,
2585                         (struct cli_smb2_create_flags){0},
2586                         SMB2_IMPERSONATION_IMPERSONATION,
2587                         FILE_READ_ATTRIBUTES,   /* desired_access */
2588                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2589                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2590                         FILE_OPEN,              /* create_disposition */
2591                         FILE_DIRECTORY_FILE,    /* create_options */
2592                         NULL,
2593                         &fnum,
2594                         NULL,
2595                         NULL,
2596                         NULL);
2597
2598         if (!NT_STATUS_IS_OK(status)) {
2599                 goto fail;
2600         }
2601
2602         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2603            level 3 (SMB_FS_SIZE_INFORMATION). */
2604
2605         status = cli_smb2_query_info_fnum(
2606                 cli,
2607                 fnum,
2608                 2, /* in_info_type */
2609                 3, /* in_file_info_class */
2610                 0xFFFF, /* in_max_output_length */
2611                 NULL, /* in_input_buffer */
2612                 0, /* in_additional_info */
2613                 0, /* in_flags */
2614                 frame,
2615                 &outbuf);
2616         if (!NT_STATUS_IS_OK(status)) {
2617                 goto fail;
2618         }
2619
2620         /* Parse the reply. */
2621         if (outbuf.length != 24) {
2622                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2623                 goto fail;
2624         }
2625
2626         total_size = BVAL(outbuf.data, 0);
2627         size_free = BVAL(outbuf.data, 8);
2628         sectors_per_unit = IVAL(outbuf.data, 16);
2629         bytes_per_sector = IVAL(outbuf.data, 20);
2630
2631         if (bsize) {
2632                 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2633         }
2634         if (total) {
2635                 *total = total_size;
2636         }
2637         if (avail) {
2638                 *avail = size_free;
2639         }
2640
2641         status = NT_STATUS_OK;
2642
2643   fail:
2644
2645         if (fnum != 0xffff) {
2646                 cli_smb2_close_fnum(cli, fnum);
2647         }
2648
2649         cli->raw_status = status;
2650
2651         TALLOC_FREE(frame);
2652         return status;
2653 }
2654
2655 /***************************************************************
2656  Wrapper that allows SMB2 to query file system sizes.
2657  Synchronous only.
2658 ***************************************************************/
2659
2660 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2661                                 uint64_t *total_allocation_units,
2662                                 uint64_t *caller_allocation_units,
2663                                 uint64_t *actual_allocation_units,
2664                                 uint64_t *sectors_per_allocation_unit,
2665                                 uint64_t *bytes_per_sector)
2666 {
2667         NTSTATUS status;
2668         uint16_t fnum = 0xffff;
2669         DATA_BLOB outbuf = data_blob_null;
2670         TALLOC_CTX *frame = talloc_stackframe();
2671
2672         if (smbXcli_conn_has_async_calls(cli->conn)) {
2673                 /*
2674                  * Can't use sync call while an async call is in flight
2675                  */
2676                 status = NT_STATUS_INVALID_PARAMETER;
2677                 goto fail;
2678         }
2679
2680         /* First open the top level directory. */
2681         status =
2682             cli_smb2_create_fnum(cli, "",
2683                                  (struct cli_smb2_create_flags){0},
2684                                  SMB2_IMPERSONATION_IMPERSONATION,
2685                                  FILE_READ_ATTRIBUTES,     /* desired_access */
2686                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2687                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
2688                                      FILE_SHARE_DELETE, /* share_access */
2689                                  FILE_OPEN,             /* create_disposition */
2690                                  FILE_DIRECTORY_FILE,   /* create_options */
2691                                  NULL,
2692                                  &fnum,
2693                                  NULL,
2694                                  NULL,
2695                                  NULL);
2696
2697         if (!NT_STATUS_IS_OK(status)) {
2698                 goto fail;
2699         }
2700
2701         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2702            level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2703
2704         status = cli_smb2_query_info_fnum(
2705                 cli,
2706                 fnum,
2707                 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2708                 SMB_FS_FULL_SIZE_INFORMATION - 1000, /* in_file_info_class */
2709                 0xFFFF, /* in_max_output_length */
2710                 NULL, /* in_input_buffer */
2711                 0, /* in_additional_info */
2712                 0, /* in_flags */
2713                 frame,
2714                 &outbuf);
2715         if (!NT_STATUS_IS_OK(status)) {
2716                 goto fail;
2717         }
2718
2719         if (outbuf.length < 32) {
2720                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2721                 goto fail;
2722         }
2723
2724         *total_allocation_units = BIG_UINT(outbuf.data, 0);
2725         *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2726         *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2727         *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2728         *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2729
2730 fail:
2731
2732         if (fnum != 0xffff) {
2733                 cli_smb2_close_fnum(cli, fnum);
2734         }
2735
2736         cli->raw_status = status;
2737
2738         TALLOC_FREE(frame);
2739         return status;
2740 }
2741
2742 /***************************************************************
2743  Wrapper that allows SMB2 to query file system attributes.
2744  Synchronous only.
2745 ***************************************************************/
2746
2747 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2748 {
2749         NTSTATUS status;
2750         uint16_t fnum = 0xffff;
2751         DATA_BLOB outbuf = data_blob_null;
2752         TALLOC_CTX *frame = talloc_stackframe();
2753
2754         if (smbXcli_conn_has_async_calls(cli->conn)) {
2755                 /*
2756                  * Can't use sync call while an async call is in flight
2757                  */
2758                 status = NT_STATUS_INVALID_PARAMETER;
2759                 goto fail;
2760         }
2761
2762         /* First open the top level directory. */
2763         status =
2764             cli_smb2_create_fnum(cli, "",
2765                                  (struct cli_smb2_create_flags){0},
2766                                  SMB2_IMPERSONATION_IMPERSONATION,
2767                                  FILE_READ_ATTRIBUTES,     /* desired_access */
2768                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2769                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
2770                                      FILE_SHARE_DELETE, /* share_access */
2771                                  FILE_OPEN,             /* create_disposition */
2772                                  FILE_DIRECTORY_FILE,   /* create_options */
2773                                  NULL,
2774                                  &fnum,
2775                                  NULL,
2776                                  NULL,
2777                                  NULL);
2778
2779         if (!NT_STATUS_IS_OK(status)) {
2780                 goto fail;
2781         }
2782
2783         status = cli_smb2_query_info_fnum(
2784                 cli,
2785                 fnum,
2786                 2, /* in_info_type */
2787                 5,                     /* in_file_info_class */
2788                 0xFFFF, /* in_max_output_length */
2789                 NULL,   /* in_input_buffer */
2790                 0,      /* in_additional_info */
2791                 0,      /* in_flags */
2792                 frame,
2793                 &outbuf);
2794         if (!NT_STATUS_IS_OK(status)) {
2795                 goto fail;
2796         }
2797
2798         if (outbuf.length < 12) {
2799                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2800                 goto fail;
2801         }
2802
2803         *fs_attr = IVAL(outbuf.data, 0);
2804
2805 fail:
2806
2807         if (fnum != 0xffff) {
2808                 cli_smb2_close_fnum(cli, fnum);
2809         }
2810
2811         cli->raw_status = status;
2812
2813         TALLOC_FREE(frame);
2814         return status;
2815 }
2816
2817 /***************************************************************
2818  Wrapper that allows SMB2 to query file system volume info.
2819  Synchronous only.
2820 ***************************************************************/
2821
2822 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2823                                 TALLOC_CTX *mem_ctx,
2824                                 char **_volume_name,
2825                                 uint32_t *pserial_number,
2826                                 time_t *pdate)
2827 {
2828         NTSTATUS status;
2829         uint16_t fnum = 0xffff;
2830         DATA_BLOB outbuf = data_blob_null;
2831         uint32_t nlen;
2832         char *volume_name = NULL;
2833         TALLOC_CTX *frame = talloc_stackframe();
2834
2835         if (smbXcli_conn_has_async_calls(cli->conn)) {
2836                 /*
2837                  * Can't use sync call while an async call is in flight
2838                  */
2839                 status = NT_STATUS_INVALID_PARAMETER;
2840                 goto fail;
2841         }
2842
2843         /* First open the top level directory. */
2844         status =
2845             cli_smb2_create_fnum(cli, "",
2846                                  (struct cli_smb2_create_flags){0},
2847                                  SMB2_IMPERSONATION_IMPERSONATION,
2848                                  FILE_READ_ATTRIBUTES,     /* desired_access */
2849                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2850                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
2851                                      FILE_SHARE_DELETE, /* share_access */
2852                                  FILE_OPEN,             /* create_disposition */
2853                                  FILE_DIRECTORY_FILE,   /* create_options */
2854                                  NULL,
2855                                  &fnum,
2856                                  NULL,
2857                                  NULL,
2858                                  NULL);
2859
2860         if (!NT_STATUS_IS_OK(status)) {
2861                 goto fail;
2862         }
2863
2864         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2865            level 1 (SMB_FS_VOLUME_INFORMATION). */
2866
2867         status = cli_smb2_query_info_fnum(
2868                 cli,
2869                 fnum,
2870                 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2871                 /* in_file_info_class */
2872                 SMB_FS_VOLUME_INFORMATION - 1000,
2873                 0xFFFF, /* in_max_output_length */
2874                 NULL, /* in_input_buffer */
2875                 0, /* in_additional_info */
2876                 0, /* in_flags */
2877                 frame,
2878                 &outbuf);
2879         if (!NT_STATUS_IS_OK(status)) {
2880                 goto fail;
2881         }
2882
2883         if (outbuf.length < 24) {
2884                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2885                 goto fail;
2886         }
2887
2888         if (pdate) {
2889                 struct timespec ts;
2890                 ts = interpret_long_date(BVAL(outbuf.data, 0));
2891                 *pdate = ts.tv_sec;
2892         }
2893         if (pserial_number) {
2894                 *pserial_number = IVAL(outbuf.data,8);
2895         }
2896         nlen = IVAL(outbuf.data,12);
2897         if (nlen + 18 < 18) {
2898                 /* Integer wrap. */
2899                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2900                 goto fail;
2901         }
2902         /*
2903          * The next check is safe as we know outbuf.length >= 24
2904          * from above.
2905          */
2906         if (nlen > (outbuf.length - 18)) {
2907                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2908                 goto fail;
2909         }
2910
2911         pull_string_talloc(mem_ctx,
2912                            (const char *)outbuf.data,
2913                            0,
2914                            &volume_name,
2915                            outbuf.data + 18,
2916                            nlen,
2917                            STR_UNICODE);
2918         if (volume_name == NULL) {
2919                 status = map_nt_error_from_unix(errno);
2920                 goto fail;
2921         }
2922
2923         *_volume_name = volume_name;
2924
2925 fail:
2926
2927         if (fnum != 0xffff) {
2928                 cli_smb2_close_fnum(cli, fnum);
2929         }
2930
2931         cli->raw_status = status;
2932
2933         TALLOC_FREE(frame);
2934         return status;
2935 }
2936
2937 struct cli_smb2_mxac_state {
2938         struct tevent_context *ev;
2939         struct cli_state *cli;
2940         const char *fname;
2941         struct smb2_create_blobs in_cblobs;
2942         uint16_t fnum;
2943         NTSTATUS status;
2944         uint32_t mxac;
2945 };
2946
2947 static void cli_smb2_mxac_opened(struct tevent_req *subreq);
2948 static void cli_smb2_mxac_closed(struct tevent_req *subreq);
2949
2950 struct tevent_req *cli_smb2_query_mxac_send(TALLOC_CTX *mem_ctx,
2951                                             struct tevent_context *ev,
2952                                             struct cli_state *cli,
2953                                             const char *fname)
2954 {
2955         struct tevent_req *req = NULL, *subreq = NULL;
2956         struct cli_smb2_mxac_state *state = NULL;
2957         NTSTATUS status;
2958
2959         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_mxac_state);
2960         if (req == NULL) {
2961                 return NULL;
2962         }
2963         *state = (struct cli_smb2_mxac_state) {
2964                 .ev = ev,
2965                 .cli = cli,
2966                 .fname = fname,
2967         };
2968
2969         status = smb2_create_blob_add(state,
2970                                       &state->in_cblobs,
2971                                       SMB2_CREATE_TAG_MXAC,
2972                                       data_blob(NULL, 0));
2973         if (tevent_req_nterror(req, status)) {
2974                 return tevent_req_post(req, ev);
2975         }
2976
2977         subreq = cli_smb2_create_fnum_send(
2978                 state,
2979                 state->ev,
2980                 state->cli,
2981                 state->fname,
2982                 (struct cli_smb2_create_flags){0},
2983                 SMB2_IMPERSONATION_IMPERSONATION,
2984                 FILE_READ_ATTRIBUTES,
2985                 0,                      /* file attributes */
2986                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
2987                 FILE_OPEN,
2988                 0,                      /* create_options */
2989                 &state->in_cblobs);
2990         if (tevent_req_nomem(subreq, req)) {
2991                 return tevent_req_post(req, ev);
2992         }
2993         tevent_req_set_callback(subreq, cli_smb2_mxac_opened, req);
2994         return req;
2995 }
2996
2997 static void cli_smb2_mxac_opened(struct tevent_req *subreq)
2998 {
2999         struct tevent_req *req = tevent_req_callback_data(
3000                 subreq, struct tevent_req);
3001         struct cli_smb2_mxac_state *state = tevent_req_data(
3002                 req, struct cli_smb2_mxac_state);
3003         struct smb2_create_blobs out_cblobs = {0};
3004         struct smb2_create_blob *mxac_blob = NULL;
3005         NTSTATUS status;
3006
3007         status = cli_smb2_create_fnum_recv(
3008                 subreq, &state->fnum, NULL, state, &out_cblobs, NULL);
3009         TALLOC_FREE(subreq);
3010
3011         if (tevent_req_nterror(req, status)) {
3012                 return;
3013         }
3014
3015         mxac_blob = smb2_create_blob_find(&out_cblobs, SMB2_CREATE_TAG_MXAC);
3016         if (mxac_blob == NULL) {
3017                 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3018                 goto close;
3019         }
3020         if (mxac_blob->data.length != 8) {
3021                 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3022                 goto close;
3023         }
3024
3025         state->status = NT_STATUS(IVAL(mxac_blob->data.data, 0));
3026         state->mxac = IVAL(mxac_blob->data.data, 4);
3027
3028 close:
3029         subreq = cli_smb2_close_fnum_send(
3030                 state, state->ev, state->cli, state->fnum);
3031         if (tevent_req_nomem(subreq, req)) {
3032                 return;
3033         }
3034         tevent_req_set_callback(subreq, cli_smb2_mxac_closed, req);
3035
3036         return;
3037 }
3038
3039 static void cli_smb2_mxac_closed(struct tevent_req *subreq)
3040 {
3041         struct tevent_req *req = tevent_req_callback_data(
3042                 subreq, struct tevent_req);
3043         NTSTATUS status;
3044
3045         status = cli_smb2_close_fnum_recv(subreq);
3046         if (tevent_req_nterror(req, status)) {
3047                 return;
3048         }
3049
3050         tevent_req_done(req);
3051 }
3052
3053 NTSTATUS cli_smb2_query_mxac_recv(struct tevent_req *req, uint32_t *mxac)
3054 {
3055         struct cli_smb2_mxac_state *state = tevent_req_data(
3056                 req, struct cli_smb2_mxac_state);
3057         NTSTATUS status;
3058
3059         if (tevent_req_is_nterror(req, &status)) {
3060                 return status;
3061         }
3062
3063         if (!NT_STATUS_IS_OK(state->status)) {
3064                 return state->status;
3065         }
3066
3067         *mxac = state->mxac;
3068         return NT_STATUS_OK;
3069 }
3070
3071 NTSTATUS cli_smb2_query_mxac(struct cli_state *cli,
3072                              const char *fname,
3073                              uint32_t *_mxac)
3074 {
3075         TALLOC_CTX *frame = talloc_stackframe();
3076         struct tevent_context *ev = NULL;
3077         struct tevent_req *req = NULL;
3078         NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
3079         bool ok;
3080
3081         if (smbXcli_conn_has_async_calls(cli->conn)) {
3082                 /*
3083                  * Can't use sync call while an async call is in flight
3084                  */
3085                 status = NT_STATUS_INVALID_PARAMETER;
3086                 goto fail;
3087         }
3088
3089         ev = samba_tevent_context_init(frame);
3090         if (ev == NULL) {
3091                 goto fail;
3092         }
3093         req = cli_smb2_query_mxac_send(frame, ev, cli, fname);
3094         if (req == NULL) {
3095                 goto fail;
3096         }
3097         ok = tevent_req_poll_ntstatus(req, ev, &status);
3098         if (!ok) {
3099                 goto fail;
3100         }
3101         status = cli_smb2_query_mxac_recv(req, _mxac);
3102
3103 fail:
3104         cli->raw_status = status;
3105         TALLOC_FREE(frame);
3106         return status;
3107 }
3108
3109 struct cli_smb2_rename_fnum_state {
3110         DATA_BLOB inbuf;
3111 };
3112
3113 static void cli_smb2_rename_fnum_done(struct tevent_req *subreq);
3114
3115 static struct tevent_req *cli_smb2_rename_fnum_send(
3116         TALLOC_CTX *mem_ctx,
3117         struct tevent_context *ev,
3118         struct cli_state *cli,
3119         uint16_t fnum,
3120         const char *fname_dst,
3121         bool replace)
3122 {
3123         struct tevent_req *req = NULL, *subreq = NULL;
3124         struct cli_smb2_rename_fnum_state *state = NULL;
3125         size_t namelen = strlen(fname_dst);
3126         smb_ucs2_t *converted_str = NULL;
3127         size_t converted_size_bytes = 0;
3128         size_t inbuf_size;
3129         bool ok;
3130
3131         req = tevent_req_create(
3132                 mem_ctx, &state, struct cli_smb2_rename_fnum_state);
3133         if (req == NULL) {
3134                 return NULL;
3135         }
3136
3137         /*
3138          * SMB2 is pickier about pathnames. Ensure it doesn't start in
3139          * a '\'
3140          */
3141         if (*fname_dst == '\\') {
3142                 fname_dst++;
3143         }
3144
3145         /*
3146          * SMB2 is pickier about pathnames. Ensure it doesn't end in a
3147          * '\'
3148          */
3149         if (namelen > 0 && fname_dst[namelen-1] == '\\') {
3150                 fname_dst = talloc_strndup(state, fname_dst, namelen-1);
3151                 if (tevent_req_nomem(fname_dst, req)) {
3152                         return tevent_req_post(req, ev);
3153                 }
3154         }
3155
3156         ok = push_ucs2_talloc(
3157                 state, &converted_str, fname_dst, &converted_size_bytes);
3158         if (!ok) {
3159                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3160                 return tevent_req_post(req, ev);
3161         }
3162
3163         /*
3164          * W2K8 insists the dest name is not null terminated. Remove
3165          * the last 2 zero bytes and reduce the name length.
3166          */
3167         if (converted_size_bytes < 2) {
3168                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3169                 return tevent_req_post(req, ev);
3170         }
3171         converted_size_bytes -= 2;
3172
3173         inbuf_size = 20 + converted_size_bytes;
3174         if (inbuf_size < 20) {
3175                 /* Integer wrap check. */
3176                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3177                 return tevent_req_post(req, ev);
3178         }
3179
3180         /*
3181          * The Windows 10 SMB2 server has a minimum length
3182          * for a SMB2_FILE_RENAME_INFORMATION buffer of
3183          * 24 bytes. It returns NT_STATUS_INFO_LENGTH_MISMATCH
3184          * if the length is less. This isn't an alignment
3185          * issue as Windows client accepts happily 2-byte align
3186          * for larger target name sizes. Also the Windows 10
3187          * SMB1 server doesn't have this restriction.
3188          *
3189          * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14403
3190          */
3191         inbuf_size = MAX(inbuf_size, 24);
3192
3193         state->inbuf = data_blob_talloc_zero(state, inbuf_size);
3194         if (tevent_req_nomem(state->inbuf.data, req)) {
3195                 return tevent_req_post(req, ev);
3196         }
3197
3198         if (replace) {
3199                 SCVAL(state->inbuf.data, 0, 1);
3200         }
3201
3202         SIVAL(state->inbuf.data, 16, converted_size_bytes);
3203         memcpy(state->inbuf.data + 20, converted_str, converted_size_bytes);
3204
3205         TALLOC_FREE(converted_str);
3206
3207         /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3208            level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3209
3210         subreq = cli_smb2_set_info_fnum_send(
3211                 state,          /* mem_ctx */
3212                 ev,             /* ev */
3213                 cli,            /* cli */
3214                 fnum,           /* fnum */
3215                 1,              /* in_info_type */
3216                 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
3217                 &state->inbuf,  /* in_input_buffer */
3218                 0);             /* in_additional_info */
3219         if (tevent_req_nomem(subreq, req)) {
3220                 return tevent_req_post(req, ev);
3221         }
3222         tevent_req_set_callback(subreq, cli_smb2_rename_fnum_done, req);
3223         return req;
3224 }
3225
3226 static void cli_smb2_rename_fnum_done(struct tevent_req *subreq)
3227 {
3228         NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
3229         tevent_req_simple_finish_ntstatus(subreq, status);
3230 }
3231
3232 static NTSTATUS cli_smb2_rename_fnum_recv(struct tevent_req *req)
3233 {
3234         return tevent_req_simple_recv_ntstatus(req);
3235 }
3236
3237 /***************************************************************
3238  Wrapper that allows SMB2 to rename a file.
3239 ***************************************************************/
3240
3241 struct cli_smb2_rename_state {
3242         struct tevent_context *ev;
3243         struct cli_state *cli;
3244         const char *fname_dst;
3245         bool replace;
3246         uint16_t fnum;
3247
3248         NTSTATUS rename_status;
3249 };
3250
3251 static void cli_smb2_rename_opened(struct tevent_req *subreq);
3252 static void cli_smb2_rename_renamed(struct tevent_req *subreq);
3253 static void cli_smb2_rename_closed(struct tevent_req *subreq);
3254
3255 struct tevent_req *cli_smb2_rename_send(
3256         TALLOC_CTX *mem_ctx,
3257         struct tevent_context *ev,
3258         struct cli_state *cli,
3259         const char *fname_src,
3260         const char *fname_dst,
3261         bool replace)
3262 {
3263         struct tevent_req *req = NULL, *subreq = NULL;
3264         struct cli_smb2_rename_state *state = NULL;
3265         NTSTATUS status;
3266
3267         req = tevent_req_create(
3268                 mem_ctx, &state, struct cli_smb2_rename_state);
3269         if (req == NULL) {
3270                 return NULL;
3271         }
3272
3273         /*
3274          * Strip a MSDFS path from fname_dst if we were given one.
3275          */
3276         status = cli_dfs_target_check(state,
3277                                 cli,
3278                                 fname_dst,
3279                                 &fname_dst);
3280         if (tevent_req_nterror(req, status)) {
3281                 return tevent_req_post(req, ev);
3282         }
3283
3284         state->ev = ev;
3285         state->cli = cli;
3286         state->fname_dst = fname_dst;
3287         state->replace = replace;
3288
3289         subreq = get_fnum_from_path_send(
3290                 state, ev, cli, fname_src, DELETE_ACCESS);
3291         if (tevent_req_nomem(subreq, req)) {
3292                 return tevent_req_post(req, ev);
3293         }
3294         tevent_req_set_callback(subreq, cli_smb2_rename_opened, req);
3295         return req;
3296 }
3297
3298 static void cli_smb2_rename_opened(struct tevent_req *subreq)
3299 {
3300         struct tevent_req *req = tevent_req_callback_data(
3301                 subreq, struct tevent_req);
3302         struct cli_smb2_rename_state *state = tevent_req_data(
3303                 req, struct cli_smb2_rename_state);
3304         NTSTATUS status;
3305
3306         status = get_fnum_from_path_recv(subreq, &state->fnum);
3307         TALLOC_FREE(subreq);
3308         if (tevent_req_nterror(req, status)) {
3309                 return;
3310         }
3311
3312         subreq = cli_smb2_rename_fnum_send(
3313                 state,
3314                 state->ev,
3315                 state->cli,
3316                 state->fnum,
3317                 state->fname_dst,
3318                 state->replace);
3319         if (tevent_req_nomem(subreq, req)) {
3320                 return;
3321         }
3322         tevent_req_set_callback(subreq, cli_smb2_rename_renamed, req);
3323 }
3324
3325 static void cli_smb2_rename_renamed(struct tevent_req *subreq)
3326 {
3327         struct tevent_req *req = tevent_req_callback_data(
3328                 subreq, struct tevent_req);
3329         struct cli_smb2_rename_state *state = tevent_req_data(
3330                 req, struct cli_smb2_rename_state);
3331
3332         state->rename_status = cli_smb2_rename_fnum_recv(subreq);
3333         TALLOC_FREE(subreq);
3334
3335         subreq = cli_smb2_close_fnum_send(
3336                 state, state->ev, state->cli, state->fnum);
3337         if (tevent_req_nomem(subreq, req)) {
3338                 return;
3339         }
3340         tevent_req_set_callback(subreq, cli_smb2_rename_closed, req);
3341 }
3342
3343 static void cli_smb2_rename_closed(struct tevent_req *subreq)
3344 {
3345         NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
3346         tevent_req_simple_finish_ntstatus(subreq, status);
3347 }
3348
3349 NTSTATUS cli_smb2_rename_recv(struct tevent_req *req)
3350 {
3351         struct cli_smb2_rename_state *state = tevent_req_data(
3352                 req, struct cli_smb2_rename_state);
3353         NTSTATUS status = NT_STATUS_OK;
3354
3355         if (!tevent_req_is_nterror(req, &status)) {
3356                 status = state->rename_status;
3357         }
3358         tevent_req_received(req);
3359         return status;
3360 }
3361
3362 /***************************************************************
3363  Wrapper that allows SMB2 to set an EA on a fnum.
3364  Synchronous only.
3365 ***************************************************************/
3366
3367 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
3368                         uint16_t fnum,
3369                         const char *ea_name,
3370                         const char *ea_val,
3371                         size_t ea_len)
3372 {
3373         NTSTATUS status;
3374         DATA_BLOB inbuf = data_blob_null;
3375         size_t bloblen = 0;
3376         char *ea_name_ascii = NULL;
3377         size_t namelen = 0;
3378         TALLOC_CTX *frame = talloc_stackframe();
3379
3380         if (smbXcli_conn_has_async_calls(cli->conn)) {
3381                 /*
3382                  * Can't use sync call while an async call is in flight
3383                  */
3384                 status = NT_STATUS_INVALID_PARAMETER;
3385                 goto fail;
3386         }
3387
3388         /* Marshall the SMB2 EA data. */
3389         if (ea_len > 0xFFFF) {
3390                 status = NT_STATUS_INVALID_PARAMETER;
3391                 goto fail;
3392         }
3393
3394         if (!push_ascii_talloc(frame,
3395                                 &ea_name_ascii,
3396                                 ea_name,
3397                                 &namelen)) {
3398                 status = NT_STATUS_INVALID_PARAMETER;
3399                 goto fail;
3400         }
3401
3402         if (namelen < 2 || namelen > 0xFF) {
3403                 status = NT_STATUS_INVALID_PARAMETER;
3404                 goto fail;
3405         }
3406
3407         bloblen = 8 + ea_len + namelen;
3408         /* Round up to a 4 byte boundary. */
3409         bloblen = ((bloblen + 3)&~3);
3410
3411         inbuf = data_blob_talloc_zero(frame, bloblen);
3412         if (inbuf.data == NULL) {
3413                 status = NT_STATUS_NO_MEMORY;
3414                 goto fail;
3415         }
3416         /* namelen doesn't include the NULL byte. */
3417         SCVAL(inbuf.data, 5, namelen - 1);
3418         SSVAL(inbuf.data, 6, ea_len);
3419         memcpy(inbuf.data + 8, ea_name_ascii, namelen);
3420         memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
3421
3422         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3423            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3424
3425         status = cli_smb2_set_info_fnum(
3426                 cli,
3427                 fnum,
3428                 1,              /* in_info_type */
3429                 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3430                 &inbuf,         /* in_input_buffer */
3431                 0);             /* in_additional_info */
3432
3433   fail:
3434
3435         cli->raw_status = status;
3436
3437         TALLOC_FREE(frame);
3438         return status;
3439 }
3440
3441 /***************************************************************
3442  Wrapper that allows SMB2 to set an EA on a pathname.
3443  Synchronous only.
3444 ***************************************************************/
3445
3446 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
3447                         const char *name,
3448                         const char *ea_name,
3449                         const char *ea_val,
3450                         size_t ea_len)
3451 {
3452         NTSTATUS status;
3453         uint16_t fnum = 0xffff;
3454
3455         if (smbXcli_conn_has_async_calls(cli->conn)) {
3456                 /*
3457                  * Can't use sync call while an async call is in flight
3458                  */
3459                 status = NT_STATUS_INVALID_PARAMETER;
3460                 goto fail;
3461         }
3462
3463         status = get_fnum_from_path(cli,
3464                                 name,
3465                                 FILE_WRITE_EA,
3466                                 &fnum);
3467
3468         if (!NT_STATUS_IS_OK(status)) {
3469                 goto fail;
3470         }
3471
3472         status = cli_set_ea_fnum(cli,
3473                                 fnum,
3474                                 ea_name,
3475                                 ea_val,
3476                                 ea_len);
3477         if (!NT_STATUS_IS_OK(status)) {
3478                 goto fail;
3479         }
3480
3481   fail:
3482
3483         if (fnum != 0xffff) {
3484                 cli_smb2_close_fnum(cli, fnum);
3485         }
3486
3487         cli->raw_status = status;
3488
3489         return status;
3490 }
3491
3492 /***************************************************************
3493  Wrapper that allows SMB2 to get an EA list on a pathname.
3494  Synchronous only.
3495 ***************************************************************/
3496
3497 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
3498                                 const char *name,
3499                                 TALLOC_CTX *ctx,
3500                                 size_t *pnum_eas,
3501                                 struct ea_struct **pea_array)
3502 {
3503         NTSTATUS status;
3504         uint16_t fnum = 0xffff;
3505         DATA_BLOB outbuf = data_blob_null;
3506         struct ea_list *ea_list = NULL;
3507         struct ea_list *eal = NULL;
3508         size_t ea_count = 0;
3509         TALLOC_CTX *frame = talloc_stackframe();
3510
3511         *pnum_eas = 0;
3512         *pea_array = NULL;
3513
3514         if (smbXcli_conn_has_async_calls(cli->conn)) {
3515                 /*
3516                  * Can't use sync call while an async call is in flight
3517                  */
3518                 status = NT_STATUS_INVALID_PARAMETER;
3519                 goto fail;
3520         }
3521
3522         status = get_fnum_from_path(cli,
3523                                 name,
3524                                 FILE_READ_EA,
3525                                 &fnum);
3526
3527         if (!NT_STATUS_IS_OK(status)) {
3528                 goto fail;
3529         }
3530
3531         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3532            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3533
3534         status = cli_smb2_query_info_fnum(
3535                 cli,
3536                 fnum,
3537                 1, /* in_info_type */
3538                 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3539                 0xFFFF, /* in_max_output_length */
3540                 NULL, /* in_input_buffer */
3541                 0, /* in_additional_info */
3542                 0, /* in_flags */
3543                 frame,
3544                 &outbuf);
3545
3546         if (!NT_STATUS_IS_OK(status)) {
3547                 goto fail;
3548         }
3549
3550         /* Parse the reply. */
3551         ea_list = read_nttrans_ea_list(ctx,
3552                                 (const char *)outbuf.data,
3553                                 outbuf.length);
3554         if (ea_list == NULL) {
3555                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3556                 goto fail;
3557         }
3558
3559         /* Convert to an array. */
3560         for (eal = ea_list; eal; eal = eal->next) {
3561                 ea_count++;
3562         }
3563
3564         if (ea_count) {
3565                 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
3566                 if (*pea_array == NULL) {
3567                         status = NT_STATUS_NO_MEMORY;
3568                         goto fail;
3569                 }
3570                 ea_count = 0;
3571                 for (eal = ea_list; eal; eal = eal->next) {
3572                         (*pea_array)[ea_count++] = eal->ea;
3573                 }
3574                 *pnum_eas = ea_count;
3575         }
3576
3577   fail:
3578
3579         if (fnum != 0xffff) {
3580                 cli_smb2_close_fnum(cli, fnum);
3581         }
3582
3583         cli->raw_status = status;
3584
3585         TALLOC_FREE(frame);
3586         return status;
3587 }
3588
3589 /***************************************************************
3590  Wrapper that allows SMB2 to get user quota.
3591  Synchronous only.
3592 ***************************************************************/
3593
3594 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
3595                                  int quota_fnum,
3596                                  SMB_NTQUOTA_STRUCT *pqt)
3597 {
3598         NTSTATUS status;
3599         DATA_BLOB inbuf = data_blob_null;
3600         DATA_BLOB info_blob = data_blob_null;
3601         DATA_BLOB outbuf = data_blob_null;
3602         TALLOC_CTX *frame = talloc_stackframe();
3603         unsigned sid_len;
3604         unsigned int offset;
3605         struct smb2_query_quota_info query = {0};
3606         struct file_get_quota_info info = {0};
3607         enum ndr_err_code err;
3608         struct ndr_push *ndr_push = NULL;
3609
3610         if (smbXcli_conn_has_async_calls(cli->conn)) {
3611                 /*
3612                  * Can't use sync call while an async call is in flight
3613                  */
3614                 status = NT_STATUS_INVALID_PARAMETER;
3615                 goto fail;
3616         }
3617
3618         sid_len = ndr_size_dom_sid(&pqt->sid, 0);
3619
3620         query.return_single = 1;
3621
3622         info.next_entry_offset = 0;
3623         info.sid_length = sid_len;
3624         info.sid = pqt->sid;
3625
3626         err = ndr_push_struct_blob(
3627                         &info_blob,
3628                         frame,
3629                         &info,
3630                         (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
3631
3632         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3633                 status = NT_STATUS_INTERNAL_ERROR;
3634                 goto fail;
3635         }
3636
3637         query.sid_list_length = info_blob.length;
3638         ndr_push = ndr_push_init_ctx(frame);
3639         if (!ndr_push) {
3640                 status = NT_STATUS_NO_MEMORY;
3641                 goto fail;
3642         }
3643
3644         err = ndr_push_smb2_query_quota_info(ndr_push,
3645                                              NDR_SCALARS | NDR_BUFFERS,
3646                                              &query);
3647
3648         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3649                 status = NT_STATUS_INTERNAL_ERROR;
3650                 goto fail;
3651         }
3652
3653         err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3654                                    info_blob.length);
3655
3656         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3657                 status = NT_STATUS_INTERNAL_ERROR;
3658                 goto fail;
3659         }
3660         inbuf.data = ndr_push->data;
3661         inbuf.length = ndr_push->offset;
3662
3663         status = cli_smb2_query_info_fnum(
3664                 cli,
3665                 quota_fnum,
3666                 4, /* in_info_type */
3667                 0,                     /* in_file_info_class */
3668                 0xFFFF, /* in_max_output_length */
3669                 &inbuf, /* in_input_buffer */
3670                 0,      /* in_additional_info */
3671                 0,      /* in_flags */
3672                 frame,
3673                 &outbuf);
3674
3675         if (!NT_STATUS_IS_OK(status)) {
3676                 goto fail;
3677         }
3678
3679         if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3680                                      pqt)) {
3681                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3682                 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3683         }
3684
3685 fail:
3686         cli->raw_status = status;
3687
3688         TALLOC_FREE(frame);
3689         return status;
3690 }
3691
3692 /***************************************************************
3693  Wrapper that allows SMB2 to list user quota.
3694  Synchronous only.
3695 ***************************************************************/
3696
3697 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3698                                        TALLOC_CTX *mem_ctx,
3699                                        int quota_fnum,
3700                                        SMB_NTQUOTA_LIST **pqt_list,
3701                                        bool first)
3702 {
3703         NTSTATUS status;
3704         DATA_BLOB inbuf = data_blob_null;
3705         DATA_BLOB outbuf = data_blob_null;
3706         TALLOC_CTX *frame = talloc_stackframe();
3707         struct smb2_query_quota_info info = {0};
3708         enum ndr_err_code err;
3709
3710         if (smbXcli_conn_has_async_calls(cli->conn)) {
3711                 /*
3712                  * Can't use sync call while an async call is in flight
3713                  */
3714                 status = NT_STATUS_INVALID_PARAMETER;
3715                 goto cleanup;
3716         }
3717
3718         info.restart_scan = first ? 1 : 0;
3719
3720         err = ndr_push_struct_blob(
3721                         &inbuf,
3722                         frame,
3723                         &info,
3724                         (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3725
3726         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3727                 status = NT_STATUS_INTERNAL_ERROR;
3728                 goto cleanup;
3729         }
3730
3731         status = cli_smb2_query_info_fnum(
3732                 cli,
3733                 quota_fnum,
3734                 4, /* in_info_type */
3735                 0, /* in_file_info_class */
3736                 0xFFFF, /* in_max_output_length */
3737                 &inbuf, /* in_input_buffer */
3738                 0,      /* in_additional_info */
3739                 0,      /* in_flags */
3740                 frame,
3741                 &outbuf);
3742
3743         /*
3744          * safeguard against panic from calling parse_user_quota_list with
3745          * NULL buffer
3746          */
3747         if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3748                 status = NT_STATUS_NO_MORE_ENTRIES;
3749         }
3750
3751         if (!NT_STATUS_IS_OK(status)) {
3752                 goto cleanup;
3753         }
3754
3755         status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3756                                        pqt_list);
3757
3758 cleanup:
3759         cli->raw_status = status;
3760
3761         TALLOC_FREE(frame);
3762         return status;
3763 }
3764
3765 /***************************************************************
3766  Wrapper that allows SMB2 to get file system quota.
3767  Synchronous only.
3768 ***************************************************************/
3769
3770 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3771                                     int quota_fnum,
3772                                     SMB_NTQUOTA_STRUCT *pqt)
3773 {
3774         NTSTATUS status;
3775         DATA_BLOB outbuf = data_blob_null;
3776         TALLOC_CTX *frame = talloc_stackframe();
3777
3778         if (smbXcli_conn_has_async_calls(cli->conn)) {
3779                 /*
3780                  * Can't use sync call while an async call is in flight
3781                  */
3782                 status = NT_STATUS_INVALID_PARAMETER;
3783                 goto cleanup;
3784         }
3785
3786         status = cli_smb2_query_info_fnum(
3787                 cli,
3788                 quota_fnum,
3789                 2,                                   /* in_info_type */
3790                 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3791                 0xFFFF,                      /* in_max_output_length */
3792                 NULL,                        /* in_input_buffer */
3793                 0,                                   /* in_additional_info */
3794                 0,                                   /* in_flags */
3795                 frame,
3796                 &outbuf);
3797
3798         if (!NT_STATUS_IS_OK(status)) {
3799                 goto cleanup;
3800         }
3801
3802         status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3803
3804 cleanup:
3805         cli->raw_status = status;
3806
3807         TALLOC_FREE(frame);
3808         return status;
3809 }
3810
3811 /***************************************************************
3812  Wrapper that allows SMB2 to set user quota.
3813  Synchronous only.
3814 ***************************************************************/
3815
3816 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3817                                  int quota_fnum,
3818                                  SMB_NTQUOTA_LIST *qtl)
3819 {
3820         NTSTATUS status;
3821         DATA_BLOB inbuf = data_blob_null;
3822         TALLOC_CTX *frame = talloc_stackframe();
3823
3824         if (smbXcli_conn_has_async_calls(cli->conn)) {
3825                 /*
3826                  * Can't use sync call while an async call is in flight
3827                  */
3828                 status = NT_STATUS_INVALID_PARAMETER;
3829                 goto cleanup;
3830         }
3831
3832         status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3833         if (!NT_STATUS_IS_OK(status)) {
3834                 goto cleanup;
3835         }
3836
3837         status = cli_smb2_set_info_fnum(
3838                 cli,
3839                 quota_fnum,
3840                 4,                        /* in_info_type */
3841                 0,                        /* in_file_info_class */
3842                 &inbuf,                   /* in_input_buffer */
3843                 0);                       /* in_additional_info */
3844 cleanup:
3845
3846         cli->raw_status = status;
3847
3848         TALLOC_FREE(frame);
3849
3850         return status;
3851 }
3852
3853 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3854                                     int quota_fnum,
3855                                     SMB_NTQUOTA_STRUCT *pqt)
3856 {
3857         NTSTATUS status;
3858         DATA_BLOB inbuf = data_blob_null;
3859         TALLOC_CTX *frame = talloc_stackframe();
3860
3861         if (smbXcli_conn_has_async_calls(cli->conn)) {
3862                 /*
3863                  * Can't use sync call while an async call is in flight
3864                  */
3865                 status = NT_STATUS_INVALID_PARAMETER;
3866                 goto cleanup;
3867         }
3868
3869         status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3870         if (!NT_STATUS_IS_OK(status)) {
3871                 goto cleanup;
3872         }
3873
3874         status = cli_smb2_set_info_fnum(
3875                 cli,
3876                 quota_fnum,
3877                 2,                           /* in_info_type */
3878                 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3879                 &inbuf,                      /* in_input_buffer */
3880                 0);                          /* in_additional_info */
3881 cleanup:
3882         cli->raw_status = status;
3883
3884         TALLOC_FREE(frame);
3885         return status;
3886 }
3887
3888 struct cli_smb2_read_state {
3889         struct tevent_context *ev;
3890         struct cli_state *cli;
3891         struct smb2_hnd *ph;
3892         uint64_t start_offset;
3893         uint32_t size;
3894         uint32_t received;
3895         uint8_t *buf;
3896 };
3897
3898 static void cli_smb2_read_done(struct tevent_req *subreq);
3899
3900 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3901                                 struct tevent_context *ev,
3902                                 struct cli_state *cli,
3903                                 uint16_t fnum,
3904                                 off_t offset,
3905                                 size_t size)
3906 {
3907         NTSTATUS status;
3908         struct tevent_req *req, *subreq;
3909         struct cli_smb2_read_state *state;
3910
3911         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3912         if (req == NULL) {
3913                 return NULL;
3914         }
3915         state->ev = ev;
3916         state->cli = cli;
3917         state->start_offset = (uint64_t)offset;
3918         state->size = (uint32_t)size;
3919         state->received = 0;
3920         state->buf = NULL;
3921
3922         status = map_fnum_to_smb2_handle(cli,
3923                                         fnum,
3924                                         &state->ph);
3925         if (tevent_req_nterror(req, status)) {
3926                 return tevent_req_post(req, ev);
3927         }
3928
3929         subreq = smb2cli_read_send(state,
3930                                 state->ev,
3931                                 state->cli->conn,
3932                                 state->cli->timeout,
3933                                 state->cli->smb2.session,
3934                                 state->cli->smb2.tcon,
3935                                 state->size,
3936                                 state->start_offset,
3937                                 state->ph->fid_persistent,
3938                                 state->ph->fid_volatile,
3939                                 0, /* minimum_count */
3940                                 0); /* remaining_bytes */
3941
3942         if (tevent_req_nomem(subreq, req)) {
3943                 return tevent_req_post(req, ev);
3944         }
3945         tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3946         return req;
3947 }
3948
3949 static void cli_smb2_read_done(struct tevent_req *subreq)
3950 {
3951         struct tevent_req *req = tevent_req_callback_data(
3952                 subreq, struct tevent_req);
3953         struct cli_smb2_read_state *state = tevent_req_data(
3954                 req, struct cli_smb2_read_state);
3955         NTSTATUS status;
3956
3957         status = smb2cli_read_recv(subreq, state,
3958                                    &state->buf, &state->received);
3959         if (tevent_req_nterror(req, status)) {
3960                 return;
3961         }
3962
3963         if (state->received > state->size) {
3964                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3965                 return;
3966         }
3967
3968         tevent_req_done(req);
3969 }
3970
3971 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
3972                                 ssize_t *received,
3973                                 uint8_t **rcvbuf)
3974 {
3975         NTSTATUS status;
3976         struct cli_smb2_read_state *state = tevent_req_data(
3977                                 req, struct cli_smb2_read_state);
3978
3979         if (tevent_req_is_nterror(req, &status)) {
3980                 state->cli->raw_status = status;
3981                 return status;
3982         }
3983         /*
3984          * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3985          * better make sure that you copy it away before you talloc_free(req).
3986          * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3987          */
3988         *received = (ssize_t)state->received;
3989         *rcvbuf = state->buf;
3990         state->cli->raw_status = NT_STATUS_OK;
3991         return NT_STATUS_OK;
3992 }
3993
3994 struct cli_smb2_write_state {
3995         struct tevent_context *ev;
3996         struct cli_state *cli;
3997         struct smb2_hnd *ph;
3998         uint32_t flags;
3999         const uint8_t *buf;
4000         uint64_t offset;
4001         uint32_t size;
4002         uint32_t written;
4003 };
4004
4005 static void cli_smb2_write_written(struct tevent_req *req);
4006
4007 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
4008                                         struct tevent_context *ev,
4009                                         struct cli_state *cli,
4010                                         uint16_t fnum,
4011                                         uint16_t mode,
4012                                         const uint8_t *buf,
4013                                         off_t offset,
4014                                         size_t size)
4015 {
4016         NTSTATUS status;
4017         struct tevent_req *req, *subreq = NULL;
4018         struct cli_smb2_write_state *state = NULL;
4019
4020         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
4021         if (req == NULL) {
4022                 return NULL;
4023         }
4024         state->ev = ev;
4025         state->cli = cli;
4026         /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4027         state->flags = (uint32_t)mode;
4028         state->buf = buf;
4029         state->offset = (uint64_t)offset;
4030         state->size = (uint32_t)size;
4031         state->written = 0;
4032
4033         status = map_fnum_to_smb2_handle(cli,
4034                                         fnum,
4035                                         &state->ph);
4036         if (tevent_req_nterror(req, status)) {
4037                 return tevent_req_post(req, ev);
4038         }
4039
4040         subreq = smb2cli_write_send(state,
4041                                 state->ev,
4042                                 state->cli->conn,
4043                                 state->cli->timeout,
4044                                 state->cli->smb2.session,
4045                                 state->cli->smb2.tcon,
4046                                 state->size,
4047                                 state->offset,
4048                                 state->ph->fid_persistent,
4049                                 state->ph->fid_volatile,
4050                                 0, /* remaining_bytes */
4051                                 state->flags, /* flags */
4052                                 state->buf);
4053
4054         if (tevent_req_nomem(subreq, req)) {
4055                 return tevent_req_post(req, ev);
4056         }
4057         tevent_req_set_callback(subreq, cli_smb2_write_written, req);
4058         return req;
4059 }
4060
4061 static void cli_smb2_write_written(struct tevent_req *subreq)
4062 {
4063         struct tevent_req *req = tevent_req_callback_data(
4064                 subreq, struct tevent_req);
4065         struct cli_smb2_write_state *state = tevent_req_data(
4066                 req, struct cli_smb2_write_state);
4067         NTSTATUS status;
4068         uint32_t written;
4069
4070         status = smb2cli_write_recv(subreq, &written);
4071         TALLOC_FREE(subreq);
4072         if (tevent_req_nterror(req, status)) {
4073                 return;
4074         }
4075
4076         state->written = written;
4077
4078         tevent_req_done(req);
4079 }
4080
4081 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
4082                              size_t *pwritten)
4083 {
4084         struct cli_smb2_write_state *state = tevent_req_data(
4085                 req, struct cli_smb2_write_state);
4086         NTSTATUS status;
4087
4088         if (tevent_req_is_nterror(req, &status)) {
4089                 state->cli->raw_status = status;
4090                 tevent_req_received(req);
4091                 return status;
4092         }
4093
4094         if (pwritten != NULL) {
4095                 *pwritten = (size_t)state->written;
4096         }
4097         state->cli->raw_status = NT_STATUS_OK;
4098         tevent_req_received(req);
4099         return NT_STATUS_OK;
4100 }
4101
4102 /***************************************************************
4103  Wrapper that allows SMB2 async write using an fnum.
4104  This is mostly cut-and-paste from Volker's code inside
4105  source3/libsmb/clireadwrite.c, adapted for SMB2.
4106
4107  Done this way so I can reuse all the logic inside cli_push()
4108  for free :-).
4109 ***************************************************************/
4110
4111 struct cli_smb2_writeall_state {
4112         struct tevent_context *ev;
4113         struct cli_state *cli;
4114         struct smb2_hnd *ph;
4115         uint32_t flags;
4116         const uint8_t *buf;
4117         uint64_t offset;
4118         uint32_t size;
4119         uint32_t written;
4120 };
4121
4122 static void cli_smb2_writeall_written(struct tevent_req *req);
4123
4124 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
4125                                         struct tevent_context *ev,
4126                                         struct cli_state *cli,
4127                                         uint16_t fnum,
4128                                         uint16_t mode,
4129                                         const uint8_t *buf,
4130                                         off_t offset,
4131                                         size_t size)
4132 {
4133         NTSTATUS status;
4134         struct tevent_req *req, *subreq = NULL;
4135         struct cli_smb2_writeall_state *state = NULL;
4136         uint32_t to_write;
4137         uint32_t max_size;
4138         bool ok;
4139
4140         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
4141         if (req == NULL) {
4142                 return NULL;
4143         }
4144         state->ev = ev;
4145         state->cli = cli;
4146         /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4147         state->flags = (uint32_t)mode;
4148         state->buf = buf;
4149         state->offset = (uint64_t)offset;
4150         state->size = (uint32_t)size;
4151         state->written = 0;
4152
4153         status = map_fnum_to_smb2_handle(cli,
4154                                         fnum,
4155                                         &state->ph);
4156         if (tevent_req_nterror(req, status)) {
4157                 return tevent_req_post(req, ev);
4158         }
4159
4160         to_write = state->size;
4161         max_size = smb2cli_conn_max_write_size(state->cli->conn);
4162         to_write = MIN(max_size, to_write);
4163         ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4164         if (ok) {
4165                 to_write = MIN(max_size, to_write);
4166         }
4167
4168         subreq = smb2cli_write_send(state,
4169                                 state->ev,
4170                                 state->cli->conn,
4171                                 state->cli->timeout,
4172                                 state->cli->smb2.session,
4173                                 state->cli->smb2.tcon,
4174                                 to_write,
4175                                 state->offset,
4176                                 state->ph->fid_persistent,
4177                                 state->ph->fid_volatile,
4178                                 0, /* remaining_bytes */
4179                                 state->flags, /* flags */
4180                                 state->buf + state->written);
4181
4182         if (tevent_req_nomem(subreq, req)) {
4183                 return tevent_req_post(req, ev);
4184         }
4185         tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4186         return req;
4187 }
4188
4189 static void cli_smb2_writeall_written(struct tevent_req *subreq)
4190 {
4191         struct tevent_req *req = tevent_req_callback_data(
4192                 subreq, struct tevent_req);
4193         struct cli_smb2_writeall_state *state = tevent_req_data(
4194                 req, struct cli_smb2_writeall_state);
4195         NTSTATUS status;
4196         uint32_t written, to_write;
4197         uint32_t max_size;
4198         bool ok;
4199
4200         status = smb2cli_write_recv(subreq, &written);
4201         TALLOC_FREE(subreq);
4202         if (tevent_req_nterror(req, status)) {
4203                 return;
4204         }
4205
4206         state->written += written;
4207
4208         if (state->written > state->size) {
4209                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4210                 return;
4211         }
4212
4213         to_write = state->size - state->written;
4214
4215         if (to_write == 0) {
4216                 tevent_req_done(req);
4217                 return;
4218         }
4219
4220         max_size = smb2cli_conn_max_write_size(state->cli->conn);
4221         to_write = MIN(max_size, to_write);
4222         ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4223         if (ok) {
4224                 to_write = MIN(max_size, to_write);
4225         }
4226
4227         subreq = smb2cli_write_send(state,
4228                                 state->ev,
4229                                 state->cli->conn,
4230                                 state->cli->timeout,
4231                                 state->cli->smb2.session,
4232                                 state->cli->smb2.tcon,
4233                                 to_write,
4234                                 state->offset + state->written,
4235                                 state->ph->fid_persistent,
4236                                 state->ph->fid_volatile,
4237                                 0, /* remaining_bytes */
4238                                 state->flags, /* flags */
4239                                 state->buf + state->written);
4240
4241         if (tevent_req_nomem(subreq, req)) {
4242                 return;
4243         }
4244         tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4245 }
4246
4247 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
4248                                 size_t *pwritten)
4249 {
4250         struct cli_smb2_writeall_state *state = tevent_req_data(
4251                 req, struct cli_smb2_writeall_state);
4252         NTSTATUS status;
4253
4254         if (tevent_req_is_nterror(req, &status)) {
4255                 state->cli->raw_status = status;
4256                 return status;
4257         }
4258         if (pwritten != NULL) {
4259                 *pwritten = (size_t)state->written;
4260         }
4261         state->cli->raw_status = NT_STATUS_OK;
4262         return NT_STATUS_OK;
4263 }
4264
4265 struct cli_smb2_splice_state {
4266         struct tevent_context *ev;
4267         struct cli_state *cli;
4268         struct smb2_hnd *src_ph;
4269         struct smb2_hnd *dst_ph;
4270         int (*splice_cb)(off_t n, void *priv);
4271         void *priv;
4272         off_t written;
4273         off_t size;
4274         off_t src_offset;
4275         off_t dst_offset;
4276         bool resized;
4277         struct req_resume_key_rsp resume_rsp;
4278         struct srv_copychunk_copy cc_copy;
4279 };
4280
4281 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4282                                       struct tevent_req *req);
4283
4284 static void cli_splice_copychunk_done(struct tevent_req *subreq)
4285 {
4286         struct tevent_req *req = tevent_req_callback_data(
4287                 subreq, struct tevent_req);
4288         struct cli_smb2_splice_state *state =
4289                 tevent_req_data(req,
4290                 struct cli_smb2_splice_state);
4291         struct smbXcli_conn *conn = state->cli->conn;
4292         DATA_BLOB out_input_buffer = data_blob_null;
4293         DATA_BLOB out_output_buffer = data_blob_null;
4294         struct srv_copychunk_rsp cc_copy_rsp;
4295         enum ndr_err_code ndr_ret;
4296         NTSTATUS status;
4297
4298         status = smb2cli_ioctl_recv(subreq, state,
4299                                     &out_input_buffer,
4300                                     &out_output_buffer);
4301         TALLOC_FREE(subreq);
4302         if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
4303              state->resized) && tevent_req_nterror(req, status)) {
4304                 return;
4305         }
4306
4307         ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
4308                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
4309         if (ndr_ret != NDR_ERR_SUCCESS) {
4310                 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4311                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4312                 return;
4313         }
4314
4315         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
4316                 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
4317                              cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
4318                 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
4319                      max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
4320                      tevent_req_nterror(req, status)) {
4321                         return;
4322                 }
4323
4324                 state->resized = true;
4325                 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
4326                 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
4327         } else {
4328                 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4329                     (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4330                     (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
4331                         tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4332                         return;
4333                 }
4334                 state->src_offset += cc_copy_rsp.total_bytes_written;
4335                 state->dst_offset += cc_copy_rsp.total_bytes_written;
4336                 state->written += cc_copy_rsp.total_bytes_written;
4337                 if (!state->splice_cb(state->written, state->priv)) {
4338                         tevent_req_nterror(req, NT_STATUS_CANCELLED);
4339                         return;
4340                 }
4341         }
4342
4343         cli_splice_copychunk_send(state, req);
4344 }
4345
4346 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4347                                       struct tevent_req *req)
4348 {
4349         struct tevent_req *subreq;
4350         enum ndr_err_code ndr_ret;
4351         struct smbXcli_conn *conn = state->cli->conn;
4352         struct srv_copychunk_copy *cc_copy = &state->cc_copy;
4353         off_t src_offset = state->src_offset;
4354         off_t dst_offset = state->dst_offset;
4355         uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
4356                                state->size - state->written);
4357         DATA_BLOB in_input_buffer = data_blob_null;
4358         DATA_BLOB in_output_buffer = data_blob_null;
4359
4360         if (state->size - state->written == 0) {
4361                 tevent_req_done(req);
4362                 return;
4363         }
4364
4365         cc_copy->chunk_count = 0;
4366         while (req_len) {
4367                 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
4368                 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
4369                 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
4370                                                                    smb2cli_conn_cc_chunk_len(conn));
4371                 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
4372                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4373                         return;
4374                 }
4375                 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
4376                 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
4377                     (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
4378                         tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4379                         return;
4380                 }
4381                 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4382                 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4383                 cc_copy->chunk_count++;
4384         }
4385
4386         ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
4387                                        (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
4388         if (ndr_ret != NDR_ERR_SUCCESS) {
4389                 DEBUG(0, ("failed to marshall copy chunk req\n"));
4390                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4391                 return;
4392         }
4393
4394         subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
4395                                state->cli->timeout,
4396                                state->cli->smb2.session,
4397                                state->cli->smb2.tcon,
4398                                state->dst_ph->fid_persistent, /* in_fid_persistent */
4399                                state->dst_ph->fid_volatile, /* in_fid_volatile */
4400                                FSCTL_SRV_COPYCHUNK_WRITE,
4401                                0, /* in_max_input_length */
4402                                &in_input_buffer,
4403                                12, /* in_max_output_length */
4404                                &in_output_buffer,
4405                                SMB2_IOCTL_FLAG_IS_FSCTL);
4406         if (tevent_req_nomem(subreq, req)) {
4407                 return;
4408         }
4409         tevent_req_set_callback(subreq,
4410                                 cli_splice_copychunk_done,
4411                                 req);
4412 }
4413
4414 static void cli_splice_key_done(struct tevent_req *subreq)
4415 {
4416         struct tevent_req *req = tevent_req_callback_data(
4417                 subreq, struct tevent_req);
4418         struct cli_smb2_splice_state *state =
4419                 tevent_req_data(req,
4420                 struct cli_smb2_splice_state);
4421         enum ndr_err_code ndr_ret;
4422         NTSTATUS status;
4423
4424         DATA_BLOB out_input_buffer = data_blob_null;
4425         DATA_BLOB out_output_buffer = data_blob_null;
4426
4427         status = smb2cli_ioctl_recv(subreq, state,
4428                                     &out_input_buffer,
4429                                     &out_output_buffer);
4430         TALLOC_FREE(subreq);
4431         if (tevent_req_nterror(req, status)) {
4432                 return;
4433         }
4434
4435         ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
4436                         state, &state->resume_rsp,
4437                         (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
4438         if (ndr_ret != NDR_ERR_SUCCESS) {
4439                 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4440                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4441                 return;
4442         }
4443
4444         memcpy(&state->cc_copy.source_key,
4445                &state->resume_rsp.resume_key,
4446                sizeof state->resume_rsp.resume_key);
4447
4448         cli_splice_copychunk_send(state, req);
4449 }
4450
4451 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
4452                                 struct tevent_context *ev,
4453                                 struct cli_state *cli,
4454                                 uint16_t src_fnum, uint16_t dst_fnum,
4455                                 off_t size, off_t src_offset, off_t dst_offset,
4456                                 int (*splice_cb)(off_t n, void *priv),
4457                                 void *priv)
4458 {
4459         struct tevent_req *req;
4460         struct tevent_req *subreq;
4461         struct cli_smb2_splice_state *state;
4462         NTSTATUS status;
4463         DATA_BLOB in_input_buffer = data_blob_null;
4464         DATA_BLOB in_output_buffer = data_blob_null;
4465
4466         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
4467         if (req == NULL) {
4468                 return NULL;
4469         }
4470         state->cli = cli;
4471         state->ev = ev;
4472         state->splice_cb = splice_cb;
4473         state->priv = priv;
4474         state->size = size;
4475         state->written = 0;
4476         state->src_offset = src_offset;
4477         state->dst_offset = dst_offset;
4478         state->cc_copy.chunks = talloc_array(state,
4479                                              struct srv_copychunk,
4480                                              smb2cli_conn_cc_max_chunks(cli->conn));
4481         if (state->cc_copy.chunks == NULL) {
4482                 return NULL;
4483         }
4484
4485         status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
4486         if (tevent_req_nterror(req, status))
4487                 return tevent_req_post(req, ev);
4488
4489         status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
4490         if (tevent_req_nterror(req, status))
4491                 return tevent_req_post(req, ev);
4492
4493         subreq = smb2cli_ioctl_send(state, ev, cli->conn,
4494                                cli->timeout,
4495                                cli->smb2.session,
4496                                cli->smb2.tcon,
4497                                state->src_ph->fid_persistent, /* in_fid_persistent */
4498                                state->src_ph->fid_volatile, /* in_fid_volatile */
4499                                FSCTL_SRV_REQUEST_RESUME_KEY,
4500                                0, /* in_max_input_length */
4501                                &in_input_buffer,
4502                                32, /* in_max_output_length */
4503                                &in_output_buffer,
4504                                SMB2_IOCTL_FLAG_IS_FSCTL);
4505         if (tevent_req_nomem(subreq, req)) {
4506                 return NULL;
4507         }
4508         tevent_req_set_callback(subreq,
4509                                 cli_splice_key_done,
4510                                 req);
4511
4512         return req;
4513 }
4514
4515 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
4516 {
4517         struct cli_smb2_splice_state *state = tevent_req_data(
4518                 req, struct cli_smb2_splice_state);
4519         NTSTATUS status;
4520
4521         if (tevent_req_is_nterror(req, &status)) {
4522                 state->cli->raw_status = status;
4523                 tevent_req_received(req);
4524                 return status;
4525         }
4526         if (written != NULL) {
4527                 *written = state->written;
4528         }
4529         state->cli->raw_status = NT_STATUS_OK;
4530         tevent_req_received(req);
4531         return NT_STATUS_OK;
4532 }
4533
4534 /***************************************************************
4535  SMB2 enum shadow copy data.
4536 ***************************************************************/
4537
4538 struct cli_smb2_shadow_copy_data_fnum_state {
4539         struct cli_state *cli;
4540         uint16_t fnum;
4541         struct smb2_hnd *ph;
4542         DATA_BLOB out_input_buffer;
4543         DATA_BLOB out_output_buffer;
4544 };
4545
4546 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
4547
4548 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
4549                                         TALLOC_CTX *mem_ctx,
4550                                         struct tevent_context *ev,
4551                                         struct cli_state *cli,
4552                                         uint16_t fnum,
4553                                         bool get_names)
4554 {
4555         struct tevent_req *req, *subreq;
4556         struct cli_smb2_shadow_copy_data_fnum_state *state;
4557         NTSTATUS status;
4558
4559         req = tevent_req_create(mem_ctx, &state,
4560                                 struct cli_smb2_shadow_copy_data_fnum_state);
4561         if (req == NULL) {
4562                 return NULL;
4563         }
4564
4565         state->cli = cli;
4566         state->fnum = fnum;
4567
4568         status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4569         if (tevent_req_nterror(req, status)) {
4570                 return tevent_req_post(req, ev);
4571         }
4572
4573         /*
4574          * TODO. Under SMB2 we should send a zero max_output_length
4575          * ioctl to get the required size, then send another ioctl
4576          * to get the data, but the current SMB1 implementation just
4577          * does one roundtrip with a 64K buffer size. Do the same
4578          * for now. JRA.
4579          */
4580
4581         subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4582                         state->cli->timeout,
4583                         state->cli->smb2.session,
4584                         state->cli->smb2.tcon,
4585                         state->ph->fid_persistent, /* in_fid_persistent */
4586                         state->ph->fid_volatile, /* in_fid_volatile */
4587                         FSCTL_GET_SHADOW_COPY_DATA,
4588                         0, /* in_max_input_length */
4589                         NULL, /* in_input_buffer */
4590                         get_names ?
4591                                 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
4592                         NULL, /* in_output_buffer */
4593                         SMB2_IOCTL_FLAG_IS_FSCTL);
4594
4595         if (tevent_req_nomem(subreq, req)) {
4596                 return tevent_req_post(req, ev);
4597         }
4598         tevent_req_set_callback(subreq,
4599                                 cli_smb2_shadow_copy_data_fnum_done,
4600                                 req);
4601
4602         return req;
4603 }
4604
4605 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4606 {
4607         struct tevent_req *req = tevent_req_callback_data(
4608                 subreq, struct tevent_req);
4609         struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4610                 req, struct cli_smb2_shadow_copy_data_fnum_state);
4611         NTSTATUS status;
4612
4613         status = smb2cli_ioctl_recv(subreq, state,
4614                                 &state->out_input_buffer,
4615                                 &state->out_output_buffer);
4616         tevent_req_simple_finish_ntstatus(subreq, status);
4617 }
4618
4619 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4620                                 TALLOC_CTX *mem_ctx,
4621                                 bool get_names,
4622                                 char ***pnames,
4623                                 int *pnum_names)
4624 {
4625         struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4626                 req, struct cli_smb2_shadow_copy_data_fnum_state);
4627         char **names = NULL;
4628         uint32_t num_names = 0;
4629         uint32_t num_names_returned = 0;
4630         uint32_t dlength = 0;
4631         uint32_t i;
4632         uint8_t *endp = NULL;
4633         NTSTATUS status;
4634
4635         if (tevent_req_is_nterror(req, &status)) {
4636                 return status;
4637         }
4638
4639         if (state->out_output_buffer.length < 16) {
4640                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4641         }
4642
4643         num_names = IVAL(state->out_output_buffer.data, 0);
4644         num_names_returned = IVAL(state->out_output_buffer.data, 4);
4645         dlength = IVAL(state->out_output_buffer.data, 8);
4646
4647         if (num_names > 0x7FFFFFFF) {
4648                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4649         }
4650
4651         if (get_names == false) {
4652                 *pnum_names = (int)num_names;
4653                 return NT_STATUS_OK;
4654         }
4655         if (num_names != num_names_returned) {
4656                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4657         }
4658         if (dlength + 12 < 12) {
4659                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4660         }
4661         /*
4662          * NB. The below is an allowable return if there are
4663          * more snapshots than the buffer size we told the
4664          * server we can receive. We currently don't support
4665          * this.
4666          */
4667         if (dlength + 12 > state->out_output_buffer.length) {
4668                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4669         }
4670         if (state->out_output_buffer.length +
4671                         (2 * sizeof(SHADOW_COPY_LABEL)) <
4672                                 state->out_output_buffer.length) {
4673                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4674         }
4675
4676         names = talloc_array(mem_ctx, char *, num_names_returned);
4677         if (names == NULL) {
4678                 return NT_STATUS_NO_MEMORY;
4679         }
4680
4681         endp = state->out_output_buffer.data +
4682                         state->out_output_buffer.length;
4683
4684         for (i=0; i<num_names_returned; i++) {
4685                 bool ret;
4686                 uint8_t *src;
4687                 size_t converted_size;
4688
4689                 src = state->out_output_buffer.data + 12 +
4690                         (i * 2 * sizeof(SHADOW_COPY_LABEL));
4691
4692                 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4693                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
4694                 }
4695                 ret = convert_string_talloc(
4696                         names, CH_UTF16LE, CH_UNIX,
4697                         src, 2 * sizeof(SHADOW_COPY_LABEL),
4698                         &names[i], &converted_size);
4699                 if (!ret) {
4700                         TALLOC_FREE(names);
4701                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
4702                 }
4703         }
4704         *pnum_names = num_names;
4705         *pnames = names;
4706         return NT_STATUS_OK;
4707 }
4708
4709 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4710                                 struct cli_state *cli,
4711                                 uint16_t fnum,
4712                                 bool get_names,
4713                                 char ***pnames,
4714                                 int *pnum_names)
4715 {
4716         TALLOC_CTX *frame = talloc_stackframe();
4717         struct tevent_context *ev;
4718         struct tevent_req *req;
4719         NTSTATUS status = NT_STATUS_NO_MEMORY;
4720
4721         if (smbXcli_conn_has_async_calls(cli->conn)) {
4722                 /*
4723                  * Can't use sync call while an async call is in flight
4724                  */
4725                 status = NT_STATUS_INVALID_PARAMETER;
4726                 goto fail;
4727         }
4728         ev = samba_tevent_context_init(frame);
4729         if (ev == NULL) {
4730                 goto fail;
4731         }
4732         req = cli_smb2_shadow_copy_data_fnum_send(frame,
4733                                         ev,
4734                                         cli,
4735                                         fnum,
4736                                         get_names);
4737         if (req == NULL) {
4738                 goto fail;
4739         }
4740         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4741                 goto fail;
4742         }
4743         status = cli_smb2_shadow_copy_data_fnum_recv(req,
4744                                                 mem_ctx,
4745                                                 get_names,
4746                                                 pnames,
4747                                                 pnum_names);
4748  fail:
4749         cli->raw_status = status;
4750
4751         TALLOC_FREE(frame);
4752         return status;
4753 }
4754
4755 /***************************************************************
4756  Wrapper that allows SMB2 to truncate a file.
4757  Synchronous only.
4758 ***************************************************************/
4759
4760 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4761                         uint16_t fnum,
4762                         uint64_t newsize)
4763 {
4764         NTSTATUS status;
4765         uint8_t buf[8] = {0};
4766         DATA_BLOB inbuf = { .data = buf, .length = sizeof(buf) };
4767         TALLOC_CTX *frame = talloc_stackframe();
4768
4769         if (smbXcli_conn_has_async_calls(cli->conn)) {
4770                 /*
4771                  * Can't use sync call while an async call is in flight
4772                  */
4773                 status = NT_STATUS_INVALID_PARAMETER;
4774                 goto fail;
4775         }
4776
4777         SBVAL(buf, 0, newsize);
4778
4779         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4780            level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4781
4782         status = cli_smb2_set_info_fnum(
4783                 cli,
4784                 fnum,
4785                 1, /* in_info_type */
4786                 SMB_FILE_END_OF_FILE_INFORMATION-1000, /* in_file_info_class */
4787                 &inbuf, /* in_input_buffer */
4788                 0);
4789
4790   fail:
4791
4792         cli->raw_status = status;
4793
4794         TALLOC_FREE(frame);
4795         return status;
4796 }
4797
4798 struct cli_smb2_notify_state {
4799         struct tevent_req *subreq;
4800         struct notify_change *changes;
4801         size_t num_changes;
4802 };
4803
4804 static void cli_smb2_notify_done(struct tevent_req *subreq);
4805 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4806
4807 struct tevent_req *cli_smb2_notify_send(
4808         TALLOC_CTX *mem_ctx,
4809         struct tevent_context *ev,
4810         struct cli_state *cli,
4811         uint16_t fnum,
4812         uint32_t buffer_size,
4813         uint32_t completion_filter,
4814         bool recursive)
4815 {
4816         struct tevent_req *req = NULL;
4817         struct cli_smb2_notify_state *state = NULL;
4818         struct smb2_hnd *ph = NULL;
4819         NTSTATUS status;
4820
4821         req = tevent_req_create(mem_ctx, &state,
4822                                 struct cli_smb2_notify_state);
4823         if (req == NULL) {
4824                 return NULL;
4825         }
4826
4827         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4828         if (tevent_req_nterror(req, status)) {
4829                 return tevent_req_post(req, ev);
4830         }
4831
4832         state->subreq = smb2cli_notify_send(
4833                 state,
4834                 ev,
4835                 cli->conn,
4836                 cli->timeout,
4837                 cli->smb2.session,
4838                 cli->smb2.tcon,
4839                 buffer_size,
4840                 ph->fid_persistent,
4841                 ph->fid_volatile,
4842                 completion_filter,
4843                 recursive);
4844         if (tevent_req_nomem(state->subreq, req)) {
4845                 return tevent_req_post(req, ev);
4846         }
4847         tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4848         tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4849         return req;
4850 }
4851
4852 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4853 {
4854         struct cli_smb2_notify_state *state = tevent_req_data(
4855                 req, struct cli_smb2_notify_state);
4856         bool ok;
4857
4858         ok = tevent_req_cancel(state->subreq);
4859         return ok;
4860 }
4861
4862 static void cli_smb2_notify_done(struct tevent_req *subreq)
4863 {
4864         struct tevent_req *req = tevent_req_callback_data(
4865                 subreq, struct tevent_req);
4866         struct cli_smb2_notify_state *state = tevent_req_data(
4867                 req, struct cli_smb2_notify_state);
4868         uint8_t *base;
4869         uint32_t len;
4870         uint32_t ofs;
4871         NTSTATUS status;
4872
4873         status = smb2cli_notify_recv(subreq, state, &base, &len);
4874         TALLOC_FREE(subreq);
4875
4876         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4877                 tevent_req_done(req);
4878                 return;
4879         }
4880         if (tevent_req_nterror(req, status)) {
4881                 return;
4882         }
4883
4884         ofs = 0;
4885
4886         while (len - ofs >= 12) {
4887                 struct notify_change *tmp;
4888                 struct notify_change *c;
4889                 uint32_t next_ofs = IVAL(base, ofs);
4890                 uint32_t file_name_length = IVAL(base, ofs+8);
4891                 size_t namelen;
4892                 bool ok;
4893
4894                 tmp = talloc_realloc(
4895                         state,
4896                         state->changes,
4897                         struct notify_change,
4898                         state->num_changes + 1);
4899                 if (tevent_req_nomem(tmp, req)) {
4900                         return;
4901                 }
4902                 state->changes = tmp;
4903                 c = &state->changes[state->num_changes];
4904                 state->num_changes += 1;
4905
4906                 if (smb_buffer_oob(len, ofs, next_ofs) ||
4907                     smb_buffer_oob(len, ofs+12, file_name_length)) {
4908                         tevent_req_nterror(
4909                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4910                         return;
4911                 }
4912
4913                 c->action = IVAL(base, ofs+4);
4914
4915                 ok = convert_string_talloc(
4916                         state->changes,
4917                         CH_UTF16LE,
4918                         CH_UNIX,
4919                         base + ofs + 12,
4920                         file_name_length,
4921                         &c->name,
4922                         &namelen);
4923                 if (!ok) {
4924                         tevent_req_nterror(
4925                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4926                         return;
4927                 }
4928
4929                 if (next_ofs == 0) {
4930                         break;
4931                 }
4932                 ofs += next_ofs;
4933         }
4934
4935         tevent_req_done(req);
4936 }
4937
4938 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
4939                               TALLOC_CTX *mem_ctx,
4940                               struct notify_change **pchanges,
4941                               uint32_t *pnum_changes)
4942 {
4943         struct cli_smb2_notify_state *state = tevent_req_data(
4944                 req, struct cli_smb2_notify_state);
4945         NTSTATUS status;
4946
4947         if (tevent_req_is_nterror(req, &status)) {
4948                 return status;
4949         }
4950         *pchanges = talloc_move(mem_ctx, &state->changes);
4951         *pnum_changes = state->num_changes;
4952         return NT_STATUS_OK;
4953 }
4954
4955 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
4956                          uint32_t buffer_size, uint32_t completion_filter,
4957                          bool recursive, TALLOC_CTX *mem_ctx,
4958                          struct notify_change **pchanges,
4959                          uint32_t *pnum_changes)
4960 {
4961         TALLOC_CTX *frame = talloc_stackframe();
4962         struct tevent_context *ev;
4963         struct tevent_req *req;
4964         NTSTATUS status = NT_STATUS_NO_MEMORY;
4965
4966         if (smbXcli_conn_has_async_calls(cli->conn)) {
4967                 /*
4968                  * Can't use sync call while an async call is in flight
4969                  */
4970                 status = NT_STATUS_INVALID_PARAMETER;
4971                 goto fail;
4972         }
4973         ev = samba_tevent_context_init(frame);
4974         if (ev == NULL) {
4975                 goto fail;
4976         }
4977         req = cli_smb2_notify_send(
4978                 frame,
4979                 ev,
4980                 cli,
4981                 fnum,
4982                 buffer_size,
4983                 completion_filter,
4984                 recursive);
4985         if (req == NULL) {
4986                 goto fail;
4987         }
4988         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4989                 goto fail;
4990         }
4991         status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
4992 fail:
4993         TALLOC_FREE(frame);
4994         return status;
4995 }
4996
4997 struct cli_smb2_fsctl_state {
4998         DATA_BLOB out;
4999 };
5000
5001 static void cli_smb2_fsctl_done(struct tevent_req *subreq);
5002
5003 struct tevent_req *cli_smb2_fsctl_send(
5004         TALLOC_CTX *mem_ctx,
5005         struct tevent_context *ev,
5006         struct cli_state *cli,
5007         uint16_t fnum,
5008         uint32_t ctl_code,
5009         const DATA_BLOB *in,
5010         uint32_t max_out)
5011 {
5012         struct tevent_req *req = NULL, *subreq = NULL;
5013         struct cli_smb2_fsctl_state *state = NULL;
5014         struct smb2_hnd *ph = NULL;
5015         NTSTATUS status;
5016
5017         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_fsctl_state);
5018         if (req == NULL) {
5019                 return NULL;
5020         }
5021
5022         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
5023         if (tevent_req_nterror(req, status)) {
5024                 return tevent_req_post(req, ev);
5025         }
5026
5027         subreq = smb2cli_ioctl_send(
5028                 state,
5029                 ev,
5030                 cli->conn,
5031                 cli->timeout,
5032                 cli->smb2.session,
5033                 cli->smb2.tcon,
5034                 ph->fid_persistent,
5035                 ph->fid_volatile,
5036                 ctl_code,
5037                 0, /* in_max_input_length */
5038                 in,
5039                 max_out,
5040                 NULL,
5041                 SMB2_IOCTL_FLAG_IS_FSCTL);
5042
5043         if (tevent_req_nomem(subreq, req)) {
5044                 return tevent_req_post(req, ev);
5045         }
5046         tevent_req_set_callback(subreq, cli_smb2_fsctl_done, req);
5047         return req;
5048 }
5049
5050 static void cli_smb2_fsctl_done(struct tevent_req *subreq)
5051 {
5052         struct tevent_req *req = tevent_req_callback_data(
5053                 subreq, struct tevent_req);
5054         struct cli_smb2_fsctl_state *state = tevent_req_data(
5055                 req, struct cli_smb2_fsctl_state);
5056         NTSTATUS status;
5057
5058         status = smb2cli_ioctl_recv(subreq, state, NULL, &state->out);
5059         tevent_req_simple_finish_ntstatus(subreq, status);
5060 }
5061
5062 NTSTATUS cli_smb2_fsctl_recv(
5063         struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *out)
5064 {
5065         struct cli_smb2_fsctl_state *state = tevent_req_data(
5066                 req, struct cli_smb2_fsctl_state);
5067         NTSTATUS status = NT_STATUS_OK;
5068
5069         if (tevent_req_is_nterror(req, &status)) {
5070                 tevent_req_received(req);
5071                 return status;
5072         }
5073
5074         if (state->out.length == 0) {
5075                 *out = (DATA_BLOB) { .data = NULL, };
5076         } else {
5077                 /*
5078                  * Can't use talloc_move() here, the outblobs from
5079                  * smb2cli_ioctl_recv() are not standalone talloc
5080                  * objects but just peek into the larger buffers
5081                  * received, hanging off "state".
5082                  */
5083                 *out = data_blob_talloc(
5084                         mem_ctx, state->out.data, state->out.length);
5085                 if (out->data == NULL) {
5086                         status = NT_STATUS_NO_MEMORY;
5087                 }
5088         }
5089
5090         tevent_req_received(req);
5091         return NT_STATUS_OK;
5092 }