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