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