s3:libsmb: pass impersonation_level to cli_smb2_create_fnum()
[samba.git] / source3 / libsmb / cli_smb2_fnum.c
1 /*
2    Unix SMB/CIFS implementation.
3    smb2 lib
4    Copyright (C) Jeremy Allison 2013
5    Copyright (C) Volker Lendecke 2013
6    Copyright (C) Stefan Metzmacher 2013
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /*
23  This code is a thin wrapper around the existing
24  cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c,
25  but allows the handles to be mapped to uint16_t fnums,
26  which are easier for smbclient to use.
27 */
28
29 #include "includes.h"
30 #include "client.h"
31 #include "async_smb.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "cli_smb2_fnum.h"
34 #include "trans2.h"
35 #include "clirap.h"
36 #include "../libcli/smb/smb2_create_blob.h"
37 #include "libsmb/proto.h"
38 #include "lib/util/tevent_ntstatus.h"
39 #include "../libcli/security/security.h"
40 #include "../librpc/gen_ndr/ndr_security.h"
41 #include "lib/util_ea.h"
42 #include "librpc/gen_ndr/ndr_ioctl.h"
43 #include "ntioctl.h"
44 #include "librpc/gen_ndr/ndr_quota.h"
45
46 struct smb2_hnd {
47         uint64_t fid_persistent;
48         uint64_t fid_volatile;
49 };
50
51 /*
52  * Handle mapping code.
53  */
54
55 /***************************************************************
56  Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
57  Ensures handle is owned by cli struct.
58 ***************************************************************/
59
60 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
61                                 const struct smb2_hnd *ph,      /* In */
62                                 uint16_t *pfnum)                /* Out */
63 {
64         int ret;
65         struct idr_context *idp = cli->smb2.open_handles;
66         struct smb2_hnd *owned_h = talloc_memdup(cli,
67                                                 ph,
68                                                 sizeof(struct smb2_hnd));
69
70         if (owned_h == NULL) {
71                 return NT_STATUS_NO_MEMORY;
72         }
73
74         if (idp == NULL) {
75                 /* Lazy init */
76                 cli->smb2.open_handles = idr_init(cli);
77                 if (cli->smb2.open_handles == NULL) {
78                         TALLOC_FREE(owned_h);
79                         return NT_STATUS_NO_MEMORY;
80                 }
81                 idp = cli->smb2.open_handles;
82         }
83
84         ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
85         if (ret == -1) {
86                 TALLOC_FREE(owned_h);
87                 return NT_STATUS_NO_MEMORY;
88         }
89
90         *pfnum = (uint16_t)ret;
91         return NT_STATUS_OK;
92 }
93
94 /***************************************************************
95  Return the smb2_hnd pointer associated with the given fnum.
96 ***************************************************************/
97
98 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
99                                 uint16_t fnum,          /* In */
100                                 struct smb2_hnd **pph)  /* Out */
101 {
102         struct idr_context *idp = cli->smb2.open_handles;
103
104         if (idp == NULL) {
105                 return NT_STATUS_INVALID_PARAMETER;
106         }
107         *pph = (struct smb2_hnd *)idr_find(idp, fnum);
108         if (*pph == NULL) {
109                 return NT_STATUS_INVALID_HANDLE;
110         }
111         return NT_STATUS_OK;
112 }
113
114 /***************************************************************
115  Delete the fnum to smb2_hnd mapping. Zeros out handle on
116  successful return.
117 ***************************************************************/
118
119 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
120                                 struct smb2_hnd **pph,  /* In */
121                                 uint16_t fnum)                  /* In */
122 {
123         struct idr_context *idp = cli->smb2.open_handles;
124         struct smb2_hnd *ph;
125
126         if (idp == NULL) {
127                 return NT_STATUS_INVALID_PARAMETER;
128         }
129
130         ph = (struct smb2_hnd *)idr_find(idp, fnum);
131         if (ph != *pph) {
132                 return NT_STATUS_INVALID_PARAMETER;
133         }
134         idr_remove(idp, fnum);
135         TALLOC_FREE(*pph);
136         return NT_STATUS_OK;
137 }
138
139 /***************************************************************
140  Oplock mapping code.
141 ***************************************************************/
142
143 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
144 {
145         if (create_flags & REQUEST_BATCH_OPLOCK) {
146                 return SMB2_OPLOCK_LEVEL_BATCH;
147         } else if (create_flags & REQUEST_OPLOCK) {
148                 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
149         }
150
151         /* create_flags doesn't do a level2 request. */
152         return SMB2_OPLOCK_LEVEL_NONE;
153 }
154
155 /***************************************************************
156  Small wrapper that allows SMB2 create to return a uint16_t fnum.
157 ***************************************************************/
158
159 struct cli_smb2_create_fnum_state {
160         struct cli_state *cli;
161         struct smb_create_returns cr;
162         uint16_t fnum;
163         struct tevent_req *subreq;
164 };
165
166 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
167 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
168
169 struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
170                                              struct tevent_context *ev,
171                                              struct cli_state *cli,
172                                              const char *fname,
173                                              uint32_t create_flags,
174                                              uint32_t impersonation_level,
175                                              uint32_t desired_access,
176                                              uint32_t file_attributes,
177                                              uint32_t share_access,
178                                              uint32_t create_disposition,
179                                              uint32_t create_options)
180 {
181         struct tevent_req *req, *subreq;
182         struct cli_smb2_create_fnum_state *state;
183         size_t fname_len = 0;
184         const char *startp = NULL;
185         const char *endp = NULL;
186         time_t tstamp = (time_t)0;
187         struct smb2_create_blobs *cblobs = NULL;
188
189         req = tevent_req_create(mem_ctx, &state,
190                                 struct cli_smb2_create_fnum_state);
191         if (req == NULL) {
192                 return NULL;
193         }
194         state->cli = cli;
195
196         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
197                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
198                 return tevent_req_post(req, ev);
199         }
200
201         if (cli->backup_intent) {
202                 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
203         }
204
205         /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
206         fname_len = strlen(fname);
207         if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
208                 size_t len_before_gmt = startp - fname;
209                 size_t len_after_gmt = fname + fname_len - endp;
210                 DATA_BLOB twrp_blob;
211                 NTTIME ntt;
212                 NTSTATUS status;
213
214                 char *new_fname = talloc_array(state, char,
215                                 len_before_gmt + len_after_gmt + 1);
216
217                 if (tevent_req_nomem(new_fname, req)) {
218                         return tevent_req_post(req, ev);
219                 }
220
221                 memcpy(new_fname, fname, len_before_gmt);
222                 memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
223                 fname = new_fname;
224                 fname_len = len_before_gmt + len_after_gmt;
225
226                 unix_to_nt_time(&ntt, tstamp);
227                 twrp_blob = data_blob_const((const void *)&ntt, 8);
228
229                 cblobs = talloc_zero(state, struct smb2_create_blobs);
230                 if (tevent_req_nomem(cblobs, req)) {
231                         return tevent_req_post(req, ev);
232                 }
233
234                 status = smb2_create_blob_add(state, cblobs,
235                                 SMB2_CREATE_TAG_TWRP, twrp_blob);
236                 if (!NT_STATUS_IS_OK(status)) {
237                         tevent_req_nterror(req, status);
238                         return tevent_req_post(req, ev);
239                 }
240         }
241
242         /* SMB2 is pickier about pathnames. Ensure it doesn't
243            start in a '\' */
244         if (*fname == '\\') {
245                 fname++;
246                 fname_len--;
247         }
248
249         /* Or end in a '\' */
250         if (fname_len > 0 && fname[fname_len-1] == '\\') {
251                 char *new_fname = talloc_strdup(state, fname);
252                 if (tevent_req_nomem(new_fname, req)) {
253                         return tevent_req_post(req, ev);
254                 }
255                 new_fname[fname_len-1] = '\0';
256                 fname = new_fname;
257         }
258
259         subreq = smb2cli_create_send(state, ev,
260                                      cli->conn,
261                                      cli->timeout,
262                                      cli->smb2.session,
263                                      cli->smb2.tcon,
264                                      fname,
265                                      flags_to_smb2_oplock(create_flags),
266                                      impersonation_level,
267                                      desired_access,
268                                      file_attributes,
269                                      share_access,
270                                      create_disposition,
271                                      create_options,
272                                      cblobs);
273         if (tevent_req_nomem(subreq, req)) {
274                 return tevent_req_post(req, ev);
275         }
276         tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
277
278         state->subreq = subreq;
279         tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
280
281         return req;
282 }
283
284 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
285 {
286         struct tevent_req *req = tevent_req_callback_data(
287                 subreq, struct tevent_req);
288         struct cli_smb2_create_fnum_state *state = tevent_req_data(
289                 req, struct cli_smb2_create_fnum_state);
290         struct smb2_hnd h;
291         NTSTATUS status;
292
293         status = smb2cli_create_recv(subreq, &h.fid_persistent,
294                                      &h.fid_volatile, &state->cr, NULL, NULL);
295         TALLOC_FREE(subreq);
296         if (tevent_req_nterror(req, status)) {
297                 return;
298         }
299
300         status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
301         if (tevent_req_nterror(req, status)) {
302                 return;
303         }
304         tevent_req_done(req);
305 }
306
307 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
308 {
309         struct cli_smb2_create_fnum_state *state = tevent_req_data(
310                 req, struct cli_smb2_create_fnum_state);
311         return tevent_req_cancel(state->subreq);
312 }
313
314 NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum,
315                                    struct smb_create_returns *cr)
316 {
317         struct cli_smb2_create_fnum_state *state = tevent_req_data(
318                 req, struct cli_smb2_create_fnum_state);
319         NTSTATUS status;
320
321         if (tevent_req_is_nterror(req, &status)) {
322                 state->cli->raw_status = status;
323                 return status;
324         }
325         if (pfnum != NULL) {
326                 *pfnum = state->fnum;
327         }
328         if (cr != NULL) {
329                 *cr = state->cr;
330         }
331         state->cli->raw_status = NT_STATUS_OK;
332         return NT_STATUS_OK;
333 }
334
335 NTSTATUS cli_smb2_create_fnum(struct cli_state *cli,
336                         const char *fname,
337                         uint32_t create_flags,
338                         uint32_t impersonation_level,
339                         uint32_t desired_access,
340                         uint32_t file_attributes,
341                         uint32_t share_access,
342                         uint32_t create_disposition,
343                         uint32_t create_options,
344                         uint16_t *pfid,
345                         struct smb_create_returns *cr)
346 {
347         TALLOC_CTX *frame = talloc_stackframe();
348         struct tevent_context *ev;
349         struct tevent_req *req;
350         NTSTATUS status = NT_STATUS_NO_MEMORY;
351
352         if (smbXcli_conn_has_async_calls(cli->conn)) {
353                 /*
354                  * Can't use sync call while an async call is in flight
355                  */
356                 status = NT_STATUS_INVALID_PARAMETER;
357                 goto fail;
358         }
359         ev = samba_tevent_context_init(frame);
360         if (ev == NULL) {
361                 goto fail;
362         }
363         req = cli_smb2_create_fnum_send(frame, ev, cli, fname, create_flags,
364                                         impersonation_level,
365                                         desired_access, file_attributes,
366                                         share_access, create_disposition,
367                                         create_options);
368         if (req == NULL) {
369                 goto fail;
370         }
371         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
372                 goto fail;
373         }
374         status = cli_smb2_create_fnum_recv(req, pfid, cr);
375  fail:
376         TALLOC_FREE(frame);
377         return status;
378 }
379
380 /***************************************************************
381  Small wrapper that allows SMB2 close to use a uint16_t fnum.
382 ***************************************************************/
383
384 struct cli_smb2_close_fnum_state {
385         struct cli_state *cli;
386         uint16_t fnum;
387         struct smb2_hnd *ph;
388 };
389
390 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
391
392 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
393                                             struct tevent_context *ev,
394                                             struct cli_state *cli,
395                                             uint16_t fnum)
396 {
397         struct tevent_req *req, *subreq;
398         struct cli_smb2_close_fnum_state *state;
399         NTSTATUS status;
400
401         req = tevent_req_create(mem_ctx, &state,
402                                 struct cli_smb2_close_fnum_state);
403         if (req == NULL) {
404                 return NULL;
405         }
406         state->cli = cli;
407         state->fnum = fnum;
408
409         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
410                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
411                 return tevent_req_post(req, ev);
412         }
413
414         status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
415         if (tevent_req_nterror(req, status)) {
416                 return tevent_req_post(req, ev);
417         }
418
419         subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
420                                     cli->smb2.session, cli->smb2.tcon,
421                                     0, state->ph->fid_persistent,
422                                     state->ph->fid_volatile);
423         if (tevent_req_nomem(subreq, req)) {
424                 return tevent_req_post(req, ev);
425         }
426         tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
427         return req;
428 }
429
430 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
431 {
432         struct tevent_req *req = tevent_req_callback_data(
433                 subreq, struct tevent_req);
434         struct cli_smb2_close_fnum_state *state = tevent_req_data(
435                 req, struct cli_smb2_close_fnum_state);
436         NTSTATUS status;
437
438         status = smb2cli_close_recv(subreq);
439         if (tevent_req_nterror(req, status)) {
440                 return;
441         }
442
443         /* Delete the fnum -> handle mapping. */
444         status = delete_smb2_handle_mapping(state->cli, &state->ph,
445                                             state->fnum);
446         if (tevent_req_nterror(req, status)) {
447                 return;
448         }
449         tevent_req_done(req);
450 }
451
452 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
453 {
454         struct cli_smb2_close_fnum_state *state = tevent_req_data(
455                 req, struct cli_smb2_close_fnum_state);
456         NTSTATUS status = NT_STATUS_OK;
457
458         if (tevent_req_is_nterror(req, &status)) {
459                 state->cli->raw_status = status;
460         }
461         tevent_req_received(req);
462         return status;
463 }
464
465 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
466 {
467         TALLOC_CTX *frame = talloc_stackframe();
468         struct tevent_context *ev;
469         struct tevent_req *req;
470         NTSTATUS status = NT_STATUS_NO_MEMORY;
471
472         if (smbXcli_conn_has_async_calls(cli->conn)) {
473                 /*
474                  * Can't use sync call while an async call is in flight
475                  */
476                 status = NT_STATUS_INVALID_PARAMETER;
477                 goto fail;
478         }
479         ev = samba_tevent_context_init(frame);
480         if (ev == NULL) {
481                 goto fail;
482         }
483         req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
484         if (req == NULL) {
485                 goto fail;
486         }
487         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
488                 goto fail;
489         }
490         status = cli_smb2_close_fnum_recv(req);
491  fail:
492         TALLOC_FREE(frame);
493         return status;
494 }
495
496 struct cli_smb2_delete_on_close_state {
497         struct cli_state *cli;
498         uint16_t fnum;
499         struct smb2_hnd *ph;
500         uint8_t data[1];
501         DATA_BLOB inbuf;
502 };
503
504 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
505
506 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
507                                         struct tevent_context *ev,
508                                         struct cli_state *cli,
509                                         uint16_t fnum,
510                                         bool flag)
511 {
512         struct tevent_req *req = NULL;
513         struct cli_smb2_delete_on_close_state *state = NULL;
514         struct tevent_req *subreq = NULL;
515         uint8_t in_info_type;
516         uint8_t in_file_info_class;
517         NTSTATUS status;
518
519         req = tevent_req_create(mem_ctx, &state,
520                                 struct cli_smb2_delete_on_close_state);
521         if (req == NULL) {
522                 return NULL;
523         }
524         state->cli = cli;
525         state->fnum = fnum;
526
527         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
528                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
529                 return tevent_req_post(req, ev);
530         }
531
532         status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
533         if (tevent_req_nterror(req, status)) {
534                 return tevent_req_post(req, ev);
535         }
536
537         /*
538          * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
539          * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
540          */
541         in_info_type = 1;
542         in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
543         /* Setup data array. */
544         SCVAL(&state->data[0], 0, flag ? 1 : 0);
545         state->inbuf.data = &state->data[0];
546         state->inbuf.length = 1;
547
548         subreq = smb2cli_set_info_send(state, ev,
549                                        cli->conn,
550                                        cli->timeout,
551                                        cli->smb2.session,
552                                        cli->smb2.tcon,
553                                        in_info_type,
554                                        in_file_info_class,
555                                        &state->inbuf, /* in_input_buffer */
556                                        0, /* in_additional_info */
557                                        state->ph->fid_persistent,
558                                        state->ph->fid_volatile);
559         if (tevent_req_nomem(subreq, req)) {
560                 return tevent_req_post(req, ev);
561         }
562         tevent_req_set_callback(subreq,
563                                 cli_smb2_delete_on_close_done,
564                                 req);
565         return req;
566 }
567
568 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
569 {
570         NTSTATUS status = smb2cli_set_info_recv(subreq);
571         tevent_req_simple_finish_ntstatus(subreq, status);
572 }
573
574 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
575 {
576         struct cli_smb2_delete_on_close_state *state =
577                 tevent_req_data(req,
578                 struct cli_smb2_delete_on_close_state);
579         NTSTATUS status;
580
581         if (tevent_req_is_nterror(req, &status)) {
582                 state->cli->raw_status = status;
583                 tevent_req_received(req);
584                 return status;
585         }
586
587         state->cli->raw_status = NT_STATUS_OK;
588         tevent_req_received(req);
589         return NT_STATUS_OK;
590 }
591
592 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
593 {
594         TALLOC_CTX *frame = talloc_stackframe();
595         struct tevent_context *ev;
596         struct tevent_req *req;
597         NTSTATUS status = NT_STATUS_NO_MEMORY;
598
599         if (smbXcli_conn_has_async_calls(cli->conn)) {
600                 /*
601                  * Can't use sync call while an async call is in flight
602                  */
603                 status = NT_STATUS_INVALID_PARAMETER;
604                 goto fail;
605         }
606         ev = samba_tevent_context_init(frame);
607         if (ev == NULL) {
608                 goto fail;
609         }
610         req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
611         if (req == NULL) {
612                 goto fail;
613         }
614         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
615                 goto fail;
616         }
617         status = cli_smb2_delete_on_close_recv(req);
618  fail:
619         TALLOC_FREE(frame);
620         return status;
621 }
622
623 /***************************************************************
624  Small wrapper that allows SMB2 to create a directory
625  Synchronous only.
626 ***************************************************************/
627
628 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
629 {
630         NTSTATUS status;
631         uint16_t fnum;
632
633         if (smbXcli_conn_has_async_calls(cli->conn)) {
634                 /*
635                  * Can't use sync call while an async call is in flight
636                  */
637                 return NT_STATUS_INVALID_PARAMETER;
638         }
639
640         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
641                 return NT_STATUS_INVALID_PARAMETER;
642         }
643
644         status = cli_smb2_create_fnum(cli,
645                         dname,
646                         0,                      /* create_flags */
647                         SMB2_IMPERSONATION_IMPERSONATION,
648                         FILE_READ_ATTRIBUTES,   /* desired_access */
649                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
650                         FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
651                         FILE_CREATE,            /* create_disposition */
652                         FILE_DIRECTORY_FILE,    /* create_options */
653                         &fnum,
654                         NULL);
655
656         if (!NT_STATUS_IS_OK(status)) {
657                 return status;
658         }
659         return cli_smb2_close_fnum(cli, fnum);
660 }
661
662 /***************************************************************
663  Small wrapper that allows SMB2 to delete a directory
664  Synchronous only.
665 ***************************************************************/
666
667 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
668 {
669         NTSTATUS status;
670         uint16_t fnum;
671
672         if (smbXcli_conn_has_async_calls(cli->conn)) {
673                 /*
674                  * Can't use sync call while an async call is in flight
675                  */
676                 return NT_STATUS_INVALID_PARAMETER;
677         }
678
679         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
680                 return NT_STATUS_INVALID_PARAMETER;
681         }
682
683         status = cli_smb2_create_fnum(cli,
684                         dname,
685                         0,                      /* create_flags */
686                         SMB2_IMPERSONATION_IMPERSONATION,
687                         DELETE_ACCESS,          /* desired_access */
688                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
689                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
690                         FILE_OPEN,              /* create_disposition */
691                         FILE_DIRECTORY_FILE,    /* create_options */
692                         &fnum,
693                         NULL);
694
695         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
696                 /*
697                  * Naive option to match our SMB1 code. Assume the
698                  * symlink path that tripped us up was the last
699                  * component and try again. Eventually we will have to
700                  * deal with the returned path unprocessed component. JRA.
701                  */
702                 status = cli_smb2_create_fnum(cli,
703                         dname,
704                         0,                      /* create_flags */
705                         SMB2_IMPERSONATION_IMPERSONATION,
706                         DELETE_ACCESS,          /* desired_access */
707                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
708                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
709                         FILE_OPEN,              /* create_disposition */
710                         FILE_DIRECTORY_FILE|
711                                 FILE_DELETE_ON_CLOSE|
712                                 FILE_OPEN_REPARSE_POINT, /* create_options */
713                         &fnum,
714                         NULL);
715         }
716
717         if (!NT_STATUS_IS_OK(status)) {
718                 return status;
719         }
720
721         status = cli_smb2_delete_on_close(cli, fnum, true);
722         if (!NT_STATUS_IS_OK(status)) {
723                 cli_smb2_close_fnum(cli, fnum);
724                 return status;
725         }
726
727         return cli_smb2_close_fnum(cli, fnum);
728 }
729
730 /***************************************************************
731  Small wrapper that allows SMB2 to unlink a pathname.
732  Synchronous only.
733 ***************************************************************/
734
735 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
736 {
737         NTSTATUS status;
738         uint16_t fnum;
739
740         if (smbXcli_conn_has_async_calls(cli->conn)) {
741                 /*
742                  * Can't use sync call while an async call is in flight
743                  */
744                 return NT_STATUS_INVALID_PARAMETER;
745         }
746
747         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
748                 return NT_STATUS_INVALID_PARAMETER;
749         }
750
751         status = cli_smb2_create_fnum(cli,
752                         fname,
753                         0,                      /* create_flags */
754                         SMB2_IMPERSONATION_IMPERSONATION,
755                         DELETE_ACCESS,          /* desired_access */
756                         FILE_ATTRIBUTE_NORMAL, /* file attributes */
757                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
758                         FILE_OPEN,              /* create_disposition */
759                         FILE_DELETE_ON_CLOSE,   /* create_options */
760                         &fnum,
761                         NULL);
762
763         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
764                 /*
765                  * Naive option to match our SMB1 code. Assume the
766                  * symlink path that tripped us up was the last
767                  * component and try again. Eventually we will have to
768                  * deal with the returned path unprocessed component. JRA.
769                  */
770                 status = cli_smb2_create_fnum(cli,
771                         fname,
772                         0,                      /* create_flags */
773                         SMB2_IMPERSONATION_IMPERSONATION,
774                         DELETE_ACCESS,          /* desired_access */
775                         FILE_ATTRIBUTE_NORMAL, /* file attributes */
776                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
777                         FILE_OPEN,              /* create_disposition */
778                         FILE_DELETE_ON_CLOSE|
779                                 FILE_OPEN_REPARSE_POINT, /* create_options */
780                         &fnum,
781                         NULL);
782         }
783
784         if (!NT_STATUS_IS_OK(status)) {
785                 return status;
786         }
787         return cli_smb2_close_fnum(cli, fnum);
788 }
789
790 /***************************************************************
791  Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
792 ***************************************************************/
793
794 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
795                                 uint32_t dir_data_length,
796                                 struct file_info *finfo,
797                                 uint32_t *next_offset)
798 {
799         size_t namelen = 0;
800         size_t slen = 0;
801         size_t ret = 0;
802
803         if (dir_data_length < 4) {
804                 return NT_STATUS_INFO_LENGTH_MISMATCH;
805         }
806
807         *next_offset = IVAL(dir_data, 0);
808
809         if (*next_offset > dir_data_length) {
810                 return NT_STATUS_INFO_LENGTH_MISMATCH;
811         }
812
813         if (*next_offset != 0) {
814                 /* Ensure we only read what in this record. */
815                 dir_data_length = *next_offset;
816         }
817
818         if (dir_data_length < 105) {
819                 return NT_STATUS_INFO_LENGTH_MISMATCH;
820         }
821
822         finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
823         finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
824         finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
825         finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
826         finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
827         finfo->mode = CVAL(dir_data + 56, 0);
828         namelen = IVAL(dir_data + 60,0);
829         if (namelen > (dir_data_length - 104)) {
830                 return NT_STATUS_INFO_LENGTH_MISMATCH;
831         }
832         slen = CVAL(dir_data + 68, 0);
833         if (slen > 24) {
834                 return NT_STATUS_INFO_LENGTH_MISMATCH;
835         }
836         ret = pull_string_talloc(finfo,
837                                 dir_data,
838                                 FLAGS2_UNICODE_STRINGS,
839                                 &finfo->short_name,
840                                 dir_data + 70,
841                                 slen,
842                                 STR_UNICODE);
843         if (ret == (size_t)-1) {
844                 /* Bad conversion. */
845                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
846         }
847
848         ret = pull_string_talloc(finfo,
849                                 dir_data,
850                                 FLAGS2_UNICODE_STRINGS,
851                                 &finfo->name,
852                                 dir_data + 104,
853                                 namelen,
854                                 STR_UNICODE);
855         if (ret == (size_t)-1) {
856                 /* Bad conversion. */
857                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
858         }
859         return NT_STATUS_OK;
860 }
861
862 /*******************************************************************
863  Given a filename - get its directory name
864 ********************************************************************/
865
866 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
867                                 const char *dir,
868                                 char **parent,
869                                 const char **name)
870 {
871         char *p;
872         ptrdiff_t len;
873
874         p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
875
876         if (p == NULL) {
877                 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
878                         return false;
879                 }
880                 if (name) {
881                         *name = dir;
882                 }
883                 return true;
884         }
885
886         len = p-dir;
887
888         if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
889                 return false;
890         }
891         (*parent)[len] = '\0';
892
893         if (name) {
894                 *name = p+1;
895         }
896         return true;
897 }
898
899 /***************************************************************
900  Wrapper that allows SMB2 to list a directory.
901  Synchronous only.
902 ***************************************************************/
903
904 NTSTATUS cli_smb2_list(struct cli_state *cli,
905                         const char *pathname,
906                         uint16_t attribute,
907                         NTSTATUS (*fn)(const char *,
908                                 struct file_info *,
909                                 const char *,
910                                 void *),
911                         void *state)
912 {
913         NTSTATUS status;
914         uint16_t fnum = 0xffff;
915         char *parent_dir = NULL;
916         const char *mask = NULL;
917         struct smb2_hnd *ph = NULL;
918         bool processed_file = false;
919         TALLOC_CTX *frame = talloc_stackframe();
920         TALLOC_CTX *subframe = NULL;
921         bool mask_has_wild;
922         uint32_t max_trans = smb2cli_conn_max_trans_size(cli->conn);
923
924         if (smbXcli_conn_has_async_calls(cli->conn)) {
925                 /*
926                  * Can't use sync call while an async call is in flight
927                  */
928                 status = NT_STATUS_INVALID_PARAMETER;
929                 goto fail;
930         }
931
932         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
933                 status = NT_STATUS_INVALID_PARAMETER;
934                 goto fail;
935         }
936
937         /* Get the directory name. */
938         if (!windows_parent_dirname(frame,
939                                 pathname,
940                                 &parent_dir,
941                                 &mask)) {
942                 status = NT_STATUS_NO_MEMORY;
943                 goto fail;
944         }
945
946         mask_has_wild = ms_has_wild(mask);
947
948         status = cli_smb2_create_fnum(cli,
949                         parent_dir,
950                         0,                      /* create_flags */
951                         SMB2_IMPERSONATION_IMPERSONATION,
952                         SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
953                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
954                         FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
955                         FILE_OPEN,              /* create_disposition */
956                         FILE_DIRECTORY_FILE,    /* create_options */
957                         &fnum,
958                         NULL);
959
960         if (!NT_STATUS_IS_OK(status)) {
961                 goto fail;
962         }
963
964         status = map_fnum_to_smb2_handle(cli,
965                                         fnum,
966                                         &ph);
967         if (!NT_STATUS_IS_OK(status)) {
968                 goto fail;
969         }
970
971         do {
972                 uint8_t *dir_data = NULL;
973                 uint32_t dir_data_length = 0;
974                 uint32_t next_offset = 0;
975                 subframe = talloc_stackframe();
976
977                 status = smb2cli_query_directory(cli->conn,
978                                         cli->timeout,
979                                         cli->smb2.session,
980                                         cli->smb2.tcon,
981                                         SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
982                                         0,      /* flags */
983                                         0,      /* file_index */
984                                         ph->fid_persistent,
985                                         ph->fid_volatile,
986                                         mask,
987                                         max_trans,
988                                         subframe,
989                                         &dir_data,
990                                         &dir_data_length);
991
992                 if (!NT_STATUS_IS_OK(status)) {
993                         if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
994                                 break;
995                         }
996                         goto fail;
997                 }
998
999                 do {
1000                         struct file_info *finfo = talloc_zero(subframe,
1001                                                         struct file_info);
1002
1003                         if (finfo == NULL) {
1004                                 status = NT_STATUS_NO_MEMORY;
1005                                 goto fail;
1006                         }
1007
1008                         status = parse_finfo_id_both_directory_info(dir_data,
1009                                                 dir_data_length,
1010                                                 finfo,
1011                                                 &next_offset);
1012
1013                         if (!NT_STATUS_IS_OK(status)) {
1014                                 goto fail;
1015                         }
1016
1017                         if (dir_check_ftype((uint32_t)finfo->mode,
1018                                         (uint32_t)attribute)) {
1019                                 /*
1020                                  * Only process if attributes match.
1021                                  * On SMB1 server does this, so on
1022                                  * SMB2 we need to emulate in the
1023                                  * client.
1024                                  *
1025                                  * https://bugzilla.samba.org/show_bug.cgi?id=10260
1026                                  */
1027                                 processed_file = true;
1028
1029                                 status = fn(cli->dfs_mountpoint,
1030                                         finfo,
1031                                         pathname,
1032                                         state);
1033
1034                                 if (!NT_STATUS_IS_OK(status)) {
1035                                         break;
1036                                 }
1037                         }
1038
1039                         TALLOC_FREE(finfo);
1040
1041                         /* Move to next entry. */
1042                         if (next_offset) {
1043                                 dir_data += next_offset;
1044                                 dir_data_length -= next_offset;
1045                         }
1046                 } while (next_offset != 0);
1047
1048                 TALLOC_FREE(subframe);
1049
1050                 if (!mask_has_wild) {
1051                         /*
1052                          * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1053                          * when handed a non-wildcard path. Do it
1054                          * for the server (with a non-wildcard path
1055                          * there should only ever be one file returned.
1056                          */
1057                         status = STATUS_NO_MORE_FILES;
1058                         break;
1059                 }
1060
1061         } while (NT_STATUS_IS_OK(status));
1062
1063         if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1064                 status = NT_STATUS_OK;
1065         }
1066
1067         if (NT_STATUS_IS_OK(status) && !processed_file) {
1068                 /*
1069                  * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1070                  * if no files match. Emulate this in the client.
1071                  */
1072                 status = NT_STATUS_NO_SUCH_FILE;
1073         }
1074
1075   fail:
1076
1077         if (fnum != 0xffff) {
1078                 cli_smb2_close_fnum(cli, fnum);
1079         }
1080
1081         cli->raw_status = status;
1082
1083         TALLOC_FREE(subframe);
1084         TALLOC_FREE(frame);
1085         return status;
1086 }
1087
1088 /***************************************************************
1089  Wrapper that allows SMB2 to query a path info (basic level).
1090  Synchronous only.
1091 ***************************************************************/
1092
1093 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1094                                 const char *name,
1095                                 SMB_STRUCT_STAT *sbuf,
1096                                 uint32_t *attributes)
1097 {
1098         NTSTATUS status;
1099         struct smb_create_returns cr;
1100         uint16_t fnum = 0xffff;
1101         size_t namelen = strlen(name);
1102
1103         if (smbXcli_conn_has_async_calls(cli->conn)) {
1104                 /*
1105                  * Can't use sync call while an async call is in flight
1106                  */
1107                 return NT_STATUS_INVALID_PARAMETER;
1108         }
1109
1110         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1111                 return NT_STATUS_INVALID_PARAMETER;
1112         }
1113
1114         /* SMB2 is pickier about pathnames. Ensure it doesn't
1115            end in a '\' */
1116         if (namelen > 0 && name[namelen-1] == '\\') {
1117                 char *modname = talloc_strdup(talloc_tos(), name);
1118                 modname[namelen-1] = '\0';
1119                 name = modname;
1120         }
1121
1122         /* This is commonly used as a 'cd'. Try qpathinfo on
1123            a directory handle first. */
1124
1125         status = cli_smb2_create_fnum(cli,
1126                         name,
1127                         0,                      /* create_flags */
1128                         SMB2_IMPERSONATION_IMPERSONATION,
1129                         FILE_READ_ATTRIBUTES,   /* desired_access */
1130                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1131                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1132                         FILE_OPEN,              /* create_disposition */
1133                         FILE_DIRECTORY_FILE,    /* create_options */
1134                         &fnum,
1135                         &cr);
1136
1137         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1138                 /* Maybe a file ? */
1139                 status = cli_smb2_create_fnum(cli,
1140                         name,
1141                         0,                      /* create_flags */
1142                         SMB2_IMPERSONATION_IMPERSONATION,
1143                         FILE_READ_ATTRIBUTES,           /* desired_access */
1144                         0, /* file attributes */
1145                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1146                         FILE_OPEN,              /* create_disposition */
1147                         0,      /* create_options */
1148                         &fnum,
1149                         &cr);
1150         }
1151
1152         if (!NT_STATUS_IS_OK(status)) {
1153                 return status;
1154         }
1155
1156         status = cli_smb2_close_fnum(cli, fnum);
1157
1158         ZERO_STRUCTP(sbuf);
1159
1160         sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1161         sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1162         sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1163         sbuf->st_ex_size = cr.end_of_file;
1164         *attributes = cr.file_attributes;
1165
1166         return status;
1167 }
1168
1169 /***************************************************************
1170  Wrapper that allows SMB2 to check if a path is a directory.
1171  Synchronous only.
1172 ***************************************************************/
1173
1174 NTSTATUS cli_smb2_chkpath(struct cli_state *cli,
1175                                 const char *name)
1176 {
1177         NTSTATUS status;
1178         uint16_t fnum = 0xffff;
1179
1180         if (smbXcli_conn_has_async_calls(cli->conn)) {
1181                 /*
1182                  * Can't use sync call while an async call is in flight
1183                  */
1184                 return NT_STATUS_INVALID_PARAMETER;
1185         }
1186
1187         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1188                 return NT_STATUS_INVALID_PARAMETER;
1189         }
1190
1191         /* Ensure this is a directory. */
1192         status = cli_smb2_create_fnum(cli,
1193                         name,
1194                         0,                      /* create_flags */
1195                         SMB2_IMPERSONATION_IMPERSONATION,
1196                         FILE_READ_ATTRIBUTES,   /* desired_access */
1197                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1198                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1199                         FILE_OPEN,              /* create_disposition */
1200                         FILE_DIRECTORY_FILE,    /* create_options */
1201                         &fnum,
1202                         NULL);
1203
1204         if (!NT_STATUS_IS_OK(status)) {
1205                 return status;
1206         }
1207
1208         return cli_smb2_close_fnum(cli, fnum);
1209 }
1210
1211 /***************************************************************
1212  Helper function for pathname operations.
1213 ***************************************************************/
1214
1215 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1216                                 const char *name,
1217                                 uint32_t desired_access,
1218                                 uint16_t *pfnum)
1219 {
1220         NTSTATUS status;
1221         size_t namelen = strlen(name);
1222         TALLOC_CTX *frame = talloc_stackframe();
1223         uint32_t create_options = 0;
1224
1225         /* SMB2 is pickier about pathnames. Ensure it doesn't
1226            end in a '\' */
1227         if (namelen > 0 && name[namelen-1] == '\\') {
1228                 char *modname = talloc_strdup(frame, name);
1229                 if (modname == NULL) {
1230                         status = NT_STATUS_NO_MEMORY;
1231                         goto fail;
1232                 }
1233                 modname[namelen-1] = '\0';
1234                 name = modname;
1235         }
1236
1237         /* Try to open a file handle first. */
1238         status = cli_smb2_create_fnum(cli,
1239                         name,
1240                         0,                      /* create_flags */
1241                         SMB2_IMPERSONATION_IMPERSONATION,
1242                         desired_access,
1243                         0, /* file attributes */
1244                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1245                         FILE_OPEN,              /* create_disposition */
1246                         create_options,
1247                         pfnum,
1248                         NULL);
1249
1250         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1251                 /*
1252                  * Naive option to match our SMB1 code. Assume the
1253                  * symlink path that tripped us up was the last
1254                  * component and try again. Eventually we will have to
1255                  * deal with the returned path unprocessed component. JRA.
1256                  */
1257                 create_options |= FILE_OPEN_REPARSE_POINT;
1258                 status = cli_smb2_create_fnum(cli,
1259                         name,
1260                         0,                      /* create_flags */
1261                         SMB2_IMPERSONATION_IMPERSONATION,
1262                         desired_access,
1263                         0, /* file attributes */
1264                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1265                         FILE_OPEN,              /* create_disposition */
1266                         create_options,
1267                         pfnum,
1268                         NULL);
1269         }
1270
1271         if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1272                 create_options |= FILE_DIRECTORY_FILE;
1273                 status = cli_smb2_create_fnum(cli,
1274                         name,
1275                         0,                      /* create_flags */
1276                         SMB2_IMPERSONATION_IMPERSONATION,
1277                         desired_access,
1278                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1279                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1280                         FILE_OPEN,              /* create_disposition */
1281                         FILE_DIRECTORY_FILE,    /* create_options */
1282                         pfnum,
1283                         NULL);
1284         }
1285
1286   fail:
1287
1288         TALLOC_FREE(frame);
1289         return status;
1290 }
1291
1292 /***************************************************************
1293  Wrapper that allows SMB2 to query a path info (ALTNAME level).
1294  Synchronous only.
1295 ***************************************************************/
1296
1297 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1298                                 const char *name,
1299                                 fstring alt_name)
1300 {
1301         NTSTATUS status;
1302         DATA_BLOB outbuf = data_blob_null;
1303         uint16_t fnum = 0xffff;
1304         struct smb2_hnd *ph = NULL;
1305         uint32_t altnamelen = 0;
1306         TALLOC_CTX *frame = talloc_stackframe();
1307
1308         if (smbXcli_conn_has_async_calls(cli->conn)) {
1309                 /*
1310                  * Can't use sync call while an async call is in flight
1311                  */
1312                 status = NT_STATUS_INVALID_PARAMETER;
1313                 goto fail;
1314         }
1315
1316         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1317                 status = NT_STATUS_INVALID_PARAMETER;
1318                 goto fail;
1319         }
1320
1321         status = get_fnum_from_path(cli,
1322                                 name,
1323                                 FILE_READ_ATTRIBUTES,
1324                                 &fnum);
1325
1326         if (!NT_STATUS_IS_OK(status)) {
1327                 goto fail;
1328         }
1329
1330         status = map_fnum_to_smb2_handle(cli,
1331                                         fnum,
1332                                         &ph);
1333         if (!NT_STATUS_IS_OK(status)) {
1334                 goto fail;
1335         }
1336
1337         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1338            level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1339
1340         status = smb2cli_query_info(cli->conn,
1341                                 cli->timeout,
1342                                 cli->smb2.session,
1343                                 cli->smb2.tcon,
1344                                 1, /* in_info_type */
1345                                 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1346                                 0xFFFF, /* in_max_output_length */
1347                                 NULL, /* in_input_buffer */
1348                                 0, /* in_additional_info */
1349                                 0, /* in_flags */
1350                                 ph->fid_persistent,
1351                                 ph->fid_volatile,
1352                                 frame,
1353                                 &outbuf);
1354
1355         if (!NT_STATUS_IS_OK(status)) {
1356                 goto fail;
1357         }
1358
1359         /* Parse the reply. */
1360         if (outbuf.length < 4) {
1361                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1362                 goto fail;
1363         }
1364
1365         altnamelen = IVAL(outbuf.data, 0);
1366         if (altnamelen > outbuf.length - 4) {
1367                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1368                 goto fail;
1369         }
1370
1371         if (altnamelen > 0) {
1372                 size_t ret = 0;
1373                 char *short_name = NULL;
1374                 ret = pull_string_talloc(frame,
1375                                 outbuf.data,
1376                                 FLAGS2_UNICODE_STRINGS,
1377                                 &short_name,
1378                                 outbuf.data + 4,
1379                                 altnamelen,
1380                                 STR_UNICODE);
1381                 if (ret == (size_t)-1) {
1382                         /* Bad conversion. */
1383                         status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1384                         goto fail;
1385                 }
1386
1387                 fstrcpy(alt_name, short_name);
1388         } else {
1389                 alt_name[0] = '\0';
1390         }
1391
1392         status = NT_STATUS_OK;
1393
1394   fail:
1395
1396         if (fnum != 0xffff) {
1397                 cli_smb2_close_fnum(cli, fnum);
1398         }
1399
1400         cli->raw_status = status;
1401
1402         TALLOC_FREE(frame);
1403         return status;
1404 }
1405
1406
1407 /***************************************************************
1408  Wrapper that allows SMB2 to query a fnum info (basic level).
1409  Synchronous only.
1410 ***************************************************************/
1411
1412 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1413                         uint16_t fnum,
1414                         uint16_t *mode,
1415                         off_t *size,
1416                         struct timespec *create_time,
1417                         struct timespec *access_time,
1418                         struct timespec *write_time,
1419                         struct timespec *change_time,
1420                         SMB_INO_T *ino)
1421 {
1422         NTSTATUS status;
1423         DATA_BLOB outbuf = data_blob_null;
1424         struct smb2_hnd *ph = NULL;
1425         TALLOC_CTX *frame = talloc_stackframe();
1426
1427         if (smbXcli_conn_has_async_calls(cli->conn)) {
1428                 /*
1429                  * Can't use sync call while an async call is in flight
1430                  */
1431                 status = NT_STATUS_INVALID_PARAMETER;
1432                 goto fail;
1433         }
1434
1435         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1436                 status = NT_STATUS_INVALID_PARAMETER;
1437                 goto fail;
1438         }
1439
1440         status = map_fnum_to_smb2_handle(cli,
1441                                         fnum,
1442                                         &ph);
1443         if (!NT_STATUS_IS_OK(status)) {
1444                 goto fail;
1445         }
1446
1447         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1448            level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1449
1450         status = smb2cli_query_info(cli->conn,
1451                                 cli->timeout,
1452                                 cli->smb2.session,
1453                                 cli->smb2.tcon,
1454                                 1, /* in_info_type */
1455                                 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1456                                 0xFFFF, /* in_max_output_length */
1457                                 NULL, /* in_input_buffer */
1458                                 0, /* in_additional_info */
1459                                 0, /* in_flags */
1460                                 ph->fid_persistent,
1461                                 ph->fid_volatile,
1462                                 frame,
1463                                 &outbuf);
1464         if (!NT_STATUS_IS_OK(status)) {
1465                 goto fail;
1466         }
1467
1468         /* Parse the reply. */
1469         if (outbuf.length < 0x60) {
1470                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1471                 goto fail;
1472         }
1473
1474         if (create_time) {
1475                 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1476         }
1477         if (access_time) {
1478                 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1479         }
1480         if (write_time) {
1481                 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1482         }
1483         if (change_time) {
1484                 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1485         }
1486         if (mode) {
1487                 uint32_t attr = IVAL(outbuf.data, 0x20);
1488                 *mode = (uint16_t)attr;
1489         }
1490         if (size) {
1491                 uint64_t file_size = BVAL(outbuf.data, 0x30);
1492                 *size = (off_t)file_size;
1493         }
1494         if (ino) {
1495                 uint64_t file_index = BVAL(outbuf.data, 0x40);
1496                 *ino = (SMB_INO_T)file_index;
1497         }
1498
1499   fail:
1500
1501         cli->raw_status = status;
1502
1503         TALLOC_FREE(frame);
1504         return status;
1505 }
1506
1507 /***************************************************************
1508  Wrapper that allows SMB2 to query an fnum.
1509  Implement on top of cli_smb2_qfileinfo_basic().
1510  Synchronous only.
1511 ***************************************************************/
1512
1513 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1514                         uint16_t fnum,
1515                         uint16_t *attr,
1516                         off_t *size,
1517                         time_t *change_time,
1518                         time_t *access_time,
1519                         time_t *write_time)
1520 {
1521         struct timespec access_time_ts;
1522         struct timespec write_time_ts;
1523         struct timespec change_time_ts;
1524         NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1525                                         fnum,
1526                                         attr,
1527                                         size,
1528                                         NULL,
1529                                         &access_time_ts,
1530                                         &write_time_ts,
1531                                         &change_time_ts,
1532                                         NULL);
1533
1534         cli->raw_status = status;
1535
1536         if (!NT_STATUS_IS_OK(status)) {
1537                 return status;
1538         }
1539
1540         if (change_time) {
1541                 *change_time = change_time_ts.tv_sec;
1542         }
1543         if (access_time) {
1544                 *access_time = access_time_ts.tv_sec;
1545         }
1546         if (write_time) {
1547                 *write_time = write_time_ts.tv_sec;
1548         }
1549         return NT_STATUS_OK;
1550 }
1551
1552 /***************************************************************
1553  Wrapper that allows SMB2 to get pathname attributes.
1554  Synchronous only.
1555 ***************************************************************/
1556
1557 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1558                         const char *name,
1559                         uint16_t *attr,
1560                         off_t *size,
1561                         time_t *write_time)
1562 {
1563         NTSTATUS status;
1564         uint16_t fnum = 0xffff;
1565         struct smb2_hnd *ph = NULL;
1566         TALLOC_CTX *frame = talloc_stackframe();
1567
1568         if (smbXcli_conn_has_async_calls(cli->conn)) {
1569                 /*
1570                  * Can't use sync call while an async call is in flight
1571                  */
1572                 status = NT_STATUS_INVALID_PARAMETER;
1573                 goto fail;
1574         }
1575
1576         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1577                 status = NT_STATUS_INVALID_PARAMETER;
1578                 goto fail;
1579         }
1580
1581         status = get_fnum_from_path(cli,
1582                                 name,
1583                                 FILE_READ_ATTRIBUTES,
1584                                 &fnum);
1585
1586         if (!NT_STATUS_IS_OK(status)) {
1587                 goto fail;
1588         }
1589
1590         status = map_fnum_to_smb2_handle(cli,
1591                                         fnum,
1592                                         &ph);
1593         if (!NT_STATUS_IS_OK(status)) {
1594                 goto fail;
1595         }
1596         status = cli_smb2_getattrE(cli,
1597                                 fnum,
1598                                 attr,
1599                                 size,
1600                                 NULL,
1601                                 NULL,
1602                                 write_time);
1603         if (!NT_STATUS_IS_OK(status)) {
1604                 goto fail;
1605         }
1606
1607   fail:
1608
1609         if (fnum != 0xffff) {
1610                 cli_smb2_close_fnum(cli, fnum);
1611         }
1612
1613         cli->raw_status = status;
1614
1615         TALLOC_FREE(frame);
1616         return status;
1617 }
1618
1619 /***************************************************************
1620  Wrapper that allows SMB2 to query a pathname info (basic level).
1621  Implement on top of cli_smb2_qfileinfo_basic().
1622  Synchronous only.
1623 ***************************************************************/
1624
1625 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1626                         const char *name,
1627                         struct timespec *create_time,
1628                         struct timespec *access_time,
1629                         struct timespec *write_time,
1630                         struct timespec *change_time,
1631                         off_t *size,
1632                         uint16_t *mode,
1633                         SMB_INO_T *ino)
1634 {
1635         NTSTATUS status;
1636         struct smb2_hnd *ph = NULL;
1637         uint16_t fnum = 0xffff;
1638         TALLOC_CTX *frame = talloc_stackframe();
1639
1640         if (smbXcli_conn_has_async_calls(cli->conn)) {
1641                 /*
1642                  * Can't use sync call while an async call is in flight
1643                  */
1644                 status = NT_STATUS_INVALID_PARAMETER;
1645                 goto fail;
1646         }
1647
1648         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1649                 status = NT_STATUS_INVALID_PARAMETER;
1650                 goto fail;
1651         }
1652
1653         status = get_fnum_from_path(cli,
1654                                         name,
1655                                         FILE_READ_ATTRIBUTES,
1656                                         &fnum);
1657
1658         if (!NT_STATUS_IS_OK(status)) {
1659                 goto fail;
1660         }
1661
1662         status = map_fnum_to_smb2_handle(cli,
1663                                         fnum,
1664                                         &ph);
1665         if (!NT_STATUS_IS_OK(status)) {
1666                 goto fail;
1667         }
1668
1669         status = cli_smb2_qfileinfo_basic(cli,
1670                                         fnum,
1671                                         mode,
1672                                         size,
1673                                         create_time,
1674                                         access_time,
1675                                         write_time,
1676                                         change_time,
1677                                         ino);
1678
1679   fail:
1680
1681         if (fnum != 0xffff) {
1682                 cli_smb2_close_fnum(cli, fnum);
1683         }
1684
1685         cli->raw_status = status;
1686
1687         TALLOC_FREE(frame);
1688         return status;
1689 }
1690
1691 /***************************************************************
1692  Wrapper that allows SMB2 to query pathname streams.
1693  Synchronous only.
1694 ***************************************************************/
1695
1696 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1697                                 const char *name,
1698                                 TALLOC_CTX *mem_ctx,
1699                                 unsigned int *pnum_streams,
1700                                 struct stream_struct **pstreams)
1701 {
1702         NTSTATUS status;
1703         struct smb2_hnd *ph = NULL;
1704         uint16_t fnum = 0xffff;
1705         DATA_BLOB outbuf = data_blob_null;
1706         TALLOC_CTX *frame = talloc_stackframe();
1707
1708         if (smbXcli_conn_has_async_calls(cli->conn)) {
1709                 /*
1710                  * Can't use sync call while an async call is in flight
1711                  */
1712                 status = NT_STATUS_INVALID_PARAMETER;
1713                 goto fail;
1714         }
1715
1716         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1717                 status = NT_STATUS_INVALID_PARAMETER;
1718                 goto fail;
1719         }
1720
1721         status = get_fnum_from_path(cli,
1722                                 name,
1723                                 FILE_READ_ATTRIBUTES,
1724                                 &fnum);
1725
1726         if (!NT_STATUS_IS_OK(status)) {
1727                 goto fail;
1728         }
1729
1730         status = map_fnum_to_smb2_handle(cli,
1731                                         fnum,
1732                                         &ph);
1733         if (!NT_STATUS_IS_OK(status)) {
1734                 goto fail;
1735         }
1736
1737         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1738            level 22 (SMB2_FILE_STREAM_INFORMATION). */
1739
1740         status = smb2cli_query_info(cli->conn,
1741                                 cli->timeout,
1742                                 cli->smb2.session,
1743                                 cli->smb2.tcon,
1744                                 1, /* in_info_type */
1745                                 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1746                                 0xFFFF, /* in_max_output_length */
1747                                 NULL, /* in_input_buffer */
1748                                 0, /* in_additional_info */
1749                                 0, /* in_flags */
1750                                 ph->fid_persistent,
1751                                 ph->fid_volatile,
1752                                 frame,
1753                                 &outbuf);
1754
1755         if (!NT_STATUS_IS_OK(status)) {
1756                 goto fail;
1757         }
1758
1759         /* Parse the reply. */
1760         if (!parse_streams_blob(mem_ctx,
1761                                 outbuf.data,
1762                                 outbuf.length,
1763                                 pnum_streams,
1764                                 pstreams)) {
1765                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1766                 goto fail;
1767         }
1768
1769   fail:
1770
1771         if (fnum != 0xffff) {
1772                 cli_smb2_close_fnum(cli, fnum);
1773         }
1774
1775         cli->raw_status = status;
1776
1777         TALLOC_FREE(frame);
1778         return status;
1779 }
1780
1781 /***************************************************************
1782  Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
1783  a pathname.
1784  Synchronous only.
1785 ***************************************************************/
1786
1787 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
1788                         const char *name,
1789                         uint8_t in_info_type,
1790                         uint8_t in_file_info_class,
1791                         const DATA_BLOB *p_in_data)
1792 {
1793         NTSTATUS status;
1794         uint16_t fnum = 0xffff;
1795         struct smb2_hnd *ph = NULL;
1796         TALLOC_CTX *frame = talloc_stackframe();
1797
1798         if (smbXcli_conn_has_async_calls(cli->conn)) {
1799                 /*
1800                  * Can't use sync call while an async call is in flight
1801                  */
1802                 status = NT_STATUS_INVALID_PARAMETER;
1803                 goto fail;
1804         }
1805
1806         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1807                 status = NT_STATUS_INVALID_PARAMETER;
1808                 goto fail;
1809         }
1810
1811         status = get_fnum_from_path(cli,
1812                                 name,
1813                                 FILE_WRITE_ATTRIBUTES,
1814                                 &fnum);
1815
1816         if (!NT_STATUS_IS_OK(status)) {
1817                 goto fail;
1818         }
1819
1820         status = map_fnum_to_smb2_handle(cli,
1821                                         fnum,
1822                                         &ph);
1823         if (!NT_STATUS_IS_OK(status)) {
1824                 goto fail;
1825         }
1826
1827         status = smb2cli_set_info(cli->conn,
1828                                 cli->timeout,
1829                                 cli->smb2.session,
1830                                 cli->smb2.tcon,
1831                                 in_info_type,
1832                                 in_file_info_class,
1833                                 p_in_data, /* in_input_buffer */
1834                                 0, /* in_additional_info */
1835                                 ph->fid_persistent,
1836                                 ph->fid_volatile);
1837   fail:
1838
1839         if (fnum != 0xffff) {
1840                 cli_smb2_close_fnum(cli, fnum);
1841         }
1842
1843         cli->raw_status = status;
1844
1845         TALLOC_FREE(frame);
1846         return status;
1847 }
1848
1849
1850 /***************************************************************
1851  Wrapper that allows SMB2 to set pathname attributes.
1852  Synchronous only.
1853 ***************************************************************/
1854
1855 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1856                         const char *name,
1857                         uint16_t attr,
1858                         time_t mtime)
1859 {
1860         uint8_t inbuf_store[40];
1861         DATA_BLOB inbuf = data_blob_null;
1862
1863         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1864            level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1865
1866         inbuf.data = inbuf_store;
1867         inbuf.length = sizeof(inbuf_store);
1868         data_blob_clear(&inbuf);
1869
1870         /*
1871          * SMB1 uses attr == 0 to clear all attributes
1872          * on a file (end up with FILE_ATTRIBUTE_NORMAL),
1873          * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
1874          * request attribute change.
1875          *
1876          * SMB2 uses exactly the reverse. Unfortunately as the
1877          * cli_setatr() ABI is exposed inside libsmbclient,
1878          * we must make the SMB2 cli_smb2_setatr() call
1879          * export the same ABI as the SMB1 cli_setatr()
1880          * which calls it. This means reversing the sense
1881          * of the requested attr argument if it's zero
1882          * or FILE_ATTRIBUTE_NORMAL.
1883          *
1884          * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
1885          */
1886
1887         if (attr == 0) {
1888                 attr = FILE_ATTRIBUTE_NORMAL;
1889         } else if (attr == FILE_ATTRIBUTE_NORMAL) {
1890                 attr = 0;
1891         }
1892
1893         SSVAL(inbuf.data, 32, attr);
1894         if (mtime != 0) {
1895                 put_long_date((char *)inbuf.data + 16,mtime);
1896         }
1897         /* Set all the other times to -1. */
1898         SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1899         SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1900         SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1901
1902         return cli_smb2_setpathinfo(cli,
1903                                 name,
1904                                 1, /* in_info_type */
1905                                 /* in_file_info_class */
1906                                 SMB_FILE_BASIC_INFORMATION - 1000,
1907                                 &inbuf);
1908 }
1909
1910
1911 /***************************************************************
1912  Wrapper that allows SMB2 to set file handle times.
1913  Synchronous only.
1914 ***************************************************************/
1915
1916 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1917                         uint16_t fnum,
1918                         time_t change_time,
1919                         time_t access_time,
1920                         time_t write_time)
1921 {
1922         NTSTATUS status;
1923         struct smb2_hnd *ph = NULL;
1924         uint8_t inbuf_store[40];
1925         DATA_BLOB inbuf = data_blob_null;
1926
1927         if (smbXcli_conn_has_async_calls(cli->conn)) {
1928                 /*
1929                  * Can't use sync call while an async call is in flight
1930                  */
1931                 return NT_STATUS_INVALID_PARAMETER;
1932         }
1933
1934         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1935                 return NT_STATUS_INVALID_PARAMETER;
1936         }
1937
1938         status = map_fnum_to_smb2_handle(cli,
1939                                         fnum,
1940                                         &ph);
1941         if (!NT_STATUS_IS_OK(status)) {
1942                 return status;
1943         }
1944
1945         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1946            level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1947
1948         inbuf.data = inbuf_store;
1949         inbuf.length = sizeof(inbuf_store);
1950         data_blob_clear(&inbuf);
1951
1952         SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1953         if (change_time != 0) {
1954                 put_long_date((char *)inbuf.data + 24, change_time);
1955         }
1956         if (access_time != 0) {
1957                 put_long_date((char *)inbuf.data + 8, access_time);
1958         }
1959         if (write_time != 0) {
1960                 put_long_date((char *)inbuf.data + 16, write_time);
1961         }
1962
1963         cli->raw_status = smb2cli_set_info(cli->conn,
1964                                 cli->timeout,
1965                                 cli->smb2.session,
1966                                 cli->smb2.tcon,
1967                                 1, /* in_info_type */
1968                                 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1969                                 &inbuf, /* in_input_buffer */
1970                                 0, /* in_additional_info */
1971                                 ph->fid_persistent,
1972                                 ph->fid_volatile);
1973
1974         return cli->raw_status;
1975 }
1976
1977 /***************************************************************
1978  Wrapper that allows SMB2 to query disk attributes (size).
1979  Synchronous only.
1980 ***************************************************************/
1981
1982 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
1983                           uint64_t *bsize, uint64_t *total, uint64_t *avail)
1984 {
1985         NTSTATUS status;
1986         uint16_t fnum = 0xffff;
1987         DATA_BLOB outbuf = data_blob_null;
1988         struct smb2_hnd *ph = NULL;
1989         uint32_t sectors_per_unit = 0;
1990         uint32_t bytes_per_sector = 0;
1991         uint64_t total_size = 0;
1992         uint64_t size_free = 0;
1993         TALLOC_CTX *frame = talloc_stackframe();
1994
1995         if (smbXcli_conn_has_async_calls(cli->conn)) {
1996                 /*
1997                  * Can't use sync call while an async call is in flight
1998                  */
1999                 status = NT_STATUS_INVALID_PARAMETER;
2000                 goto fail;
2001         }
2002
2003         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2004                 status = NT_STATUS_INVALID_PARAMETER;
2005                 goto fail;
2006         }
2007
2008         /* First open the top level directory. */
2009         status = cli_smb2_create_fnum(cli,
2010                         path,
2011                         0,                      /* create_flags */
2012                         SMB2_IMPERSONATION_IMPERSONATION,
2013                         FILE_READ_ATTRIBUTES,   /* desired_access */
2014                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2015                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2016                         FILE_OPEN,              /* create_disposition */
2017                         FILE_DIRECTORY_FILE,    /* create_options */
2018                         &fnum,
2019                         NULL);
2020
2021         if (!NT_STATUS_IS_OK(status)) {
2022                 goto fail;
2023         }
2024
2025         status = map_fnum_to_smb2_handle(cli,
2026                                         fnum,
2027                                         &ph);
2028         if (!NT_STATUS_IS_OK(status)) {
2029                 goto fail;
2030         }
2031
2032         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2033            level 3 (SMB_FS_SIZE_INFORMATION). */
2034
2035         status = smb2cli_query_info(cli->conn,
2036                                 cli->timeout,
2037                                 cli->smb2.session,
2038                                 cli->smb2.tcon,
2039                                 2, /* in_info_type */
2040                                 3, /* in_file_info_class */
2041                                 0xFFFF, /* in_max_output_length */
2042                                 NULL, /* in_input_buffer */
2043                                 0, /* in_additional_info */
2044                                 0, /* in_flags */
2045                                 ph->fid_persistent,
2046                                 ph->fid_volatile,
2047                                 frame,
2048                                 &outbuf);
2049         if (!NT_STATUS_IS_OK(status)) {
2050                 goto fail;
2051         }
2052
2053         /* Parse the reply. */
2054         if (outbuf.length != 24) {
2055                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2056                 goto fail;
2057         }
2058
2059         total_size = BVAL(outbuf.data, 0);
2060         size_free = BVAL(outbuf.data, 8);
2061         sectors_per_unit = IVAL(outbuf.data, 16);
2062         bytes_per_sector = IVAL(outbuf.data, 20);
2063
2064         if (bsize) {
2065                 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2066         }
2067         if (total) {
2068                 *total = total_size;
2069         }
2070         if (avail) {
2071                 *avail = size_free;
2072         }
2073
2074         status = NT_STATUS_OK;
2075
2076   fail:
2077
2078         if (fnum != 0xffff) {
2079                 cli_smb2_close_fnum(cli, fnum);
2080         }
2081
2082         cli->raw_status = status;
2083
2084         TALLOC_FREE(frame);
2085         return status;
2086 }
2087
2088 /***************************************************************
2089  Wrapper that allows SMB2 to query file system sizes.
2090  Synchronous only.
2091 ***************************************************************/
2092
2093 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2094                                 uint64_t *total_allocation_units,
2095                                 uint64_t *caller_allocation_units,
2096                                 uint64_t *actual_allocation_units,
2097                                 uint64_t *sectors_per_allocation_unit,
2098                                 uint64_t *bytes_per_sector)
2099 {
2100         NTSTATUS status;
2101         uint16_t fnum = 0xffff;
2102         DATA_BLOB outbuf = data_blob_null;
2103         struct smb2_hnd *ph = NULL;
2104         TALLOC_CTX *frame = talloc_stackframe();
2105
2106         if (smbXcli_conn_has_async_calls(cli->conn)) {
2107                 /*
2108                  * Can't use sync call while an async call is in flight
2109                  */
2110                 status = NT_STATUS_INVALID_PARAMETER;
2111                 goto fail;
2112         }
2113
2114         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2115                 status = NT_STATUS_INVALID_PARAMETER;
2116                 goto fail;
2117         }
2118
2119         /* First open the top level directory. */
2120         status =
2121             cli_smb2_create_fnum(cli, "", 0,               /* create_flags */
2122                                  SMB2_IMPERSONATION_IMPERSONATION,
2123                                  FILE_READ_ATTRIBUTES,     /* desired_access */
2124                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2125                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
2126                                      FILE_SHARE_DELETE, /* share_access */
2127                                  FILE_OPEN,             /* create_disposition */
2128                                  FILE_DIRECTORY_FILE,   /* create_options */
2129                                  &fnum,
2130                                  NULL);
2131
2132         if (!NT_STATUS_IS_OK(status)) {
2133                 goto fail;
2134         }
2135
2136         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2137         if (!NT_STATUS_IS_OK(status)) {
2138                 goto fail;
2139         }
2140
2141         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2142            level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2143
2144         status = smb2cli_query_info(cli->conn,
2145                                 cli->timeout,
2146                                 cli->smb2.session,
2147                                 cli->smb2.tcon,
2148                                 SMB2_GETINFO_FS, /* in_info_type */
2149                                 /* in_file_info_class */
2150                                 SMB_FS_FULL_SIZE_INFORMATION - 1000,
2151                                 0xFFFF, /* in_max_output_length */
2152                                 NULL, /* in_input_buffer */
2153                                 0, /* in_additional_info */
2154                                 0, /* in_flags */
2155                                 ph->fid_persistent,
2156                                 ph->fid_volatile,
2157                                 frame,
2158                                 &outbuf);
2159         if (!NT_STATUS_IS_OK(status)) {
2160                 goto fail;
2161         }
2162
2163         if (outbuf.length < 32) {
2164                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2165                 goto fail;
2166         }
2167
2168         *total_allocation_units = BIG_UINT(outbuf.data, 0);
2169         *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2170         *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2171         *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2172         *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2173
2174 fail:
2175
2176         if (fnum != 0xffff) {
2177                 cli_smb2_close_fnum(cli, fnum);
2178         }
2179
2180         cli->raw_status = status;
2181
2182         TALLOC_FREE(frame);
2183         return status;
2184 }
2185
2186 /***************************************************************
2187  Wrapper that allows SMB2 to query file system attributes.
2188  Synchronous only.
2189 ***************************************************************/
2190
2191 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2192 {
2193         NTSTATUS status;
2194         uint16_t fnum = 0xffff;
2195         DATA_BLOB outbuf = data_blob_null;
2196         struct smb2_hnd *ph = NULL;
2197         TALLOC_CTX *frame = talloc_stackframe();
2198
2199         if (smbXcli_conn_has_async_calls(cli->conn)) {
2200                 /*
2201                  * Can't use sync call while an async call is in flight
2202                  */
2203                 status = NT_STATUS_INVALID_PARAMETER;
2204                 goto fail;
2205         }
2206
2207         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2208                 status = NT_STATUS_INVALID_PARAMETER;
2209                 goto fail;
2210         }
2211
2212         /* First open the top level directory. */
2213         status =
2214             cli_smb2_create_fnum(cli, "", 0,               /* create_flags */
2215                                  SMB2_IMPERSONATION_IMPERSONATION,
2216                                  FILE_READ_ATTRIBUTES,     /* desired_access */
2217                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2218                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
2219                                      FILE_SHARE_DELETE, /* share_access */
2220                                  FILE_OPEN,             /* create_disposition */
2221                                  FILE_DIRECTORY_FILE,   /* create_options */
2222                                  &fnum,
2223                                  NULL);
2224
2225         if (!NT_STATUS_IS_OK(status)) {
2226                 goto fail;
2227         }
2228
2229         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2230         if (!NT_STATUS_IS_OK(status)) {
2231                 goto fail;
2232         }
2233
2234         status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2235                                     cli->smb2.tcon, 2, /* in_info_type */
2236                                     5,                 /* in_file_info_class */
2237                                     0xFFFF, /* in_max_output_length */
2238                                     NULL,   /* in_input_buffer */
2239                                     0,      /* in_additional_info */
2240                                     0,      /* in_flags */
2241                                     ph->fid_persistent, ph->fid_volatile, frame,
2242                                     &outbuf);
2243         if (!NT_STATUS_IS_OK(status)) {
2244                 goto fail;
2245         }
2246
2247         if (outbuf.length < 12) {
2248                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2249                 goto fail;
2250         }
2251
2252         *fs_attr = IVAL(outbuf.data, 0);
2253
2254 fail:
2255
2256         if (fnum != 0xffff) {
2257                 cli_smb2_close_fnum(cli, fnum);
2258         }
2259
2260         cli->raw_status = status;
2261
2262         TALLOC_FREE(frame);
2263         return status;
2264 }
2265
2266 /***************************************************************
2267  Wrapper that allows SMB2 to query file system volume info.
2268  Synchronous only.
2269 ***************************************************************/
2270
2271 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2272                                 TALLOC_CTX *mem_ctx,
2273                                 char **_volume_name,
2274                                 uint32_t *pserial_number,
2275                                 time_t *pdate)
2276 {
2277         NTSTATUS status;
2278         uint16_t fnum = 0xffff;
2279         DATA_BLOB outbuf = data_blob_null;
2280         struct smb2_hnd *ph = NULL;
2281         uint32_t nlen;
2282         char *volume_name = NULL;
2283         TALLOC_CTX *frame = talloc_stackframe();
2284
2285         if (smbXcli_conn_has_async_calls(cli->conn)) {
2286                 /*
2287                  * Can't use sync call while an async call is in flight
2288                  */
2289                 status = NT_STATUS_INVALID_PARAMETER;
2290                 goto fail;
2291         }
2292
2293         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2294                 status = NT_STATUS_INVALID_PARAMETER;
2295                 goto fail;
2296         }
2297
2298         /* First open the top level directory. */
2299         status =
2300             cli_smb2_create_fnum(cli, "", 0,               /* create_flags */
2301                                  SMB2_IMPERSONATION_IMPERSONATION,
2302                                  FILE_READ_ATTRIBUTES,     /* desired_access */
2303                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2304                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
2305                                      FILE_SHARE_DELETE, /* share_access */
2306                                  FILE_OPEN,             /* create_disposition */
2307                                  FILE_DIRECTORY_FILE,   /* create_options */
2308                                  &fnum,
2309                                  NULL);
2310
2311         if (!NT_STATUS_IS_OK(status)) {
2312                 goto fail;
2313         }
2314
2315         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2316         if (!NT_STATUS_IS_OK(status)) {
2317                 goto fail;
2318         }
2319
2320         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2321            level 1 (SMB_FS_VOLUME_INFORMATION). */
2322
2323         status = smb2cli_query_info(cli->conn,
2324                                 cli->timeout,
2325                                 cli->smb2.session,
2326                                 cli->smb2.tcon,
2327                                 SMB2_GETINFO_FS, /* in_info_type */
2328                                 /* in_file_info_class */
2329                                 SMB_FS_VOLUME_INFORMATION - 1000,
2330                                 0xFFFF, /* in_max_output_length */
2331                                 NULL, /* in_input_buffer */
2332                                 0, /* in_additional_info */
2333                                 0, /* in_flags */
2334                                 ph->fid_persistent,
2335                                 ph->fid_volatile,
2336                                 frame,
2337                                 &outbuf);
2338         if (!NT_STATUS_IS_OK(status)) {
2339                 goto fail;
2340         }
2341
2342         if (outbuf.length < 24) {
2343                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2344                 goto fail;
2345         }
2346
2347         if (pdate) {
2348                 struct timespec ts;
2349                 ts = interpret_long_date((char *)outbuf.data);
2350                 *pdate = ts.tv_sec;
2351         }
2352         if (pserial_number) {
2353                 *pserial_number = IVAL(outbuf.data,8);
2354         }
2355         nlen = IVAL(outbuf.data,12);
2356         if (nlen + 18 < 18) {
2357                 /* Integer wrap. */
2358                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2359                 goto fail;
2360         }
2361         /*
2362          * The next check is safe as we know outbuf.length >= 24
2363          * from above.
2364          */
2365         if (nlen > (outbuf.length - 18)) {
2366                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2367                 goto fail;
2368         }
2369
2370         clistr_pull_talloc(mem_ctx,
2371                         (const char *)outbuf.data,
2372                         0,
2373                         &volume_name,
2374                         outbuf.data + 18,
2375                         nlen,
2376                         STR_UNICODE);
2377         if (volume_name == NULL) {
2378                 status = map_nt_error_from_unix(errno);
2379                 goto fail;
2380         }
2381
2382         *_volume_name = volume_name;
2383
2384 fail:
2385
2386         if (fnum != 0xffff) {
2387                 cli_smb2_close_fnum(cli, fnum);
2388         }
2389
2390         cli->raw_status = status;
2391
2392         TALLOC_FREE(frame);
2393         return status;
2394 }
2395
2396
2397 /***************************************************************
2398  Wrapper that allows SMB2 to query a security descriptor.
2399  Synchronous only.
2400 ***************************************************************/
2401
2402 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2403                                         uint16_t fnum,
2404                                         uint32_t sec_info,
2405                                         TALLOC_CTX *mem_ctx,
2406                                         struct security_descriptor **ppsd)
2407 {
2408         NTSTATUS status;
2409         DATA_BLOB outbuf = data_blob_null;
2410         struct smb2_hnd *ph = NULL;
2411         struct security_descriptor *lsd = NULL;
2412         TALLOC_CTX *frame = talloc_stackframe();
2413
2414         if (smbXcli_conn_has_async_calls(cli->conn)) {
2415                 /*
2416                  * Can't use sync call while an async call is in flight
2417                  */
2418                 status = NT_STATUS_INVALID_PARAMETER;
2419                 goto fail;
2420         }
2421
2422         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2423                 status = NT_STATUS_INVALID_PARAMETER;
2424                 goto fail;
2425         }
2426
2427         status = map_fnum_to_smb2_handle(cli,
2428                                         fnum,
2429                                         &ph);
2430         if (!NT_STATUS_IS_OK(status)) {
2431                 goto fail;
2432         }
2433
2434         /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2435
2436         status = smb2cli_query_info(cli->conn,
2437                                 cli->timeout,
2438                                 cli->smb2.session,
2439                                 cli->smb2.tcon,
2440                                 3, /* in_info_type */
2441                                 0, /* in_file_info_class */
2442                                 0xFFFF, /* in_max_output_length */
2443                                 NULL, /* in_input_buffer */
2444                                 sec_info, /* in_additional_info */
2445                                 0, /* in_flags */
2446                                 ph->fid_persistent,
2447                                 ph->fid_volatile,
2448                                 frame,
2449                                 &outbuf);
2450
2451         if (!NT_STATUS_IS_OK(status)) {
2452                 goto fail;
2453         }
2454
2455         /* Parse the reply. */
2456         status = unmarshall_sec_desc(mem_ctx,
2457                                 outbuf.data,
2458                                 outbuf.length,
2459                                 &lsd);
2460
2461         if (!NT_STATUS_IS_OK(status)) {
2462                 goto fail;
2463         }
2464
2465         if (ppsd != NULL) {
2466                 *ppsd = lsd;
2467         } else {
2468                 TALLOC_FREE(lsd);
2469         }
2470
2471   fail:
2472
2473         cli->raw_status = status;
2474
2475         TALLOC_FREE(frame);
2476         return status;
2477 }
2478
2479 /***************************************************************
2480  Wrapper that allows SMB2 to set a security descriptor.
2481  Synchronous only.
2482 ***************************************************************/
2483
2484 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
2485                                         uint16_t fnum,
2486                                         uint32_t sec_info,
2487                                         const struct security_descriptor *sd)
2488 {
2489         NTSTATUS status;
2490         DATA_BLOB inbuf = data_blob_null;
2491         struct smb2_hnd *ph = NULL;
2492         TALLOC_CTX *frame = talloc_stackframe();
2493
2494         if (smbXcli_conn_has_async_calls(cli->conn)) {
2495                 /*
2496                  * Can't use sync call while an async call is in flight
2497                  */
2498                 status = NT_STATUS_INVALID_PARAMETER;
2499                 goto fail;
2500         }
2501
2502         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2503                 status = NT_STATUS_INVALID_PARAMETER;
2504                 goto fail;
2505         }
2506
2507         status = map_fnum_to_smb2_handle(cli,
2508                                         fnum,
2509                                         &ph);
2510         if (!NT_STATUS_IS_OK(status)) {
2511                 goto fail;
2512         }
2513
2514         status = marshall_sec_desc(frame,
2515                                 sd,
2516                                 &inbuf.data,
2517                                 &inbuf.length);
2518
2519         if (!NT_STATUS_IS_OK(status)) {
2520                 goto fail;
2521         }
2522
2523         /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2524
2525         status = smb2cli_set_info(cli->conn,
2526                                 cli->timeout,
2527                                 cli->smb2.session,
2528                                 cli->smb2.tcon,
2529                                 3, /* in_info_type */
2530                                 0, /* in_file_info_class */
2531                                 &inbuf, /* in_input_buffer */
2532                                 sec_info, /* in_additional_info */
2533                                 ph->fid_persistent,
2534                                 ph->fid_volatile);
2535
2536   fail:
2537
2538         cli->raw_status = status;
2539
2540         TALLOC_FREE(frame);
2541         return status;
2542 }
2543
2544 /***************************************************************
2545  Wrapper that allows SMB2 to rename a file.
2546  Synchronous only.
2547 ***************************************************************/
2548
2549 NTSTATUS cli_smb2_rename(struct cli_state *cli,
2550                          const char *fname_src,
2551                          const char *fname_dst,
2552                          bool replace)
2553 {
2554         NTSTATUS status;
2555         DATA_BLOB inbuf = data_blob_null;
2556         uint16_t fnum = 0xffff;
2557         struct smb2_hnd *ph = NULL;
2558         smb_ucs2_t *converted_str = NULL;
2559         size_t converted_size_bytes = 0;
2560         size_t namelen = 0;
2561         TALLOC_CTX *frame = talloc_stackframe();
2562
2563         if (smbXcli_conn_has_async_calls(cli->conn)) {
2564                 /*
2565                  * Can't use sync call while an async call is in flight
2566                  */
2567                 status = NT_STATUS_INVALID_PARAMETER;
2568                 goto fail;
2569         }
2570
2571         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2572                 status = NT_STATUS_INVALID_PARAMETER;
2573                 goto fail;
2574         }
2575
2576         status = get_fnum_from_path(cli,
2577                                 fname_src,
2578                                 DELETE_ACCESS,
2579                                 &fnum);
2580
2581         if (!NT_STATUS_IS_OK(status)) {
2582                 goto fail;
2583         }
2584
2585         status = map_fnum_to_smb2_handle(cli,
2586                                         fnum,
2587                                         &ph);
2588         if (!NT_STATUS_IS_OK(status)) {
2589                 goto fail;
2590         }
2591
2592         /* SMB2 is pickier about pathnames. Ensure it doesn't
2593            start in a '\' */
2594         if (*fname_dst == '\\') {
2595                 fname_dst++;
2596         }
2597
2598         /* SMB2 is pickier about pathnames. Ensure it doesn't
2599            end in a '\' */
2600         namelen = strlen(fname_dst);
2601         if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2602                 char *modname = talloc_strdup(frame, fname_dst);
2603                 modname[namelen-1] = '\0';
2604                 fname_dst = modname;
2605         }
2606
2607         if (!push_ucs2_talloc(frame,
2608                                 &converted_str,
2609                                 fname_dst,
2610                                 &converted_size_bytes)) {
2611                 status = NT_STATUS_INVALID_PARAMETER;
2612                 goto fail;
2613         }
2614
2615         /* W2K8 insists the dest name is not null
2616            terminated. Remove the last 2 zero bytes
2617            and reduce the name length. */
2618
2619         if (converted_size_bytes < 2) {
2620                 status = NT_STATUS_INVALID_PARAMETER;
2621                 goto fail;
2622         }
2623         converted_size_bytes -= 2;
2624
2625         inbuf = data_blob_talloc_zero(frame,
2626                                 20 + converted_size_bytes);
2627         if (inbuf.data == NULL) {
2628                 status = NT_STATUS_NO_MEMORY;
2629                 goto fail;
2630         }
2631
2632         if (replace) {
2633                 SCVAL(inbuf.data, 0, 1);
2634         }
2635
2636         SIVAL(inbuf.data, 16, converted_size_bytes);
2637         memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2638
2639         /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2640            level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2641
2642         status = smb2cli_set_info(cli->conn,
2643                                 cli->timeout,
2644                                 cli->smb2.session,
2645                                 cli->smb2.tcon,
2646                                 1, /* in_info_type */
2647                                 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2648                                 &inbuf, /* in_input_buffer */
2649                                 0, /* in_additional_info */
2650                                 ph->fid_persistent,
2651                                 ph->fid_volatile);
2652
2653   fail:
2654
2655         if (fnum != 0xffff) {
2656                 cli_smb2_close_fnum(cli, fnum);
2657         }
2658
2659         cli->raw_status = status;
2660
2661         TALLOC_FREE(frame);
2662         return status;
2663 }
2664
2665 /***************************************************************
2666  Wrapper that allows SMB2 to set an EA on a fnum.
2667  Synchronous only.
2668 ***************************************************************/
2669
2670 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2671                         uint16_t fnum,
2672                         const char *ea_name,
2673                         const char *ea_val,
2674                         size_t ea_len)
2675 {
2676         NTSTATUS status;
2677         DATA_BLOB inbuf = data_blob_null;
2678         size_t bloblen = 0;
2679         char *ea_name_ascii = NULL;
2680         size_t namelen = 0;
2681         struct smb2_hnd *ph = NULL;
2682         TALLOC_CTX *frame = talloc_stackframe();
2683
2684         if (smbXcli_conn_has_async_calls(cli->conn)) {
2685                 /*
2686                  * Can't use sync call while an async call is in flight
2687                  */
2688                 status = NT_STATUS_INVALID_PARAMETER;
2689                 goto fail;
2690         }
2691
2692         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2693                 status = NT_STATUS_INVALID_PARAMETER;
2694                 goto fail;
2695         }
2696
2697         status = map_fnum_to_smb2_handle(cli,
2698                                         fnum,
2699                                         &ph);
2700         if (!NT_STATUS_IS_OK(status)) {
2701                 goto fail;
2702         }
2703
2704         /* Marshall the SMB2 EA data. */
2705         if (ea_len > 0xFFFF) {
2706                 status = NT_STATUS_INVALID_PARAMETER;
2707                 goto fail;
2708         }
2709
2710         if (!push_ascii_talloc(frame,
2711                                 &ea_name_ascii,
2712                                 ea_name,
2713                                 &namelen)) {
2714                 status = NT_STATUS_INVALID_PARAMETER;
2715                 goto fail;
2716         }
2717
2718         if (namelen < 2 || namelen > 0xFF) {
2719                 status = NT_STATUS_INVALID_PARAMETER;
2720                 goto fail;
2721         }
2722
2723         bloblen = 8 + ea_len + namelen;
2724         /* Round up to a 4 byte boundary. */
2725         bloblen = ((bloblen + 3)&~3);
2726
2727         inbuf = data_blob_talloc_zero(frame, bloblen);
2728         if (inbuf.data == NULL) {
2729                 status = NT_STATUS_NO_MEMORY;
2730                 goto fail;
2731         }
2732         /* namelen doesn't include the NULL byte. */
2733         SCVAL(inbuf.data, 5, namelen - 1);
2734         SSVAL(inbuf.data, 6, ea_len);
2735         memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2736         memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2737
2738         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2739            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2740
2741         status = smb2cli_set_info(cli->conn,
2742                                 cli->timeout,
2743                                 cli->smb2.session,
2744                                 cli->smb2.tcon,
2745                                 1, /* in_info_type */
2746                                 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2747                                 &inbuf, /* in_input_buffer */
2748                                 0, /* in_additional_info */
2749                                 ph->fid_persistent,
2750                                 ph->fid_volatile);
2751
2752   fail:
2753
2754         cli->raw_status = status;
2755
2756         TALLOC_FREE(frame);
2757         return status;
2758 }
2759
2760 /***************************************************************
2761  Wrapper that allows SMB2 to set an EA on a pathname.
2762  Synchronous only.
2763 ***************************************************************/
2764
2765 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2766                         const char *name,
2767                         const char *ea_name,
2768                         const char *ea_val,
2769                         size_t ea_len)
2770 {
2771         NTSTATUS status;
2772         uint16_t fnum = 0xffff;
2773
2774         if (smbXcli_conn_has_async_calls(cli->conn)) {
2775                 /*
2776                  * Can't use sync call while an async call is in flight
2777                  */
2778                 status = NT_STATUS_INVALID_PARAMETER;
2779                 goto fail;
2780         }
2781
2782         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2783                 status = NT_STATUS_INVALID_PARAMETER;
2784                 goto fail;
2785         }
2786
2787         status = get_fnum_from_path(cli,
2788                                 name,
2789                                 FILE_WRITE_EA,
2790                                 &fnum);
2791
2792         if (!NT_STATUS_IS_OK(status)) {
2793                 goto fail;
2794         }
2795
2796         status = cli_set_ea_fnum(cli,
2797                                 fnum,
2798                                 ea_name,
2799                                 ea_val,
2800                                 ea_len);
2801         if (!NT_STATUS_IS_OK(status)) {
2802                 goto fail;
2803         }
2804
2805   fail:
2806
2807         if (fnum != 0xffff) {
2808                 cli_smb2_close_fnum(cli, fnum);
2809         }
2810
2811         cli->raw_status = status;
2812
2813         return status;
2814 }
2815
2816 /***************************************************************
2817  Wrapper that allows SMB2 to get an EA list on a pathname.
2818  Synchronous only.
2819 ***************************************************************/
2820
2821 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2822                                 const char *name,
2823                                 TALLOC_CTX *ctx,
2824                                 size_t *pnum_eas,
2825                                 struct ea_struct **pea_array)
2826 {
2827         NTSTATUS status;
2828         uint16_t fnum = 0xffff;
2829         DATA_BLOB outbuf = data_blob_null;
2830         struct smb2_hnd *ph = NULL;
2831         struct ea_list *ea_list = NULL;
2832         struct ea_list *eal = NULL;
2833         size_t ea_count = 0;
2834         TALLOC_CTX *frame = talloc_stackframe();
2835
2836         *pnum_eas = 0;
2837         *pea_array = NULL;
2838
2839         if (smbXcli_conn_has_async_calls(cli->conn)) {
2840                 /*
2841                  * Can't use sync call while an async call is in flight
2842                  */
2843                 status = NT_STATUS_INVALID_PARAMETER;
2844                 goto fail;
2845         }
2846
2847         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2848                 status = NT_STATUS_INVALID_PARAMETER;
2849                 goto fail;
2850         }
2851
2852         status = get_fnum_from_path(cli,
2853                                 name,
2854                                 FILE_READ_EA,
2855                                 &fnum);
2856
2857         if (!NT_STATUS_IS_OK(status)) {
2858                 goto fail;
2859         }
2860
2861         status = map_fnum_to_smb2_handle(cli,
2862                                         fnum,
2863                                         &ph);
2864         if (!NT_STATUS_IS_OK(status)) {
2865                 goto fail;
2866         }
2867
2868         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2869            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2870
2871         status = smb2cli_query_info(cli->conn,
2872                                 cli->timeout,
2873                                 cli->smb2.session,
2874                                 cli->smb2.tcon,
2875                                 1, /* in_info_type */
2876                                 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2877                                 0xFFFF, /* in_max_output_length */
2878                                 NULL, /* in_input_buffer */
2879                                 0, /* in_additional_info */
2880                                 0, /* in_flags */
2881                                 ph->fid_persistent,
2882                                 ph->fid_volatile,
2883                                 frame,
2884                                 &outbuf);
2885
2886         if (!NT_STATUS_IS_OK(status)) {
2887                 goto fail;
2888         }
2889
2890         /* Parse the reply. */
2891         ea_list = read_nttrans_ea_list(ctx,
2892                                 (const char *)outbuf.data,
2893                                 outbuf.length);
2894         if (ea_list == NULL) {
2895                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2896                 goto fail;
2897         }
2898
2899         /* Convert to an array. */
2900         for (eal = ea_list; eal; eal = eal->next) {
2901                 ea_count++;
2902         }
2903
2904         if (ea_count) {
2905                 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2906                 if (*pea_array == NULL) {
2907                         status = NT_STATUS_NO_MEMORY;
2908                         goto fail;
2909                 }
2910                 ea_count = 0;
2911                 for (eal = ea_list; eal; eal = eal->next) {
2912                         (*pea_array)[ea_count++] = eal->ea;
2913                 }
2914                 *pnum_eas = ea_count;
2915         }
2916
2917   fail:
2918
2919         if (fnum != 0xffff) {
2920                 cli_smb2_close_fnum(cli, fnum);
2921         }
2922
2923         cli->raw_status = status;
2924
2925         TALLOC_FREE(frame);
2926         return status;
2927 }
2928
2929 /***************************************************************
2930  Wrapper that allows SMB2 to get user quota.
2931  Synchronous only.
2932 ***************************************************************/
2933
2934 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
2935                                  int quota_fnum,
2936                                  SMB_NTQUOTA_STRUCT *pqt)
2937 {
2938         NTSTATUS status;
2939         DATA_BLOB inbuf = data_blob_null;
2940         DATA_BLOB info_blob = data_blob_null;
2941         DATA_BLOB outbuf = data_blob_null;
2942         struct smb2_hnd *ph = NULL;
2943         TALLOC_CTX *frame = talloc_stackframe();
2944         unsigned sid_len;
2945         unsigned int offset;
2946         struct smb2_query_quota_info query = {0};
2947         struct file_get_quota_info info = {0};
2948         enum ndr_err_code err;
2949         struct ndr_push *ndr_push = NULL;
2950
2951         if (smbXcli_conn_has_async_calls(cli->conn)) {
2952                 /*
2953                  * Can't use sync call while an async call is in flight
2954                  */
2955                 status = NT_STATUS_INVALID_PARAMETER;
2956                 goto fail;
2957         }
2958
2959         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2960                 status = NT_STATUS_INVALID_PARAMETER;
2961                 goto fail;
2962         }
2963
2964         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2965         if (!NT_STATUS_IS_OK(status)) {
2966                 goto fail;
2967         }
2968
2969         sid_len = ndr_size_dom_sid(&pqt->sid, 0);
2970
2971         query.return_single = 1;
2972
2973         info.next_entry_offset = 0;
2974         info.sid_length = sid_len;
2975         info.sid = pqt->sid;
2976
2977         err = ndr_push_struct_blob(
2978                         &info_blob,
2979                         frame,
2980                         &info,
2981                         (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
2982
2983         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
2984                 status = NT_STATUS_INTERNAL_ERROR;
2985                 goto fail;
2986         }
2987
2988         query.sid_list_length = info_blob.length;
2989         ndr_push = ndr_push_init_ctx(frame);
2990         if (!ndr_push) {
2991                 status = NT_STATUS_NO_MEMORY;
2992                 goto fail;
2993         }
2994
2995         err = ndr_push_smb2_query_quota_info(ndr_push,
2996                                              NDR_SCALARS | NDR_BUFFERS,
2997                                              &query);
2998
2999         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3000                 status = NT_STATUS_INTERNAL_ERROR;
3001                 goto fail;
3002         }
3003
3004         err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3005                                    info_blob.length);
3006
3007         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3008                 status = NT_STATUS_INTERNAL_ERROR;
3009                 goto fail;
3010         }
3011         inbuf.data = ndr_push->data;
3012         inbuf.length = ndr_push->offset;
3013
3014         status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
3015                                     cli->smb2.tcon, 4, /* in_info_type */
3016                                     0,                 /* in_file_info_class */
3017                                     0xFFFF, /* in_max_output_length */
3018                                     &inbuf, /* in_input_buffer */
3019                                     0,      /* in_additional_info */
3020                                     0,      /* in_flags */
3021                                     ph->fid_persistent, ph->fid_volatile, frame,
3022                                     &outbuf);
3023
3024         if (!NT_STATUS_IS_OK(status)) {
3025                 goto fail;
3026         }
3027
3028         if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3029                                      pqt)) {
3030                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3031                 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3032         }
3033
3034 fail:
3035         cli->raw_status = status;
3036
3037         TALLOC_FREE(frame);
3038         return status;
3039 }
3040
3041 /***************************************************************
3042  Wrapper that allows SMB2 to list user quota.
3043  Synchronous only.
3044 ***************************************************************/
3045
3046 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3047                                        TALLOC_CTX *mem_ctx,
3048                                        int quota_fnum,
3049                                        SMB_NTQUOTA_LIST **pqt_list,
3050                                        bool first)
3051 {
3052         NTSTATUS status;
3053         DATA_BLOB inbuf = data_blob_null;
3054         DATA_BLOB outbuf = data_blob_null;
3055         struct smb2_hnd *ph = NULL;
3056         TALLOC_CTX *frame = talloc_stackframe();
3057         struct smb2_query_quota_info info = {0};
3058         enum ndr_err_code err;
3059
3060         if (smbXcli_conn_has_async_calls(cli->conn)) {
3061                 /*
3062                  * Can't use sync call while an async call is in flight
3063                  */
3064                 status = NT_STATUS_INVALID_PARAMETER;
3065                 goto cleanup;
3066         }
3067
3068         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3069                 status = NT_STATUS_INVALID_PARAMETER;
3070                 goto cleanup;
3071         }
3072
3073         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3074         if (!NT_STATUS_IS_OK(status)) {
3075                 goto cleanup;
3076         }
3077
3078
3079         info.restart_scan = first ? 1 : 0;
3080
3081         err = ndr_push_struct_blob(
3082                         &inbuf,
3083                         frame,
3084                         &info,
3085                         (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3086
3087         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3088                 status = NT_STATUS_INTERNAL_ERROR;
3089                 goto cleanup;
3090         }
3091
3092         status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
3093                                     cli->smb2.tcon, 4, /* in_info_type */
3094                                     0,                 /* in_file_info_class */
3095                                     0xFFFF, /* in_max_output_length */
3096                                     &inbuf, /* in_input_buffer */
3097                                     0,      /* in_additional_info */
3098                                     0,      /* in_flags */
3099                                     ph->fid_persistent, ph->fid_volatile, frame,
3100                                     &outbuf);
3101
3102         /*
3103          * safeguard against panic from calling parse_user_quota_list with
3104          * NULL buffer
3105          */
3106         if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3107                 status = NT_STATUS_NO_MORE_ENTRIES;
3108         }
3109
3110         if (!NT_STATUS_IS_OK(status)) {
3111                 goto cleanup;
3112         }
3113
3114         status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3115                                        pqt_list);
3116
3117 cleanup:
3118         cli->raw_status = status;
3119
3120         TALLOC_FREE(frame);
3121         return status;
3122 }
3123
3124 /***************************************************************
3125  Wrapper that allows SMB2 to get file system quota.
3126  Synchronous only.
3127 ***************************************************************/
3128
3129 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3130                                     int quota_fnum,
3131                                     SMB_NTQUOTA_STRUCT *pqt)
3132 {
3133         NTSTATUS status;
3134         DATA_BLOB outbuf = data_blob_null;
3135         struct smb2_hnd *ph = NULL;
3136         TALLOC_CTX *frame = talloc_stackframe();
3137
3138         if (smbXcli_conn_has_async_calls(cli->conn)) {
3139                 /*
3140                  * Can't use sync call while an async call is in flight
3141                  */
3142                 status = NT_STATUS_INVALID_PARAMETER;
3143                 goto cleanup;
3144         }
3145
3146         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3147                 status = NT_STATUS_INVALID_PARAMETER;
3148                 goto cleanup;
3149         }
3150
3151         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3152         if (!NT_STATUS_IS_OK(status)) {
3153                 goto cleanup;
3154         }
3155
3156         status = smb2cli_query_info(
3157             cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3158             2,                               /* in_info_type */
3159             SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3160             0xFFFF,                          /* in_max_output_length */
3161             NULL,                            /* in_input_buffer */
3162             0,                               /* in_additional_info */
3163             0,                               /* in_flags */
3164             ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
3165
3166         if (!NT_STATUS_IS_OK(status)) {
3167                 goto cleanup;
3168         }
3169
3170         status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3171
3172 cleanup:
3173         cli->raw_status = status;
3174
3175         TALLOC_FREE(frame);
3176         return status;
3177 }
3178
3179 /***************************************************************
3180  Wrapper that allows SMB2 to set user quota.
3181  Synchronous only.
3182 ***************************************************************/
3183
3184 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3185                                  int quota_fnum,
3186                                  SMB_NTQUOTA_LIST *qtl)
3187 {
3188         NTSTATUS status;
3189         DATA_BLOB inbuf = data_blob_null;
3190         struct smb2_hnd *ph = NULL;
3191         TALLOC_CTX *frame = talloc_stackframe();
3192
3193         if (smbXcli_conn_has_async_calls(cli->conn)) {
3194                 /*
3195                  * Can't use sync call while an async call is in flight
3196                  */
3197                 status = NT_STATUS_INVALID_PARAMETER;
3198                 goto cleanup;
3199         }
3200
3201         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3202                 status = NT_STATUS_INVALID_PARAMETER;
3203                 goto cleanup;
3204         }
3205
3206         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3207         if (!NT_STATUS_IS_OK(status)) {
3208                 goto cleanup;
3209         }
3210
3211         status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3212         if (!NT_STATUS_IS_OK(status)) {
3213                 goto cleanup;
3214         }
3215
3216         status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
3217                                   cli->smb2.tcon, 4, /* in_info_type */
3218                                   0,                 /* in_file_info_class */
3219                                   &inbuf,           /* in_input_buffer */
3220                                   0,                 /* in_additional_info */
3221                                   ph->fid_persistent, ph->fid_volatile);
3222 cleanup:
3223
3224         cli->raw_status = status;
3225
3226         TALLOC_FREE(frame);
3227
3228         return status;
3229 }
3230
3231 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3232                                     int quota_fnum,
3233                                     SMB_NTQUOTA_STRUCT *pqt)
3234 {
3235         NTSTATUS status;
3236         DATA_BLOB inbuf = data_blob_null;
3237         struct smb2_hnd *ph = NULL;
3238         TALLOC_CTX *frame = talloc_stackframe();
3239
3240         if (smbXcli_conn_has_async_calls(cli->conn)) {
3241                 /*
3242                  * Can't use sync call while an async call is in flight
3243                  */
3244                 status = NT_STATUS_INVALID_PARAMETER;
3245                 goto cleanup;
3246         }
3247
3248         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3249                 status = NT_STATUS_INVALID_PARAMETER;
3250                 goto cleanup;
3251         }
3252
3253         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3254         if (!NT_STATUS_IS_OK(status)) {
3255                 goto cleanup;
3256         }
3257
3258         status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3259         if (!NT_STATUS_IS_OK(status)) {
3260                 goto cleanup;
3261         }
3262
3263         status = smb2cli_set_info(
3264             cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3265             2,                               /* in_info_type */
3266             SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3267             &inbuf,                          /* in_input_buffer */
3268             0,                               /* in_additional_info */
3269             ph->fid_persistent, ph->fid_volatile);
3270 cleanup:
3271         cli->raw_status = status;
3272
3273         TALLOC_FREE(frame);
3274         return status;
3275 }
3276
3277 struct cli_smb2_read_state {
3278         struct tevent_context *ev;
3279         struct cli_state *cli;
3280         struct smb2_hnd *ph;
3281         uint64_t start_offset;
3282         uint32_t size;
3283         uint32_t received;
3284         uint8_t *buf;
3285 };
3286
3287 static void cli_smb2_read_done(struct tevent_req *subreq);
3288
3289 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3290                                 struct tevent_context *ev,
3291                                 struct cli_state *cli,
3292                                 uint16_t fnum,
3293                                 off_t offset,
3294                                 size_t size)
3295 {
3296         NTSTATUS status;
3297         struct tevent_req *req, *subreq;
3298         struct cli_smb2_read_state *state;
3299
3300         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3301         if (req == NULL) {
3302                 return NULL;
3303         }
3304         state->ev = ev;
3305         state->cli = cli;
3306         state->start_offset = (uint64_t)offset;
3307         state->size = (uint32_t)size;
3308         state->received = 0;
3309         state->buf = NULL;
3310
3311         status = map_fnum_to_smb2_handle(cli,
3312                                         fnum,
3313                                         &state->ph);
3314         if (tevent_req_nterror(req, status)) {
3315                 return tevent_req_post(req, ev);
3316         }
3317
3318         subreq = smb2cli_read_send(state,
3319                                 state->ev,
3320                                 state->cli->conn,
3321                                 state->cli->timeout,
3322                                 state->cli->smb2.session,
3323                                 state->cli->smb2.tcon,
3324                                 state->size,
3325                                 state->start_offset,
3326                                 state->ph->fid_persistent,
3327                                 state->ph->fid_volatile,
3328                                 0, /* minimum_count */
3329                                 0); /* remaining_bytes */
3330
3331         if (tevent_req_nomem(subreq, req)) {
3332                 return tevent_req_post(req, ev);
3333         }
3334         tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3335         return req;
3336 }
3337
3338 static void cli_smb2_read_done(struct tevent_req *subreq)
3339 {
3340         struct tevent_req *req = tevent_req_callback_data(
3341                 subreq, struct tevent_req);
3342         struct cli_smb2_read_state *state = tevent_req_data(
3343                 req, struct cli_smb2_read_state);
3344         NTSTATUS status;
3345
3346         status = smb2cli_read_recv(subreq, state,
3347                                    &state->buf, &state->received);
3348         if (tevent_req_nterror(req, status)) {
3349                 return;
3350         }
3351
3352         if (state->received > state->size) {
3353                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3354                 return;
3355         }
3356
3357         tevent_req_done(req);
3358 }
3359
3360 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
3361                                 ssize_t *received,
3362                                 uint8_t **rcvbuf)
3363 {
3364         NTSTATUS status;
3365         struct cli_smb2_read_state *state = tevent_req_data(
3366                                 req, struct cli_smb2_read_state);
3367
3368         if (tevent_req_is_nterror(req, &status)) {
3369                 state->cli->raw_status = status;
3370                 return status;
3371         }
3372         /*
3373          * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3374          * better make sure that you copy it away before you talloc_free(req).
3375          * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3376          */
3377         *received = (ssize_t)state->received;
3378         *rcvbuf = state->buf;
3379         state->cli->raw_status = NT_STATUS_OK;
3380         return NT_STATUS_OK;
3381 }
3382
3383 struct cli_smb2_write_state {
3384         struct tevent_context *ev;
3385         struct cli_state *cli;
3386         struct smb2_hnd *ph;
3387         uint32_t flags;
3388         const uint8_t *buf;
3389         uint64_t offset;
3390         uint32_t size;
3391         uint32_t written;
3392 };
3393
3394 static void cli_smb2_write_written(struct tevent_req *req);
3395
3396 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
3397                                         struct tevent_context *ev,
3398                                         struct cli_state *cli,
3399                                         uint16_t fnum,
3400                                         uint16_t mode,
3401                                         const uint8_t *buf,
3402                                         off_t offset,
3403                                         size_t size)
3404 {
3405         NTSTATUS status;
3406         struct tevent_req *req, *subreq = NULL;
3407         struct cli_smb2_write_state *state = NULL;
3408
3409         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
3410         if (req == NULL) {
3411                 return NULL;
3412         }
3413         state->ev = ev;
3414         state->cli = cli;
3415         /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3416         state->flags = (uint32_t)mode;
3417         state->buf = buf;
3418         state->offset = (uint64_t)offset;
3419         state->size = (uint32_t)size;
3420         state->written = 0;
3421
3422         status = map_fnum_to_smb2_handle(cli,
3423                                         fnum,
3424                                         &state->ph);
3425         if (tevent_req_nterror(req, status)) {
3426                 return tevent_req_post(req, ev);
3427         }
3428
3429         subreq = smb2cli_write_send(state,
3430                                 state->ev,
3431                                 state->cli->conn,
3432                                 state->cli->timeout,
3433                                 state->cli->smb2.session,
3434                                 state->cli->smb2.tcon,
3435                                 state->size,
3436                                 state->offset,
3437                                 state->ph->fid_persistent,
3438                                 state->ph->fid_volatile,
3439                                 0, /* remaining_bytes */
3440                                 state->flags, /* flags */
3441                                 state->buf);
3442
3443         if (tevent_req_nomem(subreq, req)) {
3444                 return tevent_req_post(req, ev);
3445         }
3446         tevent_req_set_callback(subreq, cli_smb2_write_written, req);
3447         return req;
3448 }
3449
3450 static void cli_smb2_write_written(struct tevent_req *subreq)
3451 {
3452         struct tevent_req *req = tevent_req_callback_data(
3453                 subreq, struct tevent_req);
3454         struct cli_smb2_write_state *state = tevent_req_data(
3455                 req, struct cli_smb2_write_state);
3456         NTSTATUS status;
3457         uint32_t written;
3458
3459         status = smb2cli_write_recv(subreq, &written);
3460         TALLOC_FREE(subreq);
3461         if (tevent_req_nterror(req, status)) {
3462                 return;
3463         }
3464
3465         state->written = written;
3466
3467         tevent_req_done(req);
3468 }
3469
3470 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
3471                              size_t *pwritten)
3472 {
3473         struct cli_smb2_write_state *state = tevent_req_data(
3474                 req, struct cli_smb2_write_state);
3475         NTSTATUS status;
3476
3477         if (tevent_req_is_nterror(req, &status)) {
3478                 state->cli->raw_status = status;
3479                 tevent_req_received(req);
3480                 return status;
3481         }
3482
3483         if (pwritten != NULL) {
3484                 *pwritten = (size_t)state->written;
3485         }
3486         state->cli->raw_status = NT_STATUS_OK;
3487         tevent_req_received(req);
3488         return NT_STATUS_OK;
3489 }
3490
3491 /***************************************************************
3492  Wrapper that allows SMB2 async write using an fnum.
3493  This is mostly cut-and-paste from Volker's code inside
3494  source3/libsmb/clireadwrite.c, adapted for SMB2.
3495
3496  Done this way so I can reuse all the logic inside cli_push()
3497  for free :-).
3498 ***************************************************************/
3499
3500 struct cli_smb2_writeall_state {
3501         struct tevent_context *ev;
3502         struct cli_state *cli;
3503         struct smb2_hnd *ph;
3504         uint32_t flags;
3505         const uint8_t *buf;
3506         uint64_t offset;
3507         uint32_t size;
3508         uint32_t written;
3509 };
3510
3511 static void cli_smb2_writeall_written(struct tevent_req *req);
3512
3513 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
3514                                         struct tevent_context *ev,
3515                                         struct cli_state *cli,
3516                                         uint16_t fnum,
3517                                         uint16_t mode,
3518                                         const uint8_t *buf,
3519                                         off_t offset,
3520                                         size_t size)
3521 {
3522         NTSTATUS status;
3523         struct tevent_req *req, *subreq = NULL;
3524         struct cli_smb2_writeall_state *state = NULL;
3525         uint32_t to_write;
3526         uint32_t max_size;
3527         bool ok;
3528
3529         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
3530         if (req == NULL) {
3531                 return NULL;
3532         }
3533         state->ev = ev;
3534         state->cli = cli;
3535         /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3536         state->flags = (uint32_t)mode;
3537         state->buf = buf;
3538         state->offset = (uint64_t)offset;
3539         state->size = (uint32_t)size;
3540         state->written = 0;
3541
3542         status = map_fnum_to_smb2_handle(cli,
3543                                         fnum,
3544                                         &state->ph);
3545         if (tevent_req_nterror(req, status)) {
3546                 return tevent_req_post(req, ev);
3547         }
3548
3549         to_write = state->size;
3550         max_size = smb2cli_conn_max_write_size(state->cli->conn);
3551         to_write = MIN(max_size, to_write);
3552         ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3553         if (ok) {
3554                 to_write = MIN(max_size, to_write);
3555         }
3556
3557         subreq = smb2cli_write_send(state,
3558                                 state->ev,
3559                                 state->cli->conn,
3560                                 state->cli->timeout,
3561                                 state->cli->smb2.session,
3562                                 state->cli->smb2.tcon,
3563                                 to_write,
3564                                 state->offset,
3565                                 state->ph->fid_persistent,
3566                                 state->ph->fid_volatile,
3567                                 0, /* remaining_bytes */
3568                                 state->flags, /* flags */
3569                                 state->buf + state->written);
3570
3571         if (tevent_req_nomem(subreq, req)) {
3572                 return tevent_req_post(req, ev);
3573         }
3574         tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3575         return req;
3576 }
3577
3578 static void cli_smb2_writeall_written(struct tevent_req *subreq)
3579 {
3580         struct tevent_req *req = tevent_req_callback_data(
3581                 subreq, struct tevent_req);
3582         struct cli_smb2_writeall_state *state = tevent_req_data(
3583                 req, struct cli_smb2_writeall_state);
3584         NTSTATUS status;
3585         uint32_t written, to_write;
3586         uint32_t max_size;
3587         bool ok;
3588
3589         status = smb2cli_write_recv(subreq, &written);
3590         TALLOC_FREE(subreq);
3591         if (tevent_req_nterror(req, status)) {
3592                 return;
3593         }
3594
3595         state->written += written;
3596
3597         if (state->written > state->size) {
3598                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3599                 return;
3600         }
3601
3602         to_write = state->size - state->written;
3603
3604         if (to_write == 0) {
3605                 tevent_req_done(req);
3606                 return;
3607         }
3608
3609         max_size = smb2cli_conn_max_write_size(state->cli->conn);
3610         to_write = MIN(max_size, to_write);
3611         ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3612         if (ok) {
3613                 to_write = MIN(max_size, to_write);
3614         }
3615
3616         subreq = smb2cli_write_send(state,
3617                                 state->ev,
3618                                 state->cli->conn,
3619                                 state->cli->timeout,
3620                                 state->cli->smb2.session,
3621                                 state->cli->smb2.tcon,
3622                                 to_write,
3623                                 state->offset + state->written,
3624                                 state->ph->fid_persistent,
3625                                 state->ph->fid_volatile,
3626                                 0, /* remaining_bytes */
3627                                 state->flags, /* flags */
3628                                 state->buf + state->written);
3629
3630         if (tevent_req_nomem(subreq, req)) {
3631                 return;
3632         }
3633         tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3634 }
3635
3636 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
3637                                 size_t *pwritten)
3638 {
3639         struct cli_smb2_writeall_state *state = tevent_req_data(
3640                 req, struct cli_smb2_writeall_state);
3641         NTSTATUS status;
3642
3643         if (tevent_req_is_nterror(req, &status)) {
3644                 state->cli->raw_status = status;
3645                 return status;
3646         }
3647         if (pwritten != NULL) {
3648                 *pwritten = (size_t)state->written;
3649         }
3650         state->cli->raw_status = NT_STATUS_OK;
3651         return NT_STATUS_OK;
3652 }
3653
3654 struct cli_smb2_splice_state {
3655         struct tevent_context *ev;
3656         struct cli_state *cli;
3657         struct smb2_hnd *src_ph;
3658         struct smb2_hnd *dst_ph;
3659         int (*splice_cb)(off_t n, void *priv);
3660         void *priv;
3661         off_t written;
3662         off_t size;
3663         off_t src_offset;
3664         off_t dst_offset;
3665         bool resized;
3666         struct req_resume_key_rsp resume_rsp;
3667         struct srv_copychunk_copy cc_copy;
3668 };
3669
3670 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3671                                       struct tevent_req *req);
3672
3673 static void cli_splice_copychunk_done(struct tevent_req *subreq)
3674 {
3675         struct tevent_req *req = tevent_req_callback_data(
3676                 subreq, struct tevent_req);
3677         struct cli_smb2_splice_state *state =
3678                 tevent_req_data(req,
3679                 struct cli_smb2_splice_state);
3680         struct smbXcli_conn *conn = state->cli->conn;
3681         DATA_BLOB out_input_buffer = data_blob_null;
3682         DATA_BLOB out_output_buffer = data_blob_null;
3683         struct srv_copychunk_rsp cc_copy_rsp;
3684         enum ndr_err_code ndr_ret;
3685         NTSTATUS status;
3686
3687         status = smb2cli_ioctl_recv(subreq, state,
3688                                     &out_input_buffer,
3689                                     &out_output_buffer);
3690         TALLOC_FREE(subreq);
3691         if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
3692              state->resized) && tevent_req_nterror(req, status)) {
3693                 return;
3694         }
3695
3696         ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
3697                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
3698         if (ndr_ret != NDR_ERR_SUCCESS) {
3699                 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3700                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3701                 return;
3702         }
3703
3704         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
3705                 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
3706                              cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
3707                 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
3708                      max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
3709                      tevent_req_nterror(req, status)) {
3710                         return;
3711                 }
3712
3713                 state->resized = true;
3714                 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
3715                 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
3716         } else {
3717                 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3718                     (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3719                     (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
3720                         tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3721                         return;
3722                 }
3723                 state->src_offset += cc_copy_rsp.total_bytes_written;
3724                 state->dst_offset += cc_copy_rsp.total_bytes_written;
3725                 state->written += cc_copy_rsp.total_bytes_written;
3726                 if (!state->splice_cb(state->written, state->priv)) {
3727                         tevent_req_nterror(req, NT_STATUS_CANCELLED);
3728                         return;
3729                 }
3730         }
3731
3732         cli_splice_copychunk_send(state, req);
3733 }
3734
3735 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3736                                       struct tevent_req *req)
3737 {
3738         struct tevent_req *subreq;
3739         enum ndr_err_code ndr_ret;
3740         struct smbXcli_conn *conn = state->cli->conn;
3741         struct srv_copychunk_copy *cc_copy = &state->cc_copy;
3742         off_t src_offset = state->src_offset;
3743         off_t dst_offset = state->dst_offset;
3744         uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
3745                                state->size - state->written);
3746         DATA_BLOB in_input_buffer = data_blob_null;
3747         DATA_BLOB in_output_buffer = data_blob_null;
3748
3749         if (state->size - state->written == 0) {
3750                 tevent_req_done(req);
3751                 return;
3752         }
3753
3754         cc_copy->chunk_count = 0;
3755         while (req_len) {
3756                 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
3757                 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
3758                 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
3759                                                                    smb2cli_conn_cc_chunk_len(conn));
3760                 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
3761                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3762                         return;
3763                 }
3764                 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
3765                 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
3766                     (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
3767                         tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3768                         return;
3769                 }
3770                 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3771                 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3772                 cc_copy->chunk_count++;
3773         }
3774
3775         ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
3776                                        (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
3777         if (ndr_ret != NDR_ERR_SUCCESS) {
3778                 DEBUG(0, ("failed to marshall copy chunk req\n"));
3779                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3780                 return;
3781         }
3782
3783         subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
3784                                state->cli->timeout,
3785                                state->cli->smb2.session,
3786                                state->cli->smb2.tcon,
3787                                state->dst_ph->fid_persistent, /* in_fid_persistent */
3788                                state->dst_ph->fid_volatile, /* in_fid_volatile */
3789                                FSCTL_SRV_COPYCHUNK_WRITE,
3790                                0, /* in_max_input_length */
3791                                &in_input_buffer,
3792                                12, /* in_max_output_length */
3793                                &in_output_buffer,
3794                                SMB2_IOCTL_FLAG_IS_FSCTL);
3795         if (tevent_req_nomem(subreq, req)) {
3796                 return;
3797         }
3798         tevent_req_set_callback(subreq,
3799                                 cli_splice_copychunk_done,
3800                                 req);
3801 }
3802
3803 static void cli_splice_key_done(struct tevent_req *subreq)
3804 {
3805         struct tevent_req *req = tevent_req_callback_data(
3806                 subreq, struct tevent_req);
3807         struct cli_smb2_splice_state *state =
3808                 tevent_req_data(req,
3809                 struct cli_smb2_splice_state);
3810         enum ndr_err_code ndr_ret;
3811         NTSTATUS status;
3812
3813         DATA_BLOB out_input_buffer = data_blob_null;
3814         DATA_BLOB out_output_buffer = data_blob_null;
3815
3816         status = smb2cli_ioctl_recv(subreq, state,
3817                                     &out_input_buffer,
3818                                     &out_output_buffer);
3819         TALLOC_FREE(subreq);
3820         if (tevent_req_nterror(req, status)) {
3821                 return;
3822         }
3823
3824         ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
3825                         state, &state->resume_rsp,
3826                         (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
3827         if (ndr_ret != NDR_ERR_SUCCESS) {
3828                 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3829                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3830                 return;
3831         }
3832
3833         memcpy(&state->cc_copy.source_key,
3834                &state->resume_rsp.resume_key,
3835                sizeof state->resume_rsp.resume_key);
3836
3837         cli_splice_copychunk_send(state, req);
3838 }
3839
3840 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
3841                                 struct tevent_context *ev,
3842                                 struct cli_state *cli,
3843                                 uint16_t src_fnum, uint16_t dst_fnum,
3844                                 off_t size, off_t src_offset, off_t dst_offset,
3845                                 int (*splice_cb)(off_t n, void *priv),
3846                                 void *priv)
3847 {
3848         struct tevent_req *req;
3849         struct tevent_req *subreq;
3850         struct cli_smb2_splice_state *state;
3851         NTSTATUS status;
3852         DATA_BLOB in_input_buffer = data_blob_null;
3853         DATA_BLOB in_output_buffer = data_blob_null;
3854
3855         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
3856         if (req == NULL) {
3857                 return NULL;
3858         }
3859         state->cli = cli;
3860         state->ev = ev;
3861         state->splice_cb = splice_cb;
3862         state->priv = priv;
3863         state->size = size;
3864         state->written = 0;
3865         state->src_offset = src_offset;
3866         state->dst_offset = dst_offset;
3867         state->cc_copy.chunks = talloc_array(state,
3868                                              struct srv_copychunk,
3869                                              smb2cli_conn_cc_max_chunks(cli->conn));
3870         if (state->cc_copy.chunks == NULL) {
3871                 return NULL;
3872         }
3873
3874         status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
3875         if (tevent_req_nterror(req, status))
3876                 return tevent_req_post(req, ev);
3877
3878         status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
3879         if (tevent_req_nterror(req, status))
3880                 return tevent_req_post(req, ev);
3881
3882         subreq = smb2cli_ioctl_send(state, ev, cli->conn,
3883                                cli->timeout,
3884                                cli->smb2.session,
3885                                cli->smb2.tcon,
3886                                state->src_ph->fid_persistent, /* in_fid_persistent */
3887                                state->src_ph->fid_volatile, /* in_fid_volatile */
3888                                FSCTL_SRV_REQUEST_RESUME_KEY,
3889                                0, /* in_max_input_length */
3890                                &in_input_buffer,
3891                                32, /* in_max_output_length */
3892                                &in_output_buffer,
3893                                SMB2_IOCTL_FLAG_IS_FSCTL);
3894         if (tevent_req_nomem(subreq, req)) {
3895                 return NULL;
3896         }
3897         tevent_req_set_callback(subreq,
3898                                 cli_splice_key_done,
3899                                 req);
3900
3901         return req;
3902 }
3903
3904 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
3905 {
3906         struct cli_smb2_splice_state *state = tevent_req_data(
3907                 req, struct cli_smb2_splice_state);
3908         NTSTATUS status;
3909
3910         if (tevent_req_is_nterror(req, &status)) {
3911                 state->cli->raw_status = status;
3912                 tevent_req_received(req);
3913                 return status;
3914         }
3915         if (written != NULL) {
3916                 *written = state->written;
3917         }
3918         state->cli->raw_status = NT_STATUS_OK;
3919         tevent_req_received(req);
3920         return NT_STATUS_OK;
3921 }
3922
3923 /***************************************************************
3924  SMB2 enum shadow copy data.
3925 ***************************************************************/
3926
3927 struct cli_smb2_shadow_copy_data_fnum_state {
3928         struct cli_state *cli;
3929         uint16_t fnum;
3930         struct smb2_hnd *ph;
3931         DATA_BLOB out_input_buffer;
3932         DATA_BLOB out_output_buffer;
3933 };
3934
3935 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
3936
3937 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
3938                                         TALLOC_CTX *mem_ctx,
3939                                         struct tevent_context *ev,
3940                                         struct cli_state *cli,
3941                                         uint16_t fnum,
3942                                         bool get_names)
3943 {
3944         struct tevent_req *req, *subreq;
3945         struct cli_smb2_shadow_copy_data_fnum_state *state;
3946         NTSTATUS status;
3947
3948         req = tevent_req_create(mem_ctx, &state,
3949                                 struct cli_smb2_shadow_copy_data_fnum_state);
3950         if (req == NULL) {
3951                 return NULL;
3952         }
3953
3954         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3955                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3956                 return tevent_req_post(req, ev);
3957         }
3958
3959         state->cli = cli;
3960         state->fnum = fnum;
3961
3962         status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
3963         if (tevent_req_nterror(req, status)) {
3964                 return tevent_req_post(req, ev);
3965         }
3966
3967         /*
3968          * TODO. Under SMB2 we should send a zero max_output_length
3969          * ioctl to get the required size, then send another ioctl
3970          * to get the data, but the current SMB1 implementation just
3971          * does one roundtrip with a 64K buffer size. Do the same
3972          * for now. JRA.
3973          */
3974
3975         subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
3976                         state->cli->timeout,
3977                         state->cli->smb2.session,
3978                         state->cli->smb2.tcon,
3979                         state->ph->fid_persistent, /* in_fid_persistent */
3980                         state->ph->fid_volatile, /* in_fid_volatile */
3981                         FSCTL_GET_SHADOW_COPY_DATA,
3982                         0, /* in_max_input_length */
3983                         NULL, /* in_input_buffer */
3984                         get_names ?
3985                                 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
3986                         NULL, /* in_output_buffer */
3987                         SMB2_IOCTL_FLAG_IS_FSCTL);
3988
3989         if (tevent_req_nomem(subreq, req)) {
3990                 return tevent_req_post(req, ev);
3991         }
3992         tevent_req_set_callback(subreq,
3993                                 cli_smb2_shadow_copy_data_fnum_done,
3994                                 req);
3995
3996         return req;
3997 }
3998
3999 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4000 {
4001         struct tevent_req *req = tevent_req_callback_data(
4002                 subreq, struct tevent_req);
4003         struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4004                 req, struct cli_smb2_shadow_copy_data_fnum_state);
4005         NTSTATUS status;
4006
4007         status = smb2cli_ioctl_recv(subreq, state,
4008                                 &state->out_input_buffer,
4009                                 &state->out_output_buffer);
4010         TALLOC_FREE(subreq);
4011         if (tevent_req_nterror(req, status)) {
4012                 return;
4013         }
4014         tevent_req_done(req);
4015 }
4016
4017 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4018                                 TALLOC_CTX *mem_ctx,
4019                                 bool get_names,
4020                                 char ***pnames,
4021                                 int *pnum_names)
4022 {
4023         struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4024                 req, struct cli_smb2_shadow_copy_data_fnum_state);
4025         char **names = NULL;
4026         uint32_t num_names = 0;
4027         uint32_t num_names_returned = 0;
4028         uint32_t dlength = 0;
4029         uint32_t i;
4030         uint8_t *endp = NULL;
4031         NTSTATUS status;
4032
4033         if (tevent_req_is_nterror(req, &status)) {
4034                 return status;
4035         }
4036
4037         if (state->out_output_buffer.length < 16) {
4038                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4039         }
4040
4041         num_names = IVAL(state->out_output_buffer.data, 0);
4042         num_names_returned = IVAL(state->out_output_buffer.data, 4);
4043         dlength = IVAL(state->out_output_buffer.data, 8);
4044
4045         if (num_names > 0x7FFFFFFF) {
4046                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4047         }
4048
4049         if (get_names == false) {
4050                 *pnum_names = (int)num_names;
4051                 return NT_STATUS_OK;
4052         }
4053         if (num_names != num_names_returned) {
4054                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4055         }
4056         if (dlength + 12 < 12) {
4057                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4058         }
4059         /*
4060          * NB. The below is an allowable return if there are
4061          * more snapshots than the buffer size we told the
4062          * server we can receive. We currently don't support
4063          * this.
4064          */
4065         if (dlength + 12 > state->out_output_buffer.length) {
4066                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4067         }
4068         if (state->out_output_buffer.length +
4069                         (2 * sizeof(SHADOW_COPY_LABEL)) <
4070                                 state->out_output_buffer.length) {
4071                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4072         }
4073
4074         names = talloc_array(mem_ctx, char *, num_names_returned);
4075         if (names == NULL) {
4076                 return NT_STATUS_NO_MEMORY;
4077         }
4078
4079         endp = state->out_output_buffer.data +
4080                         state->out_output_buffer.length;
4081
4082         for (i=0; i<num_names_returned; i++) {
4083                 bool ret;
4084                 uint8_t *src;
4085                 size_t converted_size;
4086
4087                 src = state->out_output_buffer.data + 12 +
4088                         (i * 2 * sizeof(SHADOW_COPY_LABEL));
4089
4090                 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4091                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
4092                 }
4093                 ret = convert_string_talloc(
4094                         names, CH_UTF16LE, CH_UNIX,
4095                         src, 2 * sizeof(SHADOW_COPY_LABEL),
4096                         &names[i], &converted_size);
4097                 if (!ret) {
4098                         TALLOC_FREE(names);
4099                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
4100                 }
4101         }
4102         *pnum_names = num_names;
4103         *pnames = names;
4104         return NT_STATUS_OK;
4105 }
4106
4107 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4108                                 struct cli_state *cli,
4109                                 uint16_t fnum,
4110                                 bool get_names,
4111                                 char ***pnames,
4112                                 int *pnum_names)
4113 {
4114         TALLOC_CTX *frame = talloc_stackframe();
4115         struct tevent_context *ev;
4116         struct tevent_req *req;
4117         NTSTATUS status = NT_STATUS_NO_MEMORY;
4118
4119         if (smbXcli_conn_has_async_calls(cli->conn)) {
4120                 /*
4121                  * Can't use sync call while an async call is in flight
4122                  */
4123                 status = NT_STATUS_INVALID_PARAMETER;
4124                 goto fail;
4125         }
4126         ev = samba_tevent_context_init(frame);
4127         if (ev == NULL) {
4128                 goto fail;
4129         }
4130         req = cli_smb2_shadow_copy_data_fnum_send(frame,
4131                                         ev,
4132                                         cli,
4133                                         fnum,
4134                                         get_names);
4135         if (req == NULL) {
4136                 goto fail;
4137         }
4138         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4139                 goto fail;
4140         }
4141         status = cli_smb2_shadow_copy_data_fnum_recv(req,
4142                                                 mem_ctx,
4143                                                 get_names,
4144                                                 pnames,
4145                                                 pnum_names);
4146  fail:
4147         cli->raw_status = status;
4148
4149         TALLOC_FREE(frame);
4150         return status;
4151 }
4152
4153 /***************************************************************
4154  Wrapper that allows SMB2 to truncate a file.
4155  Synchronous only.
4156 ***************************************************************/
4157
4158 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4159                         uint16_t fnum,
4160                         uint64_t newsize)
4161 {
4162         NTSTATUS status;
4163         DATA_BLOB inbuf = data_blob_null;
4164         struct smb2_hnd *ph = NULL;
4165         TALLOC_CTX *frame = talloc_stackframe();
4166
4167         if (smbXcli_conn_has_async_calls(cli->conn)) {
4168                 /*
4169                  * Can't use sync call while an async call is in flight
4170                  */
4171                 status = NT_STATUS_INVALID_PARAMETER;
4172                 goto fail;
4173         }
4174
4175         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4176                 status = NT_STATUS_INVALID_PARAMETER;
4177                 goto fail;
4178         }
4179
4180         status = map_fnum_to_smb2_handle(cli,
4181                                         fnum,
4182                                         &ph);
4183         if (!NT_STATUS_IS_OK(status)) {
4184                 goto fail;
4185         }
4186
4187         inbuf = data_blob_talloc_zero(frame, 8);
4188         if (inbuf.data == NULL) {
4189                 status = NT_STATUS_NO_MEMORY;
4190                 goto fail;
4191         }
4192
4193         SBVAL(inbuf.data, 0, newsize);
4194
4195         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4196            level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4197
4198         status = smb2cli_set_info(cli->conn,
4199                                 cli->timeout,
4200                                 cli->smb2.session,
4201                                 cli->smb2.tcon,
4202                                 1, /* in_info_type */
4203                                         /* in_file_info_class */
4204                                 SMB_FILE_END_OF_FILE_INFORMATION - 1000,
4205                                 &inbuf, /* in_input_buffer */
4206                                 0, /* in_additional_info */
4207                                 ph->fid_persistent,
4208                                 ph->fid_volatile);
4209
4210   fail:
4211
4212         cli->raw_status = status;
4213
4214         TALLOC_FREE(frame);
4215         return status;
4216 }
4217
4218 struct cli_smb2_notify_state {
4219         struct tevent_req *subreq;
4220         struct notify_change *changes;
4221         size_t num_changes;
4222 };
4223
4224 static void cli_smb2_notify_done(struct tevent_req *subreq);
4225 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4226
4227 struct tevent_req *cli_smb2_notify_send(
4228         TALLOC_CTX *mem_ctx,
4229         struct tevent_context *ev,
4230         struct cli_state *cli,
4231         uint16_t fnum,
4232         uint32_t buffer_size,
4233         uint32_t completion_filter,
4234         bool recursive)
4235 {
4236         struct tevent_req *req = NULL;
4237         struct cli_smb2_notify_state *state = NULL;
4238         struct smb2_hnd *ph = NULL;
4239         NTSTATUS status;
4240
4241         req = tevent_req_create(mem_ctx, &state,
4242                                 struct cli_smb2_notify_state);
4243         if (req == NULL) {
4244                 return NULL;
4245         }
4246
4247         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4248                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4249                 return tevent_req_post(req, ev);
4250         }
4251
4252         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4253         if (tevent_req_nterror(req, status)) {
4254                 return tevent_req_post(req, ev);
4255         }
4256
4257         state->subreq = smb2cli_notify_send(
4258                 state,
4259                 ev,
4260                 cli->conn,
4261                 cli->timeout,
4262                 cli->smb2.session,
4263                 cli->smb2.tcon,
4264                 buffer_size,
4265                 ph->fid_persistent,
4266                 ph->fid_volatile,
4267                 completion_filter,
4268                 recursive);
4269         if (tevent_req_nomem(state->subreq, req)) {
4270                 return tevent_req_post(req, ev);
4271         }
4272         tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4273         tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4274         return req;
4275 }
4276
4277 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4278 {
4279         struct cli_smb2_notify_state *state = tevent_req_data(
4280                 req, struct cli_smb2_notify_state);
4281         bool ok;
4282
4283         ok = tevent_req_cancel(state->subreq);
4284         return ok;
4285 }
4286
4287 static void cli_smb2_notify_done(struct tevent_req *subreq)
4288 {
4289         struct tevent_req *req = tevent_req_callback_data(
4290                 subreq, struct tevent_req);
4291         struct cli_smb2_notify_state *state = tevent_req_data(
4292                 req, struct cli_smb2_notify_state);
4293         uint8_t *base;
4294         uint32_t len;
4295         uint32_t ofs;
4296         NTSTATUS status;
4297
4298         status = smb2cli_notify_recv(subreq, state, &base, &len);
4299         TALLOC_FREE(subreq);
4300
4301         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4302                 tevent_req_done(req);
4303                 return;
4304         }
4305         if (tevent_req_nterror(req, status)) {
4306                 return;
4307         }
4308
4309         ofs = 0;
4310
4311         while (len - ofs >= 12) {
4312                 struct notify_change *tmp;
4313                 struct notify_change *c;
4314                 uint32_t next_ofs = IVAL(base, ofs);
4315                 uint32_t file_name_length = IVAL(base, ofs+8);
4316                 size_t namelen;
4317                 bool ok;
4318
4319                 tmp = talloc_realloc(
4320                         state,
4321                         state->changes,
4322                         struct notify_change,
4323                         state->num_changes + 1);
4324                 if (tevent_req_nomem(tmp, req)) {
4325                         return;
4326                 }
4327                 state->changes = tmp;
4328                 c = &state->changes[state->num_changes];
4329                 state->num_changes += 1;
4330
4331                 if (smb_buffer_oob(len, ofs, next_ofs) ||
4332                     smb_buffer_oob(len, ofs+12, file_name_length)) {
4333                         tevent_req_nterror(
4334                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4335                         return;
4336                 }
4337
4338                 c->action = IVAL(base, ofs+4);
4339
4340                 ok = convert_string_talloc(
4341                         state->changes,
4342                         CH_UTF16LE,
4343                         CH_UNIX,
4344                         base + ofs + 12,
4345                         file_name_length,
4346                         &c->name,
4347                         &namelen);
4348                 if (!ok) {
4349                         tevent_req_nterror(
4350                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4351                         return;
4352                 }
4353
4354                 if (next_ofs == 0) {
4355                         break;
4356                 }
4357                 ofs += next_ofs;
4358         }
4359
4360         tevent_req_done(req);
4361 }
4362
4363 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
4364                               TALLOC_CTX *mem_ctx,
4365                               struct notify_change **pchanges,
4366                               uint32_t *pnum_changes)
4367 {
4368         struct cli_smb2_notify_state *state = tevent_req_data(
4369                 req, struct cli_smb2_notify_state);
4370         NTSTATUS status;
4371
4372         if (tevent_req_is_nterror(req, &status)) {
4373                 return status;
4374         }
4375         *pchanges = talloc_move(mem_ctx, &state->changes);
4376         *pnum_changes = state->num_changes;
4377         return NT_STATUS_OK;
4378 }
4379
4380 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
4381                          uint32_t buffer_size, uint32_t completion_filter,
4382                          bool recursive, TALLOC_CTX *mem_ctx,
4383                          struct notify_change **pchanges,
4384                          uint32_t *pnum_changes)
4385 {
4386         TALLOC_CTX *frame = talloc_stackframe();
4387         struct tevent_context *ev;
4388         struct tevent_req *req;
4389         NTSTATUS status = NT_STATUS_NO_MEMORY;
4390
4391         if (smbXcli_conn_has_async_calls(cli->conn)) {
4392                 /*
4393                  * Can't use sync call while an async call is in flight
4394                  */
4395                 status = NT_STATUS_INVALID_PARAMETER;
4396                 goto fail;
4397         }
4398         ev = samba_tevent_context_init(frame);
4399         if (ev == NULL) {
4400                 goto fail;
4401         }
4402         req = cli_smb2_notify_send(
4403                 frame,
4404                 ev,
4405                 cli,
4406                 fnum,
4407                 buffer_size,
4408                 completion_filter,
4409                 recursive);
4410         if (req == NULL) {
4411                 goto fail;
4412         }
4413         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4414                 goto fail;
4415         }
4416         status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
4417 fail:
4418         TALLOC_FREE(frame);
4419         return status;
4420 }
4421
4422 struct cli_smb2_set_reparse_point_fnum_state {
4423         struct cli_state *cli;
4424         uint16_t fnum;
4425         struct smb2_hnd *ph;
4426         DATA_BLOB input_buffer;
4427 };
4428
4429 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
4430
4431 struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
4432                                 TALLOC_CTX *mem_ctx,
4433                                 struct tevent_context *ev,
4434                                 struct cli_state *cli,
4435                                 uint16_t fnum,
4436                                 DATA_BLOB in_buf)
4437 {
4438         struct tevent_req *req, *subreq;
4439         struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
4440         NTSTATUS status;
4441
4442         req = tevent_req_create(mem_ctx, &state,
4443                                 struct cli_smb2_set_reparse_point_fnum_state);
4444         if (req == NULL) {
4445                 return NULL;
4446         }
4447
4448         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4449                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4450                 return tevent_req_post(req, ev);
4451         }
4452
4453         state->cli = cli;
4454         state->fnum = fnum;
4455
4456         status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4457         if (tevent_req_nterror(req, status)) {
4458                 return tevent_req_post(req, ev);
4459         }
4460
4461         state->input_buffer = data_blob_talloc(state,
4462                                                 in_buf.data,
4463                                                 in_buf.length);
4464         if (state->input_buffer.data == NULL) {
4465                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4466                 return tevent_req_post(req, ev);
4467         }
4468
4469         subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4470                         state->cli->timeout,
4471                         state->cli->smb2.session,
4472                         state->cli->smb2.tcon,
4473                         state->ph->fid_persistent, /* in_fid_persistent */
4474                         state->ph->fid_volatile, /* in_fid_volatile */
4475                         FSCTL_SET_REPARSE_POINT,
4476                         0, /* in_max_input_length */
4477                         &state->input_buffer ,
4478                         0,
4479                         NULL,
4480                         SMB2_IOCTL_FLAG_IS_FSCTL);
4481
4482         if (tevent_req_nomem(subreq, req)) {
4483                 return tevent_req_post(req, ev);
4484         }
4485         tevent_req_set_callback(subreq,
4486                                 cli_smb2_set_reparse_point_fnum_done,
4487                                 req);
4488
4489         return req;
4490 }
4491
4492 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
4493 {
4494         struct tevent_req *req = tevent_req_callback_data(
4495                 subreq, struct tevent_req);
4496         struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
4497                 req, struct cli_smb2_set_reparse_point_fnum_state);
4498         NTSTATUS status;
4499
4500         status = smb2cli_ioctl_recv(subreq, state,
4501                                 NULL,
4502                                 NULL);
4503         TALLOC_FREE(subreq);
4504         if (tevent_req_nterror(req, status)) {
4505                 return;
4506         }
4507         tevent_req_done(req);
4508 }
4509
4510 NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
4511 {
4512         return tevent_req_simple_recv_ntstatus(req);
4513 }
4514
4515 struct cli_smb2_get_reparse_point_fnum_state {
4516         struct cli_state *cli;
4517         uint16_t fnum;
4518         struct smb2_hnd *ph;
4519         DATA_BLOB output_buffer;
4520 };
4521
4522 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
4523
4524 struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
4525                                 TALLOC_CTX *mem_ctx,
4526                                 struct tevent_context *ev,
4527                                 struct cli_state *cli,
4528                                 uint16_t fnum)
4529 {
4530         struct tevent_req *req, *subreq;
4531         struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
4532         NTSTATUS status;
4533
4534         req = tevent_req_create(mem_ctx, &state,
4535                                 struct cli_smb2_get_reparse_point_fnum_state);
4536         if (req == NULL) {
4537                 return NULL;
4538         }
4539
4540         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4541                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4542                 return tevent_req_post(req, ev);
4543         }
4544
4545         state->cli = cli;
4546         state->fnum = fnum;
4547
4548         status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4549         if (tevent_req_nterror(req, status)) {
4550                 return tevent_req_post(req, ev);
4551         }
4552
4553         subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4554                         state->cli->timeout,
4555                         state->cli->smb2.session,
4556                         state->cli->smb2.tcon,
4557                         state->ph->fid_persistent, /* in_fid_persistent */
4558                         state->ph->fid_volatile, /* in_fid_volatile */
4559                         FSCTL_GET_REPARSE_POINT,
4560                         0, /* in_max_input_length */
4561                         NULL,
4562                         64*1024,
4563                         NULL,
4564                         SMB2_IOCTL_FLAG_IS_FSCTL);
4565
4566         if (tevent_req_nomem(subreq, req)) {
4567                 return tevent_req_post(req, ev);
4568         }
4569         tevent_req_set_callback(subreq,
4570                                 cli_smb2_get_reparse_point_fnum_done,
4571                                 req);
4572
4573         return req;
4574 }
4575
4576 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
4577 {
4578         struct tevent_req *req = tevent_req_callback_data(
4579                 subreq, struct tevent_req);
4580         struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
4581                 req, struct cli_smb2_get_reparse_point_fnum_state);
4582         NTSTATUS status;
4583
4584         status = smb2cli_ioctl_recv(subreq, state,
4585                                 NULL,
4586                                 &state->output_buffer);
4587         TALLOC_FREE(subreq);
4588         if (tevent_req_nterror(req, status)) {
4589                 state->cli->raw_status = status;
4590                 return;
4591         }
4592         tevent_req_done(req);
4593 }
4594
4595 NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
4596                                 TALLOC_CTX *mem_ctx,
4597                                 DATA_BLOB *output)
4598 {
4599         struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
4600                 req, struct cli_smb2_get_reparse_point_fnum_state);
4601
4602         if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
4603                 tevent_req_received(req);
4604                 return state->cli->raw_status;
4605         }
4606         *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
4607         if (output->data == NULL) {
4608                 tevent_req_received(req);
4609                 return NT_STATUS_NO_MEMORY;
4610         }
4611         tevent_req_received(req);
4612         return NT_STATUS_OK;
4613 }