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