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