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