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