32c7c21bd6d07637b7cbc0f889e6f3aead83e052
[metze/samba/wip.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  Helper function for pathname operations.
1105 ***************************************************************/
1106
1107 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1108                                 const char *name,
1109                                 uint32_t desired_access,
1110                                 uint16_t *pfnum)
1111 {
1112         NTSTATUS status;
1113         size_t namelen = strlen(name);
1114         TALLOC_CTX *frame = talloc_stackframe();
1115
1116         /* SMB2 is pickier about pathnames. Ensure it doesn't
1117            end in a '\' */
1118         if (namelen > 0 && name[namelen-1] == '\\') {
1119                 char *modname = talloc_strdup(frame, name);
1120                 if (modname == NULL) {
1121                         status = NT_STATUS_NO_MEMORY;
1122                         goto fail;
1123                 }
1124                 modname[namelen-1] = '\0';
1125                 name = modname;
1126         }
1127
1128         /* Try to open a file handle first. */
1129         status = cli_smb2_create_fnum(cli,
1130                         name,
1131                         0,                      /* create_flags */
1132                         desired_access,
1133                         0, /* file attributes */
1134                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1135                         FILE_OPEN,              /* create_disposition */
1136                         0,      /* create_options */
1137                         pfnum,
1138                         NULL);
1139
1140         if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1141                 status = cli_smb2_create_fnum(cli,
1142                         name,
1143                         0,                      /* create_flags */
1144                         desired_access,
1145                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1146                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1147                         FILE_OPEN,              /* create_disposition */
1148                         FILE_DIRECTORY_FILE,    /* create_options */
1149                         pfnum,
1150                         NULL);
1151         }
1152
1153   fail:
1154
1155         TALLOC_FREE(frame);
1156         return status;
1157 }
1158
1159 /***************************************************************
1160  Wrapper that allows SMB2 to query a path info (ALTNAME level).
1161  Synchronous only.
1162 ***************************************************************/
1163
1164 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1165                                 const char *name,
1166                                 fstring alt_name)
1167 {
1168         NTSTATUS status;
1169         DATA_BLOB outbuf = data_blob_null;
1170         uint16_t fnum = 0xffff;
1171         struct smb2_hnd *ph = NULL;
1172         uint32_t altnamelen = 0;
1173         TALLOC_CTX *frame = talloc_stackframe();
1174
1175         if (smbXcli_conn_has_async_calls(cli->conn)) {
1176                 /*
1177                  * Can't use sync call while an async call is in flight
1178                  */
1179                 status = NT_STATUS_INVALID_PARAMETER;
1180                 goto fail;
1181         }
1182
1183         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1184                 status = NT_STATUS_INVALID_PARAMETER;
1185                 goto fail;
1186         }
1187
1188         status = get_fnum_from_path(cli,
1189                                 name,
1190                                 FILE_READ_ATTRIBUTES,
1191                                 &fnum);
1192
1193         if (!NT_STATUS_IS_OK(status)) {
1194                 goto fail;
1195         }
1196
1197         status = map_fnum_to_smb2_handle(cli,
1198                                         fnum,
1199                                         &ph);
1200         if (!NT_STATUS_IS_OK(status)) {
1201                 goto fail;
1202         }
1203
1204         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1205            level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1206
1207         status = smb2cli_query_info(cli->conn,
1208                                 cli->timeout,
1209                                 cli->smb2.session,
1210                                 cli->smb2.tcon,
1211                                 1, /* in_info_type */
1212                                 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1213                                 0xFFFF, /* in_max_output_length */
1214                                 NULL, /* in_input_buffer */
1215                                 0, /* in_additional_info */
1216                                 0, /* in_flags */
1217                                 ph->fid_persistent,
1218                                 ph->fid_volatile,
1219                                 frame,
1220                                 &outbuf);
1221
1222         if (!NT_STATUS_IS_OK(status)) {
1223                 goto fail;
1224         }
1225
1226         /* Parse the reply. */
1227         if (outbuf.length < 4) {
1228                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1229                 goto fail;
1230         }
1231
1232         altnamelen = IVAL(outbuf.data, 0);
1233         if (altnamelen > outbuf.length - 4) {
1234                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1235                 goto fail;
1236         }
1237
1238         if (altnamelen > 0) {
1239                 size_t ret = 0;
1240                 char *short_name = NULL;
1241                 ret = pull_string_talloc(frame,
1242                                 outbuf.data,
1243                                 FLAGS2_UNICODE_STRINGS,
1244                                 &short_name,
1245                                 outbuf.data + 4,
1246                                 altnamelen,
1247                                 STR_UNICODE);
1248                 if (ret == (size_t)-1) {
1249                         /* Bad conversion. */
1250                         status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1251                         goto fail;
1252                 }
1253
1254                 fstrcpy(alt_name, short_name);
1255         } else {
1256                 alt_name[0] = '\0';
1257         }
1258
1259         status = NT_STATUS_OK;
1260
1261   fail:
1262
1263         if (fnum != 0xffff) {
1264                 cli_smb2_close_fnum(cli, fnum);
1265         }
1266
1267         cli->raw_status = status;
1268
1269         TALLOC_FREE(frame);
1270         return status;
1271 }
1272
1273
1274 /***************************************************************
1275  Wrapper that allows SMB2 to query a fnum info (basic level).
1276  Synchronous only.
1277 ***************************************************************/
1278
1279 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1280                         uint16_t fnum,
1281                         uint16_t *mode,
1282                         off_t *size,
1283                         struct timespec *create_time,
1284                         struct timespec *access_time,
1285                         struct timespec *write_time,
1286                         struct timespec *change_time,
1287                         SMB_INO_T *ino)
1288 {
1289         NTSTATUS status;
1290         DATA_BLOB outbuf = data_blob_null;
1291         struct smb2_hnd *ph = NULL;
1292         TALLOC_CTX *frame = talloc_stackframe();
1293
1294         if (smbXcli_conn_has_async_calls(cli->conn)) {
1295                 /*
1296                  * Can't use sync call while an async call is in flight
1297                  */
1298                 status = NT_STATUS_INVALID_PARAMETER;
1299                 goto fail;
1300         }
1301
1302         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1303                 status = NT_STATUS_INVALID_PARAMETER;
1304                 goto fail;
1305         }
1306
1307         status = map_fnum_to_smb2_handle(cli,
1308                                         fnum,
1309                                         &ph);
1310         if (!NT_STATUS_IS_OK(status)) {
1311                 goto fail;
1312         }
1313
1314         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1315            level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1316
1317         status = smb2cli_query_info(cli->conn,
1318                                 cli->timeout,
1319                                 cli->smb2.session,
1320                                 cli->smb2.tcon,
1321                                 1, /* in_info_type */
1322                                 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1323                                 0xFFFF, /* in_max_output_length */
1324                                 NULL, /* in_input_buffer */
1325                                 0, /* in_additional_info */
1326                                 0, /* in_flags */
1327                                 ph->fid_persistent,
1328                                 ph->fid_volatile,
1329                                 frame,
1330                                 &outbuf);
1331         if (!NT_STATUS_IS_OK(status)) {
1332                 goto fail;
1333         }
1334
1335         /* Parse the reply. */
1336         if (outbuf.length < 0x60) {
1337                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1338                 goto fail;
1339         }
1340
1341         if (create_time) {
1342                 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1343         }
1344         if (access_time) {
1345                 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1346         }
1347         if (write_time) {
1348                 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1349         }
1350         if (change_time) {
1351                 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1352         }
1353         if (mode) {
1354                 uint32_t attr = IVAL(outbuf.data, 0x20);
1355                 *mode = (uint16_t)attr;
1356         }
1357         if (size) {
1358                 uint64_t file_size = BVAL(outbuf.data, 0x30);
1359                 *size = (off_t)file_size;
1360         }
1361         if (ino) {
1362                 uint64_t file_index = BVAL(outbuf.data, 0x40);
1363                 *ino = (SMB_INO_T)file_index;
1364         }
1365
1366   fail:
1367
1368         cli->raw_status = status;
1369
1370         TALLOC_FREE(frame);
1371         return status;
1372 }
1373
1374 /***************************************************************
1375  Wrapper that allows SMB2 to query an fnum.
1376  Implement on top of cli_smb2_qfileinfo_basic().
1377  Synchronous only.
1378 ***************************************************************/
1379
1380 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1381                         uint16_t fnum,
1382                         uint16_t *attr,
1383                         off_t *size,
1384                         time_t *change_time,
1385                         time_t *access_time,
1386                         time_t *write_time)
1387 {
1388         struct timespec access_time_ts;
1389         struct timespec write_time_ts;
1390         struct timespec change_time_ts;
1391         NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1392                                         fnum,
1393                                         attr,
1394                                         size,
1395                                         NULL,
1396                                         &access_time_ts,
1397                                         &write_time_ts,
1398                                         &change_time_ts,
1399                                         NULL);
1400
1401         cli->raw_status = status;
1402
1403         if (!NT_STATUS_IS_OK(status)) {
1404                 return status;
1405         }
1406
1407         if (change_time) {
1408                 *change_time = change_time_ts.tv_sec;
1409         }
1410         if (access_time) {
1411                 *access_time = access_time_ts.tv_sec;
1412         }
1413         if (write_time) {
1414                 *write_time = write_time_ts.tv_sec;
1415         }
1416         return NT_STATUS_OK;
1417 }
1418
1419 /***************************************************************
1420  Wrapper that allows SMB2 to get pathname attributes.
1421  Synchronous only.
1422 ***************************************************************/
1423
1424 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1425                         const char *name,
1426                         uint16_t *attr,
1427                         off_t *size,
1428                         time_t *write_time)
1429 {
1430         NTSTATUS status;
1431         uint16_t fnum = 0xffff;
1432         struct smb2_hnd *ph = NULL;
1433         TALLOC_CTX *frame = talloc_stackframe();
1434
1435         if (smbXcli_conn_has_async_calls(cli->conn)) {
1436                 /*
1437                  * Can't use sync call while an async call is in flight
1438                  */
1439                 status = NT_STATUS_INVALID_PARAMETER;
1440                 goto fail;
1441         }
1442
1443         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1444                 status = NT_STATUS_INVALID_PARAMETER;
1445                 goto fail;
1446         }
1447
1448         status = get_fnum_from_path(cli,
1449                                 name,
1450                                 FILE_READ_ATTRIBUTES,
1451                                 &fnum);
1452
1453         if (!NT_STATUS_IS_OK(status)) {
1454                 goto fail;
1455         }
1456
1457         status = map_fnum_to_smb2_handle(cli,
1458                                         fnum,
1459                                         &ph);
1460         if (!NT_STATUS_IS_OK(status)) {
1461                 goto fail;
1462         }
1463         status = cli_smb2_getattrE(cli,
1464                                 fnum,
1465                                 attr,
1466                                 size,
1467                                 NULL,
1468                                 NULL,
1469                                 write_time);
1470         if (!NT_STATUS_IS_OK(status)) {
1471                 goto fail;
1472         }
1473
1474   fail:
1475
1476         if (fnum != 0xffff) {
1477                 cli_smb2_close_fnum(cli, fnum);
1478         }
1479
1480         cli->raw_status = status;
1481
1482         TALLOC_FREE(frame);
1483         return status;
1484 }
1485
1486 /***************************************************************
1487  Wrapper that allows SMB2 to query a pathname info (basic level).
1488  Implement on top of cli_smb2_qfileinfo_basic().
1489  Synchronous only.
1490 ***************************************************************/
1491
1492 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1493                         const char *name,
1494                         struct timespec *create_time,
1495                         struct timespec *access_time,
1496                         struct timespec *write_time,
1497                         struct timespec *change_time,
1498                         off_t *size,
1499                         uint16_t *mode,
1500                         SMB_INO_T *ino)
1501 {
1502         NTSTATUS status;
1503         struct smb2_hnd *ph = NULL;
1504         uint16_t fnum = 0xffff;
1505         TALLOC_CTX *frame = talloc_stackframe();
1506
1507         if (smbXcli_conn_has_async_calls(cli->conn)) {
1508                 /*
1509                  * Can't use sync call while an async call is in flight
1510                  */
1511                 status = NT_STATUS_INVALID_PARAMETER;
1512                 goto fail;
1513         }
1514
1515         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1516                 status = NT_STATUS_INVALID_PARAMETER;
1517                 goto fail;
1518         }
1519
1520         status = get_fnum_from_path(cli,
1521                                         name,
1522                                         FILE_READ_ATTRIBUTES,
1523                                         &fnum);
1524
1525         if (!NT_STATUS_IS_OK(status)) {
1526                 goto fail;
1527         }
1528
1529         status = map_fnum_to_smb2_handle(cli,
1530                                         fnum,
1531                                         &ph);
1532         if (!NT_STATUS_IS_OK(status)) {
1533                 goto fail;
1534         }
1535
1536         status = cli_smb2_qfileinfo_basic(cli,
1537                                         fnum,
1538                                         mode,
1539                                         size,
1540                                         create_time,
1541                                         access_time,
1542                                         write_time,
1543                                         change_time,
1544                                         ino);
1545
1546   fail:
1547
1548         if (fnum != 0xffff) {
1549                 cli_smb2_close_fnum(cli, fnum);
1550         }
1551
1552         cli->raw_status = status;
1553
1554         TALLOC_FREE(frame);
1555         return status;
1556 }
1557
1558 /***************************************************************
1559  Wrapper that allows SMB2 to query pathname streams.
1560  Synchronous only.
1561 ***************************************************************/
1562
1563 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1564                                 const char *name,
1565                                 TALLOC_CTX *mem_ctx,
1566                                 unsigned int *pnum_streams,
1567                                 struct stream_struct **pstreams)
1568 {
1569         NTSTATUS status;
1570         struct smb2_hnd *ph = NULL;
1571         uint16_t fnum = 0xffff;
1572         DATA_BLOB outbuf = data_blob_null;
1573         TALLOC_CTX *frame = talloc_stackframe();
1574
1575         if (smbXcli_conn_has_async_calls(cli->conn)) {
1576                 /*
1577                  * Can't use sync call while an async call is in flight
1578                  */
1579                 status = NT_STATUS_INVALID_PARAMETER;
1580                 goto fail;
1581         }
1582
1583         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1584                 status = NT_STATUS_INVALID_PARAMETER;
1585                 goto fail;
1586         }
1587
1588         status = get_fnum_from_path(cli,
1589                                 name,
1590                                 FILE_READ_ATTRIBUTES,
1591                                 &fnum);
1592
1593         if (!NT_STATUS_IS_OK(status)) {
1594                 goto fail;
1595         }
1596
1597         status = map_fnum_to_smb2_handle(cli,
1598                                         fnum,
1599                                         &ph);
1600         if (!NT_STATUS_IS_OK(status)) {
1601                 goto fail;
1602         }
1603
1604         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1605            level 22 (SMB2_FILE_STREAM_INFORMATION). */
1606
1607         status = smb2cli_query_info(cli->conn,
1608                                 cli->timeout,
1609                                 cli->smb2.session,
1610                                 cli->smb2.tcon,
1611                                 1, /* in_info_type */
1612                                 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1613                                 0xFFFF, /* in_max_output_length */
1614                                 NULL, /* in_input_buffer */
1615                                 0, /* in_additional_info */
1616                                 0, /* in_flags */
1617                                 ph->fid_persistent,
1618                                 ph->fid_volatile,
1619                                 frame,
1620                                 &outbuf);
1621
1622         if (!NT_STATUS_IS_OK(status)) {
1623                 goto fail;
1624         }
1625
1626         /* Parse the reply. */
1627         if (!parse_streams_blob(mem_ctx,
1628                                 outbuf.data,
1629                                 outbuf.length,
1630                                 pnum_streams,
1631                                 pstreams)) {
1632                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1633                 goto fail;
1634         }
1635
1636   fail:
1637
1638         if (fnum != 0xffff) {
1639                 cli_smb2_close_fnum(cli, fnum);
1640         }
1641
1642         cli->raw_status = status;
1643
1644         TALLOC_FREE(frame);
1645         return status;
1646 }
1647
1648 /***************************************************************
1649  Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
1650  a pathname.
1651  Synchronous only.
1652 ***************************************************************/
1653
1654 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
1655                         const char *name,
1656                         uint8_t in_info_type,
1657                         uint8_t in_file_info_class,
1658                         const DATA_BLOB *p_in_data)
1659 {
1660         NTSTATUS status;
1661         uint16_t fnum = 0xffff;
1662         struct smb2_hnd *ph = NULL;
1663         TALLOC_CTX *frame = talloc_stackframe();
1664
1665         if (smbXcli_conn_has_async_calls(cli->conn)) {
1666                 /*
1667                  * Can't use sync call while an async call is in flight
1668                  */
1669                 status = NT_STATUS_INVALID_PARAMETER;
1670                 goto fail;
1671         }
1672
1673         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1674                 status = NT_STATUS_INVALID_PARAMETER;
1675                 goto fail;
1676         }
1677
1678         status = get_fnum_from_path(cli,
1679                                 name,
1680                                 FILE_WRITE_ATTRIBUTES,
1681                                 &fnum);
1682
1683         if (!NT_STATUS_IS_OK(status)) {
1684                 goto fail;
1685         }
1686
1687         status = map_fnum_to_smb2_handle(cli,
1688                                         fnum,
1689                                         &ph);
1690         if (!NT_STATUS_IS_OK(status)) {
1691                 goto fail;
1692         }
1693
1694         status = smb2cli_set_info(cli->conn,
1695                                 cli->timeout,
1696                                 cli->smb2.session,
1697                                 cli->smb2.tcon,
1698                                 in_info_type,
1699                                 in_file_info_class,
1700                                 p_in_data, /* in_input_buffer */
1701                                 0, /* in_additional_info */
1702                                 ph->fid_persistent,
1703                                 ph->fid_volatile);
1704   fail:
1705
1706         if (fnum != 0xffff) {
1707                 cli_smb2_close_fnum(cli, fnum);
1708         }
1709
1710         cli->raw_status = status;
1711
1712         TALLOC_FREE(frame);
1713         return status;
1714 }
1715
1716
1717 /***************************************************************
1718  Wrapper that allows SMB2 to set pathname attributes.
1719  Synchronous only.
1720 ***************************************************************/
1721
1722 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1723                         const char *name,
1724                         uint16_t attr,
1725                         time_t mtime)
1726 {
1727         NTSTATUS status;
1728         uint16_t fnum = 0xffff;
1729         struct smb2_hnd *ph = NULL;
1730         uint8_t inbuf_store[40];
1731         DATA_BLOB inbuf = data_blob_null;
1732         TALLOC_CTX *frame = talloc_stackframe();
1733
1734         if (smbXcli_conn_has_async_calls(cli->conn)) {
1735                 /*
1736                  * Can't use sync call while an async call is in flight
1737                  */
1738                 status = NT_STATUS_INVALID_PARAMETER;
1739                 goto fail;
1740         }
1741
1742         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1743                 status = NT_STATUS_INVALID_PARAMETER;
1744                 goto fail;
1745         }
1746
1747         status = get_fnum_from_path(cli,
1748                                 name,
1749                                 FILE_WRITE_ATTRIBUTES,
1750                                 &fnum);
1751
1752         if (!NT_STATUS_IS_OK(status)) {
1753                 goto fail;
1754         }
1755
1756         status = map_fnum_to_smb2_handle(cli,
1757                                         fnum,
1758                                         &ph);
1759         if (!NT_STATUS_IS_OK(status)) {
1760                 goto fail;
1761         }
1762
1763         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1764            level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1765
1766         inbuf.data = inbuf_store;
1767         inbuf.length = sizeof(inbuf_store);
1768         data_blob_clear(&inbuf);
1769
1770         /*
1771          * SMB1 uses attr == 0 to clear all attributes
1772          * on a file (end up with FILE_ATTRIBUTE_NORMAL),
1773          * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
1774          * request attribute change.
1775          *
1776          * SMB2 uses exactly the reverse. Unfortunately as the
1777          * cli_setatr() ABI is exposed inside libsmbclient,
1778          * we must make the SMB2 cli_smb2_setatr() call
1779          * export the same ABI as the SMB1 cli_setatr()
1780          * which calls it. This means reversing the sense
1781          * of the requested attr argument if it's zero
1782          * or FILE_ATTRIBUTE_NORMAL.
1783          *
1784          * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
1785          */
1786
1787         if (attr == 0) {
1788                 attr = FILE_ATTRIBUTE_NORMAL;
1789         } else if (attr == FILE_ATTRIBUTE_NORMAL) {
1790                 attr = 0;
1791         }
1792
1793         SSVAL(inbuf.data, 32, attr);
1794         if (mtime != 0) {
1795                 put_long_date((char *)inbuf.data + 16,mtime);
1796         }
1797         /* Set all the other times to -1. */
1798         SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1799         SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1800         SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1801
1802         status = smb2cli_set_info(cli->conn,
1803                                 cli->timeout,
1804                                 cli->smb2.session,
1805                                 cli->smb2.tcon,
1806                                 1, /* in_info_type */
1807                                 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1808                                 &inbuf, /* in_input_buffer */
1809                                 0, /* in_additional_info */
1810                                 ph->fid_persistent,
1811                                 ph->fid_volatile);
1812   fail:
1813
1814         if (fnum != 0xffff) {
1815                 cli_smb2_close_fnum(cli, fnum);
1816         }
1817
1818         cli->raw_status = status;
1819
1820         TALLOC_FREE(frame);
1821         return status;
1822 }
1823
1824
1825 /***************************************************************
1826  Wrapper that allows SMB2 to set file handle times.
1827  Synchronous only.
1828 ***************************************************************/
1829
1830 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1831                         uint16_t fnum,
1832                         time_t change_time,
1833                         time_t access_time,
1834                         time_t write_time)
1835 {
1836         NTSTATUS status;
1837         struct smb2_hnd *ph = NULL;
1838         uint8_t inbuf_store[40];
1839         DATA_BLOB inbuf = data_blob_null;
1840
1841         if (smbXcli_conn_has_async_calls(cli->conn)) {
1842                 /*
1843                  * Can't use sync call while an async call is in flight
1844                  */
1845                 return NT_STATUS_INVALID_PARAMETER;
1846         }
1847
1848         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1849                 return NT_STATUS_INVALID_PARAMETER;
1850         }
1851
1852         status = map_fnum_to_smb2_handle(cli,
1853                                         fnum,
1854                                         &ph);
1855         if (!NT_STATUS_IS_OK(status)) {
1856                 return status;
1857         }
1858
1859         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1860            level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1861
1862         inbuf.data = inbuf_store;
1863         inbuf.length = sizeof(inbuf_store);
1864         data_blob_clear(&inbuf);
1865
1866         SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1867         if (change_time != 0) {
1868                 put_long_date((char *)inbuf.data + 24, change_time);
1869         }
1870         if (access_time != 0) {
1871                 put_long_date((char *)inbuf.data + 8, access_time);
1872         }
1873         if (write_time != 0) {
1874                 put_long_date((char *)inbuf.data + 16, write_time);
1875         }
1876
1877         cli->raw_status = smb2cli_set_info(cli->conn,
1878                                 cli->timeout,
1879                                 cli->smb2.session,
1880                                 cli->smb2.tcon,
1881                                 1, /* in_info_type */
1882                                 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1883                                 &inbuf, /* in_input_buffer */
1884                                 0, /* in_additional_info */
1885                                 ph->fid_persistent,
1886                                 ph->fid_volatile);
1887
1888         return cli->raw_status;
1889 }
1890
1891 /***************************************************************
1892  Wrapper that allows SMB2 to query disk attributes (size).
1893  Synchronous only.
1894 ***************************************************************/
1895
1896 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
1897                           uint64_t *bsize, uint64_t *total, uint64_t *avail)
1898 {
1899         NTSTATUS status;
1900         uint16_t fnum = 0xffff;
1901         DATA_BLOB outbuf = data_blob_null;
1902         struct smb2_hnd *ph = NULL;
1903         uint32_t sectors_per_unit = 0;
1904         uint32_t bytes_per_sector = 0;
1905         uint64_t total_size = 0;
1906         uint64_t size_free = 0;
1907         TALLOC_CTX *frame = talloc_stackframe();
1908
1909         if (smbXcli_conn_has_async_calls(cli->conn)) {
1910                 /*
1911                  * Can't use sync call while an async call is in flight
1912                  */
1913                 status = NT_STATUS_INVALID_PARAMETER;
1914                 goto fail;
1915         }
1916
1917         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1918                 status = NT_STATUS_INVALID_PARAMETER;
1919                 goto fail;
1920         }
1921
1922         /* First open the top level directory. */
1923         status = cli_smb2_create_fnum(cli,
1924                         path,
1925                         0,                      /* create_flags */
1926                         FILE_READ_ATTRIBUTES,   /* desired_access */
1927                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1928                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1929                         FILE_OPEN,              /* create_disposition */
1930                         FILE_DIRECTORY_FILE,    /* create_options */
1931                         &fnum,
1932                         NULL);
1933
1934         if (!NT_STATUS_IS_OK(status)) {
1935                 goto fail;
1936         }
1937
1938         status = map_fnum_to_smb2_handle(cli,
1939                                         fnum,
1940                                         &ph);
1941         if (!NT_STATUS_IS_OK(status)) {
1942                 goto fail;
1943         }
1944
1945         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1946            level 3 (SMB_FS_SIZE_INFORMATION). */
1947
1948         status = smb2cli_query_info(cli->conn,
1949                                 cli->timeout,
1950                                 cli->smb2.session,
1951                                 cli->smb2.tcon,
1952                                 2, /* in_info_type */
1953                                 3, /* in_file_info_class */
1954                                 0xFFFF, /* in_max_output_length */
1955                                 NULL, /* in_input_buffer */
1956                                 0, /* in_additional_info */
1957                                 0, /* in_flags */
1958                                 ph->fid_persistent,
1959                                 ph->fid_volatile,
1960                                 frame,
1961                                 &outbuf);
1962         if (!NT_STATUS_IS_OK(status)) {
1963                 goto fail;
1964         }
1965
1966         /* Parse the reply. */
1967         if (outbuf.length != 24) {
1968                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1969                 goto fail;
1970         }
1971
1972         total_size = BVAL(outbuf.data, 0);
1973         size_free = BVAL(outbuf.data, 8);
1974         sectors_per_unit = IVAL(outbuf.data, 16);
1975         bytes_per_sector = IVAL(outbuf.data, 20);
1976
1977         if (bsize) {
1978                 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
1979         }
1980         if (total) {
1981                 *total = total_size;
1982         }
1983         if (avail) {
1984                 *avail = size_free;
1985         }
1986
1987         status = NT_STATUS_OK;
1988
1989   fail:
1990
1991         if (fnum != 0xffff) {
1992                 cli_smb2_close_fnum(cli, fnum);
1993         }
1994
1995         cli->raw_status = status;
1996
1997         TALLOC_FREE(frame);
1998         return status;
1999 }
2000
2001 /***************************************************************
2002  Wrapper that allows SMB2 to query file system attributes.
2003  Synchronous only.
2004 ***************************************************************/
2005
2006 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2007 {
2008         NTSTATUS status;
2009         uint16_t fnum = 0xffff;
2010         DATA_BLOB outbuf = data_blob_null;
2011         struct smb2_hnd *ph = NULL;
2012         TALLOC_CTX *frame = talloc_stackframe();
2013
2014         if (smbXcli_conn_has_async_calls(cli->conn)) {
2015                 /*
2016                  * Can't use sync call while an async call is in flight
2017                  */
2018                 status = NT_STATUS_INVALID_PARAMETER;
2019                 goto fail;
2020         }
2021
2022         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2023                 status = NT_STATUS_INVALID_PARAMETER;
2024                 goto fail;
2025         }
2026
2027         /* First open the top level directory. */
2028         status =
2029             cli_smb2_create_fnum(cli, "", 0,               /* create_flags */
2030                                  FILE_READ_ATTRIBUTES,     /* desired_access */
2031                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2032                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
2033                                      FILE_SHARE_DELETE, /* share_access */
2034                                  FILE_OPEN,             /* create_disposition */
2035                                  FILE_DIRECTORY_FILE,   /* create_options */
2036                                  &fnum,
2037                                  NULL);
2038
2039         if (!NT_STATUS_IS_OK(status)) {
2040                 goto fail;
2041         }
2042
2043         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2044         if (!NT_STATUS_IS_OK(status)) {
2045                 goto fail;
2046         }
2047
2048         status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2049                                     cli->smb2.tcon, 2, /* in_info_type */
2050                                     5,                 /* in_file_info_class */
2051                                     0xFFFF, /* in_max_output_length */
2052                                     NULL,   /* in_input_buffer */
2053                                     0,      /* in_additional_info */
2054                                     0,      /* in_flags */
2055                                     ph->fid_persistent, ph->fid_volatile, frame,
2056                                     &outbuf);
2057         if (!NT_STATUS_IS_OK(status)) {
2058                 goto fail;
2059         }
2060
2061         if (outbuf.length < 12) {
2062                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2063                 goto fail;
2064         }
2065
2066         *fs_attr = IVAL(outbuf.data, 0);
2067
2068 fail:
2069
2070         if (fnum != 0xffff) {
2071                 cli_smb2_close_fnum(cli, fnum);
2072         }
2073
2074         cli->raw_status = status;
2075
2076         TALLOC_FREE(frame);
2077         return status;
2078 }
2079
2080 /***************************************************************
2081  Wrapper that allows SMB2 to query a security descriptor.
2082  Synchronous only.
2083 ***************************************************************/
2084
2085 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2086                                         uint16_t fnum,
2087                                         uint32_t sec_info,
2088                                         TALLOC_CTX *mem_ctx,
2089                                         struct security_descriptor **ppsd)
2090 {
2091         NTSTATUS status;
2092         DATA_BLOB outbuf = data_blob_null;
2093         struct smb2_hnd *ph = NULL;
2094         struct security_descriptor *lsd = NULL;
2095         TALLOC_CTX *frame = talloc_stackframe();
2096
2097         if (smbXcli_conn_has_async_calls(cli->conn)) {
2098                 /*
2099                  * Can't use sync call while an async call is in flight
2100                  */
2101                 status = NT_STATUS_INVALID_PARAMETER;
2102                 goto fail;
2103         }
2104
2105         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2106                 status = NT_STATUS_INVALID_PARAMETER;
2107                 goto fail;
2108         }
2109
2110         status = map_fnum_to_smb2_handle(cli,
2111                                         fnum,
2112                                         &ph);
2113         if (!NT_STATUS_IS_OK(status)) {
2114                 goto fail;
2115         }
2116
2117         /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2118
2119         status = smb2cli_query_info(cli->conn,
2120                                 cli->timeout,
2121                                 cli->smb2.session,
2122                                 cli->smb2.tcon,
2123                                 3, /* in_info_type */
2124                                 0, /* in_file_info_class */
2125                                 0xFFFF, /* in_max_output_length */
2126                                 NULL, /* in_input_buffer */
2127                                 sec_info, /* in_additional_info */
2128                                 0, /* in_flags */
2129                                 ph->fid_persistent,
2130                                 ph->fid_volatile,
2131                                 frame,
2132                                 &outbuf);
2133
2134         if (!NT_STATUS_IS_OK(status)) {
2135                 goto fail;
2136         }
2137
2138         /* Parse the reply. */
2139         status = unmarshall_sec_desc(mem_ctx,
2140                                 outbuf.data,
2141                                 outbuf.length,
2142                                 &lsd);
2143
2144         if (!NT_STATUS_IS_OK(status)) {
2145                 goto fail;
2146         }
2147
2148         if (ppsd != NULL) {
2149                 *ppsd = lsd;
2150         } else {
2151                 TALLOC_FREE(lsd);
2152         }
2153
2154   fail:
2155
2156         cli->raw_status = status;
2157
2158         TALLOC_FREE(frame);
2159         return status;
2160 }
2161
2162 /***************************************************************
2163  Wrapper that allows SMB2 to set a security descriptor.
2164  Synchronous only.
2165 ***************************************************************/
2166
2167 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
2168                                         uint16_t fnum,
2169                                         uint32_t sec_info,
2170                                         const struct security_descriptor *sd)
2171 {
2172         NTSTATUS status;
2173         DATA_BLOB inbuf = data_blob_null;
2174         struct smb2_hnd *ph = NULL;
2175         TALLOC_CTX *frame = talloc_stackframe();
2176
2177         if (smbXcli_conn_has_async_calls(cli->conn)) {
2178                 /*
2179                  * Can't use sync call while an async call is in flight
2180                  */
2181                 status = NT_STATUS_INVALID_PARAMETER;
2182                 goto fail;
2183         }
2184
2185         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2186                 status = NT_STATUS_INVALID_PARAMETER;
2187                 goto fail;
2188         }
2189
2190         status = map_fnum_to_smb2_handle(cli,
2191                                         fnum,
2192                                         &ph);
2193         if (!NT_STATUS_IS_OK(status)) {
2194                 goto fail;
2195         }
2196
2197         status = marshall_sec_desc(frame,
2198                                 sd,
2199                                 &inbuf.data,
2200                                 &inbuf.length);
2201
2202         if (!NT_STATUS_IS_OK(status)) {
2203                 goto fail;
2204         }
2205
2206         /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2207
2208         status = smb2cli_set_info(cli->conn,
2209                                 cli->timeout,
2210                                 cli->smb2.session,
2211                                 cli->smb2.tcon,
2212                                 3, /* in_info_type */
2213                                 0, /* in_file_info_class */
2214                                 &inbuf, /* in_input_buffer */
2215                                 sec_info, /* in_additional_info */
2216                                 ph->fid_persistent,
2217                                 ph->fid_volatile);
2218
2219   fail:
2220
2221         cli->raw_status = status;
2222
2223         TALLOC_FREE(frame);
2224         return status;
2225 }
2226
2227 /***************************************************************
2228  Wrapper that allows SMB2 to rename a file.
2229  Synchronous only.
2230 ***************************************************************/
2231
2232 NTSTATUS cli_smb2_rename(struct cli_state *cli,
2233                          const char *fname_src,
2234                          const char *fname_dst,
2235                          bool replace)
2236 {
2237         NTSTATUS status;
2238         DATA_BLOB inbuf = data_blob_null;
2239         uint16_t fnum = 0xffff;
2240         struct smb2_hnd *ph = NULL;
2241         smb_ucs2_t *converted_str = NULL;
2242         size_t converted_size_bytes = 0;
2243         size_t namelen = 0;
2244         TALLOC_CTX *frame = talloc_stackframe();
2245
2246         if (smbXcli_conn_has_async_calls(cli->conn)) {
2247                 /*
2248                  * Can't use sync call while an async call is in flight
2249                  */
2250                 status = NT_STATUS_INVALID_PARAMETER;
2251                 goto fail;
2252         }
2253
2254         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2255                 status = NT_STATUS_INVALID_PARAMETER;
2256                 goto fail;
2257         }
2258
2259         status = get_fnum_from_path(cli,
2260                                 fname_src,
2261                                 DELETE_ACCESS,
2262                                 &fnum);
2263
2264         if (!NT_STATUS_IS_OK(status)) {
2265                 goto fail;
2266         }
2267
2268         status = map_fnum_to_smb2_handle(cli,
2269                                         fnum,
2270                                         &ph);
2271         if (!NT_STATUS_IS_OK(status)) {
2272                 goto fail;
2273         }
2274
2275         /* SMB2 is pickier about pathnames. Ensure it doesn't
2276            start in a '\' */
2277         if (*fname_dst == '\\') {
2278                 fname_dst++;
2279         }
2280
2281         /* SMB2 is pickier about pathnames. Ensure it doesn't
2282            end in a '\' */
2283         namelen = strlen(fname_dst);
2284         if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2285                 char *modname = talloc_strdup(frame, fname_dst);
2286                 modname[namelen-1] = '\0';
2287                 fname_dst = modname;
2288         }
2289
2290         if (!push_ucs2_talloc(frame,
2291                                 &converted_str,
2292                                 fname_dst,
2293                                 &converted_size_bytes)) {
2294                 status = NT_STATUS_INVALID_PARAMETER;
2295                 goto fail;
2296         }
2297
2298         /* W2K8 insists the dest name is not null
2299            terminated. Remove the last 2 zero bytes
2300            and reduce the name length. */
2301
2302         if (converted_size_bytes < 2) {
2303                 status = NT_STATUS_INVALID_PARAMETER;
2304                 goto fail;
2305         }
2306         converted_size_bytes -= 2;
2307
2308         inbuf = data_blob_talloc_zero(frame,
2309                                 20 + converted_size_bytes);
2310         if (inbuf.data == NULL) {
2311                 status = NT_STATUS_NO_MEMORY;
2312                 goto fail;
2313         }
2314
2315         if (replace) {
2316                 SCVAL(inbuf.data, 0, 1);
2317         }
2318
2319         SIVAL(inbuf.data, 16, converted_size_bytes);
2320         memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2321
2322         /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2323            level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2324
2325         status = smb2cli_set_info(cli->conn,
2326                                 cli->timeout,
2327                                 cli->smb2.session,
2328                                 cli->smb2.tcon,
2329                                 1, /* in_info_type */
2330                                 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2331                                 &inbuf, /* in_input_buffer */
2332                                 0, /* in_additional_info */
2333                                 ph->fid_persistent,
2334                                 ph->fid_volatile);
2335
2336   fail:
2337
2338         if (fnum != 0xffff) {
2339                 cli_smb2_close_fnum(cli, fnum);
2340         }
2341
2342         cli->raw_status = status;
2343
2344         TALLOC_FREE(frame);
2345         return status;
2346 }
2347
2348 /***************************************************************
2349  Wrapper that allows SMB2 to set an EA on a fnum.
2350  Synchronous only.
2351 ***************************************************************/
2352
2353 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2354                         uint16_t fnum,
2355                         const char *ea_name,
2356                         const char *ea_val,
2357                         size_t ea_len)
2358 {
2359         NTSTATUS status;
2360         DATA_BLOB inbuf = data_blob_null;
2361         size_t bloblen = 0;
2362         char *ea_name_ascii = NULL;
2363         size_t namelen = 0;
2364         struct smb2_hnd *ph = NULL;
2365         TALLOC_CTX *frame = talloc_stackframe();
2366
2367         if (smbXcli_conn_has_async_calls(cli->conn)) {
2368                 /*
2369                  * Can't use sync call while an async call is in flight
2370                  */
2371                 status = NT_STATUS_INVALID_PARAMETER;
2372                 goto fail;
2373         }
2374
2375         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2376                 status = NT_STATUS_INVALID_PARAMETER;
2377                 goto fail;
2378         }
2379
2380         status = map_fnum_to_smb2_handle(cli,
2381                                         fnum,
2382                                         &ph);
2383         if (!NT_STATUS_IS_OK(status)) {
2384                 goto fail;
2385         }
2386
2387         /* Marshall the SMB2 EA data. */
2388         if (ea_len > 0xFFFF) {
2389                 status = NT_STATUS_INVALID_PARAMETER;
2390                 goto fail;
2391         }
2392
2393         if (!push_ascii_talloc(frame,
2394                                 &ea_name_ascii,
2395                                 ea_name,
2396                                 &namelen)) {
2397                 status = NT_STATUS_INVALID_PARAMETER;
2398                 goto fail;
2399         }
2400
2401         if (namelen < 2 || namelen > 0xFF) {
2402                 status = NT_STATUS_INVALID_PARAMETER;
2403                 goto fail;
2404         }
2405
2406         bloblen = 8 + ea_len + namelen;
2407         /* Round up to a 4 byte boundary. */
2408         bloblen = ((bloblen + 3)&~3);
2409
2410         inbuf = data_blob_talloc_zero(frame, bloblen);
2411         if (inbuf.data == NULL) {
2412                 status = NT_STATUS_NO_MEMORY;
2413                 goto fail;
2414         }
2415         /* namelen doesn't include the NULL byte. */
2416         SCVAL(inbuf.data, 5, namelen - 1);
2417         SSVAL(inbuf.data, 6, ea_len);
2418         memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2419         memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2420
2421         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2422            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2423
2424         status = smb2cli_set_info(cli->conn,
2425                                 cli->timeout,
2426                                 cli->smb2.session,
2427                                 cli->smb2.tcon,
2428                                 1, /* in_info_type */
2429                                 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2430                                 &inbuf, /* in_input_buffer */
2431                                 0, /* in_additional_info */
2432                                 ph->fid_persistent,
2433                                 ph->fid_volatile);
2434
2435   fail:
2436
2437         cli->raw_status = status;
2438
2439         TALLOC_FREE(frame);
2440         return status;
2441 }
2442
2443 /***************************************************************
2444  Wrapper that allows SMB2 to set an EA on a pathname.
2445  Synchronous only.
2446 ***************************************************************/
2447
2448 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2449                         const char *name,
2450                         const char *ea_name,
2451                         const char *ea_val,
2452                         size_t ea_len)
2453 {
2454         NTSTATUS status;
2455         uint16_t fnum = 0xffff;
2456
2457         if (smbXcli_conn_has_async_calls(cli->conn)) {
2458                 /*
2459                  * Can't use sync call while an async call is in flight
2460                  */
2461                 status = NT_STATUS_INVALID_PARAMETER;
2462                 goto fail;
2463         }
2464
2465         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2466                 status = NT_STATUS_INVALID_PARAMETER;
2467                 goto fail;
2468         }
2469
2470         status = get_fnum_from_path(cli,
2471                                 name,
2472                                 FILE_WRITE_EA,
2473                                 &fnum);
2474
2475         if (!NT_STATUS_IS_OK(status)) {
2476                 goto fail;
2477         }
2478
2479         status = cli_set_ea_fnum(cli,
2480                                 fnum,
2481                                 ea_name,
2482                                 ea_val,
2483                                 ea_len);
2484         if (!NT_STATUS_IS_OK(status)) {
2485                 goto fail;
2486         }
2487
2488   fail:
2489
2490         if (fnum != 0xffff) {
2491                 cli_smb2_close_fnum(cli, fnum);
2492         }
2493
2494         cli->raw_status = status;
2495
2496         return status;
2497 }
2498
2499 /***************************************************************
2500  Wrapper that allows SMB2 to get an EA list on a pathname.
2501  Synchronous only.
2502 ***************************************************************/
2503
2504 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2505                                 const char *name,
2506                                 TALLOC_CTX *ctx,
2507                                 size_t *pnum_eas,
2508                                 struct ea_struct **pea_array)
2509 {
2510         NTSTATUS status;
2511         uint16_t fnum = 0xffff;
2512         DATA_BLOB outbuf = data_blob_null;
2513         struct smb2_hnd *ph = NULL;
2514         struct ea_list *ea_list = NULL;
2515         struct ea_list *eal = NULL;
2516         size_t ea_count = 0;
2517         TALLOC_CTX *frame = talloc_stackframe();
2518
2519         *pnum_eas = 0;
2520         *pea_array = NULL;
2521
2522         if (smbXcli_conn_has_async_calls(cli->conn)) {
2523                 /*
2524                  * Can't use sync call while an async call is in flight
2525                  */
2526                 status = NT_STATUS_INVALID_PARAMETER;
2527                 goto fail;
2528         }
2529
2530         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2531                 status = NT_STATUS_INVALID_PARAMETER;
2532                 goto fail;
2533         }
2534
2535         status = get_fnum_from_path(cli,
2536                                 name,
2537                                 FILE_READ_EA,
2538                                 &fnum);
2539
2540         if (!NT_STATUS_IS_OK(status)) {
2541                 goto fail;
2542         }
2543
2544         status = map_fnum_to_smb2_handle(cli,
2545                                         fnum,
2546                                         &ph);
2547         if (!NT_STATUS_IS_OK(status)) {
2548                 goto fail;
2549         }
2550
2551         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2552            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2553
2554         status = smb2cli_query_info(cli->conn,
2555                                 cli->timeout,
2556                                 cli->smb2.session,
2557                                 cli->smb2.tcon,
2558                                 1, /* in_info_type */
2559                                 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2560                                 0xFFFF, /* in_max_output_length */
2561                                 NULL, /* in_input_buffer */
2562                                 0, /* in_additional_info */
2563                                 0, /* in_flags */
2564                                 ph->fid_persistent,
2565                                 ph->fid_volatile,
2566                                 frame,
2567                                 &outbuf);
2568
2569         if (!NT_STATUS_IS_OK(status)) {
2570                 goto fail;
2571         }
2572
2573         /* Parse the reply. */
2574         ea_list = read_nttrans_ea_list(ctx,
2575                                 (const char *)outbuf.data,
2576                                 outbuf.length);
2577         if (ea_list == NULL) {
2578                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2579                 goto fail;
2580         }
2581
2582         /* Convert to an array. */
2583         for (eal = ea_list; eal; eal = eal->next) {
2584                 ea_count++;
2585         }
2586
2587         if (ea_count) {
2588                 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2589                 if (*pea_array == NULL) {
2590                         status = NT_STATUS_NO_MEMORY;
2591                         goto fail;
2592                 }
2593                 ea_count = 0;
2594                 for (eal = ea_list; eal; eal = eal->next) {
2595                         (*pea_array)[ea_count++] = eal->ea;
2596                 }
2597                 *pnum_eas = ea_count;
2598         }
2599
2600   fail:
2601
2602         if (fnum != 0xffff) {
2603                 cli_smb2_close_fnum(cli, fnum);
2604         }
2605
2606         cli->raw_status = status;
2607
2608         TALLOC_FREE(frame);
2609         return status;
2610 }
2611
2612 /***************************************************************
2613  Wrapper that allows SMB2 to get user quota.
2614  Synchronous only.
2615 ***************************************************************/
2616
2617 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
2618                                  int quota_fnum,
2619                                  SMB_NTQUOTA_STRUCT *pqt)
2620 {
2621         NTSTATUS status;
2622         DATA_BLOB inbuf = data_blob_null;
2623         DATA_BLOB outbuf = data_blob_null;
2624         struct smb2_hnd *ph = NULL;
2625         TALLOC_CTX *frame = talloc_stackframe();
2626         unsigned sid_len;
2627         unsigned int offset;
2628         uint8_t *buf;
2629
2630         if (smbXcli_conn_has_async_calls(cli->conn)) {
2631                 /*
2632                  * Can't use sync call while an async call is in flight
2633                  */
2634                 status = NT_STATUS_INVALID_PARAMETER;
2635                 goto fail;
2636         }
2637
2638         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2639                 status = NT_STATUS_INVALID_PARAMETER;
2640                 goto fail;
2641         }
2642
2643         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2644         if (!NT_STATUS_IS_OK(status)) {
2645                 goto fail;
2646         }
2647
2648         sid_len = ndr_size_dom_sid(&pqt->sid, 0);
2649
2650         inbuf = data_blob_talloc_zero(frame, 24 + sid_len);
2651         if (inbuf.data == NULL) {
2652                 status = NT_STATUS_NO_MEMORY;
2653                 goto fail;
2654         }
2655
2656         buf = inbuf.data;
2657
2658         SCVAL(buf, 0, 1);          /* ReturnSingle */
2659         SCVAL(buf, 1, 0);          /* RestartScan */
2660         SSVAL(buf, 2, 0);          /* Reserved */
2661         if (8 + sid_len < 8) {
2662                 status = NT_STATUS_INVALID_PARAMETER;
2663                 goto fail;
2664         }
2665         SIVAL(buf, 4, 8 + sid_len); /* SidListLength */
2666         SIVAL(buf, 8, 0);          /* StartSidLength */
2667         SIVAL(buf, 12, 0);        /* StartSidOffset */
2668         SIVAL(buf, 16, 0);        /* NextEntryOffset */
2669         SIVAL(buf, 20, sid_len);    /* SidLength */
2670         sid_linearize(buf + 24, sid_len, &pqt->sid);
2671
2672         status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2673                                     cli->smb2.tcon, 4, /* in_info_type */
2674                                     0,                 /* in_file_info_class */
2675                                     0xFFFF, /* in_max_output_length */
2676                                     &inbuf, /* in_input_buffer */
2677                                     0,      /* in_additional_info */
2678                                     0,      /* in_flags */
2679                                     ph->fid_persistent, ph->fid_volatile, frame,
2680                                     &outbuf);
2681
2682         if (!NT_STATUS_IS_OK(status)) {
2683                 goto fail;
2684         }
2685
2686         if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
2687                                      pqt)) {
2688                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2689                 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
2690         }
2691
2692 fail:
2693         cli->raw_status = status;
2694
2695         TALLOC_FREE(frame);
2696         return status;
2697 }
2698
2699 /***************************************************************
2700  Wrapper that allows SMB2 to list user quota.
2701  Synchronous only.
2702 ***************************************************************/
2703
2704 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
2705                                        TALLOC_CTX *mem_ctx,
2706                                        int quota_fnum,
2707                                        SMB_NTQUOTA_LIST **pqt_list,
2708                                        bool first)
2709 {
2710         NTSTATUS status;
2711         DATA_BLOB inbuf = data_blob_null;
2712         DATA_BLOB outbuf = data_blob_null;
2713         struct smb2_hnd *ph = NULL;
2714         TALLOC_CTX *frame = talloc_stackframe();
2715         uint8_t *buf;
2716
2717         if (smbXcli_conn_has_async_calls(cli->conn)) {
2718                 /*
2719                  * Can't use sync call while an async call is in flight
2720                  */
2721                 status = NT_STATUS_INVALID_PARAMETER;
2722                 goto cleanup;
2723         }
2724
2725         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2726                 status = NT_STATUS_INVALID_PARAMETER;
2727                 goto cleanup;
2728         }
2729
2730         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2731         if (!NT_STATUS_IS_OK(status)) {
2732                 goto cleanup;
2733         }
2734
2735         inbuf = data_blob_talloc_zero(frame, 16);
2736         if (inbuf.data == NULL) {
2737                 status = NT_STATUS_NO_MEMORY;
2738                 goto cleanup;
2739         }
2740
2741         buf = inbuf.data;
2742
2743         SCVAL(buf, 0, 0);            /* ReturnSingle */
2744         SCVAL(buf, 1, first ? 1 : 0); /* RestartScan */
2745         SSVAL(buf, 2, 0);            /* Reserved */
2746         SIVAL(buf, 4, 0);            /* SidListLength */
2747         SIVAL(buf, 8, 0);            /* StartSidLength */
2748         SIVAL(buf, 12, 0);          /* StartSidOffset */
2749
2750         status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2751                                     cli->smb2.tcon, 4, /* in_info_type */
2752                                     0,                 /* in_file_info_class */
2753                                     0xFFFF, /* in_max_output_length */
2754                                     &inbuf, /* in_input_buffer */
2755                                     0,      /* in_additional_info */
2756                                     0,      /* in_flags */
2757                                     ph->fid_persistent, ph->fid_volatile, frame,
2758                                     &outbuf);
2759
2760         if (!NT_STATUS_IS_OK(status)) {
2761                 goto cleanup;
2762         }
2763
2764         status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
2765                                        pqt_list);
2766
2767 cleanup:
2768         cli->raw_status = status;
2769
2770         TALLOC_FREE(frame);
2771         return status;
2772 }
2773
2774 /***************************************************************
2775  Wrapper that allows SMB2 to get file system quota.
2776  Synchronous only.
2777 ***************************************************************/
2778
2779 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
2780                                     int quota_fnum,
2781                                     SMB_NTQUOTA_STRUCT *pqt)
2782 {
2783         NTSTATUS status;
2784         DATA_BLOB outbuf = data_blob_null;
2785         struct smb2_hnd *ph = NULL;
2786         TALLOC_CTX *frame = talloc_stackframe();
2787
2788         if (smbXcli_conn_has_async_calls(cli->conn)) {
2789                 /*
2790                  * Can't use sync call while an async call is in flight
2791                  */
2792                 status = NT_STATUS_INVALID_PARAMETER;
2793                 goto cleanup;
2794         }
2795
2796         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2797                 status = NT_STATUS_INVALID_PARAMETER;
2798                 goto cleanup;
2799         }
2800
2801         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2802         if (!NT_STATUS_IS_OK(status)) {
2803                 goto cleanup;
2804         }
2805
2806         status = smb2cli_query_info(
2807             cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
2808             2,                               /* in_info_type */
2809             SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
2810             0xFFFF,                          /* in_max_output_length */
2811             NULL,                            /* in_input_buffer */
2812             0,                               /* in_additional_info */
2813             0,                               /* in_flags */
2814             ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
2815
2816         if (!NT_STATUS_IS_OK(status)) {
2817                 goto cleanup;
2818         }
2819
2820         status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
2821
2822 cleanup:
2823         cli->raw_status = status;
2824
2825         TALLOC_FREE(frame);
2826         return status;
2827 }
2828
2829 /***************************************************************
2830  Wrapper that allows SMB2 to set user quota.
2831  Synchronous only.
2832 ***************************************************************/
2833
2834 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
2835                                  int quota_fnum,
2836                                  SMB_NTQUOTA_LIST *qtl)
2837 {
2838         NTSTATUS status;
2839         DATA_BLOB inbuf = data_blob_null;
2840         struct smb2_hnd *ph = NULL;
2841         TALLOC_CTX *frame = talloc_stackframe();
2842
2843         if (smbXcli_conn_has_async_calls(cli->conn)) {
2844                 /*
2845                  * Can't use sync call while an async call is in flight
2846                  */
2847                 status = NT_STATUS_INVALID_PARAMETER;
2848                 goto cleanup;
2849         }
2850
2851         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2852                 status = NT_STATUS_INVALID_PARAMETER;
2853                 goto cleanup;
2854         }
2855
2856         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2857         if (!NT_STATUS_IS_OK(status)) {
2858                 goto cleanup;
2859         }
2860
2861         status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
2862         if (!NT_STATUS_IS_OK(status)) {
2863                 goto cleanup;
2864         }
2865
2866         status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
2867                                   cli->smb2.tcon, 4, /* in_info_type */
2868                                   0,                 /* in_file_info_class */
2869                                   &inbuf,           /* in_input_buffer */
2870                                   0,                 /* in_additional_info */
2871                                   ph->fid_persistent, ph->fid_volatile);
2872 cleanup:
2873
2874         cli->raw_status = status;
2875
2876         TALLOC_FREE(frame);
2877
2878         return status;
2879 }
2880
2881 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
2882                                     int quota_fnum,
2883                                     SMB_NTQUOTA_STRUCT *pqt)
2884 {
2885         NTSTATUS status;
2886         DATA_BLOB inbuf = data_blob_null;
2887         struct smb2_hnd *ph = NULL;
2888         TALLOC_CTX *frame = talloc_stackframe();
2889
2890         if (smbXcli_conn_has_async_calls(cli->conn)) {
2891                 /*
2892                  * Can't use sync call while an async call is in flight
2893                  */
2894                 status = NT_STATUS_INVALID_PARAMETER;
2895                 goto cleanup;
2896         }
2897
2898         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2899                 status = NT_STATUS_INVALID_PARAMETER;
2900                 goto cleanup;
2901         }
2902
2903         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2904         if (!NT_STATUS_IS_OK(status)) {
2905                 goto cleanup;
2906         }
2907
2908         status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
2909         if (!NT_STATUS_IS_OK(status)) {
2910                 goto cleanup;
2911         }
2912
2913         status = smb2cli_set_info(
2914             cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
2915             2,                               /* in_info_type */
2916             SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
2917             &inbuf,                          /* in_input_buffer */
2918             0,                               /* in_additional_info */
2919             ph->fid_persistent, ph->fid_volatile);
2920 cleanup:
2921         cli->raw_status = status;
2922
2923         TALLOC_FREE(frame);
2924         return status;
2925 }
2926
2927 struct cli_smb2_read_state {
2928         struct tevent_context *ev;
2929         struct cli_state *cli;
2930         struct smb2_hnd *ph;
2931         uint64_t start_offset;
2932         uint32_t size;
2933         uint32_t received;
2934         uint8_t *buf;
2935 };
2936
2937 static void cli_smb2_read_done(struct tevent_req *subreq);
2938
2939 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
2940                                 struct tevent_context *ev,
2941                                 struct cli_state *cli,
2942                                 uint16_t fnum,
2943                                 off_t offset,
2944                                 size_t size)
2945 {
2946         NTSTATUS status;
2947         struct tevent_req *req, *subreq;
2948         struct cli_smb2_read_state *state;
2949
2950         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
2951         if (req == NULL) {
2952                 return NULL;
2953         }
2954         state->ev = ev;
2955         state->cli = cli;
2956         state->start_offset = (uint64_t)offset;
2957         state->size = (uint32_t)size;
2958         state->received = 0;
2959         state->buf = NULL;
2960
2961         status = map_fnum_to_smb2_handle(cli,
2962                                         fnum,
2963                                         &state->ph);
2964         if (tevent_req_nterror(req, status)) {
2965                 return tevent_req_post(req, ev);
2966         }
2967
2968         subreq = smb2cli_read_send(state,
2969                                 state->ev,
2970                                 state->cli->conn,
2971                                 state->cli->timeout,
2972                                 state->cli->smb2.session,
2973                                 state->cli->smb2.tcon,
2974                                 state->size,
2975                                 state->start_offset,
2976                                 state->ph->fid_persistent,
2977                                 state->ph->fid_volatile,
2978                                 0, /* minimum_count */
2979                                 0); /* remaining_bytes */
2980
2981         if (tevent_req_nomem(subreq, req)) {
2982                 return tevent_req_post(req, ev);
2983         }
2984         tevent_req_set_callback(subreq, cli_smb2_read_done, req);
2985         return req;
2986 }
2987
2988 static void cli_smb2_read_done(struct tevent_req *subreq)
2989 {
2990         struct tevent_req *req = tevent_req_callback_data(
2991                 subreq, struct tevent_req);
2992         struct cli_smb2_read_state *state = tevent_req_data(
2993                 req, struct cli_smb2_read_state);
2994         NTSTATUS status;
2995
2996         status = smb2cli_read_recv(subreq, state,
2997                                    &state->buf, &state->received);
2998         if (tevent_req_nterror(req, status)) {
2999                 return;
3000         }
3001
3002         if (state->received > state->size) {
3003                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3004                 return;
3005         }
3006
3007         tevent_req_done(req);
3008 }
3009
3010 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
3011                                 ssize_t *received,
3012                                 uint8_t **rcvbuf)
3013 {
3014         NTSTATUS status;
3015         struct cli_smb2_read_state *state = tevent_req_data(
3016                                 req, struct cli_smb2_read_state);
3017
3018         if (tevent_req_is_nterror(req, &status)) {
3019                 state->cli->raw_status = status;
3020                 return status;
3021         }
3022         /*
3023          * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3024          * better make sure that you copy it away before you talloc_free(req).
3025          * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3026          */
3027         *received = (ssize_t)state->received;
3028         *rcvbuf = state->buf;
3029         state->cli->raw_status = NT_STATUS_OK;
3030         return NT_STATUS_OK;
3031 }
3032
3033 struct cli_smb2_write_state {
3034         struct tevent_context *ev;
3035         struct cli_state *cli;
3036         struct smb2_hnd *ph;
3037         uint32_t flags;
3038         const uint8_t *buf;
3039         uint64_t offset;
3040         uint32_t size;
3041         uint32_t written;
3042 };
3043
3044 static void cli_smb2_write_written(struct tevent_req *req);
3045
3046 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
3047                                         struct tevent_context *ev,
3048                                         struct cli_state *cli,
3049                                         uint16_t fnum,
3050                                         uint16_t mode,
3051                                         const uint8_t *buf,
3052                                         off_t offset,
3053                                         size_t size)
3054 {
3055         NTSTATUS status;
3056         struct tevent_req *req, *subreq = NULL;
3057         struct cli_smb2_write_state *state = NULL;
3058
3059         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
3060         if (req == NULL) {
3061                 return NULL;
3062         }
3063         state->ev = ev;
3064         state->cli = cli;
3065         /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3066         state->flags = (uint32_t)mode;
3067         state->buf = buf;
3068         state->offset = (uint64_t)offset;
3069         state->size = (uint32_t)size;
3070         state->written = 0;
3071
3072         status = map_fnum_to_smb2_handle(cli,
3073                                         fnum,
3074                                         &state->ph);
3075         if (tevent_req_nterror(req, status)) {
3076                 return tevent_req_post(req, ev);
3077         }
3078
3079         subreq = smb2cli_write_send(state,
3080                                 state->ev,
3081                                 state->cli->conn,
3082                                 state->cli->timeout,
3083                                 state->cli->smb2.session,
3084                                 state->cli->smb2.tcon,
3085                                 state->size,
3086                                 state->offset,
3087                                 state->ph->fid_persistent,
3088                                 state->ph->fid_volatile,
3089                                 0, /* remaining_bytes */
3090                                 state->flags, /* flags */
3091                                 state->buf);
3092
3093         if (tevent_req_nomem(subreq, req)) {
3094                 return tevent_req_post(req, ev);
3095         }
3096         tevent_req_set_callback(subreq, cli_smb2_write_written, req);
3097         return req;
3098 }
3099
3100 static void cli_smb2_write_written(struct tevent_req *subreq)
3101 {
3102         struct tevent_req *req = tevent_req_callback_data(
3103                 subreq, struct tevent_req);
3104         struct cli_smb2_write_state *state = tevent_req_data(
3105                 req, struct cli_smb2_write_state);
3106         NTSTATUS status;
3107         uint32_t written;
3108
3109         status = smb2cli_write_recv(subreq, &written);
3110         TALLOC_FREE(subreq);
3111         if (tevent_req_nterror(req, status)) {
3112                 return;
3113         }
3114
3115         state->written = written;
3116
3117         tevent_req_done(req);
3118 }
3119
3120 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
3121                              size_t *pwritten)
3122 {
3123         struct cli_smb2_write_state *state = tevent_req_data(
3124                 req, struct cli_smb2_write_state);
3125         NTSTATUS status;
3126
3127         if (tevent_req_is_nterror(req, &status)) {
3128                 state->cli->raw_status = status;
3129                 tevent_req_received(req);
3130                 return status;
3131         }
3132
3133         if (pwritten != NULL) {
3134                 *pwritten = (size_t)state->written;
3135         }
3136         state->cli->raw_status = NT_STATUS_OK;
3137         tevent_req_received(req);
3138         return NT_STATUS_OK;
3139 }
3140
3141 /***************************************************************
3142  Wrapper that allows SMB2 async write using an fnum.
3143  This is mostly cut-and-paste from Volker's code inside
3144  source3/libsmb/clireadwrite.c, adapted for SMB2.
3145
3146  Done this way so I can reuse all the logic inside cli_push()
3147  for free :-).
3148 ***************************************************************/
3149
3150 struct cli_smb2_writeall_state {
3151         struct tevent_context *ev;
3152         struct cli_state *cli;
3153         struct smb2_hnd *ph;
3154         uint32_t flags;
3155         const uint8_t *buf;
3156         uint64_t offset;
3157         uint32_t size;
3158         uint32_t written;
3159 };
3160
3161 static void cli_smb2_writeall_written(struct tevent_req *req);
3162
3163 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
3164                                         struct tevent_context *ev,
3165                                         struct cli_state *cli,
3166                                         uint16_t fnum,
3167                                         uint16_t mode,
3168                                         const uint8_t *buf,
3169                                         off_t offset,
3170                                         size_t size)
3171 {
3172         NTSTATUS status;
3173         struct tevent_req *req, *subreq = NULL;
3174         struct cli_smb2_writeall_state *state = NULL;
3175         uint32_t to_write;
3176         uint32_t max_size;
3177         bool ok;
3178
3179         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
3180         if (req == NULL) {
3181                 return NULL;
3182         }
3183         state->ev = ev;
3184         state->cli = cli;
3185         /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3186         state->flags = (uint32_t)mode;
3187         state->buf = buf;
3188         state->offset = (uint64_t)offset;
3189         state->size = (uint32_t)size;
3190         state->written = 0;
3191
3192         status = map_fnum_to_smb2_handle(cli,
3193                                         fnum,
3194                                         &state->ph);
3195         if (tevent_req_nterror(req, status)) {
3196                 return tevent_req_post(req, ev);
3197         }
3198
3199         to_write = state->size;
3200         max_size = smb2cli_conn_max_write_size(state->cli->conn);
3201         to_write = MIN(max_size, to_write);
3202         ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3203         if (ok) {
3204                 to_write = MIN(max_size, to_write);
3205         }
3206
3207         subreq = smb2cli_write_send(state,
3208                                 state->ev,
3209                                 state->cli->conn,
3210                                 state->cli->timeout,
3211                                 state->cli->smb2.session,
3212                                 state->cli->smb2.tcon,
3213                                 to_write,
3214                                 state->offset,
3215                                 state->ph->fid_persistent,
3216                                 state->ph->fid_volatile,
3217                                 0, /* remaining_bytes */
3218                                 state->flags, /* flags */
3219                                 state->buf + state->written);
3220
3221         if (tevent_req_nomem(subreq, req)) {
3222                 return tevent_req_post(req, ev);
3223         }
3224         tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3225         return req;
3226 }
3227
3228 static void cli_smb2_writeall_written(struct tevent_req *subreq)
3229 {
3230         struct tevent_req *req = tevent_req_callback_data(
3231                 subreq, struct tevent_req);
3232         struct cli_smb2_writeall_state *state = tevent_req_data(
3233                 req, struct cli_smb2_writeall_state);
3234         NTSTATUS status;
3235         uint32_t written, to_write;
3236         uint32_t max_size;
3237         bool ok;
3238
3239         status = smb2cli_write_recv(subreq, &written);
3240         TALLOC_FREE(subreq);
3241         if (tevent_req_nterror(req, status)) {
3242                 return;
3243         }
3244
3245         state->written += written;
3246
3247         if (state->written > state->size) {
3248                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3249                 return;
3250         }
3251
3252         to_write = state->size - state->written;
3253
3254         if (to_write == 0) {
3255                 tevent_req_done(req);
3256                 return;
3257         }
3258
3259         max_size = smb2cli_conn_max_write_size(state->cli->conn);
3260         to_write = MIN(max_size, to_write);
3261         ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3262         if (ok) {
3263                 to_write = MIN(max_size, to_write);
3264         }
3265
3266         subreq = smb2cli_write_send(state,
3267                                 state->ev,
3268                                 state->cli->conn,
3269                                 state->cli->timeout,
3270                                 state->cli->smb2.session,
3271                                 state->cli->smb2.tcon,
3272                                 to_write,
3273                                 state->offset + state->written,
3274                                 state->ph->fid_persistent,
3275                                 state->ph->fid_volatile,
3276                                 0, /* remaining_bytes */
3277                                 state->flags, /* flags */
3278                                 state->buf + state->written);
3279
3280         if (tevent_req_nomem(subreq, req)) {
3281                 return;
3282         }
3283         tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3284 }
3285
3286 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
3287                                 size_t *pwritten)
3288 {
3289         struct cli_smb2_writeall_state *state = tevent_req_data(
3290                 req, struct cli_smb2_writeall_state);
3291         NTSTATUS status;
3292
3293         if (tevent_req_is_nterror(req, &status)) {
3294                 state->cli->raw_status = status;
3295                 return status;
3296         }
3297         if (pwritten != NULL) {
3298                 *pwritten = (size_t)state->written;
3299         }
3300         state->cli->raw_status = NT_STATUS_OK;
3301         return NT_STATUS_OK;
3302 }
3303
3304 struct cli_smb2_splice_state {
3305         struct tevent_context *ev;
3306         struct cli_state *cli;
3307         struct smb2_hnd *src_ph;
3308         struct smb2_hnd *dst_ph;
3309         int (*splice_cb)(off_t n, void *priv);
3310         void *priv;
3311         off_t written;
3312         off_t size;
3313         off_t src_offset;
3314         off_t dst_offset;
3315         bool resized;
3316         struct req_resume_key_rsp resume_rsp;
3317         struct srv_copychunk_copy cc_copy;
3318 };
3319
3320 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3321                                       struct tevent_req *req);
3322
3323 static void cli_splice_copychunk_done(struct tevent_req *subreq)
3324 {
3325         struct tevent_req *req = tevent_req_callback_data(
3326                 subreq, struct tevent_req);
3327         struct cli_smb2_splice_state *state =
3328                 tevent_req_data(req,
3329                 struct cli_smb2_splice_state);
3330         struct smbXcli_conn *conn = state->cli->conn;
3331         DATA_BLOB out_input_buffer = data_blob_null;
3332         DATA_BLOB out_output_buffer = data_blob_null;
3333         struct srv_copychunk_rsp cc_copy_rsp;
3334         enum ndr_err_code ndr_ret;
3335         NTSTATUS status;
3336
3337         status = smb2cli_ioctl_recv(subreq, state,
3338                                     &out_input_buffer,
3339                                     &out_output_buffer);
3340         TALLOC_FREE(subreq);
3341         if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
3342              state->resized) && tevent_req_nterror(req, status)) {
3343                 return;
3344         }
3345
3346         ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
3347                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
3348         if (ndr_ret != NDR_ERR_SUCCESS) {
3349                 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3350                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3351                 return;
3352         }
3353
3354         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
3355                 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
3356                              cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
3357                 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
3358                      max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
3359                      tevent_req_nterror(req, status)) {
3360                         return;
3361                 }
3362
3363                 state->resized = true;
3364                 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
3365                 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
3366         } else {
3367                 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3368                     (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3369                     (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
3370                         tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3371                         return;
3372                 }
3373                 state->src_offset += cc_copy_rsp.total_bytes_written;
3374                 state->dst_offset += cc_copy_rsp.total_bytes_written;
3375                 state->written += cc_copy_rsp.total_bytes_written;
3376                 if (!state->splice_cb(state->written, state->priv)) {
3377                         tevent_req_nterror(req, NT_STATUS_CANCELLED);
3378                         return;
3379                 }
3380         }
3381
3382         cli_splice_copychunk_send(state, req);
3383 }
3384
3385 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3386                                       struct tevent_req *req)
3387 {
3388         struct tevent_req *subreq;
3389         enum ndr_err_code ndr_ret;
3390         struct smbXcli_conn *conn = state->cli->conn;
3391         struct srv_copychunk_copy *cc_copy = &state->cc_copy;
3392         off_t src_offset = state->src_offset;
3393         off_t dst_offset = state->dst_offset;
3394         uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
3395                                state->size - state->written);
3396         DATA_BLOB in_input_buffer = data_blob_null;
3397         DATA_BLOB in_output_buffer = data_blob_null;
3398
3399         if (state->size - state->written == 0) {
3400                 tevent_req_done(req);
3401                 return;
3402         }
3403
3404         cc_copy->chunk_count = 0;
3405         while (req_len) {
3406                 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
3407                 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
3408                 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
3409                                                                    smb2cli_conn_cc_chunk_len(conn));
3410                 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
3411                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3412                         return;
3413                 }
3414                 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
3415                 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
3416                     (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
3417                         tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3418                         return;
3419                 }
3420                 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3421                 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3422                 cc_copy->chunk_count++;
3423         }
3424
3425         ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
3426                                        (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
3427         if (ndr_ret != NDR_ERR_SUCCESS) {
3428                 DEBUG(0, ("failed to marshall copy chunk req\n"));
3429                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3430                 return;
3431         }
3432
3433         subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
3434                                state->cli->timeout,
3435                                state->cli->smb2.session,
3436                                state->cli->smb2.tcon,
3437                                state->dst_ph->fid_persistent, /* in_fid_persistent */
3438                                state->dst_ph->fid_volatile, /* in_fid_volatile */
3439                                FSCTL_SRV_COPYCHUNK_WRITE,
3440                                0, /* in_max_input_length */
3441                                &in_input_buffer,
3442                                12, /* in_max_output_length */
3443                                &in_output_buffer,
3444                                SMB2_IOCTL_FLAG_IS_FSCTL);
3445         if (tevent_req_nomem(subreq, req)) {
3446                 return;
3447         }
3448         tevent_req_set_callback(subreq,
3449                                 cli_splice_copychunk_done,
3450                                 req);
3451 }
3452
3453 static void cli_splice_key_done(struct tevent_req *subreq)
3454 {
3455         struct tevent_req *req = tevent_req_callback_data(
3456                 subreq, struct tevent_req);
3457         struct cli_smb2_splice_state *state =
3458                 tevent_req_data(req,
3459                 struct cli_smb2_splice_state);
3460         enum ndr_err_code ndr_ret;
3461         NTSTATUS status;
3462
3463         DATA_BLOB out_input_buffer = data_blob_null;
3464         DATA_BLOB out_output_buffer = data_blob_null;
3465
3466         status = smb2cli_ioctl_recv(subreq, state,
3467                                     &out_input_buffer,
3468                                     &out_output_buffer);
3469         TALLOC_FREE(subreq);
3470         if (tevent_req_nterror(req, status)) {
3471                 return;
3472         }
3473
3474         ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
3475                         state, &state->resume_rsp,
3476                         (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
3477         if (ndr_ret != NDR_ERR_SUCCESS) {
3478                 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3479                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3480                 return;
3481         }
3482
3483         memcpy(&state->cc_copy.source_key,
3484                &state->resume_rsp.resume_key,
3485                sizeof state->resume_rsp.resume_key);
3486
3487         cli_splice_copychunk_send(state, req);
3488 }
3489
3490 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
3491                                 struct tevent_context *ev,
3492                                 struct cli_state *cli,
3493                                 uint16_t src_fnum, uint16_t dst_fnum,
3494                                 off_t size, off_t src_offset, off_t dst_offset,
3495                                 int (*splice_cb)(off_t n, void *priv),
3496                                 void *priv)
3497 {
3498         struct tevent_req *req;
3499         struct tevent_req *subreq;
3500         struct cli_smb2_splice_state *state;
3501         NTSTATUS status;
3502         DATA_BLOB in_input_buffer = data_blob_null;
3503         DATA_BLOB in_output_buffer = data_blob_null;
3504
3505         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
3506         if (req == NULL) {
3507                 return NULL;
3508         }
3509         state->cli = cli;
3510         state->ev = ev;
3511         state->splice_cb = splice_cb;
3512         state->priv = priv;
3513         state->size = size;
3514         state->written = 0;
3515         state->src_offset = src_offset;
3516         state->dst_offset = dst_offset;
3517         state->cc_copy.chunks = talloc_array(state,
3518                                              struct srv_copychunk,
3519                                              smb2cli_conn_cc_max_chunks(cli->conn));
3520         if (state->cc_copy.chunks == NULL) {
3521                 return NULL;
3522         }
3523
3524         status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
3525         if (tevent_req_nterror(req, status))
3526                 return tevent_req_post(req, ev);
3527
3528         status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
3529         if (tevent_req_nterror(req, status))
3530                 return tevent_req_post(req, ev);
3531
3532         subreq = smb2cli_ioctl_send(state, ev, cli->conn,
3533                                cli->timeout,
3534                                cli->smb2.session,
3535                                cli->smb2.tcon,
3536                                state->src_ph->fid_persistent, /* in_fid_persistent */
3537                                state->src_ph->fid_volatile, /* in_fid_volatile */
3538                                FSCTL_SRV_REQUEST_RESUME_KEY,
3539                                0, /* in_max_input_length */
3540                                &in_input_buffer,
3541                                32, /* in_max_output_length */
3542                                &in_output_buffer,
3543                                SMB2_IOCTL_FLAG_IS_FSCTL);
3544         if (tevent_req_nomem(subreq, req)) {
3545                 return NULL;
3546         }
3547         tevent_req_set_callback(subreq,
3548                                 cli_splice_key_done,
3549                                 req);
3550
3551         return req;
3552 }
3553
3554 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
3555 {
3556         struct cli_smb2_splice_state *state = tevent_req_data(
3557                 req, struct cli_smb2_splice_state);
3558         NTSTATUS status;
3559
3560         if (tevent_req_is_nterror(req, &status)) {
3561                 state->cli->raw_status = status;
3562                 tevent_req_received(req);
3563                 return status;
3564         }
3565         if (written != NULL) {
3566                 *written = state->written;
3567         }
3568         state->cli->raw_status = NT_STATUS_OK;
3569         tevent_req_received(req);
3570         return NT_STATUS_OK;
3571 }
3572
3573 /***************************************************************
3574  SMB2 enum shadow copy data.
3575 ***************************************************************/
3576
3577 struct cli_smb2_shadow_copy_data_fnum_state {
3578         struct cli_state *cli;
3579         uint16_t fnum;
3580         struct smb2_hnd *ph;
3581         DATA_BLOB out_input_buffer;
3582         DATA_BLOB out_output_buffer;
3583 };
3584
3585 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
3586
3587 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
3588                                         TALLOC_CTX *mem_ctx,
3589                                         struct tevent_context *ev,
3590                                         struct cli_state *cli,
3591                                         uint16_t fnum,
3592                                         bool get_names)
3593 {
3594         struct tevent_req *req, *subreq;
3595         struct cli_smb2_shadow_copy_data_fnum_state *state;
3596         NTSTATUS status;
3597
3598         req = tevent_req_create(mem_ctx, &state,
3599                                 struct cli_smb2_shadow_copy_data_fnum_state);
3600         if (req == NULL) {
3601                 return NULL;
3602         }
3603
3604         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3605                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3606                 return tevent_req_post(req, ev);
3607         }
3608
3609         state->cli = cli;
3610         state->fnum = fnum;
3611
3612         status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
3613         if (tevent_req_nterror(req, status)) {
3614                 return tevent_req_post(req, ev);
3615         }
3616
3617         /*
3618          * TODO. Under SMB2 we should send a zero max_output_length
3619          * ioctl to get the required size, then send another ioctl
3620          * to get the data, but the current SMB1 implementation just
3621          * does one roundtrip with a 64K buffer size. Do the same
3622          * for now. JRA.
3623          */
3624
3625         subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
3626                         state->cli->timeout,
3627                         state->cli->smb2.session,
3628                         state->cli->smb2.tcon,
3629                         state->ph->fid_persistent, /* in_fid_persistent */
3630                         state->ph->fid_volatile, /* in_fid_volatile */
3631                         FSCTL_GET_SHADOW_COPY_DATA,
3632                         0, /* in_max_input_length */
3633                         NULL, /* in_input_buffer */
3634                         get_names ?
3635                                 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
3636                         NULL, /* in_output_buffer */
3637                         SMB2_IOCTL_FLAG_IS_FSCTL);
3638
3639         if (tevent_req_nomem(subreq, req)) {
3640                 return tevent_req_post(req, ev);
3641         }
3642         tevent_req_set_callback(subreq,
3643                                 cli_smb2_shadow_copy_data_fnum_done,
3644                                 req);
3645
3646         return req;
3647 }
3648
3649 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
3650 {
3651         struct tevent_req *req = tevent_req_callback_data(
3652                 subreq, struct tevent_req);
3653         struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3654                 req, struct cli_smb2_shadow_copy_data_fnum_state);
3655         NTSTATUS status;
3656
3657         status = smb2cli_ioctl_recv(subreq, state,
3658                                 &state->out_input_buffer,
3659                                 &state->out_output_buffer);
3660         TALLOC_FREE(subreq);
3661         if (tevent_req_nterror(req, status)) {
3662                 return;
3663         }
3664         tevent_req_done(req);
3665 }
3666
3667 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
3668                                 TALLOC_CTX *mem_ctx,
3669                                 bool get_names,
3670                                 char ***pnames,
3671                                 int *pnum_names)
3672 {
3673         struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3674                 req, struct cli_smb2_shadow_copy_data_fnum_state);
3675         char **names = NULL;
3676         uint32_t num_names = 0;
3677         uint32_t num_names_returned = 0;
3678         uint32_t dlength = 0;
3679         uint32_t i;
3680         uint8_t *endp = NULL;
3681         NTSTATUS status;
3682
3683         if (tevent_req_is_nterror(req, &status)) {
3684                 return status;
3685         }
3686
3687         if (state->out_output_buffer.length < 16) {
3688                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3689         }
3690
3691         num_names = IVAL(state->out_output_buffer.data, 0);
3692         num_names_returned = IVAL(state->out_output_buffer.data, 4);
3693         dlength = IVAL(state->out_output_buffer.data, 8);
3694
3695         if (num_names > 0x7FFFFFFF) {
3696                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3697         }
3698
3699         if (get_names == false) {
3700                 *pnum_names = (int)num_names;
3701                 return NT_STATUS_OK;
3702         }
3703         if (num_names != num_names_returned) {
3704                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3705         }
3706         if (dlength + 12 < 12) {
3707                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3708         }
3709         /*
3710          * NB. The below is an allowable return if there are
3711          * more snapshots than the buffer size we told the
3712          * server we can receive. We currently don't support
3713          * this.
3714          */
3715         if (dlength + 12 > state->out_output_buffer.length) {
3716                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3717         }
3718         if (state->out_output_buffer.length +
3719                         (2 * sizeof(SHADOW_COPY_LABEL)) <
3720                                 state->out_output_buffer.length) {
3721                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3722         }
3723
3724         names = talloc_array(mem_ctx, char *, num_names_returned);
3725         if (names == NULL) {
3726                 return NT_STATUS_NO_MEMORY;
3727         }
3728
3729         endp = state->out_output_buffer.data +
3730                         state->out_output_buffer.length;
3731
3732         for (i=0; i<num_names_returned; i++) {
3733                 bool ret;
3734                 uint8_t *src;
3735                 size_t converted_size;
3736
3737                 src = state->out_output_buffer.data + 12 +
3738                         (i * 2 * sizeof(SHADOW_COPY_LABEL));
3739
3740                 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
3741                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
3742                 }
3743                 ret = convert_string_talloc(
3744                         names, CH_UTF16LE, CH_UNIX,
3745                         src, 2 * sizeof(SHADOW_COPY_LABEL),
3746                         &names[i], &converted_size);
3747                 if (!ret) {
3748                         TALLOC_FREE(names);
3749                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
3750                 }
3751         }
3752         *pnum_names = num_names;
3753         *pnames = names;
3754         return NT_STATUS_OK;
3755 }
3756
3757 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
3758                                 struct cli_state *cli,
3759                                 uint16_t fnum,
3760                                 bool get_names,
3761                                 char ***pnames,
3762                                 int *pnum_names)
3763 {
3764         TALLOC_CTX *frame = talloc_stackframe();
3765         struct tevent_context *ev;
3766         struct tevent_req *req;
3767         NTSTATUS status = NT_STATUS_NO_MEMORY;
3768
3769         if (smbXcli_conn_has_async_calls(cli->conn)) {
3770                 /*
3771                  * Can't use sync call while an async call is in flight
3772                  */
3773                 status = NT_STATUS_INVALID_PARAMETER;
3774                 goto fail;
3775         }
3776         ev = samba_tevent_context_init(frame);
3777         if (ev == NULL) {
3778                 goto fail;
3779         }
3780         req = cli_smb2_shadow_copy_data_fnum_send(frame,
3781                                         ev,
3782                                         cli,
3783                                         fnum,
3784                                         get_names);
3785         if (req == NULL) {
3786                 goto fail;
3787         }
3788         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3789                 goto fail;
3790         }
3791         status = cli_smb2_shadow_copy_data_fnum_recv(req,
3792                                                 mem_ctx,
3793                                                 get_names,
3794                                                 pnames,
3795                                                 pnum_names);
3796  fail:
3797         cli->raw_status = status;
3798
3799         TALLOC_FREE(frame);
3800         return status;
3801 }
3802
3803 /***************************************************************
3804  Wrapper that allows SMB2 to truncate a file.
3805  Synchronous only.
3806 ***************************************************************/
3807
3808 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
3809                         uint16_t fnum,
3810                         uint64_t newsize)
3811 {
3812         NTSTATUS status;
3813         DATA_BLOB inbuf = data_blob_null;
3814         struct smb2_hnd *ph = NULL;
3815         TALLOC_CTX *frame = talloc_stackframe();
3816
3817         if (smbXcli_conn_has_async_calls(cli->conn)) {
3818                 /*
3819                  * Can't use sync call while an async call is in flight
3820                  */
3821                 status = NT_STATUS_INVALID_PARAMETER;
3822                 goto fail;
3823         }
3824
3825         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3826                 status = NT_STATUS_INVALID_PARAMETER;
3827                 goto fail;
3828         }
3829
3830         status = map_fnum_to_smb2_handle(cli,
3831                                         fnum,
3832                                         &ph);
3833         if (!NT_STATUS_IS_OK(status)) {
3834                 goto fail;
3835         }
3836
3837         inbuf = data_blob_talloc_zero(frame, 8);
3838         if (inbuf.data == NULL) {
3839                 status = NT_STATUS_NO_MEMORY;
3840                 goto fail;
3841         }
3842
3843         SBVAL(inbuf.data, 0, newsize);
3844
3845         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3846            level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
3847
3848         status = smb2cli_set_info(cli->conn,
3849                                 cli->timeout,
3850                                 cli->smb2.session,
3851                                 cli->smb2.tcon,
3852                                 1, /* in_info_type */
3853                                         /* in_file_info_class */
3854                                 SMB_FILE_END_OF_FILE_INFORMATION - 1000,
3855                                 &inbuf, /* in_input_buffer */
3856                                 0, /* in_additional_info */
3857                                 ph->fid_persistent,
3858                                 ph->fid_volatile);
3859
3860   fail:
3861
3862         cli->raw_status = status;
3863
3864         TALLOC_FREE(frame);
3865         return status;
3866 }