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