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