s3: libsmb: Add cli_smb2_chkpath() and use from cli_chkpath().
[bbaumbach/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 attributes.
1997  Synchronous only.
1998 ***************************************************************/
1999
2000 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2001 {
2002         NTSTATUS status;
2003         uint16_t fnum = 0xffff;
2004         DATA_BLOB outbuf = data_blob_null;
2005         struct smb2_hnd *ph = NULL;
2006         TALLOC_CTX *frame = talloc_stackframe();
2007
2008         if (smbXcli_conn_has_async_calls(cli->conn)) {
2009                 /*
2010                  * Can't use sync call while an async call is in flight
2011                  */
2012                 status = NT_STATUS_INVALID_PARAMETER;
2013                 goto fail;
2014         }
2015
2016         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2017                 status = NT_STATUS_INVALID_PARAMETER;
2018                 goto fail;
2019         }
2020
2021         /* First open the top level directory. */
2022         status =
2023             cli_smb2_create_fnum(cli, "", 0,               /* create_flags */
2024                                  FILE_READ_ATTRIBUTES,     /* desired_access */
2025                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2026                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
2027                                      FILE_SHARE_DELETE, /* share_access */
2028                                  FILE_OPEN,             /* create_disposition */
2029                                  FILE_DIRECTORY_FILE,   /* create_options */
2030                                  &fnum,
2031                                  NULL);
2032
2033         if (!NT_STATUS_IS_OK(status)) {
2034                 goto fail;
2035         }
2036
2037         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2038         if (!NT_STATUS_IS_OK(status)) {
2039                 goto fail;
2040         }
2041
2042         status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2043                                     cli->smb2.tcon, 2, /* in_info_type */
2044                                     5,                 /* in_file_info_class */
2045                                     0xFFFF, /* in_max_output_length */
2046                                     NULL,   /* in_input_buffer */
2047                                     0,      /* in_additional_info */
2048                                     0,      /* in_flags */
2049                                     ph->fid_persistent, ph->fid_volatile, frame,
2050                                     &outbuf);
2051         if (!NT_STATUS_IS_OK(status)) {
2052                 goto fail;
2053         }
2054
2055         if (outbuf.length < 12) {
2056                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2057                 goto fail;
2058         }
2059
2060         *fs_attr = IVAL(outbuf.data, 0);
2061
2062 fail:
2063
2064         if (fnum != 0xffff) {
2065                 cli_smb2_close_fnum(cli, fnum);
2066         }
2067
2068         cli->raw_status = status;
2069
2070         TALLOC_FREE(frame);
2071         return status;
2072 }
2073
2074 /***************************************************************
2075  Wrapper that allows SMB2 to query a security descriptor.
2076  Synchronous only.
2077 ***************************************************************/
2078
2079 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2080                                         uint16_t fnum,
2081                                         uint32_t sec_info,
2082                                         TALLOC_CTX *mem_ctx,
2083                                         struct security_descriptor **ppsd)
2084 {
2085         NTSTATUS status;
2086         DATA_BLOB outbuf = data_blob_null;
2087         struct smb2_hnd *ph = NULL;
2088         struct security_descriptor *lsd = NULL;
2089         TALLOC_CTX *frame = talloc_stackframe();
2090
2091         if (smbXcli_conn_has_async_calls(cli->conn)) {
2092                 /*
2093                  * Can't use sync call while an async call is in flight
2094                  */
2095                 status = NT_STATUS_INVALID_PARAMETER;
2096                 goto fail;
2097         }
2098
2099         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2100                 status = NT_STATUS_INVALID_PARAMETER;
2101                 goto fail;
2102         }
2103
2104         status = map_fnum_to_smb2_handle(cli,
2105                                         fnum,
2106                                         &ph);
2107         if (!NT_STATUS_IS_OK(status)) {
2108                 goto fail;
2109         }
2110
2111         /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2112
2113         status = smb2cli_query_info(cli->conn,
2114                                 cli->timeout,
2115                                 cli->smb2.session,
2116                                 cli->smb2.tcon,
2117                                 3, /* in_info_type */
2118                                 0, /* in_file_info_class */
2119                                 0xFFFF, /* in_max_output_length */
2120                                 NULL, /* in_input_buffer */
2121                                 sec_info, /* in_additional_info */
2122                                 0, /* in_flags */
2123                                 ph->fid_persistent,
2124                                 ph->fid_volatile,
2125                                 frame,
2126                                 &outbuf);
2127
2128         if (!NT_STATUS_IS_OK(status)) {
2129                 goto fail;
2130         }
2131
2132         /* Parse the reply. */
2133         status = unmarshall_sec_desc(mem_ctx,
2134                                 outbuf.data,
2135                                 outbuf.length,
2136                                 &lsd);
2137
2138         if (!NT_STATUS_IS_OK(status)) {
2139                 goto fail;
2140         }
2141
2142         if (ppsd != NULL) {
2143                 *ppsd = lsd;
2144         } else {
2145                 TALLOC_FREE(lsd);
2146         }
2147
2148   fail:
2149
2150         cli->raw_status = status;
2151
2152         TALLOC_FREE(frame);
2153         return status;
2154 }
2155
2156 /***************************************************************
2157  Wrapper that allows SMB2 to set a security descriptor.
2158  Synchronous only.
2159 ***************************************************************/
2160
2161 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
2162                                         uint16_t fnum,
2163                                         uint32_t sec_info,
2164                                         const struct security_descriptor *sd)
2165 {
2166         NTSTATUS status;
2167         DATA_BLOB inbuf = data_blob_null;
2168         struct smb2_hnd *ph = NULL;
2169         TALLOC_CTX *frame = talloc_stackframe();
2170
2171         if (smbXcli_conn_has_async_calls(cli->conn)) {
2172                 /*
2173                  * Can't use sync call while an async call is in flight
2174                  */
2175                 status = NT_STATUS_INVALID_PARAMETER;
2176                 goto fail;
2177         }
2178
2179         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2180                 status = NT_STATUS_INVALID_PARAMETER;
2181                 goto fail;
2182         }
2183
2184         status = map_fnum_to_smb2_handle(cli,
2185                                         fnum,
2186                                         &ph);
2187         if (!NT_STATUS_IS_OK(status)) {
2188                 goto fail;
2189         }
2190
2191         status = marshall_sec_desc(frame,
2192                                 sd,
2193                                 &inbuf.data,
2194                                 &inbuf.length);
2195
2196         if (!NT_STATUS_IS_OK(status)) {
2197                 goto fail;
2198         }
2199
2200         /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2201
2202         status = smb2cli_set_info(cli->conn,
2203                                 cli->timeout,
2204                                 cli->smb2.session,
2205                                 cli->smb2.tcon,
2206                                 3, /* in_info_type */
2207                                 0, /* in_file_info_class */
2208                                 &inbuf, /* in_input_buffer */
2209                                 sec_info, /* in_additional_info */
2210                                 ph->fid_persistent,
2211                                 ph->fid_volatile);
2212
2213   fail:
2214
2215         cli->raw_status = status;
2216
2217         TALLOC_FREE(frame);
2218         return status;
2219 }
2220
2221 /***************************************************************
2222  Wrapper that allows SMB2 to rename a file.
2223  Synchronous only.
2224 ***************************************************************/
2225
2226 NTSTATUS cli_smb2_rename(struct cli_state *cli,
2227                          const char *fname_src,
2228                          const char *fname_dst,
2229                          bool replace)
2230 {
2231         NTSTATUS status;
2232         DATA_BLOB inbuf = data_blob_null;
2233         uint16_t fnum = 0xffff;
2234         struct smb2_hnd *ph = NULL;
2235         smb_ucs2_t *converted_str = NULL;
2236         size_t converted_size_bytes = 0;
2237         size_t namelen = 0;
2238         TALLOC_CTX *frame = talloc_stackframe();
2239
2240         if (smbXcli_conn_has_async_calls(cli->conn)) {
2241                 /*
2242                  * Can't use sync call while an async call is in flight
2243                  */
2244                 status = NT_STATUS_INVALID_PARAMETER;
2245                 goto fail;
2246         }
2247
2248         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2249                 status = NT_STATUS_INVALID_PARAMETER;
2250                 goto fail;
2251         }
2252
2253         status = get_fnum_from_path(cli,
2254                                 fname_src,
2255                                 DELETE_ACCESS,
2256                                 &fnum);
2257
2258         if (!NT_STATUS_IS_OK(status)) {
2259                 goto fail;
2260         }
2261
2262         status = map_fnum_to_smb2_handle(cli,
2263                                         fnum,
2264                                         &ph);
2265         if (!NT_STATUS_IS_OK(status)) {
2266                 goto fail;
2267         }
2268
2269         /* SMB2 is pickier about pathnames. Ensure it doesn't
2270            start in a '\' */
2271         if (*fname_dst == '\\') {
2272                 fname_dst++;
2273         }
2274
2275         /* SMB2 is pickier about pathnames. Ensure it doesn't
2276            end in a '\' */
2277         namelen = strlen(fname_dst);
2278         if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2279                 char *modname = talloc_strdup(frame, fname_dst);
2280                 modname[namelen-1] = '\0';
2281                 fname_dst = modname;
2282         }
2283
2284         if (!push_ucs2_talloc(frame,
2285                                 &converted_str,
2286                                 fname_dst,
2287                                 &converted_size_bytes)) {
2288                 status = NT_STATUS_INVALID_PARAMETER;
2289                 goto fail;
2290         }
2291
2292         /* W2K8 insists the dest name is not null
2293            terminated. Remove the last 2 zero bytes
2294            and reduce the name length. */
2295
2296         if (converted_size_bytes < 2) {
2297                 status = NT_STATUS_INVALID_PARAMETER;
2298                 goto fail;
2299         }
2300         converted_size_bytes -= 2;
2301
2302         inbuf = data_blob_talloc_zero(frame,
2303                                 20 + converted_size_bytes);
2304         if (inbuf.data == NULL) {
2305                 status = NT_STATUS_NO_MEMORY;
2306                 goto fail;
2307         }
2308
2309         if (replace) {
2310                 SCVAL(inbuf.data, 0, 1);
2311         }
2312
2313         SIVAL(inbuf.data, 16, converted_size_bytes);
2314         memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2315
2316         /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2317            level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2318
2319         status = smb2cli_set_info(cli->conn,
2320                                 cli->timeout,
2321                                 cli->smb2.session,
2322                                 cli->smb2.tcon,
2323                                 1, /* in_info_type */
2324                                 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2325                                 &inbuf, /* in_input_buffer */
2326                                 0, /* in_additional_info */
2327                                 ph->fid_persistent,
2328                                 ph->fid_volatile);
2329
2330   fail:
2331
2332         if (fnum != 0xffff) {
2333                 cli_smb2_close_fnum(cli, fnum);
2334         }
2335
2336         cli->raw_status = status;
2337
2338         TALLOC_FREE(frame);
2339         return status;
2340 }
2341
2342 /***************************************************************
2343  Wrapper that allows SMB2 to set an EA on a fnum.
2344  Synchronous only.
2345 ***************************************************************/
2346
2347 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2348                         uint16_t fnum,
2349                         const char *ea_name,
2350                         const char *ea_val,
2351                         size_t ea_len)
2352 {
2353         NTSTATUS status;
2354         DATA_BLOB inbuf = data_blob_null;
2355         size_t bloblen = 0;
2356         char *ea_name_ascii = NULL;
2357         size_t namelen = 0;
2358         struct smb2_hnd *ph = NULL;
2359         TALLOC_CTX *frame = talloc_stackframe();
2360
2361         if (smbXcli_conn_has_async_calls(cli->conn)) {
2362                 /*
2363                  * Can't use sync call while an async call is in flight
2364                  */
2365                 status = NT_STATUS_INVALID_PARAMETER;
2366                 goto fail;
2367         }
2368
2369         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2370                 status = NT_STATUS_INVALID_PARAMETER;
2371                 goto fail;
2372         }
2373
2374         status = map_fnum_to_smb2_handle(cli,
2375                                         fnum,
2376                                         &ph);
2377         if (!NT_STATUS_IS_OK(status)) {
2378                 goto fail;
2379         }
2380
2381         /* Marshall the SMB2 EA data. */
2382         if (ea_len > 0xFFFF) {
2383                 status = NT_STATUS_INVALID_PARAMETER;
2384                 goto fail;
2385         }
2386
2387         if (!push_ascii_talloc(frame,
2388                                 &ea_name_ascii,
2389                                 ea_name,
2390                                 &namelen)) {
2391                 status = NT_STATUS_INVALID_PARAMETER;
2392                 goto fail;
2393         }
2394
2395         if (namelen < 2 || namelen > 0xFF) {
2396                 status = NT_STATUS_INVALID_PARAMETER;
2397                 goto fail;
2398         }
2399
2400         bloblen = 8 + ea_len + namelen;
2401         /* Round up to a 4 byte boundary. */
2402         bloblen = ((bloblen + 3)&~3);
2403
2404         inbuf = data_blob_talloc_zero(frame, bloblen);
2405         if (inbuf.data == NULL) {
2406                 status = NT_STATUS_NO_MEMORY;
2407                 goto fail;
2408         }
2409         /* namelen doesn't include the NULL byte. */
2410         SCVAL(inbuf.data, 5, namelen - 1);
2411         SSVAL(inbuf.data, 6, ea_len);
2412         memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2413         memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2414
2415         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2416            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2417
2418         status = smb2cli_set_info(cli->conn,
2419                                 cli->timeout,
2420                                 cli->smb2.session,
2421                                 cli->smb2.tcon,
2422                                 1, /* in_info_type */
2423                                 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2424                                 &inbuf, /* in_input_buffer */
2425                                 0, /* in_additional_info */
2426                                 ph->fid_persistent,
2427                                 ph->fid_volatile);
2428
2429   fail:
2430
2431         cli->raw_status = status;
2432
2433         TALLOC_FREE(frame);
2434         return status;
2435 }
2436
2437 /***************************************************************
2438  Wrapper that allows SMB2 to set an EA on a pathname.
2439  Synchronous only.
2440 ***************************************************************/
2441
2442 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2443                         const char *name,
2444                         const char *ea_name,
2445                         const char *ea_val,
2446                         size_t ea_len)
2447 {
2448         NTSTATUS status;
2449         uint16_t fnum = 0xffff;
2450
2451         if (smbXcli_conn_has_async_calls(cli->conn)) {
2452                 /*
2453                  * Can't use sync call while an async call is in flight
2454                  */
2455                 status = NT_STATUS_INVALID_PARAMETER;
2456                 goto fail;
2457         }
2458
2459         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2460                 status = NT_STATUS_INVALID_PARAMETER;
2461                 goto fail;
2462         }
2463
2464         status = get_fnum_from_path(cli,
2465                                 name,
2466                                 FILE_WRITE_EA,
2467                                 &fnum);
2468
2469         if (!NT_STATUS_IS_OK(status)) {
2470                 goto fail;
2471         }
2472
2473         status = cli_set_ea_fnum(cli,
2474                                 fnum,
2475                                 ea_name,
2476                                 ea_val,
2477                                 ea_len);
2478         if (!NT_STATUS_IS_OK(status)) {
2479                 goto fail;
2480         }
2481
2482   fail:
2483
2484         if (fnum != 0xffff) {
2485                 cli_smb2_close_fnum(cli, fnum);
2486         }
2487
2488         cli->raw_status = status;
2489
2490         return status;
2491 }
2492
2493 /***************************************************************
2494  Wrapper that allows SMB2 to get an EA list on a pathname.
2495  Synchronous only.
2496 ***************************************************************/
2497
2498 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2499                                 const char *name,
2500                                 TALLOC_CTX *ctx,
2501                                 size_t *pnum_eas,
2502                                 struct ea_struct **pea_array)
2503 {
2504         NTSTATUS status;
2505         uint16_t fnum = 0xffff;
2506         DATA_BLOB outbuf = data_blob_null;
2507         struct smb2_hnd *ph = NULL;
2508         struct ea_list *ea_list = NULL;
2509         struct ea_list *eal = NULL;
2510         size_t ea_count = 0;
2511         TALLOC_CTX *frame = talloc_stackframe();
2512
2513         *pnum_eas = 0;
2514         *pea_array = NULL;
2515
2516         if (smbXcli_conn_has_async_calls(cli->conn)) {
2517                 /*
2518                  * Can't use sync call while an async call is in flight
2519                  */
2520                 status = NT_STATUS_INVALID_PARAMETER;
2521                 goto fail;
2522         }
2523
2524         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2525                 status = NT_STATUS_INVALID_PARAMETER;
2526                 goto fail;
2527         }
2528
2529         status = get_fnum_from_path(cli,
2530                                 name,
2531                                 FILE_READ_EA,
2532                                 &fnum);
2533
2534         if (!NT_STATUS_IS_OK(status)) {
2535                 goto fail;
2536         }
2537
2538         status = map_fnum_to_smb2_handle(cli,
2539                                         fnum,
2540                                         &ph);
2541         if (!NT_STATUS_IS_OK(status)) {
2542                 goto fail;
2543         }
2544
2545         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2546            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2547
2548         status = smb2cli_query_info(cli->conn,
2549                                 cli->timeout,
2550                                 cli->smb2.session,
2551                                 cli->smb2.tcon,
2552                                 1, /* in_info_type */
2553                                 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2554                                 0xFFFF, /* in_max_output_length */
2555                                 NULL, /* in_input_buffer */
2556                                 0, /* in_additional_info */
2557                                 0, /* in_flags */
2558                                 ph->fid_persistent,
2559                                 ph->fid_volatile,
2560                                 frame,
2561                                 &outbuf);
2562
2563         if (!NT_STATUS_IS_OK(status)) {
2564                 goto fail;
2565         }
2566
2567         /* Parse the reply. */
2568         ea_list = read_nttrans_ea_list(ctx,
2569                                 (const char *)outbuf.data,
2570                                 outbuf.length);
2571         if (ea_list == NULL) {
2572                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2573                 goto fail;
2574         }
2575
2576         /* Convert to an array. */
2577         for (eal = ea_list; eal; eal = eal->next) {
2578                 ea_count++;
2579         }
2580
2581         if (ea_count) {
2582                 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2583                 if (*pea_array == NULL) {
2584                         status = NT_STATUS_NO_MEMORY;
2585                         goto fail;
2586                 }
2587                 ea_count = 0;
2588                 for (eal = ea_list; eal; eal = eal->next) {
2589                         (*pea_array)[ea_count++] = eal->ea;
2590                 }
2591                 *pnum_eas = ea_count;
2592         }
2593
2594   fail:
2595
2596         if (fnum != 0xffff) {
2597                 cli_smb2_close_fnum(cli, fnum);
2598         }
2599
2600         cli->raw_status = status;
2601
2602         TALLOC_FREE(frame);
2603         return status;
2604 }
2605
2606 /***************************************************************
2607  Wrapper that allows SMB2 to get user quota.
2608  Synchronous only.
2609 ***************************************************************/
2610
2611 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
2612                                  int quota_fnum,
2613                                  SMB_NTQUOTA_STRUCT *pqt)
2614 {
2615         NTSTATUS status;
2616         DATA_BLOB inbuf = data_blob_null;
2617         DATA_BLOB outbuf = data_blob_null;
2618         struct smb2_hnd *ph = NULL;
2619         TALLOC_CTX *frame = talloc_stackframe();
2620         unsigned sid_len;
2621         unsigned int offset;
2622         uint8_t *buf;
2623
2624         if (smbXcli_conn_has_async_calls(cli->conn)) {
2625                 /*
2626                  * Can't use sync call while an async call is in flight
2627                  */
2628                 status = NT_STATUS_INVALID_PARAMETER;
2629                 goto fail;
2630         }
2631
2632         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2633                 status = NT_STATUS_INVALID_PARAMETER;
2634                 goto fail;
2635         }
2636
2637         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2638         if (!NT_STATUS_IS_OK(status)) {
2639                 goto fail;
2640         }
2641
2642         sid_len = ndr_size_dom_sid(&pqt->sid, 0);
2643
2644         inbuf = data_blob_talloc_zero(frame, 24 + sid_len);
2645         if (inbuf.data == NULL) {
2646                 status = NT_STATUS_NO_MEMORY;
2647                 goto fail;
2648         }
2649
2650         buf = inbuf.data;
2651
2652         SCVAL(buf, 0, 1);          /* ReturnSingle */
2653         SCVAL(buf, 1, 0);          /* RestartScan */
2654         SSVAL(buf, 2, 0);          /* Reserved */
2655         if (8 + sid_len < 8) {
2656                 status = NT_STATUS_INVALID_PARAMETER;
2657                 goto fail;
2658         }
2659         SIVAL(buf, 4, 8 + sid_len); /* SidListLength */
2660         SIVAL(buf, 8, 0);          /* StartSidLength */
2661         SIVAL(buf, 12, 0);        /* StartSidOffset */
2662         SIVAL(buf, 16, 0);        /* NextEntryOffset */
2663         SIVAL(buf, 20, sid_len);    /* SidLength */
2664         sid_linearize(buf + 24, sid_len, &pqt->sid);
2665
2666         status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2667                                     cli->smb2.tcon, 4, /* in_info_type */
2668                                     0,                 /* in_file_info_class */
2669                                     0xFFFF, /* in_max_output_length */
2670                                     &inbuf, /* in_input_buffer */
2671                                     0,      /* in_additional_info */
2672                                     0,      /* in_flags */
2673                                     ph->fid_persistent, ph->fid_volatile, frame,
2674                                     &outbuf);
2675
2676         if (!NT_STATUS_IS_OK(status)) {
2677                 goto fail;
2678         }
2679
2680         if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
2681                                      pqt)) {
2682                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2683                 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
2684         }
2685
2686 fail:
2687         cli->raw_status = status;
2688
2689         TALLOC_FREE(frame);
2690         return status;
2691 }
2692
2693 /***************************************************************
2694  Wrapper that allows SMB2 to list user quota.
2695  Synchronous only.
2696 ***************************************************************/
2697
2698 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
2699                                        TALLOC_CTX *mem_ctx,
2700                                        int quota_fnum,
2701                                        SMB_NTQUOTA_LIST **pqt_list,
2702                                        bool first)
2703 {
2704         NTSTATUS status;
2705         DATA_BLOB inbuf = data_blob_null;
2706         DATA_BLOB outbuf = data_blob_null;
2707         struct smb2_hnd *ph = NULL;
2708         TALLOC_CTX *frame = talloc_stackframe();
2709         uint8_t *buf;
2710
2711         if (smbXcli_conn_has_async_calls(cli->conn)) {
2712                 /*
2713                  * Can't use sync call while an async call is in flight
2714                  */
2715                 status = NT_STATUS_INVALID_PARAMETER;
2716                 goto cleanup;
2717         }
2718
2719         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2720                 status = NT_STATUS_INVALID_PARAMETER;
2721                 goto cleanup;
2722         }
2723
2724         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2725         if (!NT_STATUS_IS_OK(status)) {
2726                 goto cleanup;
2727         }
2728
2729         inbuf = data_blob_talloc_zero(frame, 16);
2730         if (inbuf.data == NULL) {
2731                 status = NT_STATUS_NO_MEMORY;
2732                 goto cleanup;
2733         }
2734
2735         buf = inbuf.data;
2736
2737         SCVAL(buf, 0, 0);            /* ReturnSingle */
2738         SCVAL(buf, 1, first ? 1 : 0); /* RestartScan */
2739         SSVAL(buf, 2, 0);            /* Reserved */
2740         SIVAL(buf, 4, 0);            /* SidListLength */
2741         SIVAL(buf, 8, 0);            /* StartSidLength */
2742         SIVAL(buf, 12, 0);          /* StartSidOffset */
2743
2744         status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2745                                     cli->smb2.tcon, 4, /* in_info_type */
2746                                     0,                 /* in_file_info_class */
2747                                     0xFFFF, /* in_max_output_length */
2748                                     &inbuf, /* in_input_buffer */
2749                                     0,      /* in_additional_info */
2750                                     0,      /* in_flags */
2751                                     ph->fid_persistent, ph->fid_volatile, frame,
2752                                     &outbuf);
2753
2754         if (!NT_STATUS_IS_OK(status)) {
2755                 goto cleanup;
2756         }
2757
2758         status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
2759                                        pqt_list);
2760
2761 cleanup:
2762         cli->raw_status = status;
2763
2764         TALLOC_FREE(frame);
2765         return status;
2766 }
2767
2768 /***************************************************************
2769  Wrapper that allows SMB2 to get file system quota.
2770  Synchronous only.
2771 ***************************************************************/
2772
2773 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
2774                                     int quota_fnum,
2775                                     SMB_NTQUOTA_STRUCT *pqt)
2776 {
2777         NTSTATUS status;
2778         DATA_BLOB outbuf = data_blob_null;
2779         struct smb2_hnd *ph = NULL;
2780         TALLOC_CTX *frame = talloc_stackframe();
2781
2782         if (smbXcli_conn_has_async_calls(cli->conn)) {
2783                 /*
2784                  * Can't use sync call while an async call is in flight
2785                  */
2786                 status = NT_STATUS_INVALID_PARAMETER;
2787                 goto cleanup;
2788         }
2789
2790         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2791                 status = NT_STATUS_INVALID_PARAMETER;
2792                 goto cleanup;
2793         }
2794
2795         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2796         if (!NT_STATUS_IS_OK(status)) {
2797                 goto cleanup;
2798         }
2799
2800         status = smb2cli_query_info(
2801             cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
2802             2,                               /* in_info_type */
2803             SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
2804             0xFFFF,                          /* in_max_output_length */
2805             NULL,                            /* in_input_buffer */
2806             0,                               /* in_additional_info */
2807             0,                               /* in_flags */
2808             ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
2809
2810         if (!NT_STATUS_IS_OK(status)) {
2811                 goto cleanup;
2812         }
2813
2814         status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
2815
2816 cleanup:
2817         cli->raw_status = status;
2818
2819         TALLOC_FREE(frame);
2820         return status;
2821 }
2822
2823 /***************************************************************
2824  Wrapper that allows SMB2 to set user quota.
2825  Synchronous only.
2826 ***************************************************************/
2827
2828 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
2829                                  int quota_fnum,
2830                                  SMB_NTQUOTA_LIST *qtl)
2831 {
2832         NTSTATUS status;
2833         DATA_BLOB inbuf = data_blob_null;
2834         struct smb2_hnd *ph = NULL;
2835         TALLOC_CTX *frame = talloc_stackframe();
2836
2837         if (smbXcli_conn_has_async_calls(cli->conn)) {
2838                 /*
2839                  * Can't use sync call while an async call is in flight
2840                  */
2841                 status = NT_STATUS_INVALID_PARAMETER;
2842                 goto cleanup;
2843         }
2844
2845         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2846                 status = NT_STATUS_INVALID_PARAMETER;
2847                 goto cleanup;
2848         }
2849
2850         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2851         if (!NT_STATUS_IS_OK(status)) {
2852                 goto cleanup;
2853         }
2854
2855         status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
2856         if (!NT_STATUS_IS_OK(status)) {
2857                 goto cleanup;
2858         }
2859
2860         status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
2861                                   cli->smb2.tcon, 4, /* in_info_type */
2862                                   0,                 /* in_file_info_class */
2863                                   &inbuf,           /* in_input_buffer */
2864                                   0,                 /* in_additional_info */
2865                                   ph->fid_persistent, ph->fid_volatile);
2866 cleanup:
2867
2868         cli->raw_status = status;
2869
2870         TALLOC_FREE(frame);
2871
2872         return status;
2873 }
2874
2875 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
2876                                     int quota_fnum,
2877                                     SMB_NTQUOTA_STRUCT *pqt)
2878 {
2879         NTSTATUS status;
2880         DATA_BLOB inbuf = data_blob_null;
2881         struct smb2_hnd *ph = NULL;
2882         TALLOC_CTX *frame = talloc_stackframe();
2883
2884         if (smbXcli_conn_has_async_calls(cli->conn)) {
2885                 /*
2886                  * Can't use sync call while an async call is in flight
2887                  */
2888                 status = NT_STATUS_INVALID_PARAMETER;
2889                 goto cleanup;
2890         }
2891
2892         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2893                 status = NT_STATUS_INVALID_PARAMETER;
2894                 goto cleanup;
2895         }
2896
2897         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2898         if (!NT_STATUS_IS_OK(status)) {
2899                 goto cleanup;
2900         }
2901
2902         status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
2903         if (!NT_STATUS_IS_OK(status)) {
2904                 goto cleanup;
2905         }
2906
2907         status = smb2cli_set_info(
2908             cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
2909             2,                               /* in_info_type */
2910             SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
2911             &inbuf,                          /* in_input_buffer */
2912             0,                               /* in_additional_info */
2913             ph->fid_persistent, ph->fid_volatile);
2914 cleanup:
2915         cli->raw_status = status;
2916
2917         TALLOC_FREE(frame);
2918         return status;
2919 }
2920
2921 struct cli_smb2_read_state {
2922         struct tevent_context *ev;
2923         struct cli_state *cli;
2924         struct smb2_hnd *ph;
2925         uint64_t start_offset;
2926         uint32_t size;
2927         uint32_t received;
2928         uint8_t *buf;
2929 };
2930
2931 static void cli_smb2_read_done(struct tevent_req *subreq);
2932
2933 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
2934                                 struct tevent_context *ev,
2935                                 struct cli_state *cli,
2936                                 uint16_t fnum,
2937                                 off_t offset,
2938                                 size_t size)
2939 {
2940         NTSTATUS status;
2941         struct tevent_req *req, *subreq;
2942         struct cli_smb2_read_state *state;
2943
2944         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
2945         if (req == NULL) {
2946                 return NULL;
2947         }
2948         state->ev = ev;
2949         state->cli = cli;
2950         state->start_offset = (uint64_t)offset;
2951         state->size = (uint32_t)size;
2952         state->received = 0;
2953         state->buf = NULL;
2954
2955         status = map_fnum_to_smb2_handle(cli,
2956                                         fnum,
2957                                         &state->ph);
2958         if (tevent_req_nterror(req, status)) {
2959                 return tevent_req_post(req, ev);
2960         }
2961
2962         subreq = smb2cli_read_send(state,
2963                                 state->ev,
2964                                 state->cli->conn,
2965                                 state->cli->timeout,
2966                                 state->cli->smb2.session,
2967                                 state->cli->smb2.tcon,
2968                                 state->size,
2969                                 state->start_offset,
2970                                 state->ph->fid_persistent,
2971                                 state->ph->fid_volatile,
2972                                 0, /* minimum_count */
2973                                 0); /* remaining_bytes */
2974
2975         if (tevent_req_nomem(subreq, req)) {
2976                 return tevent_req_post(req, ev);
2977         }
2978         tevent_req_set_callback(subreq, cli_smb2_read_done, req);
2979         return req;
2980 }
2981
2982 static void cli_smb2_read_done(struct tevent_req *subreq)
2983 {
2984         struct tevent_req *req = tevent_req_callback_data(
2985                 subreq, struct tevent_req);
2986         struct cli_smb2_read_state *state = tevent_req_data(
2987                 req, struct cli_smb2_read_state);
2988         NTSTATUS status;
2989
2990         status = smb2cli_read_recv(subreq, state,
2991                                    &state->buf, &state->received);
2992         if (tevent_req_nterror(req, status)) {
2993                 return;
2994         }
2995
2996         if (state->received > state->size) {
2997                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2998                 return;
2999         }
3000
3001         tevent_req_done(req);
3002 }
3003
3004 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
3005                                 ssize_t *received,
3006                                 uint8_t **rcvbuf)
3007 {
3008         NTSTATUS status;
3009         struct cli_smb2_read_state *state = tevent_req_data(
3010                                 req, struct cli_smb2_read_state);
3011
3012         if (tevent_req_is_nterror(req, &status)) {
3013                 state->cli->raw_status = status;
3014                 return status;
3015         }
3016         /*
3017          * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3018          * better make sure that you copy it away before you talloc_free(req).
3019          * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3020          */
3021         *received = (ssize_t)state->received;
3022         *rcvbuf = state->buf;
3023         state->cli->raw_status = NT_STATUS_OK;
3024         return NT_STATUS_OK;
3025 }
3026
3027 struct cli_smb2_write_state {
3028         struct tevent_context *ev;
3029         struct cli_state *cli;
3030         struct smb2_hnd *ph;
3031         uint32_t flags;
3032         const uint8_t *buf;
3033         uint64_t offset;
3034         uint32_t size;
3035         uint32_t written;
3036 };
3037
3038 static void cli_smb2_write_written(struct tevent_req *req);
3039
3040 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
3041                                         struct tevent_context *ev,
3042                                         struct cli_state *cli,
3043                                         uint16_t fnum,
3044                                         uint16_t mode,
3045                                         const uint8_t *buf,
3046                                         off_t offset,
3047                                         size_t size)
3048 {
3049         NTSTATUS status;
3050         struct tevent_req *req, *subreq = NULL;
3051         struct cli_smb2_write_state *state = NULL;
3052
3053         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
3054         if (req == NULL) {
3055                 return NULL;
3056         }
3057         state->ev = ev;
3058         state->cli = cli;
3059         /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3060         state->flags = (uint32_t)mode;
3061         state->buf = buf;
3062         state->offset = (uint64_t)offset;
3063         state->size = (uint32_t)size;
3064         state->written = 0;
3065
3066         status = map_fnum_to_smb2_handle(cli,
3067                                         fnum,
3068                                         &state->ph);
3069         if (tevent_req_nterror(req, status)) {
3070                 return tevent_req_post(req, ev);
3071         }
3072
3073         subreq = smb2cli_write_send(state,
3074                                 state->ev,
3075                                 state->cli->conn,
3076                                 state->cli->timeout,
3077                                 state->cli->smb2.session,
3078                                 state->cli->smb2.tcon,
3079                                 state->size,
3080                                 state->offset,
3081                                 state->ph->fid_persistent,
3082                                 state->ph->fid_volatile,
3083                                 0, /* remaining_bytes */
3084                                 state->flags, /* flags */
3085                                 state->buf);
3086
3087         if (tevent_req_nomem(subreq, req)) {
3088                 return tevent_req_post(req, ev);
3089         }
3090         tevent_req_set_callback(subreq, cli_smb2_write_written, req);
3091         return req;
3092 }
3093
3094 static void cli_smb2_write_written(struct tevent_req *subreq)
3095 {
3096         struct tevent_req *req = tevent_req_callback_data(
3097                 subreq, struct tevent_req);
3098         struct cli_smb2_write_state *state = tevent_req_data(
3099                 req, struct cli_smb2_write_state);
3100         NTSTATUS status;
3101         uint32_t written;
3102
3103         status = smb2cli_write_recv(subreq, &written);
3104         TALLOC_FREE(subreq);
3105         if (tevent_req_nterror(req, status)) {
3106                 return;
3107         }
3108
3109         state->written = written;
3110
3111         tevent_req_done(req);
3112 }
3113
3114 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
3115                              size_t *pwritten)
3116 {
3117         struct cli_smb2_write_state *state = tevent_req_data(
3118                 req, struct cli_smb2_write_state);
3119         NTSTATUS status;
3120
3121         if (tevent_req_is_nterror(req, &status)) {
3122                 state->cli->raw_status = status;
3123                 tevent_req_received(req);
3124                 return status;
3125         }
3126
3127         if (pwritten != NULL) {
3128                 *pwritten = (size_t)state->written;
3129         }
3130         state->cli->raw_status = NT_STATUS_OK;
3131         tevent_req_received(req);
3132         return NT_STATUS_OK;
3133 }
3134
3135 /***************************************************************
3136  Wrapper that allows SMB2 async write using an fnum.
3137  This is mostly cut-and-paste from Volker's code inside
3138  source3/libsmb/clireadwrite.c, adapted for SMB2.
3139
3140  Done this way so I can reuse all the logic inside cli_push()
3141  for free :-).
3142 ***************************************************************/
3143
3144 struct cli_smb2_writeall_state {
3145         struct tevent_context *ev;
3146         struct cli_state *cli;
3147         struct smb2_hnd *ph;
3148         uint32_t flags;
3149         const uint8_t *buf;
3150         uint64_t offset;
3151         uint32_t size;
3152         uint32_t written;
3153 };
3154
3155 static void cli_smb2_writeall_written(struct tevent_req *req);
3156
3157 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
3158                                         struct tevent_context *ev,
3159                                         struct cli_state *cli,
3160                                         uint16_t fnum,
3161                                         uint16_t mode,
3162                                         const uint8_t *buf,
3163                                         off_t offset,
3164                                         size_t size)
3165 {
3166         NTSTATUS status;
3167         struct tevent_req *req, *subreq = NULL;
3168         struct cli_smb2_writeall_state *state = NULL;
3169         uint32_t to_write;
3170         uint32_t max_size;
3171         bool ok;
3172
3173         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
3174         if (req == NULL) {
3175                 return NULL;
3176         }
3177         state->ev = ev;
3178         state->cli = cli;
3179         /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3180         state->flags = (uint32_t)mode;
3181         state->buf = buf;
3182         state->offset = (uint64_t)offset;
3183         state->size = (uint32_t)size;
3184         state->written = 0;
3185
3186         status = map_fnum_to_smb2_handle(cli,
3187                                         fnum,
3188                                         &state->ph);
3189         if (tevent_req_nterror(req, status)) {
3190                 return tevent_req_post(req, ev);
3191         }
3192
3193         to_write = state->size;
3194         max_size = smb2cli_conn_max_write_size(state->cli->conn);
3195         to_write = MIN(max_size, to_write);
3196         ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3197         if (ok) {
3198                 to_write = MIN(max_size, to_write);
3199         }
3200
3201         subreq = smb2cli_write_send(state,
3202                                 state->ev,
3203                                 state->cli->conn,
3204                                 state->cli->timeout,
3205                                 state->cli->smb2.session,
3206                                 state->cli->smb2.tcon,
3207                                 to_write,
3208                                 state->offset,
3209                                 state->ph->fid_persistent,
3210                                 state->ph->fid_volatile,
3211                                 0, /* remaining_bytes */
3212                                 state->flags, /* flags */
3213                                 state->buf + state->written);
3214
3215         if (tevent_req_nomem(subreq, req)) {
3216                 return tevent_req_post(req, ev);
3217         }
3218         tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3219         return req;
3220 }
3221
3222 static void cli_smb2_writeall_written(struct tevent_req *subreq)
3223 {
3224         struct tevent_req *req = tevent_req_callback_data(
3225                 subreq, struct tevent_req);
3226         struct cli_smb2_writeall_state *state = tevent_req_data(
3227                 req, struct cli_smb2_writeall_state);
3228         NTSTATUS status;
3229         uint32_t written, to_write;
3230         uint32_t max_size;
3231         bool ok;
3232
3233         status = smb2cli_write_recv(subreq, &written);
3234         TALLOC_FREE(subreq);
3235         if (tevent_req_nterror(req, status)) {
3236                 return;
3237         }
3238
3239         state->written += written;
3240
3241         if (state->written > state->size) {
3242                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3243                 return;
3244         }
3245
3246         to_write = state->size - state->written;
3247
3248         if (to_write == 0) {
3249                 tevent_req_done(req);
3250                 return;
3251         }
3252
3253         max_size = smb2cli_conn_max_write_size(state->cli->conn);
3254         to_write = MIN(max_size, to_write);
3255         ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3256         if (ok) {
3257                 to_write = MIN(max_size, to_write);
3258         }
3259
3260         subreq = smb2cli_write_send(state,
3261                                 state->ev,
3262                                 state->cli->conn,
3263                                 state->cli->timeout,
3264                                 state->cli->smb2.session,
3265                                 state->cli->smb2.tcon,
3266                                 to_write,
3267                                 state->offset + state->written,
3268                                 state->ph->fid_persistent,
3269                                 state->ph->fid_volatile,
3270                                 0, /* remaining_bytes */
3271                                 state->flags, /* flags */
3272                                 state->buf + state->written);
3273
3274         if (tevent_req_nomem(subreq, req)) {
3275                 return;
3276         }
3277         tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3278 }
3279
3280 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
3281                                 size_t *pwritten)
3282 {
3283         struct cli_smb2_writeall_state *state = tevent_req_data(
3284                 req, struct cli_smb2_writeall_state);
3285         NTSTATUS status;
3286
3287         if (tevent_req_is_nterror(req, &status)) {
3288                 state->cli->raw_status = status;
3289                 return status;
3290         }
3291         if (pwritten != NULL) {
3292                 *pwritten = (size_t)state->written;
3293         }
3294         state->cli->raw_status = NT_STATUS_OK;
3295         return NT_STATUS_OK;
3296 }
3297
3298 struct cli_smb2_splice_state {
3299         struct tevent_context *ev;
3300         struct cli_state *cli;
3301         struct smb2_hnd *src_ph;
3302         struct smb2_hnd *dst_ph;
3303         int (*splice_cb)(off_t n, void *priv);
3304         void *priv;
3305         off_t written;
3306         off_t size;
3307         off_t src_offset;
3308         off_t dst_offset;
3309         bool resized;
3310         struct req_resume_key_rsp resume_rsp;
3311         struct srv_copychunk_copy cc_copy;
3312 };
3313
3314 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3315                                       struct tevent_req *req);
3316
3317 static void cli_splice_copychunk_done(struct tevent_req *subreq)
3318 {
3319         struct tevent_req *req = tevent_req_callback_data(
3320                 subreq, struct tevent_req);
3321         struct cli_smb2_splice_state *state =
3322                 tevent_req_data(req,
3323                 struct cli_smb2_splice_state);
3324         struct smbXcli_conn *conn = state->cli->conn;
3325         DATA_BLOB out_input_buffer = data_blob_null;
3326         DATA_BLOB out_output_buffer = data_blob_null;
3327         struct srv_copychunk_rsp cc_copy_rsp;
3328         enum ndr_err_code ndr_ret;
3329         NTSTATUS status;
3330
3331         status = smb2cli_ioctl_recv(subreq, state,
3332                                     &out_input_buffer,
3333                                     &out_output_buffer);
3334         TALLOC_FREE(subreq);
3335         if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
3336              state->resized) && tevent_req_nterror(req, status)) {
3337                 return;
3338         }
3339
3340         ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
3341                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
3342         if (ndr_ret != NDR_ERR_SUCCESS) {
3343                 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3344                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3345                 return;
3346         }
3347
3348         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
3349                 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
3350                              cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
3351                 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
3352                      max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
3353                      tevent_req_nterror(req, status)) {
3354                         return;
3355                 }
3356
3357                 state->resized = true;
3358                 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
3359                 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
3360         } else {
3361                 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3362                     (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3363                     (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
3364                         tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3365                         return;
3366                 }
3367                 state->src_offset += cc_copy_rsp.total_bytes_written;
3368                 state->dst_offset += cc_copy_rsp.total_bytes_written;
3369                 state->written += cc_copy_rsp.total_bytes_written;
3370                 if (!state->splice_cb(state->written, state->priv)) {
3371                         tevent_req_nterror(req, NT_STATUS_CANCELLED);
3372                         return;
3373                 }
3374         }
3375
3376         cli_splice_copychunk_send(state, req);
3377 }
3378
3379 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3380                                       struct tevent_req *req)
3381 {
3382         struct tevent_req *subreq;
3383         enum ndr_err_code ndr_ret;
3384         struct smbXcli_conn *conn = state->cli->conn;
3385         struct srv_copychunk_copy *cc_copy = &state->cc_copy;
3386         off_t src_offset = state->src_offset;
3387         off_t dst_offset = state->dst_offset;
3388         uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
3389                                state->size - state->written);
3390         DATA_BLOB in_input_buffer = data_blob_null;
3391         DATA_BLOB in_output_buffer = data_blob_null;
3392
3393         if (state->size - state->written == 0) {
3394                 tevent_req_done(req);
3395                 return;
3396         }
3397
3398         cc_copy->chunk_count = 0;
3399         while (req_len) {
3400                 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
3401                 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
3402                 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
3403                                                                    smb2cli_conn_cc_chunk_len(conn));
3404                 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
3405                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3406                         return;
3407                 }
3408                 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
3409                 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
3410                     (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
3411                         tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3412                         return;
3413                 }
3414                 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3415                 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3416                 cc_copy->chunk_count++;
3417         }
3418
3419         ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
3420                                        (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
3421         if (ndr_ret != NDR_ERR_SUCCESS) {
3422                 DEBUG(0, ("failed to marshall copy chunk req\n"));
3423                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3424                 return;
3425         }
3426
3427         subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
3428                                state->cli->timeout,
3429                                state->cli->smb2.session,
3430                                state->cli->smb2.tcon,
3431                                state->dst_ph->fid_persistent, /* in_fid_persistent */
3432                                state->dst_ph->fid_volatile, /* in_fid_volatile */
3433                                FSCTL_SRV_COPYCHUNK_WRITE,
3434                                0, /* in_max_input_length */
3435                                &in_input_buffer,
3436                                12, /* in_max_output_length */
3437                                &in_output_buffer,
3438                                SMB2_IOCTL_FLAG_IS_FSCTL);
3439         if (tevent_req_nomem(subreq, req)) {
3440                 return;
3441         }
3442         tevent_req_set_callback(subreq,
3443                                 cli_splice_copychunk_done,
3444                                 req);
3445 }
3446
3447 static void cli_splice_key_done(struct tevent_req *subreq)
3448 {
3449         struct tevent_req *req = tevent_req_callback_data(
3450                 subreq, struct tevent_req);
3451         struct cli_smb2_splice_state *state =
3452                 tevent_req_data(req,
3453                 struct cli_smb2_splice_state);
3454         enum ndr_err_code ndr_ret;
3455         NTSTATUS status;
3456
3457         DATA_BLOB out_input_buffer = data_blob_null;
3458         DATA_BLOB out_output_buffer = data_blob_null;
3459
3460         status = smb2cli_ioctl_recv(subreq, state,
3461                                     &out_input_buffer,
3462                                     &out_output_buffer);
3463         TALLOC_FREE(subreq);
3464         if (tevent_req_nterror(req, status)) {
3465                 return;
3466         }
3467
3468         ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
3469                         state, &state->resume_rsp,
3470                         (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
3471         if (ndr_ret != NDR_ERR_SUCCESS) {
3472                 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3473                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3474                 return;
3475         }
3476
3477         memcpy(&state->cc_copy.source_key,
3478                &state->resume_rsp.resume_key,
3479                sizeof state->resume_rsp.resume_key);
3480
3481         cli_splice_copychunk_send(state, req);
3482 }
3483
3484 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
3485                                 struct tevent_context *ev,
3486                                 struct cli_state *cli,
3487                                 uint16_t src_fnum, uint16_t dst_fnum,
3488                                 off_t size, off_t src_offset, off_t dst_offset,
3489                                 int (*splice_cb)(off_t n, void *priv),
3490                                 void *priv)
3491 {
3492         struct tevent_req *req;
3493         struct tevent_req *subreq;
3494         struct cli_smb2_splice_state *state;
3495         NTSTATUS status;
3496         DATA_BLOB in_input_buffer = data_blob_null;
3497         DATA_BLOB in_output_buffer = data_blob_null;
3498
3499         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
3500         if (req == NULL) {
3501                 return NULL;
3502         }
3503         state->cli = cli;
3504         state->ev = ev;
3505         state->splice_cb = splice_cb;
3506         state->priv = priv;
3507         state->size = size;
3508         state->written = 0;
3509         state->src_offset = src_offset;
3510         state->dst_offset = dst_offset;
3511         state->cc_copy.chunks = talloc_array(state,
3512                                              struct srv_copychunk,
3513                                              smb2cli_conn_cc_max_chunks(cli->conn));
3514         if (state->cc_copy.chunks == NULL) {
3515                 return NULL;
3516         }
3517
3518         status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
3519         if (tevent_req_nterror(req, status))
3520                 return tevent_req_post(req, ev);
3521
3522         status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
3523         if (tevent_req_nterror(req, status))
3524                 return tevent_req_post(req, ev);
3525
3526         subreq = smb2cli_ioctl_send(state, ev, cli->conn,
3527                                cli->timeout,
3528                                cli->smb2.session,
3529                                cli->smb2.tcon,
3530                                state->src_ph->fid_persistent, /* in_fid_persistent */
3531                                state->src_ph->fid_volatile, /* in_fid_volatile */
3532                                FSCTL_SRV_REQUEST_RESUME_KEY,
3533                                0, /* in_max_input_length */
3534                                &in_input_buffer,
3535                                32, /* in_max_output_length */
3536                                &in_output_buffer,
3537                                SMB2_IOCTL_FLAG_IS_FSCTL);
3538         if (tevent_req_nomem(subreq, req)) {
3539                 return NULL;
3540         }
3541         tevent_req_set_callback(subreq,
3542                                 cli_splice_key_done,
3543                                 req);
3544
3545         return req;
3546 }
3547
3548 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
3549 {
3550         struct cli_smb2_splice_state *state = tevent_req_data(
3551                 req, struct cli_smb2_splice_state);
3552         NTSTATUS status;
3553
3554         if (tevent_req_is_nterror(req, &status)) {
3555                 state->cli->raw_status = status;
3556                 tevent_req_received(req);
3557                 return status;
3558         }
3559         if (written != NULL) {
3560                 *written = state->written;
3561         }
3562         state->cli->raw_status = NT_STATUS_OK;
3563         tevent_req_received(req);
3564         return NT_STATUS_OK;
3565 }
3566
3567 /***************************************************************
3568  SMB2 enum shadow copy data.
3569 ***************************************************************/
3570
3571 struct cli_smb2_shadow_copy_data_fnum_state {
3572         struct cli_state *cli;
3573         uint16_t fnum;
3574         struct smb2_hnd *ph;
3575         DATA_BLOB out_input_buffer;
3576         DATA_BLOB out_output_buffer;
3577 };
3578
3579 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
3580
3581 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
3582                                         TALLOC_CTX *mem_ctx,
3583                                         struct tevent_context *ev,
3584                                         struct cli_state *cli,
3585                                         uint16_t fnum,
3586                                         bool get_names)
3587 {
3588         struct tevent_req *req, *subreq;
3589         struct cli_smb2_shadow_copy_data_fnum_state *state;
3590         NTSTATUS status;
3591
3592         req = tevent_req_create(mem_ctx, &state,
3593                                 struct cli_smb2_shadow_copy_data_fnum_state);
3594         if (req == NULL) {
3595                 return NULL;
3596         }
3597
3598         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3599                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3600                 return tevent_req_post(req, ev);
3601         }
3602
3603         state->cli = cli;
3604         state->fnum = fnum;
3605
3606         status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
3607         if (tevent_req_nterror(req, status)) {
3608                 return tevent_req_post(req, ev);
3609         }
3610
3611         /*
3612          * TODO. Under SMB2 we should send a zero max_output_length
3613          * ioctl to get the required size, then send another ioctl
3614          * to get the data, but the current SMB1 implementation just
3615          * does one roundtrip with a 64K buffer size. Do the same
3616          * for now. JRA.
3617          */
3618
3619         subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
3620                         state->cli->timeout,
3621                         state->cli->smb2.session,
3622                         state->cli->smb2.tcon,
3623                         state->ph->fid_persistent, /* in_fid_persistent */
3624                         state->ph->fid_volatile, /* in_fid_volatile */
3625                         FSCTL_GET_SHADOW_COPY_DATA,
3626                         0, /* in_max_input_length */
3627                         NULL, /* in_input_buffer */
3628                         get_names ?
3629                                 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
3630                         NULL, /* in_output_buffer */
3631                         SMB2_IOCTL_FLAG_IS_FSCTL);
3632
3633         if (tevent_req_nomem(subreq, req)) {
3634                 return tevent_req_post(req, ev);
3635         }
3636         tevent_req_set_callback(subreq,
3637                                 cli_smb2_shadow_copy_data_fnum_done,
3638                                 req);
3639
3640         return req;
3641 }
3642
3643 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
3644 {
3645         struct tevent_req *req = tevent_req_callback_data(
3646                 subreq, struct tevent_req);
3647         struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3648                 req, struct cli_smb2_shadow_copy_data_fnum_state);
3649         NTSTATUS status;
3650
3651         status = smb2cli_ioctl_recv(subreq, state,
3652                                 &state->out_input_buffer,
3653                                 &state->out_output_buffer);
3654         TALLOC_FREE(subreq);
3655         if (tevent_req_nterror(req, status)) {
3656                 return;
3657         }
3658         tevent_req_done(req);
3659 }
3660
3661 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
3662                                 TALLOC_CTX *mem_ctx,
3663                                 bool get_names,
3664                                 char ***pnames,
3665                                 int *pnum_names)
3666 {
3667         struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3668                 req, struct cli_smb2_shadow_copy_data_fnum_state);
3669         char **names = NULL;
3670         uint32_t num_names = 0;
3671         uint32_t num_names_returned = 0;
3672         uint32_t dlength = 0;
3673         uint32_t i;
3674         uint8_t *endp = NULL;
3675         NTSTATUS status;
3676
3677         if (tevent_req_is_nterror(req, &status)) {
3678                 return status;
3679         }
3680
3681         if (state->out_output_buffer.length < 16) {
3682                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3683         }
3684
3685         num_names = IVAL(state->out_output_buffer.data, 0);
3686         num_names_returned = IVAL(state->out_output_buffer.data, 4);
3687         dlength = IVAL(state->out_output_buffer.data, 8);
3688
3689         if (num_names > 0x7FFFFFFF) {
3690                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3691         }
3692
3693         if (get_names == false) {
3694                 *pnum_names = (int)num_names;
3695                 return NT_STATUS_OK;
3696         }
3697         if (num_names != num_names_returned) {
3698                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3699         }
3700         if (dlength + 12 < 12) {
3701                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3702         }
3703         /*
3704          * NB. The below is an allowable return if there are
3705          * more snapshots than the buffer size we told the
3706          * server we can receive. We currently don't support
3707          * this.
3708          */
3709         if (dlength + 12 > state->out_output_buffer.length) {
3710                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3711         }
3712         if (state->out_output_buffer.length +
3713                         (2 * sizeof(SHADOW_COPY_LABEL)) <
3714                                 state->out_output_buffer.length) {
3715                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3716         }
3717
3718         names = talloc_array(mem_ctx, char *, num_names_returned);
3719         if (names == NULL) {
3720                 return NT_STATUS_NO_MEMORY;
3721         }
3722
3723         endp = state->out_output_buffer.data +
3724                         state->out_output_buffer.length;
3725
3726         for (i=0; i<num_names_returned; i++) {
3727                 bool ret;
3728                 uint8_t *src;
3729                 size_t converted_size;
3730
3731                 src = state->out_output_buffer.data + 12 +
3732                         (i * 2 * sizeof(SHADOW_COPY_LABEL));
3733
3734                 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
3735                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
3736                 }
3737                 ret = convert_string_talloc(
3738                         names, CH_UTF16LE, CH_UNIX,
3739                         src, 2 * sizeof(SHADOW_COPY_LABEL),
3740                         &names[i], &converted_size);
3741                 if (!ret) {
3742                         TALLOC_FREE(names);
3743                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
3744                 }
3745         }
3746         *pnum_names = num_names;
3747         *pnames = names;
3748         return NT_STATUS_OK;
3749 }
3750
3751 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
3752                                 struct cli_state *cli,
3753                                 uint16_t fnum,
3754                                 bool get_names,
3755                                 char ***pnames,
3756                                 int *pnum_names)
3757 {
3758         TALLOC_CTX *frame = talloc_stackframe();
3759         struct tevent_context *ev;
3760         struct tevent_req *req;
3761         NTSTATUS status = NT_STATUS_NO_MEMORY;
3762
3763         if (smbXcli_conn_has_async_calls(cli->conn)) {
3764                 /*
3765                  * Can't use sync call while an async call is in flight
3766                  */
3767                 status = NT_STATUS_INVALID_PARAMETER;
3768                 goto fail;
3769         }
3770         ev = samba_tevent_context_init(frame);
3771         if (ev == NULL) {
3772                 goto fail;
3773         }
3774         req = cli_smb2_shadow_copy_data_fnum_send(frame,
3775                                         ev,
3776                                         cli,
3777                                         fnum,
3778                                         get_names);
3779         if (req == NULL) {
3780                 goto fail;
3781         }
3782         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3783                 goto fail;
3784         }
3785         status = cli_smb2_shadow_copy_data_fnum_recv(req,
3786                                                 mem_ctx,
3787                                                 get_names,
3788                                                 pnames,
3789                                                 pnum_names);
3790  fail:
3791         cli->raw_status = status;
3792
3793         TALLOC_FREE(frame);
3794         return status;
3795 }
3796
3797 /***************************************************************
3798  Wrapper that allows SMB2 to truncate a file.
3799  Synchronous only.
3800 ***************************************************************/
3801
3802 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
3803                         uint16_t fnum,
3804                         uint64_t newsize)
3805 {
3806         NTSTATUS status;
3807         DATA_BLOB inbuf = data_blob_null;
3808         struct smb2_hnd *ph = NULL;
3809         TALLOC_CTX *frame = talloc_stackframe();
3810
3811         if (smbXcli_conn_has_async_calls(cli->conn)) {
3812                 /*
3813                  * Can't use sync call while an async call is in flight
3814                  */
3815                 status = NT_STATUS_INVALID_PARAMETER;
3816                 goto fail;
3817         }
3818
3819         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3820                 status = NT_STATUS_INVALID_PARAMETER;
3821                 goto fail;
3822         }
3823
3824         status = map_fnum_to_smb2_handle(cli,
3825                                         fnum,
3826                                         &ph);
3827         if (!NT_STATUS_IS_OK(status)) {
3828                 goto fail;
3829         }
3830
3831         inbuf = data_blob_talloc_zero(frame, 8);
3832         if (inbuf.data == NULL) {
3833                 status = NT_STATUS_NO_MEMORY;
3834                 goto fail;
3835         }
3836
3837         SBVAL(inbuf.data, 0, newsize);
3838
3839         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3840            level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
3841
3842         status = smb2cli_set_info(cli->conn,
3843                                 cli->timeout,
3844                                 cli->smb2.session,
3845                                 cli->smb2.tcon,
3846                                 1, /* in_info_type */
3847                                         /* in_file_info_class */
3848                                 SMB_FILE_END_OF_FILE_INFORMATION - 1000,
3849                                 &inbuf, /* in_input_buffer */
3850                                 0, /* in_additional_info */
3851                                 ph->fid_persistent,
3852                                 ph->fid_volatile);
3853
3854   fail:
3855
3856         cli->raw_status = status;
3857
3858         TALLOC_FREE(frame);
3859         return status;
3860 }
3861
3862 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
3863                          uint32_t buffer_size, uint32_t completion_filter,
3864                          bool recursive, TALLOC_CTX *mem_ctx,
3865                          struct notify_change **pchanges,
3866                          uint32_t *pnum_changes)
3867 {
3868         NTSTATUS status;
3869         struct smb2_hnd *ph = NULL;
3870         TALLOC_CTX *frame = talloc_stackframe();
3871         uint8_t *base;
3872         uint32_t len, ofs;
3873         struct notify_change *changes = NULL;
3874         size_t num_changes = 0;
3875
3876         if (smbXcli_conn_has_async_calls(cli->conn)) {
3877                 /*
3878                  * Can't use sync call while an async call is in flight
3879                  */
3880                 status = NT_STATUS_INVALID_PARAMETER;
3881                 goto fail;
3882         }
3883
3884         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3885                 status = NT_STATUS_INVALID_PARAMETER;
3886                 goto fail;
3887         }
3888
3889         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
3890         if (!NT_STATUS_IS_OK(status)) {
3891                 goto fail;
3892         }
3893
3894         status = smb2cli_notify(cli->conn, cli->timeout,
3895                                 cli->smb2.session, cli->smb2.tcon,
3896                                 buffer_size,
3897                                 ph->fid_persistent, ph->fid_volatile,
3898                                 completion_filter, recursive,
3899                                 frame, &base, &len);
3900
3901         ofs = 0;
3902
3903         while (len - ofs >= 12) {
3904                 struct notify_change *tmp;
3905                 struct notify_change *c;
3906                 uint32_t next_ofs = IVAL(base, ofs);
3907                 uint32_t file_name_length = IVAL(base, ofs+8);
3908                 size_t namelen;
3909                 bool ok;
3910
3911                 tmp = talloc_realloc(frame, changes, struct notify_change,
3912                                      num_changes + 1);
3913                 if (tmp == NULL) {
3914                         status = NT_STATUS_NO_MEMORY;
3915                         goto fail;
3916                 }
3917                 changes = tmp;
3918                 c = &changes[num_changes];
3919                 num_changes += 1;
3920
3921                 if (smb_buffer_oob(len, ofs, next_ofs) ||
3922                     smb_buffer_oob(len, ofs+12, file_name_length)) {
3923                         status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3924                         goto fail;
3925                 }
3926
3927                 c->action = IVAL(base, ofs+4);
3928
3929                 ok = convert_string_talloc(changes, CH_UTF16LE, CH_UNIX,
3930                                            base + ofs + 12, file_name_length,
3931                                            &c->name, &namelen);
3932                 if (!ok) {
3933                         status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3934                         goto fail;
3935                 }
3936
3937                 if (next_ofs == 0) {
3938                         break;
3939                 }
3940                 ofs += next_ofs;
3941         }
3942
3943         *pchanges = talloc_move(mem_ctx, &changes);
3944         *pnum_changes = num_changes;
3945         status = NT_STATUS_OK;
3946
3947 fail:
3948         cli->raw_status = status;
3949
3950         TALLOC_FREE(frame);
3951         return status;
3952 }