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