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