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