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