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