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