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