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