ctdb-scripts: Ignore shellcheck SC2181 warning (use of $?)
[metze/samba/wip.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 = tevent_req_simple_recv_ntstatus(req);
453         state->cli->raw_status = status;
454         return status;
455 }
456
457 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
458 {
459         TALLOC_CTX *frame = talloc_stackframe();
460         struct tevent_context *ev;
461         struct tevent_req *req;
462         NTSTATUS status = NT_STATUS_NO_MEMORY;
463
464         if (smbXcli_conn_has_async_calls(cli->conn)) {
465                 /*
466                  * Can't use sync call while an async call is in flight
467                  */
468                 status = NT_STATUS_INVALID_PARAMETER;
469                 goto fail;
470         }
471         ev = samba_tevent_context_init(frame);
472         if (ev == NULL) {
473                 goto fail;
474         }
475         req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
476         if (req == NULL) {
477                 goto fail;
478         }
479         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
480                 goto fail;
481         }
482         status = cli_smb2_close_fnum_recv(req);
483  fail:
484         TALLOC_FREE(frame);
485         return status;
486 }
487
488 struct cli_smb2_delete_on_close_state {
489         struct cli_state *cli;
490         uint16_t fnum;
491         struct smb2_hnd *ph;
492         uint8_t data[1];
493         DATA_BLOB inbuf;
494 };
495
496 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
497
498 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
499                                         struct tevent_context *ev,
500                                         struct cli_state *cli,
501                                         uint16_t fnum,
502                                         bool flag)
503 {
504         struct tevent_req *req = NULL;
505         struct cli_smb2_delete_on_close_state *state = NULL;
506         struct tevent_req *subreq = NULL;
507         uint8_t in_info_type;
508         uint8_t in_file_info_class;
509         NTSTATUS status;
510
511         req = tevent_req_create(mem_ctx, &state,
512                                 struct cli_smb2_delete_on_close_state);
513         if (req == NULL) {
514                 return NULL;
515         }
516         state->cli = cli;
517         state->fnum = fnum;
518
519         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
520                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
521                 return tevent_req_post(req, ev);
522         }
523
524         status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
525         if (tevent_req_nterror(req, status)) {
526                 return tevent_req_post(req, ev);
527         }
528
529         /*
530          * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
531          * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
532          */
533         in_info_type = 1;
534         in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
535         /* Setup data array. */
536         SCVAL(&state->data[0], 0, flag ? 1 : 0);
537         state->inbuf.data = &state->data[0];
538         state->inbuf.length = 1;
539
540         subreq = smb2cli_set_info_send(state, ev,
541                                        cli->conn,
542                                        cli->timeout,
543                                        cli->smb2.session,
544                                        cli->smb2.tcon,
545                                        in_info_type,
546                                        in_file_info_class,
547                                        &state->inbuf, /* in_input_buffer */
548                                        0, /* in_additional_info */
549                                        state->ph->fid_persistent,
550                                        state->ph->fid_volatile);
551         if (tevent_req_nomem(subreq, req)) {
552                 return tevent_req_post(req, ev);
553         }
554         tevent_req_set_callback(subreq,
555                                 cli_smb2_delete_on_close_done,
556                                 req);
557         return req;
558 }
559
560 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
561 {
562         NTSTATUS status = smb2cli_set_info_recv(subreq);
563         tevent_req_simple_finish_ntstatus(subreq, status);
564 }
565
566 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
567 {
568         struct cli_smb2_delete_on_close_state *state =
569                 tevent_req_data(req,
570                 struct cli_smb2_delete_on_close_state);
571         NTSTATUS status;
572
573         if (tevent_req_is_nterror(req, &status)) {
574                 state->cli->raw_status = status;
575                 tevent_req_received(req);
576                 return status;
577         }
578
579         state->cli->raw_status = NT_STATUS_OK;
580         tevent_req_received(req);
581         return NT_STATUS_OK;
582 }
583
584 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
585 {
586         TALLOC_CTX *frame = talloc_stackframe();
587         struct tevent_context *ev;
588         struct tevent_req *req;
589         NTSTATUS status = NT_STATUS_NO_MEMORY;
590
591         if (smbXcli_conn_has_async_calls(cli->conn)) {
592                 /*
593                  * Can't use sync call while an async call is in flight
594                  */
595                 status = NT_STATUS_INVALID_PARAMETER;
596                 goto fail;
597         }
598         ev = samba_tevent_context_init(frame);
599         if (ev == NULL) {
600                 goto fail;
601         }
602         req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
603         if (req == NULL) {
604                 goto fail;
605         }
606         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
607                 goto fail;
608         }
609         status = cli_smb2_delete_on_close_recv(req);
610  fail:
611         TALLOC_FREE(frame);
612         return status;
613 }
614
615 /***************************************************************
616  Small wrapper that allows SMB2 to create a directory
617  Synchronous only.
618 ***************************************************************/
619
620 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
621 {
622         NTSTATUS status;
623         uint16_t fnum;
624
625         if (smbXcli_conn_has_async_calls(cli->conn)) {
626                 /*
627                  * Can't use sync call while an async call is in flight
628                  */
629                 return NT_STATUS_INVALID_PARAMETER;
630         }
631
632         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
633                 return NT_STATUS_INVALID_PARAMETER;
634         }
635
636         status = cli_smb2_create_fnum(cli,
637                         dname,
638                         0,                      /* create_flags */
639                         FILE_READ_ATTRIBUTES,   /* desired_access */
640                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
641                         FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
642                         FILE_CREATE,            /* create_disposition */
643                         FILE_DIRECTORY_FILE,    /* create_options */
644                         &fnum,
645                         NULL);
646
647         if (!NT_STATUS_IS_OK(status)) {
648                 return status;
649         }
650         return cli_smb2_close_fnum(cli, fnum);
651 }
652
653 /***************************************************************
654  Small wrapper that allows SMB2 to delete a directory
655  Synchronous only.
656 ***************************************************************/
657
658 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
659 {
660         NTSTATUS status;
661         uint16_t fnum;
662
663         if (smbXcli_conn_has_async_calls(cli->conn)) {
664                 /*
665                  * Can't use sync call while an async call is in flight
666                  */
667                 return NT_STATUS_INVALID_PARAMETER;
668         }
669
670         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
671                 return NT_STATUS_INVALID_PARAMETER;
672         }
673
674         status = cli_smb2_create_fnum(cli,
675                         dname,
676                         0,                      /* create_flags */
677                         DELETE_ACCESS,          /* desired_access */
678                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
679                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
680                         FILE_OPEN,              /* create_disposition */
681                         FILE_DIRECTORY_FILE|FILE_DELETE_ON_CLOSE,       /* create_options */
682                         &fnum,
683                         NULL);
684
685         if (!NT_STATUS_IS_OK(status)) {
686                 return status;
687         }
688         return cli_smb2_close_fnum(cli, fnum);
689 }
690
691 /***************************************************************
692  Small wrapper that allows SMB2 to unlink a pathname.
693  Synchronous only.
694 ***************************************************************/
695
696 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
697 {
698         NTSTATUS status;
699         uint16_t fnum;
700
701         if (smbXcli_conn_has_async_calls(cli->conn)) {
702                 /*
703                  * Can't use sync call while an async call is in flight
704                  */
705                 return NT_STATUS_INVALID_PARAMETER;
706         }
707
708         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
709                 return NT_STATUS_INVALID_PARAMETER;
710         }
711
712         status = cli_smb2_create_fnum(cli,
713                         fname,
714                         0,                      /* create_flags */
715                         DELETE_ACCESS,          /* desired_access */
716                         FILE_ATTRIBUTE_NORMAL, /* file attributes */
717                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
718                         FILE_OPEN,              /* create_disposition */
719                         FILE_DELETE_ON_CLOSE,   /* create_options */
720                         &fnum,
721                         NULL);
722
723         if (!NT_STATUS_IS_OK(status)) {
724                 return status;
725         }
726         return cli_smb2_close_fnum(cli, fnum);
727 }
728
729 /***************************************************************
730  Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
731 ***************************************************************/
732
733 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
734                                 uint32_t dir_data_length,
735                                 struct file_info *finfo,
736                                 uint32_t *next_offset)
737 {
738         size_t namelen = 0;
739         size_t slen = 0;
740         size_t ret = 0;
741
742         if (dir_data_length < 4) {
743                 return NT_STATUS_INFO_LENGTH_MISMATCH;
744         }
745
746         *next_offset = IVAL(dir_data, 0);
747
748         if (*next_offset > dir_data_length) {
749                 return NT_STATUS_INFO_LENGTH_MISMATCH;
750         }
751
752         if (*next_offset != 0) {
753                 /* Ensure we only read what in this record. */
754                 dir_data_length = *next_offset;
755         }
756
757         if (dir_data_length < 105) {
758                 return NT_STATUS_INFO_LENGTH_MISMATCH;
759         }
760
761         finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
762         finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
763         finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
764         finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
765         finfo->mode = CVAL(dir_data + 56, 0);
766         namelen = IVAL(dir_data + 60,0);
767         if (namelen > (dir_data_length - 104)) {
768                 return NT_STATUS_INFO_LENGTH_MISMATCH;
769         }
770         slen = CVAL(dir_data + 68, 0);
771         if (slen > 24) {
772                 return NT_STATUS_INFO_LENGTH_MISMATCH;
773         }
774         ret = pull_string_talloc(finfo,
775                                 dir_data,
776                                 FLAGS2_UNICODE_STRINGS,
777                                 &finfo->short_name,
778                                 dir_data + 70,
779                                 slen,
780                                 STR_UNICODE);
781         if (ret == (size_t)-1) {
782                 /* Bad conversion. */
783                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
784         }
785
786         ret = pull_string_talloc(finfo,
787                                 dir_data,
788                                 FLAGS2_UNICODE_STRINGS,
789                                 &finfo->name,
790                                 dir_data + 104,
791                                 namelen,
792                                 STR_UNICODE);
793         if (ret == (size_t)-1) {
794                 /* Bad conversion. */
795                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
796         }
797         return NT_STATUS_OK;
798 }
799
800 /*******************************************************************
801  Given a filename - get its directory name
802 ********************************************************************/
803
804 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
805                                 const char *dir,
806                                 char **parent,
807                                 const char **name)
808 {
809         char *p;
810         ptrdiff_t len;
811
812         p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
813
814         if (p == NULL) {
815                 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
816                         return false;
817                 }
818                 if (name) {
819                         *name = dir;
820                 }
821                 return true;
822         }
823
824         len = p-dir;
825
826         if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
827                 return false;
828         }
829         (*parent)[len] = '\0';
830
831         if (name) {
832                 *name = p+1;
833         }
834         return true;
835 }
836
837 /***************************************************************
838  Wrapper that allows SMB2 to list a directory.
839  Synchronous only.
840 ***************************************************************/
841
842 NTSTATUS cli_smb2_list(struct cli_state *cli,
843                         const char *pathname,
844                         uint16_t attribute,
845                         NTSTATUS (*fn)(const char *,
846                                 struct file_info *,
847                                 const char *,
848                                 void *),
849                         void *state)
850 {
851         NTSTATUS status;
852         uint16_t fnum = 0xffff;
853         char *parent_dir = NULL;
854         const char *mask = NULL;
855         struct smb2_hnd *ph = NULL;
856         bool processed_file = false;
857         TALLOC_CTX *frame = talloc_stackframe();
858         TALLOC_CTX *subframe = NULL;
859         bool mask_has_wild;
860
861         if (smbXcli_conn_has_async_calls(cli->conn)) {
862                 /*
863                  * Can't use sync call while an async call is in flight
864                  */
865                 status = NT_STATUS_INVALID_PARAMETER;
866                 goto fail;
867         }
868
869         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
870                 status = NT_STATUS_INVALID_PARAMETER;
871                 goto fail;
872         }
873
874         /* Get the directory name. */
875         if (!windows_parent_dirname(frame,
876                                 pathname,
877                                 &parent_dir,
878                                 &mask)) {
879                 status = NT_STATUS_NO_MEMORY;
880                 goto fail;
881         }
882
883         mask_has_wild = ms_has_wild(mask);
884
885         status = cli_smb2_create_fnum(cli,
886                         parent_dir,
887                         0,                      /* create_flags */
888                         SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
889                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
890                         FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
891                         FILE_OPEN,              /* create_disposition */
892                         FILE_DIRECTORY_FILE,    /* create_options */
893                         &fnum,
894                         NULL);
895
896         if (!NT_STATUS_IS_OK(status)) {
897                 goto fail;
898         }
899
900         status = map_fnum_to_smb2_handle(cli,
901                                         fnum,
902                                         &ph);
903         if (!NT_STATUS_IS_OK(status)) {
904                 goto fail;
905         }
906
907         do {
908                 uint8_t *dir_data = NULL;
909                 uint32_t dir_data_length = 0;
910                 uint32_t next_offset = 0;
911                 subframe = talloc_stackframe();
912
913                 status = smb2cli_query_directory(cli->conn,
914                                         cli->timeout,
915                                         cli->smb2.session,
916                                         cli->smb2.tcon,
917                                         SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
918                                         0,      /* flags */
919                                         0,      /* file_index */
920                                         ph->fid_persistent,
921                                         ph->fid_volatile,
922                                         mask,
923                                         0xffff,
924                                         subframe,
925                                         &dir_data,
926                                         &dir_data_length);
927
928                 if (!NT_STATUS_IS_OK(status)) {
929                         if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
930                                 break;
931                         }
932                         goto fail;
933                 }
934
935                 do {
936                         struct file_info *finfo = talloc_zero(subframe,
937                                                         struct file_info);
938
939                         if (finfo == NULL) {
940                                 status = NT_STATUS_NO_MEMORY;
941                                 goto fail;
942                         }
943
944                         status = parse_finfo_id_both_directory_info(dir_data,
945                                                 dir_data_length,
946                                                 finfo,
947                                                 &next_offset);
948
949                         if (!NT_STATUS_IS_OK(status)) {
950                                 goto fail;
951                         }
952
953                         if (dir_check_ftype((uint32_t)finfo->mode,
954                                         (uint32_t)attribute)) {
955                                 /*
956                                  * Only process if attributes match.
957                                  * On SMB1 server does this, so on
958                                  * SMB2 we need to emulate in the
959                                  * client.
960                                  *
961                                  * https://bugzilla.samba.org/show_bug.cgi?id=10260
962                                  */
963                                 processed_file = true;
964
965                                 status = fn(cli->dfs_mountpoint,
966                                         finfo,
967                                         pathname,
968                                         state);
969
970                                 if (!NT_STATUS_IS_OK(status)) {
971                                         break;
972                                 }
973                         }
974
975                         TALLOC_FREE(finfo);
976
977                         /* Move to next entry. */
978                         if (next_offset) {
979                                 dir_data += next_offset;
980                                 dir_data_length -= next_offset;
981                         }
982                 } while (next_offset != 0);
983
984                 TALLOC_FREE(subframe);
985
986                 if (!mask_has_wild) {
987                         /*
988                          * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
989                          * when handed a non-wildcard path. Do it
990                          * for the server (with a non-wildcard path
991                          * there should only ever be one file returned.
992                          */
993                         status = STATUS_NO_MORE_FILES;
994                         break;
995                 }
996
997         } while (NT_STATUS_IS_OK(status));
998
999         if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1000                 status = NT_STATUS_OK;
1001         }
1002
1003         if (NT_STATUS_IS_OK(status) && !processed_file) {
1004                 /*
1005                  * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1006                  * if no files match. Emulate this in the client.
1007                  */
1008                 status = NT_STATUS_NO_SUCH_FILE;
1009         }
1010
1011   fail:
1012
1013         if (fnum != 0xffff) {
1014                 cli_smb2_close_fnum(cli, fnum);
1015         }
1016
1017         cli->raw_status = status;
1018
1019         TALLOC_FREE(subframe);
1020         TALLOC_FREE(frame);
1021         return status;
1022 }
1023
1024 /***************************************************************
1025  Wrapper that allows SMB2 to query a path info (basic level).
1026  Synchronous only.
1027 ***************************************************************/
1028
1029 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1030                                 const char *name,
1031                                 SMB_STRUCT_STAT *sbuf,
1032                                 uint32_t *attributes)
1033 {
1034         NTSTATUS status;
1035         struct smb_create_returns cr;
1036         uint16_t fnum = 0xffff;
1037         size_t namelen = strlen(name);
1038
1039         if (smbXcli_conn_has_async_calls(cli->conn)) {
1040                 /*
1041                  * Can't use sync call while an async call is in flight
1042                  */
1043                 return NT_STATUS_INVALID_PARAMETER;
1044         }
1045
1046         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1047                 return NT_STATUS_INVALID_PARAMETER;
1048         }
1049
1050         /* SMB2 is pickier about pathnames. Ensure it doesn't
1051            end in a '\' */
1052         if (namelen > 0 && name[namelen-1] == '\\') {
1053                 char *modname = talloc_strdup(talloc_tos(), name);
1054                 modname[namelen-1] = '\0';
1055                 name = modname;
1056         }
1057
1058         /* This is commonly used as a 'cd'. Try qpathinfo on
1059            a directory handle first. */
1060
1061         status = cli_smb2_create_fnum(cli,
1062                         name,
1063                         0,                      /* create_flags */
1064                         FILE_READ_ATTRIBUTES,   /* desired_access */
1065                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1066                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1067                         FILE_OPEN,              /* create_disposition */
1068                         FILE_DIRECTORY_FILE,    /* create_options */
1069                         &fnum,
1070                         &cr);
1071
1072         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1073                 /* Maybe a file ? */
1074                 status = cli_smb2_create_fnum(cli,
1075                         name,
1076                         0,                      /* create_flags */
1077                         FILE_READ_ATTRIBUTES,           /* desired_access */
1078                         0, /* file attributes */
1079                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1080                         FILE_OPEN,              /* create_disposition */
1081                         0,      /* create_options */
1082                         &fnum,
1083                         &cr);
1084         }
1085
1086         if (!NT_STATUS_IS_OK(status)) {
1087                 return status;
1088         }
1089
1090         status = cli_smb2_close_fnum(cli, fnum);
1091
1092         ZERO_STRUCTP(sbuf);
1093
1094         sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1095         sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1096         sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1097         sbuf->st_ex_size = cr.end_of_file;
1098         *attributes = cr.file_attributes;
1099
1100         return status;
1101 }
1102
1103 /***************************************************************
1104  Helper function for pathname operations.
1105 ***************************************************************/
1106
1107 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1108                                 const char *name,
1109                                 uint32_t desired_access,
1110                                 uint16_t *pfnum)
1111 {
1112         NTSTATUS status;
1113         size_t namelen = strlen(name);
1114         TALLOC_CTX *frame = talloc_stackframe();
1115
1116         /* SMB2 is pickier about pathnames. Ensure it doesn't
1117            end in a '\' */
1118         if (namelen > 0 && name[namelen-1] == '\\') {
1119                 char *modname = talloc_strdup(frame, name);
1120                 if (modname == NULL) {
1121                         status = NT_STATUS_NO_MEMORY;
1122                         goto fail;
1123                 }
1124                 modname[namelen-1] = '\0';
1125                 name = modname;
1126         }
1127
1128         /* Try to open a file handle first. */
1129         status = cli_smb2_create_fnum(cli,
1130                         name,
1131                         0,                      /* create_flags */
1132                         desired_access,
1133                         0, /* file attributes */
1134                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1135                         FILE_OPEN,              /* create_disposition */
1136                         0,      /* create_options */
1137                         pfnum,
1138                         NULL);
1139
1140         if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1141                 status = cli_smb2_create_fnum(cli,
1142                         name,
1143                         0,                      /* create_flags */
1144                         desired_access,
1145                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1146                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1147                         FILE_OPEN,              /* create_disposition */
1148                         FILE_DIRECTORY_FILE,    /* create_options */
1149                         pfnum,
1150                         NULL);
1151         }
1152
1153   fail:
1154
1155         TALLOC_FREE(frame);
1156         return status;
1157 }
1158
1159 /***************************************************************
1160  Wrapper that allows SMB2 to query a path info (ALTNAME level).
1161  Synchronous only.
1162 ***************************************************************/
1163
1164 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1165                                 const char *name,
1166                                 fstring alt_name)
1167 {
1168         NTSTATUS status;
1169         DATA_BLOB outbuf = data_blob_null;
1170         uint16_t fnum = 0xffff;
1171         struct smb2_hnd *ph = NULL;
1172         uint32_t altnamelen = 0;
1173         TALLOC_CTX *frame = talloc_stackframe();
1174
1175         if (smbXcli_conn_has_async_calls(cli->conn)) {
1176                 /*
1177                  * Can't use sync call while an async call is in flight
1178                  */
1179                 status = NT_STATUS_INVALID_PARAMETER;
1180                 goto fail;
1181         }
1182
1183         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1184                 status = NT_STATUS_INVALID_PARAMETER;
1185                 goto fail;
1186         }
1187
1188         status = get_fnum_from_path(cli,
1189                                 name,
1190                                 FILE_READ_ATTRIBUTES,
1191                                 &fnum);
1192
1193         if (!NT_STATUS_IS_OK(status)) {
1194                 goto fail;
1195         }
1196
1197         status = map_fnum_to_smb2_handle(cli,
1198                                         fnum,
1199                                         &ph);
1200         if (!NT_STATUS_IS_OK(status)) {
1201                 goto fail;
1202         }
1203
1204         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1205            level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1206
1207         status = smb2cli_query_info(cli->conn,
1208                                 cli->timeout,
1209                                 cli->smb2.session,
1210                                 cli->smb2.tcon,
1211                                 1, /* in_info_type */
1212                                 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1213                                 0xFFFF, /* in_max_output_length */
1214                                 NULL, /* in_input_buffer */
1215                                 0, /* in_additional_info */
1216                                 0, /* in_flags */
1217                                 ph->fid_persistent,
1218                                 ph->fid_volatile,
1219                                 frame,
1220                                 &outbuf);
1221
1222         if (!NT_STATUS_IS_OK(status)) {
1223                 goto fail;
1224         }
1225
1226         /* Parse the reply. */
1227         if (outbuf.length < 4) {
1228                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1229                 goto fail;
1230         }
1231
1232         altnamelen = IVAL(outbuf.data, 0);
1233         if (altnamelen > outbuf.length - 4) {
1234                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1235                 goto fail;
1236         }
1237
1238         if (altnamelen > 0) {
1239                 size_t ret = 0;
1240                 char *short_name = NULL;
1241                 ret = pull_string_talloc(frame,
1242                                 outbuf.data,
1243                                 FLAGS2_UNICODE_STRINGS,
1244                                 &short_name,
1245                                 outbuf.data + 4,
1246                                 altnamelen,
1247                                 STR_UNICODE);
1248                 if (ret == (size_t)-1) {
1249                         /* Bad conversion. */
1250                         status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1251                         goto fail;
1252                 }
1253
1254                 fstrcpy(alt_name, short_name);
1255         } else {
1256                 alt_name[0] = '\0';
1257         }
1258
1259         status = NT_STATUS_OK;
1260
1261   fail:
1262
1263         if (fnum != 0xffff) {
1264                 cli_smb2_close_fnum(cli, fnum);
1265         }
1266
1267         cli->raw_status = status;
1268
1269         TALLOC_FREE(frame);
1270         return status;
1271 }
1272
1273
1274 /***************************************************************
1275  Wrapper that allows SMB2 to query a fnum info (basic level).
1276  Synchronous only.
1277 ***************************************************************/
1278
1279 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1280                         uint16_t fnum,
1281                         uint16_t *mode,
1282                         off_t *size,
1283                         struct timespec *create_time,
1284                         struct timespec *access_time,
1285                         struct timespec *write_time,
1286                         struct timespec *change_time,
1287                         SMB_INO_T *ino)
1288 {
1289         NTSTATUS status;
1290         DATA_BLOB outbuf = data_blob_null;
1291         struct smb2_hnd *ph = NULL;
1292         TALLOC_CTX *frame = talloc_stackframe();
1293
1294         if (smbXcli_conn_has_async_calls(cli->conn)) {
1295                 /*
1296                  * Can't use sync call while an async call is in flight
1297                  */
1298                 status = NT_STATUS_INVALID_PARAMETER;
1299                 goto fail;
1300         }
1301
1302         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1303                 status = NT_STATUS_INVALID_PARAMETER;
1304                 goto fail;
1305         }
1306
1307         status = map_fnum_to_smb2_handle(cli,
1308                                         fnum,
1309                                         &ph);
1310         if (!NT_STATUS_IS_OK(status)) {
1311                 goto fail;
1312         }
1313
1314         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1315            level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1316
1317         status = smb2cli_query_info(cli->conn,
1318                                 cli->timeout,
1319                                 cli->smb2.session,
1320                                 cli->smb2.tcon,
1321                                 1, /* in_info_type */
1322                                 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1323                                 0xFFFF, /* in_max_output_length */
1324                                 NULL, /* in_input_buffer */
1325                                 0, /* in_additional_info */
1326                                 0, /* in_flags */
1327                                 ph->fid_persistent,
1328                                 ph->fid_volatile,
1329                                 frame,
1330                                 &outbuf);
1331         if (!NT_STATUS_IS_OK(status)) {
1332                 goto fail;
1333         }
1334
1335         /* Parse the reply. */
1336         if (outbuf.length < 0x60) {
1337                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1338                 goto fail;
1339         }
1340
1341         if (create_time) {
1342                 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1343         }
1344         if (access_time) {
1345                 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1346         }
1347         if (write_time) {
1348                 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1349         }
1350         if (change_time) {
1351                 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1352         }
1353         if (mode) {
1354                 uint32_t attr = IVAL(outbuf.data, 0x20);
1355                 *mode = (uint16_t)attr;
1356         }
1357         if (size) {
1358                 uint64_t file_size = BVAL(outbuf.data, 0x30);
1359                 *size = (off_t)file_size;
1360         }
1361         if (ino) {
1362                 uint64_t file_index = BVAL(outbuf.data, 0x40);
1363                 *ino = (SMB_INO_T)file_index;
1364         }
1365
1366   fail:
1367
1368         cli->raw_status = status;
1369
1370         TALLOC_FREE(frame);
1371         return status;
1372 }
1373
1374 /***************************************************************
1375  Wrapper that allows SMB2 to query an fnum.
1376  Implement on top of cli_smb2_qfileinfo_basic().
1377  Synchronous only.
1378 ***************************************************************/
1379
1380 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1381                         uint16_t fnum,
1382                         uint16_t *attr,
1383                         off_t *size,
1384                         time_t *change_time,
1385                         time_t *access_time,
1386                         time_t *write_time)
1387 {
1388         struct timespec access_time_ts;
1389         struct timespec write_time_ts;
1390         struct timespec change_time_ts;
1391         NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1392                                         fnum,
1393                                         attr,
1394                                         size,
1395                                         NULL,
1396                                         &access_time_ts,
1397                                         &write_time_ts,
1398                                         &change_time_ts,
1399                                         NULL);
1400
1401         cli->raw_status = status;
1402
1403         if (!NT_STATUS_IS_OK(status)) {
1404                 return status;
1405         }
1406
1407         if (change_time) {
1408                 *change_time = change_time_ts.tv_sec;
1409         }
1410         if (access_time) {
1411                 *access_time = access_time_ts.tv_sec;
1412         }
1413         if (write_time) {
1414                 *write_time = write_time_ts.tv_sec;
1415         }
1416         return NT_STATUS_OK;
1417 }
1418
1419 /***************************************************************
1420  Wrapper that allows SMB2 to get pathname attributes.
1421  Synchronous only.
1422 ***************************************************************/
1423
1424 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1425                         const char *name,
1426                         uint16_t *attr,
1427                         off_t *size,
1428                         time_t *write_time)
1429 {
1430         NTSTATUS status;
1431         uint16_t fnum = 0xffff;
1432         struct smb2_hnd *ph = NULL;
1433         TALLOC_CTX *frame = talloc_stackframe();
1434
1435         if (smbXcli_conn_has_async_calls(cli->conn)) {
1436                 /*
1437                  * Can't use sync call while an async call is in flight
1438                  */
1439                 status = NT_STATUS_INVALID_PARAMETER;
1440                 goto fail;
1441         }
1442
1443         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1444                 status = NT_STATUS_INVALID_PARAMETER;
1445                 goto fail;
1446         }
1447
1448         status = get_fnum_from_path(cli,
1449                                 name,
1450                                 FILE_READ_ATTRIBUTES,
1451                                 &fnum);
1452
1453         if (!NT_STATUS_IS_OK(status)) {
1454                 goto fail;
1455         }
1456
1457         status = map_fnum_to_smb2_handle(cli,
1458                                         fnum,
1459                                         &ph);
1460         if (!NT_STATUS_IS_OK(status)) {
1461                 goto fail;
1462         }
1463         status = cli_smb2_getattrE(cli,
1464                                 fnum,
1465                                 attr,
1466                                 size,
1467                                 NULL,
1468                                 NULL,
1469                                 write_time);
1470         if (!NT_STATUS_IS_OK(status)) {
1471                 goto fail;
1472         }
1473
1474   fail:
1475
1476         if (fnum != 0xffff) {
1477                 cli_smb2_close_fnum(cli, fnum);
1478         }
1479
1480         cli->raw_status = status;
1481
1482         TALLOC_FREE(frame);
1483         return status;
1484 }
1485
1486 /***************************************************************
1487  Wrapper that allows SMB2 to query a pathname info (basic level).
1488  Implement on top of cli_smb2_qfileinfo_basic().
1489  Synchronous only.
1490 ***************************************************************/
1491
1492 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1493                         const char *name,
1494                         struct timespec *create_time,
1495                         struct timespec *access_time,
1496                         struct timespec *write_time,
1497                         struct timespec *change_time,
1498                         off_t *size,
1499                         uint16_t *mode,
1500                         SMB_INO_T *ino)
1501 {
1502         NTSTATUS status;
1503         struct smb2_hnd *ph = NULL;
1504         uint16_t fnum = 0xffff;
1505         TALLOC_CTX *frame = talloc_stackframe();
1506
1507         if (smbXcli_conn_has_async_calls(cli->conn)) {
1508                 /*
1509                  * Can't use sync call while an async call is in flight
1510                  */
1511                 status = NT_STATUS_INVALID_PARAMETER;
1512                 goto fail;
1513         }
1514
1515         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1516                 status = NT_STATUS_INVALID_PARAMETER;
1517                 goto fail;
1518         }
1519
1520         status = get_fnum_from_path(cli,
1521                                         name,
1522                                         FILE_READ_ATTRIBUTES,
1523                                         &fnum);
1524
1525         if (!NT_STATUS_IS_OK(status)) {
1526                 goto fail;
1527         }
1528
1529         status = map_fnum_to_smb2_handle(cli,
1530                                         fnum,
1531                                         &ph);
1532         if (!NT_STATUS_IS_OK(status)) {
1533                 goto fail;
1534         }
1535
1536         status = cli_smb2_qfileinfo_basic(cli,
1537                                         fnum,
1538                                         mode,
1539                                         size,
1540                                         create_time,
1541                                         access_time,
1542                                         write_time,
1543                                         change_time,
1544                                         ino);
1545
1546   fail:
1547
1548         if (fnum != 0xffff) {
1549                 cli_smb2_close_fnum(cli, fnum);
1550         }
1551
1552         cli->raw_status = status;
1553
1554         TALLOC_FREE(frame);
1555         return status;
1556 }
1557
1558 /***************************************************************
1559  Wrapper that allows SMB2 to query pathname streams.
1560  Synchronous only.
1561 ***************************************************************/
1562
1563 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1564                                 const char *name,
1565                                 TALLOC_CTX *mem_ctx,
1566                                 unsigned int *pnum_streams,
1567                                 struct stream_struct **pstreams)
1568 {
1569         NTSTATUS status;
1570         struct smb2_hnd *ph = NULL;
1571         uint16_t fnum = 0xffff;
1572         DATA_BLOB outbuf = data_blob_null;
1573         TALLOC_CTX *frame = talloc_stackframe();
1574
1575         if (smbXcli_conn_has_async_calls(cli->conn)) {
1576                 /*
1577                  * Can't use sync call while an async call is in flight
1578                  */
1579                 status = NT_STATUS_INVALID_PARAMETER;
1580                 goto fail;
1581         }
1582
1583         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1584                 status = NT_STATUS_INVALID_PARAMETER;
1585                 goto fail;
1586         }
1587
1588         status = get_fnum_from_path(cli,
1589                                 name,
1590                                 FILE_READ_ATTRIBUTES,
1591                                 &fnum);
1592
1593         if (!NT_STATUS_IS_OK(status)) {
1594                 goto fail;
1595         }
1596
1597         status = map_fnum_to_smb2_handle(cli,
1598                                         fnum,
1599                                         &ph);
1600         if (!NT_STATUS_IS_OK(status)) {
1601                 goto fail;
1602         }
1603
1604         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1605            level 22 (SMB2_FILE_STREAM_INFORMATION). */
1606
1607         status = smb2cli_query_info(cli->conn,
1608                                 cli->timeout,
1609                                 cli->smb2.session,
1610                                 cli->smb2.tcon,
1611                                 1, /* in_info_type */
1612                                 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1613                                 0xFFFF, /* in_max_output_length */
1614                                 NULL, /* in_input_buffer */
1615                                 0, /* in_additional_info */
1616                                 0, /* in_flags */
1617                                 ph->fid_persistent,
1618                                 ph->fid_volatile,
1619                                 frame,
1620                                 &outbuf);
1621
1622         if (!NT_STATUS_IS_OK(status)) {
1623                 goto fail;
1624         }
1625
1626         /* Parse the reply. */
1627         if (!parse_streams_blob(mem_ctx,
1628                                 outbuf.data,
1629                                 outbuf.length,
1630                                 pnum_streams,
1631                                 pstreams)) {
1632                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1633                 goto fail;
1634         }
1635
1636   fail:
1637
1638         if (fnum != 0xffff) {
1639                 cli_smb2_close_fnum(cli, fnum);
1640         }
1641
1642         cli->raw_status = status;
1643
1644         TALLOC_FREE(frame);
1645         return status;
1646 }
1647
1648 /***************************************************************
1649  Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
1650  a pathname.
1651  Synchronous only.
1652 ***************************************************************/
1653
1654 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
1655                         const char *name,
1656                         uint8_t in_info_type,
1657                         uint8_t in_file_info_class,
1658                         const DATA_BLOB *p_in_data)
1659 {
1660         NTSTATUS status;
1661         uint16_t fnum = 0xffff;
1662         struct smb2_hnd *ph = NULL;
1663         TALLOC_CTX *frame = talloc_stackframe();
1664
1665         if (smbXcli_conn_has_async_calls(cli->conn)) {
1666                 /*
1667                  * Can't use sync call while an async call is in flight
1668                  */
1669                 status = NT_STATUS_INVALID_PARAMETER;
1670                 goto fail;
1671         }
1672
1673         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1674                 status = NT_STATUS_INVALID_PARAMETER;
1675                 goto fail;
1676         }
1677
1678         status = get_fnum_from_path(cli,
1679                                 name,
1680                                 FILE_WRITE_ATTRIBUTES,
1681                                 &fnum);
1682
1683         if (!NT_STATUS_IS_OK(status)) {
1684                 goto fail;
1685         }
1686
1687         status = map_fnum_to_smb2_handle(cli,
1688                                         fnum,
1689                                         &ph);
1690         if (!NT_STATUS_IS_OK(status)) {
1691                 goto fail;
1692         }
1693
1694         status = smb2cli_set_info(cli->conn,
1695                                 cli->timeout,
1696                                 cli->smb2.session,
1697                                 cli->smb2.tcon,
1698                                 in_info_type,
1699                                 in_file_info_class,
1700                                 p_in_data, /* in_input_buffer */
1701                                 0, /* in_additional_info */
1702                                 ph->fid_persistent,
1703                                 ph->fid_volatile);
1704   fail:
1705
1706         if (fnum != 0xffff) {
1707                 cli_smb2_close_fnum(cli, fnum);
1708         }
1709
1710         cli->raw_status = status;
1711
1712         TALLOC_FREE(frame);
1713         return status;
1714 }
1715
1716
1717 /***************************************************************
1718  Wrapper that allows SMB2 to set pathname attributes.
1719  Synchronous only.
1720 ***************************************************************/
1721
1722 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1723                         const char *name,
1724                         uint16_t attr,
1725                         time_t mtime)
1726 {
1727         uint8_t inbuf_store[40];
1728         DATA_BLOB inbuf = data_blob_null;
1729
1730         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1731            level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1732
1733         inbuf.data = inbuf_store;
1734         inbuf.length = sizeof(inbuf_store);
1735         data_blob_clear(&inbuf);
1736
1737         /*
1738          * SMB1 uses attr == 0 to clear all attributes
1739          * on a file (end up with FILE_ATTRIBUTE_NORMAL),
1740          * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
1741          * request attribute change.
1742          *
1743          * SMB2 uses exactly the reverse. Unfortunately as the
1744          * cli_setatr() ABI is exposed inside libsmbclient,
1745          * we must make the SMB2 cli_smb2_setatr() call
1746          * export the same ABI as the SMB1 cli_setatr()
1747          * which calls it. This means reversing the sense
1748          * of the requested attr argument if it's zero
1749          * or FILE_ATTRIBUTE_NORMAL.
1750          *
1751          * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
1752          */
1753
1754         if (attr == 0) {
1755                 attr = FILE_ATTRIBUTE_NORMAL;
1756         } else if (attr == FILE_ATTRIBUTE_NORMAL) {
1757                 attr = 0;
1758         }
1759
1760         SSVAL(inbuf.data, 32, attr);
1761         if (mtime != 0) {
1762                 put_long_date((char *)inbuf.data + 16,mtime);
1763         }
1764         /* Set all the other times to -1. */
1765         SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1766         SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1767         SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1768
1769         return cli_smb2_setpathinfo(cli,
1770                                 name,
1771                                 1, /* in_info_type */
1772                                 /* in_file_info_class */
1773                                 SMB_FILE_BASIC_INFORMATION - 1000,
1774                                 &inbuf);
1775 }
1776
1777
1778 /***************************************************************
1779  Wrapper that allows SMB2 to set file handle times.
1780  Synchronous only.
1781 ***************************************************************/
1782
1783 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1784                         uint16_t fnum,
1785                         time_t change_time,
1786                         time_t access_time,
1787                         time_t write_time)
1788 {
1789         NTSTATUS status;
1790         struct smb2_hnd *ph = NULL;
1791         uint8_t inbuf_store[40];
1792         DATA_BLOB inbuf = data_blob_null;
1793
1794         if (smbXcli_conn_has_async_calls(cli->conn)) {
1795                 /*
1796                  * Can't use sync call while an async call is in flight
1797                  */
1798                 return NT_STATUS_INVALID_PARAMETER;
1799         }
1800
1801         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1802                 return NT_STATUS_INVALID_PARAMETER;
1803         }
1804
1805         status = map_fnum_to_smb2_handle(cli,
1806                                         fnum,
1807                                         &ph);
1808         if (!NT_STATUS_IS_OK(status)) {
1809                 return status;
1810         }
1811
1812         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1813            level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1814
1815         inbuf.data = inbuf_store;
1816         inbuf.length = sizeof(inbuf_store);
1817         data_blob_clear(&inbuf);
1818
1819         SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1820         if (change_time != 0) {
1821                 put_long_date((char *)inbuf.data + 24, change_time);
1822         }
1823         if (access_time != 0) {
1824                 put_long_date((char *)inbuf.data + 8, access_time);
1825         }
1826         if (write_time != 0) {
1827                 put_long_date((char *)inbuf.data + 16, write_time);
1828         }
1829
1830         cli->raw_status = smb2cli_set_info(cli->conn,
1831                                 cli->timeout,
1832                                 cli->smb2.session,
1833                                 cli->smb2.tcon,
1834                                 1, /* in_info_type */
1835                                 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1836                                 &inbuf, /* in_input_buffer */
1837                                 0, /* in_additional_info */
1838                                 ph->fid_persistent,
1839                                 ph->fid_volatile);
1840
1841         return cli->raw_status;
1842 }
1843
1844 /***************************************************************
1845  Wrapper that allows SMB2 to query disk attributes (size).
1846  Synchronous only.
1847 ***************************************************************/
1848
1849 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
1850                           uint64_t *bsize, uint64_t *total, uint64_t *avail)
1851 {
1852         NTSTATUS status;
1853         uint16_t fnum = 0xffff;
1854         DATA_BLOB outbuf = data_blob_null;
1855         struct smb2_hnd *ph = NULL;
1856         uint32_t sectors_per_unit = 0;
1857         uint32_t bytes_per_sector = 0;
1858         uint64_t total_size = 0;
1859         uint64_t size_free = 0;
1860         TALLOC_CTX *frame = talloc_stackframe();
1861
1862         if (smbXcli_conn_has_async_calls(cli->conn)) {
1863                 /*
1864                  * Can't use sync call while an async call is in flight
1865                  */
1866                 status = NT_STATUS_INVALID_PARAMETER;
1867                 goto fail;
1868         }
1869
1870         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1871                 status = NT_STATUS_INVALID_PARAMETER;
1872                 goto fail;
1873         }
1874
1875         /* First open the top level directory. */
1876         status = cli_smb2_create_fnum(cli,
1877                         path,
1878                         0,                      /* create_flags */
1879                         FILE_READ_ATTRIBUTES,   /* desired_access */
1880                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1881                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1882                         FILE_OPEN,              /* create_disposition */
1883                         FILE_DIRECTORY_FILE,    /* create_options */
1884                         &fnum,
1885                         NULL);
1886
1887         if (!NT_STATUS_IS_OK(status)) {
1888                 goto fail;
1889         }
1890
1891         status = map_fnum_to_smb2_handle(cli,
1892                                         fnum,
1893                                         &ph);
1894         if (!NT_STATUS_IS_OK(status)) {
1895                 goto fail;
1896         }
1897
1898         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1899            level 3 (SMB_FS_SIZE_INFORMATION). */
1900
1901         status = smb2cli_query_info(cli->conn,
1902                                 cli->timeout,
1903                                 cli->smb2.session,
1904                                 cli->smb2.tcon,
1905                                 2, /* in_info_type */
1906                                 3, /* in_file_info_class */
1907                                 0xFFFF, /* in_max_output_length */
1908                                 NULL, /* in_input_buffer */
1909                                 0, /* in_additional_info */
1910                                 0, /* in_flags */
1911                                 ph->fid_persistent,
1912                                 ph->fid_volatile,
1913                                 frame,
1914                                 &outbuf);
1915         if (!NT_STATUS_IS_OK(status)) {
1916                 goto fail;
1917         }
1918
1919         /* Parse the reply. */
1920         if (outbuf.length != 24) {
1921                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1922                 goto fail;
1923         }
1924
1925         total_size = BVAL(outbuf.data, 0);
1926         size_free = BVAL(outbuf.data, 8);
1927         sectors_per_unit = IVAL(outbuf.data, 16);
1928         bytes_per_sector = IVAL(outbuf.data, 20);
1929
1930         if (bsize) {
1931                 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
1932         }
1933         if (total) {
1934                 *total = total_size;
1935         }
1936         if (avail) {
1937                 *avail = size_free;
1938         }
1939
1940         status = NT_STATUS_OK;
1941
1942   fail:
1943
1944         if (fnum != 0xffff) {
1945                 cli_smb2_close_fnum(cli, fnum);
1946         }
1947
1948         cli->raw_status = status;
1949
1950         TALLOC_FREE(frame);
1951         return status;
1952 }
1953
1954 /***************************************************************
1955  Wrapper that allows SMB2 to query file system attributes.
1956  Synchronous only.
1957 ***************************************************************/
1958
1959 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
1960 {
1961         NTSTATUS status;
1962         uint16_t fnum = 0xffff;
1963         DATA_BLOB outbuf = data_blob_null;
1964         struct smb2_hnd *ph = NULL;
1965         TALLOC_CTX *frame = talloc_stackframe();
1966
1967         if (smbXcli_conn_has_async_calls(cli->conn)) {
1968                 /*
1969                  * Can't use sync call while an async call is in flight
1970                  */
1971                 status = NT_STATUS_INVALID_PARAMETER;
1972                 goto fail;
1973         }
1974
1975         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1976                 status = NT_STATUS_INVALID_PARAMETER;
1977                 goto fail;
1978         }
1979
1980         /* First open the top level directory. */
1981         status =
1982             cli_smb2_create_fnum(cli, "", 0,               /* create_flags */
1983                                  FILE_READ_ATTRIBUTES,     /* desired_access */
1984                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1985                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
1986                                      FILE_SHARE_DELETE, /* share_access */
1987                                  FILE_OPEN,             /* create_disposition */
1988                                  FILE_DIRECTORY_FILE,   /* create_options */
1989                                  &fnum,
1990                                  NULL);
1991
1992         if (!NT_STATUS_IS_OK(status)) {
1993                 goto fail;
1994         }
1995
1996         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1997         if (!NT_STATUS_IS_OK(status)) {
1998                 goto fail;
1999         }
2000
2001         status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2002                                     cli->smb2.tcon, 2, /* in_info_type */
2003                                     5,                 /* in_file_info_class */
2004                                     0xFFFF, /* in_max_output_length */
2005                                     NULL,   /* in_input_buffer */
2006                                     0,      /* in_additional_info */
2007                                     0,      /* in_flags */
2008                                     ph->fid_persistent, ph->fid_volatile, frame,
2009                                     &outbuf);
2010         if (!NT_STATUS_IS_OK(status)) {
2011                 goto fail;
2012         }
2013
2014         if (outbuf.length < 12) {
2015                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2016                 goto fail;
2017         }
2018
2019         *fs_attr = IVAL(outbuf.data, 0);
2020
2021 fail:
2022
2023         if (fnum != 0xffff) {
2024                 cli_smb2_close_fnum(cli, fnum);
2025         }
2026
2027         cli->raw_status = status;
2028
2029         TALLOC_FREE(frame);
2030         return status;
2031 }
2032
2033 /***************************************************************
2034  Wrapper that allows SMB2 to query a security descriptor.
2035  Synchronous only.
2036 ***************************************************************/
2037
2038 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2039                                         uint16_t fnum,
2040                                         uint32_t sec_info,
2041                                         TALLOC_CTX *mem_ctx,
2042                                         struct security_descriptor **ppsd)
2043 {
2044         NTSTATUS status;
2045         DATA_BLOB outbuf = data_blob_null;
2046         struct smb2_hnd *ph = NULL;
2047         struct security_descriptor *lsd = NULL;
2048         TALLOC_CTX *frame = talloc_stackframe();
2049
2050         if (smbXcli_conn_has_async_calls(cli->conn)) {
2051                 /*
2052                  * Can't use sync call while an async call is in flight
2053                  */
2054                 status = NT_STATUS_INVALID_PARAMETER;
2055                 goto fail;
2056         }
2057
2058         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2059                 status = NT_STATUS_INVALID_PARAMETER;
2060                 goto fail;
2061         }
2062
2063         status = map_fnum_to_smb2_handle(cli,
2064                                         fnum,
2065                                         &ph);
2066         if (!NT_STATUS_IS_OK(status)) {
2067                 goto fail;
2068         }
2069
2070         /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2071
2072         status = smb2cli_query_info(cli->conn,
2073                                 cli->timeout,
2074                                 cli->smb2.session,
2075                                 cli->smb2.tcon,
2076                                 3, /* in_info_type */
2077                                 0, /* in_file_info_class */
2078                                 0xFFFF, /* in_max_output_length */
2079                                 NULL, /* in_input_buffer */
2080                                 sec_info, /* in_additional_info */
2081                                 0, /* in_flags */
2082                                 ph->fid_persistent,
2083                                 ph->fid_volatile,
2084                                 frame,
2085                                 &outbuf);
2086
2087         if (!NT_STATUS_IS_OK(status)) {
2088                 goto fail;
2089         }
2090
2091         /* Parse the reply. */
2092         status = unmarshall_sec_desc(mem_ctx,
2093                                 outbuf.data,
2094                                 outbuf.length,
2095                                 &lsd);
2096
2097         if (!NT_STATUS_IS_OK(status)) {
2098                 goto fail;
2099         }
2100
2101         if (ppsd != NULL) {
2102                 *ppsd = lsd;
2103         } else {
2104                 TALLOC_FREE(lsd);
2105         }
2106
2107   fail:
2108
2109         cli->raw_status = status;
2110
2111         TALLOC_FREE(frame);
2112         return status;
2113 }
2114
2115 /***************************************************************
2116  Wrapper that allows SMB2 to set a security descriptor.
2117  Synchronous only.
2118 ***************************************************************/
2119
2120 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
2121                                         uint16_t fnum,
2122                                         uint32_t sec_info,
2123                                         const struct security_descriptor *sd)
2124 {
2125         NTSTATUS status;
2126         DATA_BLOB inbuf = data_blob_null;
2127         struct smb2_hnd *ph = NULL;
2128         TALLOC_CTX *frame = talloc_stackframe();
2129
2130         if (smbXcli_conn_has_async_calls(cli->conn)) {
2131                 /*
2132                  * Can't use sync call while an async call is in flight
2133                  */
2134                 status = NT_STATUS_INVALID_PARAMETER;
2135                 goto fail;
2136         }
2137
2138         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2139                 status = NT_STATUS_INVALID_PARAMETER;
2140                 goto fail;
2141         }
2142
2143         status = map_fnum_to_smb2_handle(cli,
2144                                         fnum,
2145                                         &ph);
2146         if (!NT_STATUS_IS_OK(status)) {
2147                 goto fail;
2148         }
2149
2150         status = marshall_sec_desc(frame,
2151                                 sd,
2152                                 &inbuf.data,
2153                                 &inbuf.length);
2154
2155         if (!NT_STATUS_IS_OK(status)) {
2156                 goto fail;
2157         }
2158
2159         /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2160
2161         status = smb2cli_set_info(cli->conn,
2162                                 cli->timeout,
2163                                 cli->smb2.session,
2164                                 cli->smb2.tcon,
2165                                 3, /* in_info_type */
2166                                 0, /* in_file_info_class */
2167                                 &inbuf, /* in_input_buffer */
2168                                 sec_info, /* in_additional_info */
2169                                 ph->fid_persistent,
2170                                 ph->fid_volatile);
2171
2172   fail:
2173
2174         cli->raw_status = status;
2175
2176         TALLOC_FREE(frame);
2177         return status;
2178 }
2179
2180 /***************************************************************
2181  Wrapper that allows SMB2 to rename a file.
2182  Synchronous only.
2183 ***************************************************************/
2184
2185 NTSTATUS cli_smb2_rename(struct cli_state *cli,
2186                          const char *fname_src,
2187                          const char *fname_dst,
2188                          bool replace)
2189 {
2190         NTSTATUS status;
2191         DATA_BLOB inbuf = data_blob_null;
2192         uint16_t fnum = 0xffff;
2193         struct smb2_hnd *ph = NULL;
2194         smb_ucs2_t *converted_str = NULL;
2195         size_t converted_size_bytes = 0;
2196         size_t namelen = 0;
2197         TALLOC_CTX *frame = talloc_stackframe();
2198
2199         if (smbXcli_conn_has_async_calls(cli->conn)) {
2200                 /*
2201                  * Can't use sync call while an async call is in flight
2202                  */
2203                 status = NT_STATUS_INVALID_PARAMETER;
2204                 goto fail;
2205         }
2206
2207         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2208                 status = NT_STATUS_INVALID_PARAMETER;
2209                 goto fail;
2210         }
2211
2212         status = get_fnum_from_path(cli,
2213                                 fname_src,
2214                                 DELETE_ACCESS,
2215                                 &fnum);
2216
2217         if (!NT_STATUS_IS_OK(status)) {
2218                 goto fail;
2219         }
2220
2221         status = map_fnum_to_smb2_handle(cli,
2222                                         fnum,
2223                                         &ph);
2224         if (!NT_STATUS_IS_OK(status)) {
2225                 goto fail;
2226         }
2227
2228         /* SMB2 is pickier about pathnames. Ensure it doesn't
2229            start in a '\' */
2230         if (*fname_dst == '\\') {
2231                 fname_dst++;
2232         }
2233
2234         /* SMB2 is pickier about pathnames. Ensure it doesn't
2235            end in a '\' */
2236         namelen = strlen(fname_dst);
2237         if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2238                 char *modname = talloc_strdup(frame, fname_dst);
2239                 modname[namelen-1] = '\0';
2240                 fname_dst = modname;
2241         }
2242
2243         if (!push_ucs2_talloc(frame,
2244                                 &converted_str,
2245                                 fname_dst,
2246                                 &converted_size_bytes)) {
2247                 status = NT_STATUS_INVALID_PARAMETER;
2248                 goto fail;
2249         }
2250
2251         /* W2K8 insists the dest name is not null
2252            terminated. Remove the last 2 zero bytes
2253            and reduce the name length. */
2254
2255         if (converted_size_bytes < 2) {
2256                 status = NT_STATUS_INVALID_PARAMETER;
2257                 goto fail;
2258         }
2259         converted_size_bytes -= 2;
2260
2261         inbuf = data_blob_talloc_zero(frame,
2262                                 20 + converted_size_bytes);
2263         if (inbuf.data == NULL) {
2264                 status = NT_STATUS_NO_MEMORY;
2265                 goto fail;
2266         }
2267
2268         if (replace) {
2269                 SCVAL(inbuf.data, 0, 1);
2270         }
2271
2272         SIVAL(inbuf.data, 16, converted_size_bytes);
2273         memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2274
2275         /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2276            level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2277
2278         status = smb2cli_set_info(cli->conn,
2279                                 cli->timeout,
2280                                 cli->smb2.session,
2281                                 cli->smb2.tcon,
2282                                 1, /* in_info_type */
2283                                 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2284                                 &inbuf, /* in_input_buffer */
2285                                 0, /* in_additional_info */
2286                                 ph->fid_persistent,
2287                                 ph->fid_volatile);
2288
2289   fail:
2290
2291         if (fnum != 0xffff) {
2292                 cli_smb2_close_fnum(cli, fnum);
2293         }
2294
2295         cli->raw_status = status;
2296
2297         TALLOC_FREE(frame);
2298         return status;
2299 }
2300
2301 /***************************************************************
2302  Wrapper that allows SMB2 to set an EA on a fnum.
2303  Synchronous only.
2304 ***************************************************************/
2305
2306 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2307                         uint16_t fnum,
2308                         const char *ea_name,
2309                         const char *ea_val,
2310                         size_t ea_len)
2311 {
2312         NTSTATUS status;
2313         DATA_BLOB inbuf = data_blob_null;
2314         size_t bloblen = 0;
2315         char *ea_name_ascii = NULL;
2316         size_t namelen = 0;
2317         struct smb2_hnd *ph = NULL;
2318         TALLOC_CTX *frame = talloc_stackframe();
2319
2320         if (smbXcli_conn_has_async_calls(cli->conn)) {
2321                 /*
2322                  * Can't use sync call while an async call is in flight
2323                  */
2324                 status = NT_STATUS_INVALID_PARAMETER;
2325                 goto fail;
2326         }
2327
2328         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2329                 status = NT_STATUS_INVALID_PARAMETER;
2330                 goto fail;
2331         }
2332
2333         status = map_fnum_to_smb2_handle(cli,
2334                                         fnum,
2335                                         &ph);
2336         if (!NT_STATUS_IS_OK(status)) {
2337                 goto fail;
2338         }
2339
2340         /* Marshall the SMB2 EA data. */
2341         if (ea_len > 0xFFFF) {
2342                 status = NT_STATUS_INVALID_PARAMETER;
2343                 goto fail;
2344         }
2345
2346         if (!push_ascii_talloc(frame,
2347                                 &ea_name_ascii,
2348                                 ea_name,
2349                                 &namelen)) {
2350                 status = NT_STATUS_INVALID_PARAMETER;
2351                 goto fail;
2352         }
2353
2354         if (namelen < 2 || namelen > 0xFF) {
2355                 status = NT_STATUS_INVALID_PARAMETER;
2356                 goto fail;
2357         }
2358
2359         bloblen = 8 + ea_len + namelen;
2360         /* Round up to a 4 byte boundary. */
2361         bloblen = ((bloblen + 3)&~3);
2362
2363         inbuf = data_blob_talloc_zero(frame, bloblen);
2364         if (inbuf.data == NULL) {
2365                 status = NT_STATUS_NO_MEMORY;
2366                 goto fail;
2367         }
2368         /* namelen doesn't include the NULL byte. */
2369         SCVAL(inbuf.data, 5, namelen - 1);
2370         SSVAL(inbuf.data, 6, ea_len);
2371         memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2372         memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2373
2374         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2375            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2376
2377         status = smb2cli_set_info(cli->conn,
2378                                 cli->timeout,
2379                                 cli->smb2.session,
2380                                 cli->smb2.tcon,
2381                                 1, /* in_info_type */
2382                                 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2383                                 &inbuf, /* in_input_buffer */
2384                                 0, /* in_additional_info */
2385                                 ph->fid_persistent,
2386                                 ph->fid_volatile);
2387
2388   fail:
2389
2390         cli->raw_status = status;
2391
2392         TALLOC_FREE(frame);
2393         return status;
2394 }
2395
2396 /***************************************************************
2397  Wrapper that allows SMB2 to set an EA on a pathname.
2398  Synchronous only.
2399 ***************************************************************/
2400
2401 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2402                         const char *name,
2403                         const char *ea_name,
2404                         const char *ea_val,
2405                         size_t ea_len)
2406 {
2407         NTSTATUS status;
2408         uint16_t fnum = 0xffff;
2409
2410         if (smbXcli_conn_has_async_calls(cli->conn)) {
2411                 /*
2412                  * Can't use sync call while an async call is in flight
2413                  */
2414                 status = NT_STATUS_INVALID_PARAMETER;
2415                 goto fail;
2416         }
2417
2418         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2419                 status = NT_STATUS_INVALID_PARAMETER;
2420                 goto fail;
2421         }
2422
2423         status = get_fnum_from_path(cli,
2424                                 name,
2425                                 FILE_WRITE_EA,
2426                                 &fnum);
2427
2428         if (!NT_STATUS_IS_OK(status)) {
2429                 goto fail;
2430         }
2431
2432         status = cli_set_ea_fnum(cli,
2433                                 fnum,
2434                                 ea_name,
2435                                 ea_val,
2436                                 ea_len);
2437         if (!NT_STATUS_IS_OK(status)) {
2438                 goto fail;
2439         }
2440
2441   fail:
2442
2443         if (fnum != 0xffff) {
2444                 cli_smb2_close_fnum(cli, fnum);
2445         }
2446
2447         cli->raw_status = status;
2448
2449         return status;
2450 }
2451
2452 /***************************************************************
2453  Wrapper that allows SMB2 to get an EA list on a pathname.
2454  Synchronous only.
2455 ***************************************************************/
2456
2457 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2458                                 const char *name,
2459                                 TALLOC_CTX *ctx,
2460                                 size_t *pnum_eas,
2461                                 struct ea_struct **pea_array)
2462 {
2463         NTSTATUS status;
2464         uint16_t fnum = 0xffff;
2465         DATA_BLOB outbuf = data_blob_null;
2466         struct smb2_hnd *ph = NULL;
2467         struct ea_list *ea_list = NULL;
2468         struct ea_list *eal = NULL;
2469         size_t ea_count = 0;
2470         TALLOC_CTX *frame = talloc_stackframe();
2471
2472         *pnum_eas = 0;
2473         *pea_array = NULL;
2474
2475         if (smbXcli_conn_has_async_calls(cli->conn)) {
2476                 /*
2477                  * Can't use sync call while an async call is in flight
2478                  */
2479                 status = NT_STATUS_INVALID_PARAMETER;
2480                 goto fail;
2481         }
2482
2483         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2484                 status = NT_STATUS_INVALID_PARAMETER;
2485                 goto fail;
2486         }
2487
2488         status = get_fnum_from_path(cli,
2489                                 name,
2490                                 FILE_READ_EA,
2491                                 &fnum);
2492
2493         if (!NT_STATUS_IS_OK(status)) {
2494                 goto fail;
2495         }
2496
2497         status = map_fnum_to_smb2_handle(cli,
2498                                         fnum,
2499                                         &ph);
2500         if (!NT_STATUS_IS_OK(status)) {
2501                 goto fail;
2502         }
2503
2504         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2505            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2506
2507         status = smb2cli_query_info(cli->conn,
2508                                 cli->timeout,
2509                                 cli->smb2.session,
2510                                 cli->smb2.tcon,
2511                                 1, /* in_info_type */
2512                                 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2513                                 0xFFFF, /* in_max_output_length */
2514                                 NULL, /* in_input_buffer */
2515                                 0, /* in_additional_info */
2516                                 0, /* in_flags */
2517                                 ph->fid_persistent,
2518                                 ph->fid_volatile,
2519                                 frame,
2520                                 &outbuf);
2521
2522         if (!NT_STATUS_IS_OK(status)) {
2523                 goto fail;
2524         }
2525
2526         /* Parse the reply. */
2527         ea_list = read_nttrans_ea_list(ctx,
2528                                 (const char *)outbuf.data,
2529                                 outbuf.length);
2530         if (ea_list == NULL) {
2531                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2532                 goto fail;
2533         }
2534
2535         /* Convert to an array. */
2536         for (eal = ea_list; eal; eal = eal->next) {
2537                 ea_count++;
2538         }
2539
2540         if (ea_count) {
2541                 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2542                 if (*pea_array == NULL) {
2543                         status = NT_STATUS_NO_MEMORY;
2544                         goto fail;
2545                 }
2546                 ea_count = 0;
2547                 for (eal = ea_list; eal; eal = eal->next) {
2548                         (*pea_array)[ea_count++] = eal->ea;
2549                 }
2550                 *pnum_eas = ea_count;
2551         }
2552
2553   fail:
2554
2555         if (fnum != 0xffff) {
2556                 cli_smb2_close_fnum(cli, fnum);
2557         }
2558
2559         cli->raw_status = status;
2560
2561         TALLOC_FREE(frame);
2562         return status;
2563 }
2564
2565 /***************************************************************
2566  Wrapper that allows SMB2 to get user quota.
2567  Synchronous only.
2568 ***************************************************************/
2569
2570 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
2571                                  int quota_fnum,
2572                                  SMB_NTQUOTA_STRUCT *pqt)
2573 {
2574         NTSTATUS status;
2575         DATA_BLOB inbuf = data_blob_null;
2576         DATA_BLOB outbuf = data_blob_null;
2577         struct smb2_hnd *ph = NULL;
2578         TALLOC_CTX *frame = talloc_stackframe();
2579         unsigned sid_len;
2580         unsigned int offset;
2581         uint8_t *buf;
2582
2583         if (smbXcli_conn_has_async_calls(cli->conn)) {
2584                 /*
2585                  * Can't use sync call while an async call is in flight
2586                  */
2587                 status = NT_STATUS_INVALID_PARAMETER;
2588                 goto fail;
2589         }
2590
2591         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2592                 status = NT_STATUS_INVALID_PARAMETER;
2593                 goto fail;
2594         }
2595
2596         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2597         if (!NT_STATUS_IS_OK(status)) {
2598                 goto fail;
2599         }
2600
2601         sid_len = ndr_size_dom_sid(&pqt->sid, 0);
2602
2603         inbuf = data_blob_talloc_zero(frame, 24 + sid_len);
2604         if (inbuf.data == NULL) {
2605                 status = NT_STATUS_NO_MEMORY;
2606                 goto fail;
2607         }
2608
2609         buf = inbuf.data;
2610
2611         SCVAL(buf, 0, 1);          /* ReturnSingle */
2612         SCVAL(buf, 1, 0);          /* RestartScan */
2613         SSVAL(buf, 2, 0);          /* Reserved */
2614         if (8 + sid_len < 8) {
2615                 status = NT_STATUS_INVALID_PARAMETER;
2616                 goto fail;
2617         }
2618         SIVAL(buf, 4, 8 + sid_len); /* SidListLength */
2619         SIVAL(buf, 8, 0);          /* StartSidLength */
2620         SIVAL(buf, 12, 0);        /* StartSidOffset */
2621         SIVAL(buf, 16, 0);        /* NextEntryOffset */
2622         SIVAL(buf, 20, sid_len);    /* SidLength */
2623         sid_linearize(buf + 24, sid_len, &pqt->sid);
2624
2625         status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2626                                     cli->smb2.tcon, 4, /* in_info_type */
2627                                     0,                 /* in_file_info_class */
2628                                     0xFFFF, /* in_max_output_length */
2629                                     &inbuf, /* in_input_buffer */
2630                                     0,      /* in_additional_info */
2631                                     0,      /* in_flags */
2632                                     ph->fid_persistent, ph->fid_volatile, frame,
2633                                     &outbuf);
2634
2635         if (!NT_STATUS_IS_OK(status)) {
2636                 goto fail;
2637         }
2638
2639         if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
2640                                      pqt)) {
2641                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2642                 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
2643         }
2644
2645 fail:
2646         cli->raw_status = status;
2647
2648         TALLOC_FREE(frame);
2649         return status;
2650 }
2651
2652 /***************************************************************
2653  Wrapper that allows SMB2 to list user quota.
2654  Synchronous only.
2655 ***************************************************************/
2656
2657 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
2658                                        TALLOC_CTX *mem_ctx,
2659                                        int quota_fnum,
2660                                        SMB_NTQUOTA_LIST **pqt_list,
2661                                        bool first)
2662 {
2663         NTSTATUS status;
2664         DATA_BLOB inbuf = data_blob_null;
2665         DATA_BLOB outbuf = data_blob_null;
2666         struct smb2_hnd *ph = NULL;
2667         TALLOC_CTX *frame = talloc_stackframe();
2668         uint8_t *buf;
2669
2670         if (smbXcli_conn_has_async_calls(cli->conn)) {
2671                 /*
2672                  * Can't use sync call while an async call is in flight
2673                  */
2674                 status = NT_STATUS_INVALID_PARAMETER;
2675                 goto cleanup;
2676         }
2677
2678         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2679                 status = NT_STATUS_INVALID_PARAMETER;
2680                 goto cleanup;
2681         }
2682
2683         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2684         if (!NT_STATUS_IS_OK(status)) {
2685                 goto cleanup;
2686         }
2687
2688         inbuf = data_blob_talloc_zero(frame, 16);
2689         if (inbuf.data == NULL) {
2690                 status = NT_STATUS_NO_MEMORY;
2691                 goto cleanup;
2692         }
2693
2694         buf = inbuf.data;
2695
2696         SCVAL(buf, 0, 0);            /* ReturnSingle */
2697         SCVAL(buf, 1, first ? 1 : 0); /* RestartScan */
2698         SSVAL(buf, 2, 0);            /* Reserved */
2699         SIVAL(buf, 4, 0);            /* SidListLength */
2700         SIVAL(buf, 8, 0);            /* StartSidLength */
2701         SIVAL(buf, 12, 0);          /* StartSidOffset */
2702
2703         status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2704                                     cli->smb2.tcon, 4, /* in_info_type */
2705                                     0,                 /* in_file_info_class */
2706                                     0xFFFF, /* in_max_output_length */
2707                                     &inbuf, /* in_input_buffer */
2708                                     0,      /* in_additional_info */
2709                                     0,      /* in_flags */
2710                                     ph->fid_persistent, ph->fid_volatile, frame,
2711                                     &outbuf);
2712
2713         if (!NT_STATUS_IS_OK(status)) {
2714                 goto cleanup;
2715         }
2716
2717         status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
2718                                        pqt_list);
2719
2720 cleanup:
2721         cli->raw_status = status;
2722
2723         TALLOC_FREE(frame);
2724         return status;
2725 }
2726
2727 /***************************************************************
2728  Wrapper that allows SMB2 to get file system quota.
2729  Synchronous only.
2730 ***************************************************************/
2731
2732 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
2733                                     int quota_fnum,
2734                                     SMB_NTQUOTA_STRUCT *pqt)
2735 {
2736         NTSTATUS status;
2737         DATA_BLOB outbuf = data_blob_null;
2738         struct smb2_hnd *ph = NULL;
2739         TALLOC_CTX *frame = talloc_stackframe();
2740
2741         if (smbXcli_conn_has_async_calls(cli->conn)) {
2742                 /*
2743                  * Can't use sync call while an async call is in flight
2744                  */
2745                 status = NT_STATUS_INVALID_PARAMETER;
2746                 goto cleanup;
2747         }
2748
2749         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2750                 status = NT_STATUS_INVALID_PARAMETER;
2751                 goto cleanup;
2752         }
2753
2754         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2755         if (!NT_STATUS_IS_OK(status)) {
2756                 goto cleanup;
2757         }
2758
2759         status = smb2cli_query_info(
2760             cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
2761             2,                               /* in_info_type */
2762             SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
2763             0xFFFF,                          /* in_max_output_length */
2764             NULL,                            /* in_input_buffer */
2765             0,                               /* in_additional_info */
2766             0,                               /* in_flags */
2767             ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
2768
2769         if (!NT_STATUS_IS_OK(status)) {
2770                 goto cleanup;
2771         }
2772
2773         status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
2774
2775 cleanup:
2776         cli->raw_status = status;
2777
2778         TALLOC_FREE(frame);
2779         return status;
2780 }
2781
2782 /***************************************************************
2783  Wrapper that allows SMB2 to set user quota.
2784  Synchronous only.
2785 ***************************************************************/
2786
2787 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
2788                                  int quota_fnum,
2789                                  SMB_NTQUOTA_LIST *qtl)
2790 {
2791         NTSTATUS status;
2792         DATA_BLOB inbuf = data_blob_null;
2793         struct smb2_hnd *ph = NULL;
2794         TALLOC_CTX *frame = talloc_stackframe();
2795
2796         if (smbXcli_conn_has_async_calls(cli->conn)) {
2797                 /*
2798                  * Can't use sync call while an async call is in flight
2799                  */
2800                 status = NT_STATUS_INVALID_PARAMETER;
2801                 goto cleanup;
2802         }
2803
2804         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2805                 status = NT_STATUS_INVALID_PARAMETER;
2806                 goto cleanup;
2807         }
2808
2809         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2810         if (!NT_STATUS_IS_OK(status)) {
2811                 goto cleanup;
2812         }
2813
2814         status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
2815         if (!NT_STATUS_IS_OK(status)) {
2816                 goto cleanup;
2817         }
2818
2819         status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
2820                                   cli->smb2.tcon, 4, /* in_info_type */
2821                                   0,                 /* in_file_info_class */
2822                                   &inbuf,           /* in_input_buffer */
2823                                   0,                 /* in_additional_info */
2824                                   ph->fid_persistent, ph->fid_volatile);
2825 cleanup:
2826
2827         cli->raw_status = status;
2828
2829         TALLOC_FREE(frame);
2830
2831         return status;
2832 }
2833
2834 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
2835                                     int quota_fnum,
2836                                     SMB_NTQUOTA_STRUCT *pqt)
2837 {
2838         NTSTATUS status;
2839         DATA_BLOB inbuf = data_blob_null;
2840         struct smb2_hnd *ph = NULL;
2841         TALLOC_CTX *frame = talloc_stackframe();
2842
2843         if (smbXcli_conn_has_async_calls(cli->conn)) {
2844                 /*
2845                  * Can't use sync call while an async call is in flight
2846                  */
2847                 status = NT_STATUS_INVALID_PARAMETER;
2848                 goto cleanup;
2849         }
2850
2851         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2852                 status = NT_STATUS_INVALID_PARAMETER;
2853                 goto cleanup;
2854         }
2855
2856         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2857         if (!NT_STATUS_IS_OK(status)) {
2858                 goto cleanup;
2859         }
2860
2861         status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
2862         if (!NT_STATUS_IS_OK(status)) {
2863                 goto cleanup;
2864         }
2865
2866         status = smb2cli_set_info(
2867             cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
2868             2,                               /* in_info_type */
2869             SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
2870             &inbuf,                          /* in_input_buffer */
2871             0,                               /* in_additional_info */
2872             ph->fid_persistent, ph->fid_volatile);
2873 cleanup:
2874         cli->raw_status = status;
2875
2876         TALLOC_FREE(frame);
2877         return status;
2878 }
2879
2880 struct cli_smb2_read_state {
2881         struct tevent_context *ev;
2882         struct cli_state *cli;
2883         struct smb2_hnd *ph;
2884         uint64_t start_offset;
2885         uint32_t size;
2886         uint32_t received;
2887         uint8_t *buf;
2888 };
2889
2890 static void cli_smb2_read_done(struct tevent_req *subreq);
2891
2892 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
2893                                 struct tevent_context *ev,
2894                                 struct cli_state *cli,
2895                                 uint16_t fnum,
2896                                 off_t offset,
2897                                 size_t size)
2898 {
2899         NTSTATUS status;
2900         struct tevent_req *req, *subreq;
2901         struct cli_smb2_read_state *state;
2902
2903         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
2904         if (req == NULL) {
2905                 return NULL;
2906         }
2907         state->ev = ev;
2908         state->cli = cli;
2909         state->start_offset = (uint64_t)offset;
2910         state->size = (uint32_t)size;
2911         state->received = 0;
2912         state->buf = NULL;
2913
2914         status = map_fnum_to_smb2_handle(cli,
2915                                         fnum,
2916                                         &state->ph);
2917         if (tevent_req_nterror(req, status)) {
2918                 return tevent_req_post(req, ev);
2919         }
2920
2921         subreq = smb2cli_read_send(state,
2922                                 state->ev,
2923                                 state->cli->conn,
2924                                 state->cli->timeout,
2925                                 state->cli->smb2.session,
2926                                 state->cli->smb2.tcon,
2927                                 state->size,
2928                                 state->start_offset,
2929                                 state->ph->fid_persistent,
2930                                 state->ph->fid_volatile,
2931                                 0, /* minimum_count */
2932                                 0); /* remaining_bytes */
2933
2934         if (tevent_req_nomem(subreq, req)) {
2935                 return tevent_req_post(req, ev);
2936         }
2937         tevent_req_set_callback(subreq, cli_smb2_read_done, req);
2938         return req;
2939 }
2940
2941 static void cli_smb2_read_done(struct tevent_req *subreq)
2942 {
2943         struct tevent_req *req = tevent_req_callback_data(
2944                 subreq, struct tevent_req);
2945         struct cli_smb2_read_state *state = tevent_req_data(
2946                 req, struct cli_smb2_read_state);
2947         NTSTATUS status;
2948
2949         status = smb2cli_read_recv(subreq, state,
2950                                    &state->buf, &state->received);
2951         if (tevent_req_nterror(req, status)) {
2952                 return;
2953         }
2954
2955         if (state->received > state->size) {
2956                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2957                 return;
2958         }
2959
2960         tevent_req_done(req);
2961 }
2962
2963 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
2964                                 ssize_t *received,
2965                                 uint8_t **rcvbuf)
2966 {
2967         NTSTATUS status;
2968         struct cli_smb2_read_state *state = tevent_req_data(
2969                                 req, struct cli_smb2_read_state);
2970
2971         if (tevent_req_is_nterror(req, &status)) {
2972                 state->cli->raw_status = status;
2973                 return status;
2974         }
2975         /*
2976          * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2977          * better make sure that you copy it away before you talloc_free(req).
2978          * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2979          */
2980         *received = (ssize_t)state->received;
2981         *rcvbuf = state->buf;
2982         state->cli->raw_status = NT_STATUS_OK;
2983         return NT_STATUS_OK;
2984 }
2985
2986 struct cli_smb2_write_state {
2987         struct tevent_context *ev;
2988         struct cli_state *cli;
2989         struct smb2_hnd *ph;
2990         uint32_t flags;
2991         const uint8_t *buf;
2992         uint64_t offset;
2993         uint32_t size;
2994         uint32_t written;
2995 };
2996
2997 static void cli_smb2_write_written(struct tevent_req *req);
2998
2999 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
3000                                         struct tevent_context *ev,
3001                                         struct cli_state *cli,
3002                                         uint16_t fnum,
3003                                         uint16_t mode,
3004                                         const uint8_t *buf,
3005                                         off_t offset,
3006                                         size_t size)
3007 {
3008         NTSTATUS status;
3009         struct tevent_req *req, *subreq = NULL;
3010         struct cli_smb2_write_state *state = NULL;
3011
3012         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
3013         if (req == NULL) {
3014                 return NULL;
3015         }
3016         state->ev = ev;
3017         state->cli = cli;
3018         /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3019         state->flags = (uint32_t)mode;
3020         state->buf = buf;
3021         state->offset = (uint64_t)offset;
3022         state->size = (uint32_t)size;
3023         state->written = 0;
3024
3025         status = map_fnum_to_smb2_handle(cli,
3026                                         fnum,
3027                                         &state->ph);
3028         if (tevent_req_nterror(req, status)) {
3029                 return tevent_req_post(req, ev);
3030         }
3031
3032         subreq = smb2cli_write_send(state,
3033                                 state->ev,
3034                                 state->cli->conn,
3035                                 state->cli->timeout,
3036                                 state->cli->smb2.session,
3037                                 state->cli->smb2.tcon,
3038                                 state->size,
3039                                 state->offset,
3040                                 state->ph->fid_persistent,
3041                                 state->ph->fid_volatile,
3042                                 0, /* remaining_bytes */
3043                                 state->flags, /* flags */
3044                                 state->buf);
3045
3046         if (tevent_req_nomem(subreq, req)) {
3047                 return tevent_req_post(req, ev);
3048         }
3049         tevent_req_set_callback(subreq, cli_smb2_write_written, req);
3050         return req;
3051 }
3052
3053 static void cli_smb2_write_written(struct tevent_req *subreq)
3054 {
3055         struct tevent_req *req = tevent_req_callback_data(
3056                 subreq, struct tevent_req);
3057         struct cli_smb2_write_state *state = tevent_req_data(
3058                 req, struct cli_smb2_write_state);
3059         NTSTATUS status;
3060         uint32_t written;
3061
3062         status = smb2cli_write_recv(subreq, &written);
3063         TALLOC_FREE(subreq);
3064         if (tevent_req_nterror(req, status)) {
3065                 return;
3066         }
3067
3068         state->written = written;
3069
3070         tevent_req_done(req);
3071 }
3072
3073 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
3074                              size_t *pwritten)
3075 {
3076         struct cli_smb2_write_state *state = tevent_req_data(
3077                 req, struct cli_smb2_write_state);
3078         NTSTATUS status;
3079
3080         if (tevent_req_is_nterror(req, &status)) {
3081                 state->cli->raw_status = status;
3082                 tevent_req_received(req);
3083                 return status;
3084         }
3085
3086         if (pwritten != NULL) {
3087                 *pwritten = (size_t)state->written;
3088         }
3089         state->cli->raw_status = NT_STATUS_OK;
3090         tevent_req_received(req);
3091         return NT_STATUS_OK;
3092 }
3093
3094 /***************************************************************
3095  Wrapper that allows SMB2 async write using an fnum.
3096  This is mostly cut-and-paste from Volker's code inside
3097  source3/libsmb/clireadwrite.c, adapted for SMB2.
3098
3099  Done this way so I can reuse all the logic inside cli_push()
3100  for free :-).
3101 ***************************************************************/
3102
3103 struct cli_smb2_writeall_state {
3104         struct tevent_context *ev;
3105         struct cli_state *cli;
3106         struct smb2_hnd *ph;
3107         uint32_t flags;
3108         const uint8_t *buf;
3109         uint64_t offset;
3110         uint32_t size;
3111         uint32_t written;
3112 };
3113
3114 static void cli_smb2_writeall_written(struct tevent_req *req);
3115
3116 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
3117                                         struct tevent_context *ev,
3118                                         struct cli_state *cli,
3119                                         uint16_t fnum,
3120                                         uint16_t mode,
3121                                         const uint8_t *buf,
3122                                         off_t offset,
3123                                         size_t size)
3124 {
3125         NTSTATUS status;
3126         struct tevent_req *req, *subreq = NULL;
3127         struct cli_smb2_writeall_state *state = NULL;
3128         uint32_t to_write;
3129         uint32_t max_size;
3130         bool ok;
3131
3132         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
3133         if (req == NULL) {
3134                 return NULL;
3135         }
3136         state->ev = ev;
3137         state->cli = cli;
3138         /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3139         state->flags = (uint32_t)mode;
3140         state->buf = buf;
3141         state->offset = (uint64_t)offset;
3142         state->size = (uint32_t)size;
3143         state->written = 0;
3144
3145         status = map_fnum_to_smb2_handle(cli,
3146                                         fnum,
3147                                         &state->ph);
3148         if (tevent_req_nterror(req, status)) {
3149                 return tevent_req_post(req, ev);
3150         }
3151
3152         to_write = state->size;
3153         max_size = smb2cli_conn_max_write_size(state->cli->conn);
3154         to_write = MIN(max_size, to_write);
3155         ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3156         if (ok) {
3157                 to_write = MIN(max_size, to_write);
3158         }
3159
3160  &nb