CVE-2015-7560: s3: libsmb: Rename cli_posix_getfaclXX() functions to cli_posix_getacl...
[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 "lib/util_ea.h"
41 #include "librpc/gen_ndr/ndr_ioctl.h"
42
43 struct smb2_hnd {
44         uint64_t fid_persistent;
45         uint64_t fid_volatile;
46 };
47
48 /*
49  * Handle mapping code.
50  */
51
52 /***************************************************************
53  Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
54  Ensures handle is owned by cli struct.
55 ***************************************************************/
56
57 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
58                                 const struct smb2_hnd *ph,      /* In */
59                                 uint16_t *pfnum)                /* Out */
60 {
61         int ret;
62         struct idr_context *idp = cli->smb2.open_handles;
63         struct smb2_hnd *owned_h = talloc_memdup(cli,
64                                                 ph,
65                                                 sizeof(struct smb2_hnd));
66
67         if (owned_h == NULL) {
68                 return NT_STATUS_NO_MEMORY;
69         }
70
71         if (idp == NULL) {
72                 /* Lazy init */
73                 cli->smb2.open_handles = idr_init(cli);
74                 if (cli->smb2.open_handles == NULL) {
75                         TALLOC_FREE(owned_h);
76                         return NT_STATUS_NO_MEMORY;
77                 }
78                 idp = cli->smb2.open_handles;
79         }
80
81         ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
82         if (ret == -1) {
83                 TALLOC_FREE(owned_h);
84                 return NT_STATUS_NO_MEMORY;
85         }
86
87         *pfnum = (uint16_t)ret;
88         return NT_STATUS_OK;
89 }
90
91 /***************************************************************
92  Return the smb2_hnd pointer associated with the given fnum.
93 ***************************************************************/
94
95 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
96                                 uint16_t fnum,          /* In */
97                                 struct smb2_hnd **pph)  /* Out */
98 {
99         struct idr_context *idp = cli->smb2.open_handles;
100
101         if (idp == NULL) {
102                 return NT_STATUS_INVALID_PARAMETER;
103         }
104         *pph = (struct smb2_hnd *)idr_find(idp, fnum);
105         if (*pph == NULL) {
106                 return NT_STATUS_INVALID_HANDLE;
107         }
108         return NT_STATUS_OK;
109 }
110
111 /***************************************************************
112  Delete the fnum to smb2_hnd mapping. Zeros out handle on
113  successful return.
114 ***************************************************************/
115
116 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
117                                 struct smb2_hnd **pph,  /* In */
118                                 uint16_t fnum)                  /* In */
119 {
120         struct idr_context *idp = cli->smb2.open_handles;
121         struct smb2_hnd *ph;
122
123         if (idp == NULL) {
124                 return NT_STATUS_INVALID_PARAMETER;
125         }
126
127         ph = (struct smb2_hnd *)idr_find(idp, fnum);
128         if (ph != *pph) {
129                 return NT_STATUS_INVALID_PARAMETER;
130         }
131         idr_remove(idp, fnum);
132         TALLOC_FREE(*pph);
133         return NT_STATUS_OK;
134 }
135
136 /***************************************************************
137  Oplock mapping code.
138 ***************************************************************/
139
140 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
141 {
142         if (create_flags & REQUEST_BATCH_OPLOCK) {
143                 return SMB2_OPLOCK_LEVEL_BATCH;
144         } else if (create_flags & REQUEST_OPLOCK) {
145                 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
146         }
147
148         /* create_flags doesn't do a level2 request. */
149         return SMB2_OPLOCK_LEVEL_NONE;
150 }
151
152 /***************************************************************
153  Small wrapper that allows SMB2 create to return a uint16_t fnum.
154 ***************************************************************/
155
156 struct cli_smb2_create_fnum_state {
157         struct cli_state *cli;
158         struct smb_create_returns cr;
159         uint16_t fnum;
160         struct tevent_req *subreq;
161 };
162
163 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
164 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
165
166 struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
167                                              struct tevent_context *ev,
168                                              struct cli_state *cli,
169                                              const char *fname,
170                                              uint32_t create_flags,
171                                              uint32_t desired_access,
172                                              uint32_t file_attributes,
173                                              uint32_t share_access,
174                                              uint32_t create_disposition,
175                                              uint32_t create_options)
176 {
177         struct tevent_req *req, *subreq;
178         struct cli_smb2_create_fnum_state *state;
179
180         req = tevent_req_create(mem_ctx, &state,
181                                 struct cli_smb2_create_fnum_state);
182         if (req == NULL) {
183                 return NULL;
184         }
185         state->cli = cli;
186
187         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
188                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
189                 return tevent_req_post(req, ev);
190         }
191
192         if (cli->backup_intent) {
193                 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
194         }
195
196         /* SMB2 is pickier about pathnames. Ensure it doesn't
197            start in a '\' */
198         if (*fname == '\\') {
199                 fname++;
200         }
201
202         subreq = smb2cli_create_send(state, ev,
203                                      cli->conn,
204                                      cli->timeout,
205                                      cli->smb2.session,
206                                      cli->smb2.tcon,
207                                      fname,
208                                      flags_to_smb2_oplock(create_flags),
209                                      SMB2_IMPERSONATION_IMPERSONATION,
210                                      desired_access,
211                                      file_attributes,
212                                      share_access,
213                                      create_disposition,
214                                      create_options,
215                                      NULL);
216         if (tevent_req_nomem(subreq, req)) {
217                 return tevent_req_post(req, ev);
218         }
219         tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
220
221         state->subreq = subreq;
222         tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
223
224         return req;
225 }
226
227 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
228 {
229         struct tevent_req *req = tevent_req_callback_data(
230                 subreq, struct tevent_req);
231         struct cli_smb2_create_fnum_state *state = tevent_req_data(
232                 req, struct cli_smb2_create_fnum_state);
233         struct smb2_hnd h;
234         NTSTATUS status;
235
236         status = smb2cli_create_recv(subreq, &h.fid_persistent,
237                                      &h.fid_volatile, &state->cr, NULL, NULL);
238         TALLOC_FREE(subreq);
239         if (tevent_req_nterror(req, status)) {
240                 return;
241         }
242
243         status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
244         if (tevent_req_nterror(req, status)) {
245                 return;
246         }
247         tevent_req_done(req);
248 }
249
250 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
251 {
252         struct cli_smb2_create_fnum_state *state = tevent_req_data(
253                 req, struct cli_smb2_create_fnum_state);
254         return tevent_req_cancel(state->subreq);
255 }
256
257 NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum,
258                                    struct smb_create_returns *cr)
259 {
260         struct cli_smb2_create_fnum_state *state = tevent_req_data(
261                 req, struct cli_smb2_create_fnum_state);
262         NTSTATUS status;
263
264         if (tevent_req_is_nterror(req, &status)) {
265                 return status;
266         }
267         if (pfnum != NULL) {
268                 *pfnum = state->fnum;
269         }
270         if (cr != NULL) {
271                 *cr = state->cr;
272         }
273         return NT_STATUS_OK;
274 }
275
276 NTSTATUS cli_smb2_create_fnum(struct cli_state *cli,
277                         const char *fname,
278                         uint32_t create_flags,
279                         uint32_t desired_access,
280                         uint32_t file_attributes,
281                         uint32_t share_access,
282                         uint32_t create_disposition,
283                         uint32_t create_options,
284                         uint16_t *pfid,
285                         struct smb_create_returns *cr)
286 {
287         TALLOC_CTX *frame = talloc_stackframe();
288         struct tevent_context *ev;
289         struct tevent_req *req;
290         NTSTATUS status = NT_STATUS_NO_MEMORY;
291
292         if (smbXcli_conn_has_async_calls(cli->conn)) {
293                 /*
294                  * Can't use sync call while an async call is in flight
295                  */
296                 status = NT_STATUS_INVALID_PARAMETER;
297                 goto fail;
298         }
299         ev = samba_tevent_context_init(frame);
300         if (ev == NULL) {
301                 goto fail;
302         }
303         req = cli_smb2_create_fnum_send(frame, ev, cli, fname, create_flags,
304                                         desired_access, file_attributes,
305                                         share_access, create_disposition,
306                                         create_options);
307         if (req == NULL) {
308                 goto fail;
309         }
310         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
311                 goto fail;
312         }
313         status = cli_smb2_create_fnum_recv(req, pfid, cr);
314  fail:
315         TALLOC_FREE(frame);
316         return status;
317 }
318
319 /***************************************************************
320  Small wrapper that allows SMB2 close to use a uint16_t fnum.
321 ***************************************************************/
322
323 struct cli_smb2_close_fnum_state {
324         struct cli_state *cli;
325         uint16_t fnum;
326         struct smb2_hnd *ph;
327 };
328
329 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
330
331 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
332                                             struct tevent_context *ev,
333                                             struct cli_state *cli,
334                                             uint16_t fnum)
335 {
336         struct tevent_req *req, *subreq;
337         struct cli_smb2_close_fnum_state *state;
338         NTSTATUS status;
339
340         req = tevent_req_create(mem_ctx, &state,
341                                 struct cli_smb2_close_fnum_state);
342         if (req == NULL) {
343                 return NULL;
344         }
345         state->cli = cli;
346         state->fnum = fnum;
347
348         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
349                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
350                 return tevent_req_post(req, ev);
351         }
352
353         status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
354         if (tevent_req_nterror(req, status)) {
355                 return tevent_req_post(req, ev);
356         }
357
358         subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
359                                     cli->smb2.session, cli->smb2.tcon,
360                                     0, state->ph->fid_persistent,
361                                     state->ph->fid_volatile);
362         if (tevent_req_nomem(subreq, req)) {
363                 return tevent_req_post(req, ev);
364         }
365         tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
366         return req;
367 }
368
369 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
370 {
371         struct tevent_req *req = tevent_req_callback_data(
372                 subreq, struct tevent_req);
373         struct cli_smb2_close_fnum_state *state = tevent_req_data(
374                 req, struct cli_smb2_close_fnum_state);
375         NTSTATUS status;
376
377         status = smb2cli_close_recv(subreq);
378         if (tevent_req_nterror(req, status)) {
379                 return;
380         }
381
382         /* Delete the fnum -> handle mapping. */
383         status = delete_smb2_handle_mapping(state->cli, &state->ph,
384                                             state->fnum);
385         if (tevent_req_nterror(req, status)) {
386                 return;
387         }
388         tevent_req_done(req);
389 }
390
391 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
392 {
393         return tevent_req_simple_recv_ntstatus(req);
394 }
395
396 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
397 {
398         TALLOC_CTX *frame = talloc_stackframe();
399         struct tevent_context *ev;
400         struct tevent_req *req;
401         NTSTATUS status = NT_STATUS_NO_MEMORY;
402
403         if (smbXcli_conn_has_async_calls(cli->conn)) {
404                 /*
405                  * Can't use sync call while an async call is in flight
406                  */
407                 status = NT_STATUS_INVALID_PARAMETER;
408                 goto fail;
409         }
410         ev = samba_tevent_context_init(frame);
411         if (ev == NULL) {
412                 goto fail;
413         }
414         req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
415         if (req == NULL) {
416                 goto fail;
417         }
418         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
419                 goto fail;
420         }
421         status = cli_smb2_close_fnum_recv(req);
422  fail:
423         TALLOC_FREE(frame);
424         return status;
425 }
426
427 /***************************************************************
428  Small wrapper that allows SMB2 to create a directory
429  Synchronous only.
430 ***************************************************************/
431
432 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
433 {
434         NTSTATUS status;
435         uint16_t fnum;
436
437         if (smbXcli_conn_has_async_calls(cli->conn)) {
438                 /*
439                  * Can't use sync call while an async call is in flight
440                  */
441                 return NT_STATUS_INVALID_PARAMETER;
442         }
443
444         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
445                 return NT_STATUS_INVALID_PARAMETER;
446         }
447
448         status = cli_smb2_create_fnum(cli,
449                         dname,
450                         0,                      /* create_flags */
451                         FILE_READ_ATTRIBUTES,   /* desired_access */
452                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
453                         FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
454                         FILE_CREATE,            /* create_disposition */
455                         FILE_DIRECTORY_FILE,    /* create_options */
456                         &fnum,
457                         NULL);
458
459         if (!NT_STATUS_IS_OK(status)) {
460                 return status;
461         }
462         return cli_smb2_close_fnum(cli, fnum);
463 }
464
465 /***************************************************************
466  Small wrapper that allows SMB2 to delete a directory
467  Synchronous only.
468 ***************************************************************/
469
470 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
471 {
472         NTSTATUS status;
473         uint16_t fnum;
474
475         if (smbXcli_conn_has_async_calls(cli->conn)) {
476                 /*
477                  * Can't use sync call while an async call is in flight
478                  */
479                 return NT_STATUS_INVALID_PARAMETER;
480         }
481
482         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
483                 return NT_STATUS_INVALID_PARAMETER;
484         }
485
486         status = cli_smb2_create_fnum(cli,
487                         dname,
488                         0,                      /* create_flags */
489                         DELETE_ACCESS,          /* desired_access */
490                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
491                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
492                         FILE_OPEN,              /* create_disposition */
493                         FILE_DIRECTORY_FILE|FILE_DELETE_ON_CLOSE,       /* create_options */
494                         &fnum,
495                         NULL);
496
497         if (!NT_STATUS_IS_OK(status)) {
498                 return status;
499         }
500         return cli_smb2_close_fnum(cli, fnum);
501 }
502
503 /***************************************************************
504  Small wrapper that allows SMB2 to unlink a pathname.
505  Synchronous only.
506 ***************************************************************/
507
508 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
509 {
510         NTSTATUS status;
511         uint16_t fnum;
512
513         if (smbXcli_conn_has_async_calls(cli->conn)) {
514                 /*
515                  * Can't use sync call while an async call is in flight
516                  */
517                 return NT_STATUS_INVALID_PARAMETER;
518         }
519
520         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
521                 return NT_STATUS_INVALID_PARAMETER;
522         }
523
524         status = cli_smb2_create_fnum(cli,
525                         fname,
526                         0,                      /* create_flags */
527                         DELETE_ACCESS,          /* desired_access */
528                         FILE_ATTRIBUTE_NORMAL, /* file attributes */
529                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
530                         FILE_OPEN,              /* create_disposition */
531                         FILE_DELETE_ON_CLOSE,   /* create_options */
532                         &fnum,
533                         NULL);
534
535         if (!NT_STATUS_IS_OK(status)) {
536                 return status;
537         }
538         return cli_smb2_close_fnum(cli, fnum);
539 }
540
541 /***************************************************************
542  Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
543 ***************************************************************/
544
545 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
546                                 uint32_t dir_data_length,
547                                 struct file_info *finfo,
548                                 uint32_t *next_offset)
549 {
550         size_t namelen = 0;
551         size_t slen = 0;
552         size_t ret = 0;
553
554         if (dir_data_length < 4) {
555                 return NT_STATUS_INFO_LENGTH_MISMATCH;
556         }
557
558         *next_offset = IVAL(dir_data, 0);
559
560         if (*next_offset > dir_data_length) {
561                 return NT_STATUS_INFO_LENGTH_MISMATCH;
562         }
563
564         if (*next_offset != 0) {
565                 /* Ensure we only read what in this record. */
566                 dir_data_length = *next_offset;
567         }
568
569         if (dir_data_length < 105) {
570                 return NT_STATUS_INFO_LENGTH_MISMATCH;
571         }
572
573         finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
574         finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
575         finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
576         finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
577         finfo->mode = CVAL(dir_data + 56, 0);
578         namelen = IVAL(dir_data + 60,0);
579         if (namelen > (dir_data_length - 104)) {
580                 return NT_STATUS_INFO_LENGTH_MISMATCH;
581         }
582         slen = CVAL(dir_data + 68, 0);
583         if (slen > 24) {
584                 return NT_STATUS_INFO_LENGTH_MISMATCH;
585         }
586         ret = pull_string_talloc(finfo,
587                                 dir_data,
588                                 FLAGS2_UNICODE_STRINGS,
589                                 &finfo->short_name,
590                                 dir_data + 70,
591                                 slen,
592                                 STR_UNICODE);
593         if (ret == (size_t)-1) {
594                 /* Bad conversion. */
595                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
596         }
597
598         ret = pull_string_talloc(finfo,
599                                 dir_data,
600                                 FLAGS2_UNICODE_STRINGS,
601                                 &finfo->name,
602                                 dir_data + 104,
603                                 namelen,
604                                 STR_UNICODE);
605         if (ret == (size_t)-1) {
606                 /* Bad conversion. */
607                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
608         }
609         return NT_STATUS_OK;
610 }
611
612 /*******************************************************************
613  Given a filename - get its directory name
614 ********************************************************************/
615
616 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
617                                 const char *dir,
618                                 char **parent,
619                                 const char **name)
620 {
621         char *p;
622         ptrdiff_t len;
623
624         p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
625
626         if (p == NULL) {
627                 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
628                         return false;
629                 }
630                 if (name) {
631                         *name = dir;
632                 }
633                 return true;
634         }
635
636         len = p-dir;
637
638         if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
639                 return false;
640         }
641         (*parent)[len] = '\0';
642
643         if (name) {
644                 *name = p+1;
645         }
646         return true;
647 }
648
649 /***************************************************************
650  Wrapper that allows SMB2 to list a directory.
651  Synchronous only.
652 ***************************************************************/
653
654 NTSTATUS cli_smb2_list(struct cli_state *cli,
655                         const char *pathname,
656                         uint16_t attribute,
657                         NTSTATUS (*fn)(const char *,
658                                 struct file_info *,
659                                 const char *,
660                                 void *),
661                         void *state)
662 {
663         NTSTATUS status;
664         uint16_t fnum = 0xffff;
665         char *parent_dir = NULL;
666         const char *mask = NULL;
667         struct smb2_hnd *ph = NULL;
668         bool processed_file = false;
669         TALLOC_CTX *frame = talloc_stackframe();
670         TALLOC_CTX *subframe = NULL;
671         bool mask_has_wild;
672
673         if (smbXcli_conn_has_async_calls(cli->conn)) {
674                 /*
675                  * Can't use sync call while an async call is in flight
676                  */
677                 status = NT_STATUS_INVALID_PARAMETER;
678                 goto fail;
679         }
680
681         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
682                 status = NT_STATUS_INVALID_PARAMETER;
683                 goto fail;
684         }
685
686         /* Get the directory name. */
687         if (!windows_parent_dirname(frame,
688                                 pathname,
689                                 &parent_dir,
690                                 &mask)) {
691                 status = NT_STATUS_NO_MEMORY;
692                 goto fail;
693         }
694
695         mask_has_wild = ms_has_wild(mask);
696
697         status = cli_smb2_create_fnum(cli,
698                         parent_dir,
699                         0,                      /* create_flags */
700                         SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
701                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
702                         FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
703                         FILE_OPEN,              /* create_disposition */
704                         FILE_DIRECTORY_FILE,    /* create_options */
705                         &fnum,
706                         NULL);
707
708         if (!NT_STATUS_IS_OK(status)) {
709                 goto fail;
710         }
711
712         status = map_fnum_to_smb2_handle(cli,
713                                         fnum,
714                                         &ph);
715         if (!NT_STATUS_IS_OK(status)) {
716                 goto fail;
717         }
718
719         do {
720                 uint8_t *dir_data = NULL;
721                 uint32_t dir_data_length = 0;
722                 uint32_t next_offset = 0;
723                 subframe = talloc_stackframe();
724
725                 status = smb2cli_query_directory(cli->conn,
726                                         cli->timeout,
727                                         cli->smb2.session,
728                                         cli->smb2.tcon,
729                                         SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
730                                         0,      /* flags */
731                                         0,      /* file_index */
732                                         ph->fid_persistent,
733                                         ph->fid_volatile,
734                                         mask,
735                                         0xffff,
736                                         subframe,
737                                         &dir_data,
738                                         &dir_data_length);
739
740                 if (!NT_STATUS_IS_OK(status)) {
741                         if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
742                                 break;
743                         }
744                         goto fail;
745                 }
746
747                 do {
748                         struct file_info *finfo = talloc_zero(subframe,
749                                                         struct file_info);
750
751                         if (finfo == NULL) {
752                                 status = NT_STATUS_NO_MEMORY;
753                                 goto fail;
754                         }
755
756                         status = parse_finfo_id_both_directory_info(dir_data,
757                                                 dir_data_length,
758                                                 finfo,
759                                                 &next_offset);
760
761                         if (!NT_STATUS_IS_OK(status)) {
762                                 goto fail;
763                         }
764
765                         if (dir_check_ftype((uint32_t)finfo->mode,
766                                         (uint32_t)attribute)) {
767                                 /*
768                                  * Only process if attributes match.
769                                  * On SMB1 server does this, so on
770                                  * SMB2 we need to emulate in the
771                                  * client.
772                                  *
773                                  * https://bugzilla.samba.org/show_bug.cgi?id=10260
774                                  */
775                                 processed_file = true;
776
777                                 status = fn(cli->dfs_mountpoint,
778                                         finfo,
779                                         pathname,
780                                         state);
781
782                                 if (!NT_STATUS_IS_OK(status)) {
783                                         break;
784                                 }
785                         }
786
787                         TALLOC_FREE(finfo);
788
789                         /* Move to next entry. */
790                         if (next_offset) {
791                                 dir_data += next_offset;
792                                 dir_data_length -= next_offset;
793                         }
794                 } while (next_offset != 0);
795
796                 TALLOC_FREE(subframe);
797
798                 if (!mask_has_wild) {
799                         /*
800                          * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
801                          * when handed a non-wildcard path. Do it
802                          * for the server (with a non-wildcard path
803                          * there should only ever be one file returned.
804                          */
805                         status = STATUS_NO_MORE_FILES;
806                         break;
807                 }
808
809         } while (NT_STATUS_IS_OK(status));
810
811         if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
812                 status = NT_STATUS_OK;
813         }
814
815         if (NT_STATUS_IS_OK(status) && !processed_file) {
816                 /*
817                  * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
818                  * if no files match. Emulate this in the client.
819                  */
820                 status = NT_STATUS_NO_SUCH_FILE;
821         }
822
823   fail:
824
825         if (fnum != 0xffff) {
826                 cli_smb2_close_fnum(cli, fnum);
827         }
828         TALLOC_FREE(subframe);
829         TALLOC_FREE(frame);
830         return status;
831 }
832
833 /***************************************************************
834  Wrapper that allows SMB2 to query a path info (basic level).
835  Synchronous only.
836 ***************************************************************/
837
838 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
839                                 const char *name,
840                                 SMB_STRUCT_STAT *sbuf,
841                                 uint32_t *attributes)
842 {
843         NTSTATUS status;
844         struct smb_create_returns cr;
845         uint16_t fnum = 0xffff;
846         size_t namelen = strlen(name);
847
848         if (smbXcli_conn_has_async_calls(cli->conn)) {
849                 /*
850                  * Can't use sync call while an async call is in flight
851                  */
852                 return NT_STATUS_INVALID_PARAMETER;
853         }
854
855         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
856                 return NT_STATUS_INVALID_PARAMETER;
857         }
858
859         /* SMB2 is pickier about pathnames. Ensure it doesn't
860            end in a '\' */
861         if (namelen > 0 && name[namelen-1] == '\\') {
862                 char *modname = talloc_strdup(talloc_tos(), name);
863                 modname[namelen-1] = '\0';
864                 name = modname;
865         }
866
867         /* This is commonly used as a 'cd'. Try qpathinfo on
868            a directory handle first. */
869
870         status = cli_smb2_create_fnum(cli,
871                         name,
872                         0,                      /* create_flags */
873                         FILE_READ_ATTRIBUTES,   /* desired_access */
874                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
875                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
876                         FILE_OPEN,              /* create_disposition */
877                         FILE_DIRECTORY_FILE,    /* create_options */
878                         &fnum,
879                         &cr);
880
881         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
882                 /* Maybe a file ? */
883                 status = cli_smb2_create_fnum(cli,
884                         name,
885                         0,                      /* create_flags */
886                         FILE_READ_ATTRIBUTES,           /* desired_access */
887                         0, /* file attributes */
888                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
889                         FILE_OPEN,              /* create_disposition */
890                         0,      /* create_options */
891                         &fnum,
892                         &cr);
893         }
894
895         if (!NT_STATUS_IS_OK(status)) {
896                 return status;
897         }
898
899         cli_smb2_close_fnum(cli, fnum);
900
901         ZERO_STRUCTP(sbuf);
902
903         sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
904         sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
905         sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
906         sbuf->st_ex_size = cr.end_of_file;
907         *attributes = cr.file_attributes;
908
909         return NT_STATUS_OK;
910 }
911
912 /***************************************************************
913  Helper function for pathname operations.
914 ***************************************************************/
915
916 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
917                                 const char *name,
918                                 uint32_t desired_access,
919                                 uint16_t *pfnum)
920 {
921         NTSTATUS status;
922         size_t namelen = strlen(name);
923         TALLOC_CTX *frame = talloc_stackframe();
924
925         /* SMB2 is pickier about pathnames. Ensure it doesn't
926            end in a '\' */
927         if (namelen > 0 && name[namelen-1] == '\\') {
928                 char *modname = talloc_strdup(frame, name);
929                 if (modname == NULL) {
930                         status = NT_STATUS_NO_MEMORY;
931                         goto fail;
932                 }
933                 modname[namelen-1] = '\0';
934                 name = modname;
935         }
936
937         /* Try to open a file handle first. */
938         status = cli_smb2_create_fnum(cli,
939                         name,
940                         0,                      /* create_flags */
941                         desired_access,
942                         0, /* file attributes */
943                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
944                         FILE_OPEN,              /* create_disposition */
945                         0,      /* create_options */
946                         pfnum,
947                         NULL);
948
949         if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
950                 status = cli_smb2_create_fnum(cli,
951                         name,
952                         0,                      /* create_flags */
953                         desired_access,
954                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
955                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
956                         FILE_OPEN,              /* create_disposition */
957                         FILE_DIRECTORY_FILE,    /* create_options */
958                         pfnum,
959                         NULL);
960         }
961
962   fail:
963
964         TALLOC_FREE(frame);
965         return status;
966 }
967
968 /***************************************************************
969  Wrapper that allows SMB2 to query a path info (ALTNAME level).
970  Synchronous only.
971 ***************************************************************/
972
973 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
974                                 const char *name,
975                                 fstring alt_name)
976 {
977         NTSTATUS status;
978         DATA_BLOB outbuf = data_blob_null;
979         uint16_t fnum = 0xffff;
980         struct smb2_hnd *ph = NULL;
981         uint32_t altnamelen = 0;
982         TALLOC_CTX *frame = talloc_stackframe();
983
984         if (smbXcli_conn_has_async_calls(cli->conn)) {
985                 /*
986                  * Can't use sync call while an async call is in flight
987                  */
988                 status = NT_STATUS_INVALID_PARAMETER;
989                 goto fail;
990         }
991
992         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
993                 status = NT_STATUS_INVALID_PARAMETER;
994                 goto fail;
995         }
996
997         status = get_fnum_from_path(cli,
998                                 name,
999                                 FILE_READ_ATTRIBUTES,
1000                                 &fnum);
1001
1002         if (!NT_STATUS_IS_OK(status)) {
1003                 goto fail;
1004         }
1005
1006         status = map_fnum_to_smb2_handle(cli,
1007                                         fnum,
1008                                         &ph);
1009         if (!NT_STATUS_IS_OK(status)) {
1010                 goto fail;
1011         }
1012
1013         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1014            level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1015
1016         status = smb2cli_query_info(cli->conn,
1017                                 cli->timeout,
1018                                 cli->smb2.session,
1019                                 cli->smb2.tcon,
1020                                 1, /* in_info_type */
1021                                 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1022                                 0xFFFF, /* in_max_output_length */
1023                                 NULL, /* in_input_buffer */
1024                                 0, /* in_additional_info */
1025                                 0, /* in_flags */
1026                                 ph->fid_persistent,
1027                                 ph->fid_volatile,
1028                                 frame,
1029                                 &outbuf);
1030
1031         if (!NT_STATUS_IS_OK(status)) {
1032                 goto fail;
1033         }
1034
1035         /* Parse the reply. */
1036         if (outbuf.length < 4) {
1037                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1038                 goto fail;
1039         }
1040
1041         altnamelen = IVAL(outbuf.data, 0);
1042         if (altnamelen > outbuf.length - 4) {
1043                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1044                 goto fail;
1045         }
1046
1047         if (altnamelen > 0) {
1048                 size_t ret = 0;
1049                 char *short_name = NULL;
1050                 ret = pull_string_talloc(frame,
1051                                 outbuf.data,
1052                                 FLAGS2_UNICODE_STRINGS,
1053                                 &short_name,
1054                                 outbuf.data + 4,
1055                                 altnamelen,
1056                                 STR_UNICODE);
1057                 if (ret == (size_t)-1) {
1058                         /* Bad conversion. */
1059                         status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1060                         goto fail;
1061                 }
1062
1063                 fstrcpy(alt_name, short_name);
1064         } else {
1065                 alt_name[0] = '\0';
1066         }
1067
1068         status = NT_STATUS_OK;
1069
1070   fail:
1071
1072         if (fnum != 0xffff) {
1073                 cli_smb2_close_fnum(cli, fnum);
1074         }
1075         TALLOC_FREE(frame);
1076         return status;
1077 }
1078
1079
1080 /***************************************************************
1081  Wrapper that allows SMB2 to query a fnum info (basic level).
1082  Synchronous only.
1083 ***************************************************************/
1084
1085 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1086                         uint16_t fnum,
1087                         uint16_t *mode,
1088                         off_t *size,
1089                         struct timespec *create_time,
1090                         struct timespec *access_time,
1091                         struct timespec *write_time,
1092                         struct timespec *change_time,
1093                         SMB_INO_T *ino)
1094 {
1095         NTSTATUS status;
1096         DATA_BLOB outbuf = data_blob_null;
1097         struct smb2_hnd *ph = NULL;
1098         TALLOC_CTX *frame = talloc_stackframe();
1099
1100         if (smbXcli_conn_has_async_calls(cli->conn)) {
1101                 /*
1102                  * Can't use sync call while an async call is in flight
1103                  */
1104                 status = NT_STATUS_INVALID_PARAMETER;
1105                 goto fail;
1106         }
1107
1108         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1109                 status = NT_STATUS_INVALID_PARAMETER;
1110                 goto fail;
1111         }
1112
1113         status = map_fnum_to_smb2_handle(cli,
1114                                         fnum,
1115                                         &ph);
1116         if (!NT_STATUS_IS_OK(status)) {
1117                 goto fail;
1118         }
1119
1120         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1121            level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1122
1123         status = smb2cli_query_info(cli->conn,
1124                                 cli->timeout,
1125                                 cli->smb2.session,
1126                                 cli->smb2.tcon,
1127                                 1, /* in_info_type */
1128                                 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1129                                 0xFFFF, /* in_max_output_length */
1130                                 NULL, /* in_input_buffer */
1131                                 0, /* in_additional_info */
1132                                 0, /* in_flags */
1133                                 ph->fid_persistent,
1134                                 ph->fid_volatile,
1135                                 frame,
1136                                 &outbuf);
1137         if (!NT_STATUS_IS_OK(status)) {
1138                 goto fail;
1139         }
1140
1141         /* Parse the reply. */
1142         if (outbuf.length < 0x60) {
1143                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1144                 goto fail;
1145         }
1146
1147         if (create_time) {
1148                 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1149         }
1150         if (access_time) {
1151                 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1152         }
1153         if (write_time) {
1154                 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1155         }
1156         if (change_time) {
1157                 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1158         }
1159         if (mode) {
1160                 uint32_t attr = IVAL(outbuf.data, 0x20);
1161                 *mode = (uint16_t)attr;
1162         }
1163         if (size) {
1164                 uint64_t file_size = BVAL(outbuf.data, 0x30);
1165                 *size = (off_t)file_size;
1166         }
1167         if (ino) {
1168                 uint64_t file_index = BVAL(outbuf.data, 0x40);
1169                 *ino = (SMB_INO_T)file_index;
1170         }
1171
1172   fail:
1173
1174         TALLOC_FREE(frame);
1175         return status;
1176 }
1177
1178 /***************************************************************
1179  Wrapper that allows SMB2 to query an fnum.
1180  Implement on top of cli_smb2_qfileinfo_basic().
1181  Synchronous only.
1182 ***************************************************************/
1183
1184 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1185                         uint16_t fnum,
1186                         uint16_t *attr,
1187                         off_t *size,
1188                         time_t *change_time,
1189                         time_t *access_time,
1190                         time_t *write_time)
1191 {
1192         struct timespec access_time_ts;
1193         struct timespec write_time_ts;
1194         struct timespec change_time_ts;
1195         NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1196                                         fnum,
1197                                         attr,
1198                                         size,
1199                                         NULL,
1200                                         &access_time_ts,
1201                                         &write_time_ts,
1202                                         &change_time_ts,
1203                                         NULL);
1204
1205         if (!NT_STATUS_IS_OK(status)) {
1206                 return status;
1207         }
1208
1209         if (change_time) {
1210                 *change_time = change_time_ts.tv_sec;
1211         }
1212         if (access_time) {
1213                 *access_time = access_time_ts.tv_sec;
1214         }
1215         if (write_time) {
1216                 *write_time = write_time_ts.tv_sec;
1217         }
1218         return NT_STATUS_OK;
1219 }
1220
1221 /***************************************************************
1222  Wrapper that allows SMB2 to get pathname attributes.
1223  Synchronous only.
1224 ***************************************************************/
1225
1226 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1227                         const char *name,
1228                         uint16_t *attr,
1229                         off_t *size,
1230                         time_t *write_time)
1231 {
1232         NTSTATUS status;
1233         uint16_t fnum = 0xffff;
1234         struct smb2_hnd *ph = NULL;
1235         TALLOC_CTX *frame = talloc_stackframe();
1236
1237         if (smbXcli_conn_has_async_calls(cli->conn)) {
1238                 /*
1239                  * Can't use sync call while an async call is in flight
1240                  */
1241                 status = NT_STATUS_INVALID_PARAMETER;
1242                 goto fail;
1243         }
1244
1245         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1246                 status = NT_STATUS_INVALID_PARAMETER;
1247                 goto fail;
1248         }
1249
1250         status = get_fnum_from_path(cli,
1251                                 name,
1252                                 FILE_READ_ATTRIBUTES,
1253                                 &fnum);
1254
1255         if (!NT_STATUS_IS_OK(status)) {
1256                 goto fail;
1257         }
1258
1259         status = map_fnum_to_smb2_handle(cli,
1260                                         fnum,
1261                                         &ph);
1262         if (!NT_STATUS_IS_OK(status)) {
1263                 goto fail;
1264         }
1265         status = cli_smb2_getattrE(cli,
1266                                 fnum,
1267                                 attr,
1268                                 size,
1269                                 NULL,
1270                                 NULL,
1271                                 write_time);
1272         if (!NT_STATUS_IS_OK(status)) {
1273                 goto fail;
1274         }
1275
1276   fail:
1277
1278         if (fnum != 0xffff) {
1279                 cli_smb2_close_fnum(cli, fnum);
1280         }
1281
1282         TALLOC_FREE(frame);
1283         return status;
1284 }
1285
1286 /***************************************************************
1287  Wrapper that allows SMB2 to query a pathname info (basic level).
1288  Implement on top of cli_smb2_qfileinfo_basic().
1289  Synchronous only.
1290 ***************************************************************/
1291
1292 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1293                         const char *name,
1294                         struct timespec *create_time,
1295                         struct timespec *access_time,
1296                         struct timespec *write_time,
1297                         struct timespec *change_time,
1298                         off_t *size,
1299                         uint16_t *mode,
1300                         SMB_INO_T *ino)
1301 {
1302         NTSTATUS status;
1303         struct smb2_hnd *ph = NULL;
1304         uint16_t fnum = 0xffff;
1305         TALLOC_CTX *frame = talloc_stackframe();
1306
1307         if (smbXcli_conn_has_async_calls(cli->conn)) {
1308                 /*
1309                  * Can't use sync call while an async call is in flight
1310                  */
1311                 status = NT_STATUS_INVALID_PARAMETER;
1312                 goto fail;
1313         }
1314
1315         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1316                 status = NT_STATUS_INVALID_PARAMETER;
1317                 goto fail;
1318         }
1319
1320         status = get_fnum_from_path(cli,
1321                                         name,
1322                                         FILE_READ_ATTRIBUTES,
1323                                         &fnum);
1324
1325         if (!NT_STATUS_IS_OK(status)) {
1326                 goto fail;
1327         }
1328
1329         status = map_fnum_to_smb2_handle(cli,
1330                                         fnum,
1331                                         &ph);
1332         if (!NT_STATUS_IS_OK(status)) {
1333                 goto fail;
1334         }
1335
1336         status = cli_smb2_qfileinfo_basic(cli,
1337                                         fnum,
1338                                         mode,
1339                                         size,
1340                                         create_time,
1341                                         access_time,
1342                                         write_time,
1343                                         change_time,
1344                                         ino);
1345
1346   fail:
1347
1348         if (fnum != 0xffff) {
1349                 cli_smb2_close_fnum(cli, fnum);
1350         }
1351
1352         TALLOC_FREE(frame);
1353         return status;
1354 }
1355
1356 /***************************************************************
1357  Wrapper that allows SMB2 to query pathname streams.
1358  Synchronous only.
1359 ***************************************************************/
1360
1361 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1362                                 const char *name,
1363                                 TALLOC_CTX *mem_ctx,
1364                                 unsigned int *pnum_streams,
1365                                 struct stream_struct **pstreams)
1366 {
1367         NTSTATUS status;
1368         struct smb2_hnd *ph = NULL;
1369         uint16_t fnum = 0xffff;
1370         DATA_BLOB outbuf = data_blob_null;
1371         TALLOC_CTX *frame = talloc_stackframe();
1372
1373         if (smbXcli_conn_has_async_calls(cli->conn)) {
1374                 /*
1375                  * Can't use sync call while an async call is in flight
1376                  */
1377                 status = NT_STATUS_INVALID_PARAMETER;
1378                 goto fail;
1379         }
1380
1381         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1382                 status = NT_STATUS_INVALID_PARAMETER;
1383                 goto fail;
1384         }
1385
1386         status = get_fnum_from_path(cli,
1387                                 name,
1388                                 FILE_READ_ATTRIBUTES,
1389                                 &fnum);
1390
1391         if (!NT_STATUS_IS_OK(status)) {
1392                 goto fail;
1393         }
1394
1395         status = map_fnum_to_smb2_handle(cli,
1396                                         fnum,
1397                                         &ph);
1398         if (!NT_STATUS_IS_OK(status)) {
1399                 goto fail;
1400         }
1401
1402         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1403            level 22 (SMB2_FILE_STREAM_INFORMATION). */
1404
1405         status = smb2cli_query_info(cli->conn,
1406                                 cli->timeout,
1407                                 cli->smb2.session,
1408                                 cli->smb2.tcon,
1409                                 1, /* in_info_type */
1410                                 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1411                                 0xFFFF, /* in_max_output_length */
1412                                 NULL, /* in_input_buffer */
1413                                 0, /* in_additional_info */
1414                                 0, /* in_flags */
1415                                 ph->fid_persistent,
1416                                 ph->fid_volatile,
1417                                 frame,
1418                                 &outbuf);
1419
1420         if (!NT_STATUS_IS_OK(status)) {
1421                 goto fail;
1422         }
1423
1424         /* Parse the reply. */
1425         if (!parse_streams_blob(mem_ctx,
1426                                 outbuf.data,
1427                                 outbuf.length,
1428                                 pnum_streams,
1429                                 pstreams)) {
1430                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1431                 goto fail;
1432         }
1433
1434   fail:
1435
1436         if (fnum != 0xffff) {
1437                 cli_smb2_close_fnum(cli, fnum);
1438         }
1439
1440         TALLOC_FREE(frame);
1441         return status;
1442 }
1443
1444 /***************************************************************
1445  Wrapper that allows SMB2 to set pathname attributes.
1446  Synchronous only.
1447 ***************************************************************/
1448
1449 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1450                         const char *name,
1451                         uint16_t attr,
1452                         time_t mtime)
1453 {
1454         NTSTATUS status;
1455         uint16_t fnum = 0xffff;
1456         struct smb2_hnd *ph = NULL;
1457         uint8_t inbuf_store[40];
1458         DATA_BLOB inbuf = data_blob_null;
1459         TALLOC_CTX *frame = talloc_stackframe();
1460
1461         if (smbXcli_conn_has_async_calls(cli->conn)) {
1462                 /*
1463                  * Can't use sync call while an async call is in flight
1464                  */
1465                 status = NT_STATUS_INVALID_PARAMETER;
1466                 goto fail;
1467         }
1468
1469         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1470                 status = NT_STATUS_INVALID_PARAMETER;
1471                 goto fail;
1472         }
1473
1474         status = get_fnum_from_path(cli,
1475                                 name,
1476                                 FILE_WRITE_ATTRIBUTES,
1477                                 &fnum);
1478
1479         if (!NT_STATUS_IS_OK(status)) {
1480                 goto fail;
1481         }
1482
1483         status = map_fnum_to_smb2_handle(cli,
1484                                         fnum,
1485                                         &ph);
1486         if (!NT_STATUS_IS_OK(status)) {
1487                 goto fail;
1488         }
1489
1490         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1491            level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1492
1493         inbuf.data = inbuf_store;
1494         inbuf.length = sizeof(inbuf_store);
1495         data_blob_clear(&inbuf);
1496
1497         SSVAL(inbuf.data, 32, attr);
1498         if (mtime != 0) {
1499                 put_long_date((char *)inbuf.data + 16,mtime);
1500         }
1501         /* Set all the other times to -1. */
1502         SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1503         SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1504         SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1505
1506         status = smb2cli_set_info(cli->conn,
1507                                 cli->timeout,
1508                                 cli->smb2.session,
1509                                 cli->smb2.tcon,
1510                                 1, /* in_info_type */
1511                                 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1512                                 &inbuf, /* in_input_buffer */
1513                                 0, /* in_additional_info */
1514                                 ph->fid_persistent,
1515                                 ph->fid_volatile);
1516   fail:
1517
1518         if (fnum != 0xffff) {
1519                 cli_smb2_close_fnum(cli, fnum);
1520         }
1521
1522         TALLOC_FREE(frame);
1523         return status;
1524 }
1525
1526 /***************************************************************
1527  Wrapper that allows SMB2 to set file handle times.
1528  Synchronous only.
1529 ***************************************************************/
1530
1531 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1532                         uint16_t fnum,
1533                         time_t change_time,
1534                         time_t access_time,
1535                         time_t write_time)
1536 {
1537         NTSTATUS status;
1538         struct smb2_hnd *ph = NULL;
1539         uint8_t inbuf_store[40];
1540         DATA_BLOB inbuf = data_blob_null;
1541
1542         if (smbXcli_conn_has_async_calls(cli->conn)) {
1543                 /*
1544                  * Can't use sync call while an async call is in flight
1545                  */
1546                 return NT_STATUS_INVALID_PARAMETER;
1547         }
1548
1549         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1550                 return NT_STATUS_INVALID_PARAMETER;
1551         }
1552
1553         status = map_fnum_to_smb2_handle(cli,
1554                                         fnum,
1555                                         &ph);
1556         if (!NT_STATUS_IS_OK(status)) {
1557                 return status;
1558         }
1559
1560         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1561            level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1562
1563         inbuf.data = inbuf_store;
1564         inbuf.length = sizeof(inbuf_store);
1565         data_blob_clear(&inbuf);
1566
1567         SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1568         if (change_time != 0) {
1569                 put_long_date((char *)inbuf.data + 24, change_time);
1570         }
1571         if (access_time != 0) {
1572                 put_long_date((char *)inbuf.data + 8, access_time);
1573         }
1574         if (write_time != 0) {
1575                 put_long_date((char *)inbuf.data + 16, write_time);
1576         }
1577
1578         return smb2cli_set_info(cli->conn,
1579                                 cli->timeout,
1580                                 cli->smb2.session,
1581                                 cli->smb2.tcon,
1582                                 1, /* in_info_type */
1583                                 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1584                                 &inbuf, /* in_input_buffer */
1585                                 0, /* in_additional_info */
1586                                 ph->fid_persistent,
1587                                 ph->fid_volatile);
1588 }
1589
1590 /***************************************************************
1591  Wrapper that allows SMB2 to query disk attributes (size).
1592  Synchronous only.
1593 ***************************************************************/
1594
1595 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
1596                           uint64_t *bsize, uint64_t *total, uint64_t *avail)
1597 {
1598         NTSTATUS status;
1599         uint16_t fnum = 0xffff;
1600         DATA_BLOB outbuf = data_blob_null;
1601         struct smb2_hnd *ph = NULL;
1602         uint32_t sectors_per_unit = 0;
1603         uint32_t bytes_per_sector = 0;
1604         uint64_t total_size = 0;
1605         uint64_t size_free = 0;
1606         TALLOC_CTX *frame = talloc_stackframe();
1607
1608         if (smbXcli_conn_has_async_calls(cli->conn)) {
1609                 /*
1610                  * Can't use sync call while an async call is in flight
1611                  */
1612                 status = NT_STATUS_INVALID_PARAMETER;
1613                 goto fail;
1614         }
1615
1616         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1617                 status = NT_STATUS_INVALID_PARAMETER;
1618                 goto fail;
1619         }
1620
1621         /* First open the top level directory. */
1622         status = cli_smb2_create_fnum(cli,
1623                         path,
1624                         0,                      /* create_flags */
1625                         FILE_READ_ATTRIBUTES,   /* desired_access */
1626                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1627                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1628                         FILE_OPEN,              /* create_disposition */
1629                         FILE_DIRECTORY_FILE,    /* create_options */
1630                         &fnum,
1631                         NULL);
1632
1633         if (!NT_STATUS_IS_OK(status)) {
1634                 goto fail;
1635         }
1636
1637         status = map_fnum_to_smb2_handle(cli,
1638                                         fnum,
1639                                         &ph);
1640         if (!NT_STATUS_IS_OK(status)) {
1641                 goto fail;
1642         }
1643
1644         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1645            level 3 (SMB_FS_SIZE_INFORMATION). */
1646
1647         status = smb2cli_query_info(cli->conn,
1648                                 cli->timeout,
1649                                 cli->smb2.session,
1650                                 cli->smb2.tcon,
1651                                 2, /* in_info_type */
1652                                 3, /* in_file_info_class */
1653                                 0xFFFF, /* in_max_output_length */
1654                                 NULL, /* in_input_buffer */
1655                                 0, /* in_additional_info */
1656                                 0, /* in_flags */
1657                                 ph->fid_persistent,
1658                                 ph->fid_volatile,
1659                                 frame,
1660                                 &outbuf);
1661         if (!NT_STATUS_IS_OK(status)) {
1662                 goto fail;
1663         }
1664
1665         /* Parse the reply. */
1666         if (outbuf.length != 24) {
1667                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1668                 goto fail;
1669         }
1670
1671         total_size = BVAL(outbuf.data, 0);
1672         size_free = BVAL(outbuf.data, 8);
1673         sectors_per_unit = IVAL(outbuf.data, 16);
1674         bytes_per_sector = IVAL(outbuf.data, 20);
1675
1676         if (bsize) {
1677                 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
1678         }
1679         if (total) {
1680                 *total = total_size;
1681         }
1682         if (avail) {
1683                 *avail = size_free;
1684         }
1685
1686         status = NT_STATUS_OK;
1687
1688   fail:
1689
1690         if (fnum != 0xffff) {
1691                 cli_smb2_close_fnum(cli, fnum);
1692         }
1693
1694         TALLOC_FREE(frame);
1695         return status;
1696 }
1697
1698 /***************************************************************
1699  Wrapper that allows SMB2 to query a security descriptor.
1700  Synchronous only.
1701 ***************************************************************/
1702
1703 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
1704                                         uint16_t fnum,
1705                                         uint32_t sec_info,
1706                                         TALLOC_CTX *mem_ctx,
1707                                         struct security_descriptor **ppsd)
1708 {
1709         NTSTATUS status;
1710         DATA_BLOB outbuf = data_blob_null;
1711         struct smb2_hnd *ph = NULL;
1712         struct security_descriptor *lsd = NULL;
1713         TALLOC_CTX *frame = talloc_stackframe();
1714
1715         if (smbXcli_conn_has_async_calls(cli->conn)) {
1716                 /*
1717                  * Can't use sync call while an async call is in flight
1718                  */
1719                 status = NT_STATUS_INVALID_PARAMETER;
1720                 goto fail;
1721         }
1722
1723         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1724                 status = NT_STATUS_INVALID_PARAMETER;
1725                 goto fail;
1726         }
1727
1728         status = map_fnum_to_smb2_handle(cli,
1729                                         fnum,
1730                                         &ph);
1731         if (!NT_STATUS_IS_OK(status)) {
1732                 goto fail;
1733         }
1734
1735         /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1736
1737         status = smb2cli_query_info(cli->conn,
1738                                 cli->timeout,
1739                                 cli->smb2.session,
1740                                 cli->smb2.tcon,
1741                                 3, /* in_info_type */
1742                                 0, /* in_file_info_class */
1743                                 0xFFFF, /* in_max_output_length */
1744                                 NULL, /* in_input_buffer */
1745                                 sec_info, /* in_additional_info */
1746                                 0, /* in_flags */
1747                                 ph->fid_persistent,
1748                                 ph->fid_volatile,
1749                                 frame,
1750                                 &outbuf);
1751
1752         if (!NT_STATUS_IS_OK(status)) {
1753                 goto fail;
1754         }
1755
1756         /* Parse the reply. */
1757         status = unmarshall_sec_desc(mem_ctx,
1758                                 outbuf.data,
1759                                 outbuf.length,
1760                                 &lsd);
1761
1762         if (!NT_STATUS_IS_OK(status)) {
1763                 goto fail;
1764         }
1765
1766         if (ppsd != NULL) {
1767                 *ppsd = lsd;
1768         } else {
1769                 TALLOC_FREE(lsd);
1770         }
1771
1772   fail:
1773
1774         TALLOC_FREE(frame);
1775         return status;
1776 }
1777
1778 /***************************************************************
1779  Wrapper that allows SMB2 to set a security descriptor.
1780  Synchronous only.
1781 ***************************************************************/
1782
1783 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
1784                                         uint16_t fnum,
1785                                         uint32_t sec_info,
1786                                         const struct security_descriptor *sd)
1787 {
1788         NTSTATUS status;
1789         DATA_BLOB inbuf = data_blob_null;
1790         struct smb2_hnd *ph = NULL;
1791         TALLOC_CTX *frame = talloc_stackframe();
1792
1793         if (smbXcli_conn_has_async_calls(cli->conn)) {
1794                 /*
1795                  * Can't use sync call while an async call is in flight
1796                  */
1797                 status = NT_STATUS_INVALID_PARAMETER;
1798                 goto fail;
1799         }
1800
1801         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1802                 status = NT_STATUS_INVALID_PARAMETER;
1803                 goto fail;
1804         }
1805
1806         status = map_fnum_to_smb2_handle(cli,
1807                                         fnum,
1808                                         &ph);
1809         if (!NT_STATUS_IS_OK(status)) {
1810                 goto fail;
1811         }
1812
1813         status = marshall_sec_desc(frame,
1814                                 sd,
1815                                 &inbuf.data,
1816                                 &inbuf.length);
1817
1818         if (!NT_STATUS_IS_OK(status)) {
1819                 goto fail;
1820         }
1821
1822         /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1823
1824         status = smb2cli_set_info(cli->conn,
1825                                 cli->timeout,
1826                                 cli->smb2.session,
1827                                 cli->smb2.tcon,
1828                                 3, /* in_info_type */
1829                                 0, /* in_file_info_class */
1830                                 &inbuf, /* in_input_buffer */
1831                                 sec_info, /* in_additional_info */
1832                                 ph->fid_persistent,
1833                                 ph->fid_volatile);
1834
1835   fail:
1836
1837         TALLOC_FREE(frame);
1838         return status;
1839 }
1840
1841 /***************************************************************
1842  Wrapper that allows SMB2 to rename a file.
1843  Synchronous only.
1844 ***************************************************************/
1845
1846 NTSTATUS cli_smb2_rename(struct cli_state *cli,
1847                         const char *fname_src,
1848                         const char *fname_dst)
1849 {
1850         NTSTATUS status;
1851         DATA_BLOB inbuf = data_blob_null;
1852         uint16_t fnum = 0xffff;
1853         struct smb2_hnd *ph = NULL;
1854         smb_ucs2_t *converted_str = NULL;
1855         size_t converted_size_bytes = 0;
1856         size_t namelen = 0;
1857         TALLOC_CTX *frame = talloc_stackframe();
1858
1859         if (smbXcli_conn_has_async_calls(cli->conn)) {
1860                 /*
1861                  * Can't use sync call while an async call is in flight
1862                  */
1863                 status = NT_STATUS_INVALID_PARAMETER;
1864                 goto fail;
1865         }
1866
1867         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1868                 status = NT_STATUS_INVALID_PARAMETER;
1869                 goto fail;
1870         }
1871
1872         status = get_fnum_from_path(cli,
1873                                 fname_src,
1874                                 DELETE_ACCESS,
1875                                 &fnum);
1876
1877         if (!NT_STATUS_IS_OK(status)) {
1878                 goto fail;
1879         }
1880
1881         status = map_fnum_to_smb2_handle(cli,
1882                                         fnum,
1883                                         &ph);
1884         if (!NT_STATUS_IS_OK(status)) {
1885                 goto fail;
1886         }
1887
1888         /* SMB2 is pickier about pathnames. Ensure it doesn't
1889            start in a '\' */
1890         if (*fname_dst == '\\') {
1891                 fname_dst++;
1892         }
1893
1894         /* SMB2 is pickier about pathnames. Ensure it doesn't
1895            end in a '\' */
1896         namelen = strlen(fname_dst);
1897         if (namelen > 0 && fname_dst[namelen-1] == '\\') {
1898                 char *modname = talloc_strdup(frame, fname_dst);
1899                 modname[namelen-1] = '\0';
1900                 fname_dst = modname;
1901         }
1902
1903         if (!push_ucs2_talloc(frame,
1904                                 &converted_str,
1905                                 fname_dst,
1906                                 &converted_size_bytes)) {
1907                 status = NT_STATUS_INVALID_PARAMETER;
1908                 goto fail;
1909         }
1910
1911         /* W2K8 insists the dest name is not null
1912            terminated. Remove the last 2 zero bytes
1913            and reduce the name length. */
1914
1915         if (converted_size_bytes < 2) {
1916                 status = NT_STATUS_INVALID_PARAMETER;
1917                 goto fail;
1918         }
1919         converted_size_bytes -= 2;
1920
1921         inbuf = data_blob_talloc_zero(frame,
1922                                 20 + converted_size_bytes);
1923         if (inbuf.data == NULL) {
1924                 status = NT_STATUS_NO_MEMORY;
1925                 goto fail;
1926         }
1927
1928         SIVAL(inbuf.data, 16, converted_size_bytes);
1929         memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
1930
1931         /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
1932            level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
1933
1934         status = smb2cli_set_info(cli->conn,
1935                                 cli->timeout,
1936                                 cli->smb2.session,
1937                                 cli->smb2.tcon,
1938                                 1, /* in_info_type */
1939                                 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
1940                                 &inbuf, /* in_input_buffer */
1941                                 0, /* in_additional_info */
1942                                 ph->fid_persistent,
1943                                 ph->fid_volatile);
1944
1945   fail:
1946
1947         if (fnum != 0xffff) {
1948                 cli_smb2_close_fnum(cli, fnum);
1949         }
1950
1951         TALLOC_FREE(frame);
1952         return status;
1953 }
1954
1955 /***************************************************************
1956  Wrapper that allows SMB2 to set an EA on a fnum.
1957  Synchronous only.
1958 ***************************************************************/
1959
1960 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
1961                         uint16_t fnum,
1962                         const char *ea_name,
1963                         const char *ea_val,
1964                         size_t ea_len)
1965 {
1966         NTSTATUS status;
1967         DATA_BLOB inbuf = data_blob_null;
1968         size_t bloblen = 0;
1969         char *ea_name_ascii = NULL;
1970         size_t namelen = 0;
1971         struct smb2_hnd *ph = NULL;
1972         TALLOC_CTX *frame = talloc_stackframe();
1973
1974         if (smbXcli_conn_has_async_calls(cli->conn)) {
1975                 /*
1976                  * Can't use sync call while an async call is in flight
1977                  */
1978                 status = NT_STATUS_INVALID_PARAMETER;
1979                 goto fail;
1980         }
1981
1982         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1983                 status = NT_STATUS_INVALID_PARAMETER;
1984                 goto fail;
1985         }
1986
1987         status = map_fnum_to_smb2_handle(cli,
1988                                         fnum,
1989                                         &ph);
1990         if (!NT_STATUS_IS_OK(status)) {
1991                 goto fail;
1992         }
1993
1994         /* Marshall the SMB2 EA data. */
1995         if (ea_len > 0xFFFF) {
1996                 status = NT_STATUS_INVALID_PARAMETER;
1997                 goto fail;
1998         }
1999
2000         if (!push_ascii_talloc(frame,
2001                                 &ea_name_ascii,
2002                                 ea_name,
2003                                 &namelen)) {
2004                 status = NT_STATUS_INVALID_PARAMETER;
2005                 goto fail;
2006         }
2007
2008         if (namelen < 2 || namelen > 0xFF) {
2009                 status = NT_STATUS_INVALID_PARAMETER;
2010                 goto fail;
2011         }
2012
2013         bloblen = 8 + ea_len + namelen;
2014         /* Round up to a 4 byte boundary. */
2015         bloblen = ((bloblen + 3)&~3);
2016
2017         inbuf = data_blob_talloc_zero(frame, bloblen);
2018         if (inbuf.data == NULL) {
2019                 status = NT_STATUS_NO_MEMORY;
2020                 goto fail;
2021         }
2022         /* namelen doesn't include the NULL byte. */
2023         SCVAL(inbuf.data, 5, namelen - 1);
2024         SSVAL(inbuf.data, 6, ea_len);
2025         memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2026         memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2027
2028         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2029            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2030
2031         status = smb2cli_set_info(cli->conn,
2032                                 cli->timeout,
2033                                 cli->smb2.session,
2034                                 cli->smb2.tcon,
2035                                 1, /* in_info_type */
2036                                 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2037                                 &inbuf, /* in_input_buffer */
2038                                 0, /* in_additional_info */
2039                                 ph->fid_persistent,
2040                                 ph->fid_volatile);
2041
2042   fail:
2043
2044         TALLOC_FREE(frame);
2045         return status;
2046 }
2047
2048 /***************************************************************
2049  Wrapper that allows SMB2 to set an EA on a pathname.
2050  Synchronous only.
2051 ***************************************************************/
2052
2053 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2054                         const char *name,
2055                         const char *ea_name,
2056                         const char *ea_val,
2057                         size_t ea_len)
2058 {
2059         NTSTATUS status;
2060         uint16_t fnum = 0xffff;
2061
2062         if (smbXcli_conn_has_async_calls(cli->conn)) {
2063                 /*
2064                  * Can't use sync call while an async call is in flight
2065                  */
2066                 status = NT_STATUS_INVALID_PARAMETER;
2067                 goto fail;
2068         }
2069
2070         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2071                 status = NT_STATUS_INVALID_PARAMETER;
2072                 goto fail;
2073         }
2074
2075         status = get_fnum_from_path(cli,
2076                                 name,
2077                                 FILE_WRITE_EA,
2078                                 &fnum);
2079
2080         if (!NT_STATUS_IS_OK(status)) {
2081                 goto fail;
2082         }
2083
2084         status = cli_set_ea_fnum(cli,
2085                                 fnum,
2086                                 ea_name,
2087                                 ea_val,
2088                                 ea_len);
2089         if (!NT_STATUS_IS_OK(status)) {
2090                 goto fail;
2091         }
2092
2093   fail:
2094
2095         if (fnum != 0xffff) {
2096                 cli_smb2_close_fnum(cli, fnum);
2097         }
2098
2099         return status;
2100 }
2101
2102 /***************************************************************
2103  Wrapper that allows SMB2 to get an EA list on a pathname.
2104  Synchronous only.
2105 ***************************************************************/
2106
2107 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2108                                 const char *name,
2109                                 TALLOC_CTX *ctx,
2110                                 size_t *pnum_eas,
2111                                 struct ea_struct **pea_array)
2112 {
2113         NTSTATUS status;
2114         uint16_t fnum = 0xffff;
2115         DATA_BLOB outbuf = data_blob_null;
2116         struct smb2_hnd *ph = NULL;
2117         struct ea_list *ea_list = NULL;
2118         struct ea_list *eal = NULL;
2119         size_t ea_count = 0;
2120         TALLOC_CTX *frame = talloc_stackframe();
2121
2122         *pnum_eas = 0;
2123         *pea_array = NULL;
2124
2125         if (smbXcli_conn_has_async_calls(cli->conn)) {
2126                 /*
2127                  * Can't use sync call while an async call is in flight
2128                  */
2129                 status = NT_STATUS_INVALID_PARAMETER;
2130                 goto fail;
2131         }
2132
2133         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2134                 status = NT_STATUS_INVALID_PARAMETER;
2135                 goto fail;
2136         }
2137
2138         status = get_fnum_from_path(cli,
2139                                 name,
2140                                 FILE_READ_EA,
2141                                 &fnum);
2142
2143         if (!NT_STATUS_IS_OK(status)) {
2144                 goto fail;
2145         }
2146
2147         status = map_fnum_to_smb2_handle(cli,
2148                                         fnum,
2149                                         &ph);
2150         if (!NT_STATUS_IS_OK(status)) {
2151                 goto fail;
2152         }
2153
2154         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2155            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2156
2157         status = smb2cli_query_info(cli->conn,
2158                                 cli->timeout,
2159                                 cli->smb2.session,
2160                                 cli->smb2.tcon,
2161                                 1, /* in_info_type */
2162                                 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2163                                 0xFFFF, /* in_max_output_length */
2164                                 NULL, /* in_input_buffer */
2165                                 0, /* in_additional_info */
2166                                 0, /* in_flags */
2167                                 ph->fid_persistent,
2168                                 ph->fid_volatile,
2169                                 frame,
2170                                 &outbuf);
2171
2172         if (!NT_STATUS_IS_OK(status)) {
2173                 goto fail;
2174         }
2175
2176         /* Parse the reply. */
2177         ea_list = read_nttrans_ea_list(ctx,
2178                                 (const char *)outbuf.data,
2179                                 outbuf.length);
2180         if (ea_list == NULL) {
2181                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2182                 goto fail;
2183         }
2184
2185         /* Convert to an array. */
2186         for (eal = ea_list; eal; eal = eal->next) {
2187                 ea_count++;
2188         }
2189
2190         if (ea_count) {
2191                 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2192                 if (*pea_array == NULL) {
2193                         status = NT_STATUS_NO_MEMORY;
2194                         goto fail;
2195                 }
2196                 ea_count = 0;
2197                 for (eal = ea_list; eal; eal = eal->next) {
2198                         (*pea_array)[ea_count++] = eal->ea;
2199                 }
2200                 *pnum_eas = ea_count;
2201         }
2202
2203   fail:
2204
2205         if (fnum != 0xffff) {
2206                 cli_smb2_close_fnum(cli, fnum);
2207         }
2208
2209         TALLOC_FREE(frame);
2210         return status;
2211 }
2212
2213 struct cli_smb2_read_state {
2214         struct tevent_context *ev;
2215         struct cli_state *cli;
2216         struct smb2_hnd *ph;
2217         uint64_t start_offset;
2218         uint32_t size;
2219         uint32_t received;
2220         uint8_t *buf;
2221 };
2222
2223 static void cli_smb2_read_done(struct tevent_req *subreq);
2224
2225 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
2226                                 struct tevent_context *ev,
2227                                 struct cli_state *cli,
2228                                 uint16_t fnum,
2229                                 off_t offset,
2230                                 size_t size)
2231 {
2232         NTSTATUS status;
2233         struct tevent_req *req, *subreq;
2234         struct cli_smb2_read_state *state;
2235
2236         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
2237         if (req == NULL) {
2238                 return NULL;
2239         }
2240         state->ev = ev;
2241         state->cli = cli;
2242         state->start_offset = (uint64_t)offset;
2243         state->size = (uint32_t)size;
2244         state->received = 0;
2245         state->buf = NULL;
2246
2247         status = map_fnum_to_smb2_handle(cli,
2248                                         fnum,
2249                                         &state->ph);
2250         if (tevent_req_nterror(req, status)) {
2251                 return tevent_req_post(req, ev);
2252         }
2253
2254         subreq = smb2cli_read_send(state,
2255                                 state->ev,
2256                                 state->cli->conn,
2257                                 state->cli->timeout,
2258                                 state->cli->smb2.session,
2259                                 state->cli->smb2.tcon,
2260                                 state->size,
2261                                 state->start_offset,
2262                                 state->ph->fid_persistent,
2263                                 state->ph->fid_volatile,
2264                                 0, /* minimum_count */
2265                                 0); /* remaining_bytes */
2266
2267         if (tevent_req_nomem(subreq, req)) {
2268                 return tevent_req_post(req, ev);
2269         }
2270         tevent_req_set_callback(subreq, cli_smb2_read_done, req);
2271         return req;
2272 }
2273
2274 static void cli_smb2_read_done(struct tevent_req *subreq)
2275 {
2276         struct tevent_req *req = tevent_req_callback_data(
2277                 subreq, struct tevent_req);
2278         struct cli_smb2_read_state *state = tevent_req_data(
2279                 req, struct cli_smb2_read_state);
2280         NTSTATUS status;
2281
2282         status = smb2cli_read_recv(subreq, state,
2283                                    &state->buf, &state->received);
2284         if (tevent_req_nterror(req, status)) {
2285                 return;
2286         }
2287
2288         if (state->received > state->size) {
2289                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2290                 return;
2291         }
2292
2293         tevent_req_done(req);
2294 }
2295
2296 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
2297                                 ssize_t *received,
2298                                 uint8_t **rcvbuf)
2299 {
2300         NTSTATUS status;
2301         struct cli_smb2_read_state *state = tevent_req_data(
2302                                 req, struct cli_smb2_read_state);
2303
2304         if (tevent_req_is_nterror(req, &status)) {
2305                 return status;
2306         }
2307         /*
2308          * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2309          * better make sure that you copy it away before you talloc_free(req).
2310          * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2311          */
2312         *received = (ssize_t)state->received;
2313         *rcvbuf = state->buf;
2314         return NT_STATUS_OK;
2315 }
2316
2317 struct cli_smb2_write_state {
2318         struct tevent_context *ev;
2319         struct cli_state *cli;
2320         struct smb2_hnd *ph;
2321         uint32_t flags;
2322         const uint8_t *buf;
2323         uint64_t offset;
2324         uint32_t size;
2325         uint32_t written;
2326 };
2327
2328 static void cli_smb2_write_written(struct tevent_req *req);
2329
2330 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
2331                                         struct tevent_context *ev,
2332                                         struct cli_state *cli,
2333                                         uint16_t fnum,
2334                                         uint16_t mode,
2335                                         const uint8_t *buf,
2336                                         off_t offset,
2337                                         size_t size)
2338 {
2339         NTSTATUS status;
2340         struct tevent_req *req, *subreq = NULL;
2341         struct cli_smb2_write_state *state = NULL;
2342
2343         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
2344         if (req == NULL) {
2345                 return NULL;
2346         }
2347         state->ev = ev;
2348         state->cli = cli;
2349         /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2350         state->flags = (uint32_t)mode;
2351         state->buf = buf;
2352         state->offset = (uint64_t)offset;
2353         state->size = (uint32_t)size;
2354         state->written = 0;
2355
2356         status = map_fnum_to_smb2_handle(cli,
2357                                         fnum,
2358                                         &state->ph);
2359         if (tevent_req_nterror(req, status)) {
2360                 return tevent_req_post(req, ev);
2361         }
2362
2363         subreq = smb2cli_write_send(state,
2364                                 state->ev,
2365                                 state->cli->conn,
2366                                 state->cli->timeout,
2367                                 state->cli->smb2.session,
2368                                 state->cli->smb2.tcon,
2369                                 state->size,
2370                                 state->offset,
2371                                 state->ph->fid_persistent,
2372                                 state->ph->fid_volatile,
2373                                 0, /* remaining_bytes */
2374                                 state->flags, /* flags */
2375                                 state->buf);
2376
2377         if (tevent_req_nomem(subreq, req)) {
2378                 return tevent_req_post(req, ev);
2379         }
2380         tevent_req_set_callback(subreq, cli_smb2_write_written, req);
2381         return req;
2382 }
2383
2384 static void cli_smb2_write_written(struct tevent_req *subreq)
2385 {
2386         struct tevent_req *req = tevent_req_callback_data(
2387                 subreq, struct tevent_req);
2388         struct cli_smb2_write_state *state = tevent_req_data(
2389                 req, struct cli_smb2_write_state);
2390         NTSTATUS status;
2391         uint32_t written;
2392
2393         status = smb2cli_write_recv(subreq, &written);
2394         TALLOC_FREE(subreq);
2395         if (tevent_req_nterror(req, status)) {
2396                 return;
2397         }
2398
2399         state->written = written;
2400
2401         tevent_req_done(req);
2402 }
2403
2404 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
2405                              size_t *pwritten)
2406 {
2407         struct cli_smb2_write_state *state = tevent_req_data(
2408                 req, struct cli_smb2_write_state);
2409         NTSTATUS status;
2410
2411         if (tevent_req_is_nterror(req, &status)) {
2412                 tevent_req_received(req);
2413                 return status;
2414         }
2415
2416         if (pwritten != NULL) {
2417                 *pwritten = (size_t)state->written;
2418         }
2419         tevent_req_received(req);
2420         return NT_STATUS_OK;
2421 }
2422
2423 /***************************************************************
2424  Wrapper that allows SMB2 async write using an fnum.
2425  This is mostly cut-and-paste from Volker's code inside
2426  source3/libsmb/clireadwrite.c, adapted for SMB2.
2427
2428  Done this way so I can reuse all the logic inside cli_push()
2429  for free :-).
2430 ***************************************************************/
2431
2432 struct cli_smb2_writeall_state {
2433         struct tevent_context *ev;
2434         struct cli_state *cli;
2435         struct smb2_hnd *ph;
2436         uint32_t flags;
2437         const uint8_t *buf;
2438         uint64_t offset;
2439         uint32_t size;
2440         uint32_t written;
2441 };
2442
2443 static void cli_smb2_writeall_written(struct tevent_req *req);
2444
2445 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
2446                                         struct tevent_context *ev,
2447                                         struct cli_state *cli,
2448                                         uint16_t fnum,
2449                                         uint16_t mode,
2450                                         const uint8_t *buf,
2451                                         off_t offset,
2452                                         size_t size)
2453 {
2454         NTSTATUS status;
2455         struct tevent_req *req, *subreq = NULL;
2456         struct cli_smb2_writeall_state *state = NULL;
2457         uint32_t to_write;
2458         uint32_t max_size;
2459         bool ok;
2460
2461         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
2462         if (req == NULL) {
2463                 return NULL;
2464         }
2465         state->ev = ev;
2466         state->cli = cli;
2467         /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2468         state->flags = (uint32_t)mode;
2469         state->buf = buf;
2470         state->offset = (uint64_t)offset;
2471         state->size = (uint32_t)size;
2472         state->written = 0;
2473
2474         status = map_fnum_to_smb2_handle(cli,
2475                                         fnum,
2476                                         &state->ph);
2477         if (tevent_req_nterror(req, status)) {
2478                 return tevent_req_post(req, ev);
2479         }
2480
2481         to_write = state->size;
2482         max_size = smb2cli_conn_max_write_size(state->cli->conn);
2483         to_write = MIN(max_size, to_write);
2484         ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2485         if (ok) {
2486                 to_write = MIN(max_size, to_write);
2487         }
2488
2489         subreq = smb2cli_write_send(state,
2490                                 state->ev,
2491                                 state->cli->conn,
2492                                 state->cli->timeout,
2493                                 state->cli->smb2.session,
2494                                 state->cli->smb2.tcon,
2495                                 to_write,
2496                                 state->offset,
2497                                 state->ph->fid_persistent,
2498                                 state->ph->fid_volatile,
2499                                 0, /* remaining_bytes */
2500                                 state->flags, /* flags */
2501                                 state->buf + state->written);
2502
2503         if (tevent_req_nomem(subreq, req)) {
2504                 return tevent_req_post(req, ev);
2505         }
2506         tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2507         return req;
2508 }
2509
2510 static void cli_smb2_writeall_written(struct tevent_req *subreq)
2511 {
2512         struct tevent_req *req = tevent_req_callback_data(
2513                 subreq, struct tevent_req);
2514         struct cli_smb2_writeall_state *state = tevent_req_data(
2515                 req, struct cli_smb2_writeall_state);
2516         NTSTATUS status;
2517         uint32_t written, to_write;
2518         uint32_t max_size;
2519         bool ok;
2520
2521         status = smb2cli_write_recv(subreq, &written);
2522         TALLOC_FREE(subreq);
2523         if (tevent_req_nterror(req, status)) {
2524                 return;
2525         }
2526
2527         state->written += written;
2528
2529         if (state->written > state->size) {
2530                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2531                 return;
2532         }
2533
2534         to_write = state->size - state->written;
2535
2536         if (to_write == 0) {
2537                 tevent_req_done(req);
2538                 return;
2539         }
2540
2541         max_size = smb2cli_conn_max_write_size(state->cli->conn);
2542         to_write = MIN(max_size, to_write);
2543         ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2544         if (ok) {
2545                 to_write = MIN(max_size, to_write);
2546         }
2547
2548         subreq = smb2cli_write_send(state,
2549                                 state->ev,
2550                                 state->cli->conn,
2551                                 state->cli->timeout,
2552                                 state->cli->smb2.session,
2553                                 state->cli->smb2.tcon,
2554                                 to_write,
2555                                 state->offset + state->written,
2556                                 state->ph->fid_persistent,
2557                                 state->ph->fid_volatile,
2558                                 0, /* remaining_bytes */
2559                                 state->flags, /* flags */
2560                                 state->buf + state->written);
2561
2562         if (tevent_req_nomem(subreq, req)) {
2563                 return;
2564         }
2565         tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2566 }
2567
2568 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
2569                                 size_t *pwritten)
2570 {
2571         struct cli_smb2_writeall_state *state = tevent_req_data(
2572                 req, struct cli_smb2_writeall_state);
2573         NTSTATUS status;
2574
2575         if (tevent_req_is_nterror(req, &status)) {
2576                 return status;
2577         }
2578         if (pwritten != NULL) {
2579                 *pwritten = (size_t)state->written;
2580         }
2581         return NT_STATUS_OK;
2582 }
2583
2584 struct cli_smb2_splice_state {
2585         struct tevent_context *ev;
2586         struct cli_state *cli;
2587         struct smb2_hnd *src_ph;
2588         struct smb2_hnd *dst_ph;
2589         int (*splice_cb)(off_t n, void *priv);
2590         void *priv;
2591         off_t written;
2592         off_t size;
2593         off_t src_offset;
2594         off_t dst_offset;
2595         bool resized;
2596         struct req_resume_key_rsp resume_rsp;
2597         struct srv_copychunk_copy cc_copy;
2598 };
2599
2600 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
2601                                       struct tevent_req *req);
2602
2603 static void cli_splice_copychunk_done(struct tevent_req *subreq)
2604 {
2605         struct tevent_req *req = tevent_req_callback_data(
2606                 subreq, struct tevent_req);
2607         struct cli_smb2_splice_state *state =
2608                 tevent_req_data(req,
2609                 struct cli_smb2_splice_state);
2610         struct smbXcli_conn *conn = state->cli->conn;
2611         DATA_BLOB out_input_buffer = data_blob_null;
2612         DATA_BLOB out_output_buffer = data_blob_null;
2613         struct srv_copychunk_rsp cc_copy_rsp;
2614         enum ndr_err_code ndr_ret;
2615         NTSTATUS status;
2616
2617         status = smb2cli_ioctl_recv(subreq, state,
2618                                     &out_input_buffer,
2619                                     &out_output_buffer);
2620         TALLOC_FREE(subreq);
2621         if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
2622              state->resized) && tevent_req_nterror(req, status)) {
2623                 return;
2624         }
2625
2626         ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
2627                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
2628         if (ndr_ret != NDR_ERR_SUCCESS) {
2629                 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
2630                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2631                 return;
2632         }
2633
2634         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
2635                 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
2636                              cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
2637                 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
2638                      max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
2639                      tevent_req_nterror(req, status)) {
2640                         return;
2641                 }
2642
2643                 state->resized = true;
2644                 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
2645                 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
2646         } else {
2647                 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
2648                     (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
2649                     (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
2650                         tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
2651                         return;
2652                 }
2653                 state->src_offset += cc_copy_rsp.total_bytes_written;
2654                 state->dst_offset += cc_copy_rsp.total_bytes_written;
2655                 state->written += cc_copy_rsp.total_bytes_written;
2656                 if (!state->splice_cb(state->written, state->priv)) {
2657                         tevent_req_nterror(req, NT_STATUS_CANCELLED);
2658                         return;
2659                 }
2660         }
2661
2662         cli_splice_copychunk_send(state, req);
2663 }
2664
2665 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
2666                                       struct tevent_req *req)
2667 {
2668         struct tevent_req *subreq;
2669         enum ndr_err_code ndr_ret;
2670         struct smbXcli_conn *conn = state->cli->conn;
2671         struct srv_copychunk_copy *cc_copy = &state->cc_copy;
2672         off_t src_offset = state->src_offset;
2673         off_t dst_offset = state->dst_offset;
2674         uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
2675                                state->size - state->written);
2676         DATA_BLOB in_input_buffer = data_blob_null;
2677         DATA_BLOB in_output_buffer = data_blob_null;
2678
2679         if (state->size - state->written == 0) {
2680                 tevent_req_done(req);
2681                 return;
2682         }
2683
2684         cc_copy->chunk_count = 0;
2685         while (req_len) {
2686                 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
2687                 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
2688                 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
2689                                                                    smb2cli_conn_cc_chunk_len(conn));
2690                 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
2691                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2692                         return;
2693                 }
2694                 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
2695                 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
2696                     (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
2697                         tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
2698                         return;
2699                 }
2700                 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
2701                 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
2702                 cc_copy->chunk_count++;
2703         }
2704
2705         ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
2706                                        (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
2707         if (ndr_ret != NDR_ERR_SUCCESS) {
2708                 DEBUG(0, ("failed to marshall copy chunk req\n"));
2709                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2710                 return;
2711         }
2712
2713         subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
2714                                state->cli->timeout,
2715                                state->cli->smb2.session,
2716                                state->cli->smb2.tcon,
2717                                state->dst_ph->fid_persistent, /* in_fid_persistent */
2718                                state->dst_ph->fid_volatile, /* in_fid_volatile */
2719                                FSCTL_SRV_COPYCHUNK_WRITE,
2720                                0, /* in_max_input_length */
2721                                &in_input_buffer,
2722                                12, /* in_max_output_length */
2723                                &in_output_buffer,
2724                                SMB2_IOCTL_FLAG_IS_FSCTL);
2725         if (tevent_req_nomem(subreq, req)) {
2726                 return;
2727         }
2728         tevent_req_set_callback(subreq,
2729                                 cli_splice_copychunk_done,
2730                                 req);
2731 }
2732
2733 static void cli_splice_key_done(struct tevent_req *subreq)
2734 {
2735         struct tevent_req *req = tevent_req_callback_data(
2736                 subreq, struct tevent_req);
2737         struct cli_smb2_splice_state *state =
2738                 tevent_req_data(req,
2739                 struct cli_smb2_splice_state);
2740         enum ndr_err_code ndr_ret;
2741         NTSTATUS status;
2742
2743         DATA_BLOB out_input_buffer = data_blob_null;
2744         DATA_BLOB out_output_buffer = data_blob_null;
2745
2746         status = smb2cli_ioctl_recv(subreq, state,
2747                                     &out_input_buffer,
2748                                     &out_output_buffer);
2749         TALLOC_FREE(subreq);
2750         if (tevent_req_nterror(req, status)) {
2751                 return;
2752         }
2753
2754         ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
2755                         state, &state->resume_rsp,
2756                         (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
2757         if (ndr_ret != NDR_ERR_SUCCESS) {
2758                 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
2759                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2760                 return;
2761         }
2762
2763         memcpy(&state->cc_copy.source_key,
2764                &state->resume_rsp.resume_key,
2765                sizeof state->resume_rsp.resume_key);
2766
2767         cli_splice_copychunk_send(state, req);
2768 }
2769
2770 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
2771                                 struct tevent_context *ev,
2772                                 struct cli_state *cli,
2773                                 uint16_t src_fnum, uint16_t dst_fnum,
2774                                 off_t size, off_t src_offset, off_t dst_offset,
2775                                 int (*splice_cb)(off_t n, void *priv),
2776                                 void *priv)
2777 {
2778         struct tevent_req *req;
2779         struct tevent_req *subreq;
2780         struct cli_smb2_splice_state *state;
2781         NTSTATUS status;
2782         DATA_BLOB in_input_buffer = data_blob_null;
2783         DATA_BLOB in_output_buffer = data_blob_null;
2784
2785         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
2786         if (req == NULL) {
2787                 return NULL;
2788         }
2789         state->cli = cli;
2790         state->ev = ev;
2791         state->splice_cb = splice_cb;
2792         state->priv = priv;
2793         state->size = size;
2794         state->written = 0;
2795         state->src_offset = src_offset;
2796         state->dst_offset = dst_offset;
2797         state->cc_copy.chunks = talloc_array(state,
2798                                              struct srv_copychunk,
2799                                              smb2cli_conn_cc_max_chunks(cli->conn));
2800         if (state->cc_copy.chunks == NULL) {
2801                 return NULL;
2802         }
2803
2804         status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
2805         if (tevent_req_nterror(req, status))
2806                 return tevent_req_post(req, ev);
2807
2808         status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
2809         if (tevent_req_nterror(req, status))
2810                 return tevent_req_post(req, ev);
2811
2812         subreq = smb2cli_ioctl_send(state, ev, cli->conn,
2813                                cli->timeout,
2814                                cli->smb2.session,
2815                                cli->smb2.tcon,
2816                                state->src_ph->fid_persistent, /* in_fid_persistent */
2817                                state->src_ph->fid_volatile, /* in_fid_volatile */
2818                                FSCTL_SRV_REQUEST_RESUME_KEY,
2819                                0, /* in_max_input_length */
2820                                &in_input_buffer,
2821                                32, /* in_max_output_length */
2822                                &in_output_buffer,
2823                                SMB2_IOCTL_FLAG_IS_FSCTL);
2824         if (tevent_req_nomem(subreq, req)) {
2825                 return NULL;
2826         }
2827         tevent_req_set_callback(subreq,
2828                                 cli_splice_key_done,
2829                                 req);
2830
2831         return req;
2832 }
2833
2834 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
2835 {
2836         struct cli_smb2_splice_state *state = tevent_req_data(
2837                 req, struct cli_smb2_splice_state);
2838         NTSTATUS status;
2839
2840         if (tevent_req_is_nterror(req, &status)) {
2841                 tevent_req_received(req);
2842                 return status;
2843         }
2844         if (written != NULL) {
2845                 *written = state->written;
2846         }
2847         tevent_req_received(req);
2848         return NT_STATUS_OK;
2849 }