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