s3:libsmb: pass impersonation_level to cli_smb2_create_fnum_send()
[garming/samba-autobuild/.git] / source3 / libsmb / cli_smb2_fnum.c
1 /*
2    Unix SMB/CIFS implementation.
3    smb2 lib
4    Copyright (C) Jeremy Allison 2013
5    Copyright (C) Volker Lendecke 2013
6    Copyright (C) Stefan Metzmacher 2013
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /*
23  This code is a thin wrapper around the existing
24  cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c,
25  but allows the handles to be mapped to uint16_t fnums,
26  which are easier for smbclient to use.
27 */
28
29 #include "includes.h"
30 #include "client.h"
31 #include "async_smb.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "cli_smb2_fnum.h"
34 #include "trans2.h"
35 #include "clirap.h"
36 #include "../libcli/smb/smb2_create_blob.h"
37 #include "libsmb/proto.h"
38 #include "lib/util/tevent_ntstatus.h"
39 #include "../libcli/security/security.h"
40 #include "../librpc/gen_ndr/ndr_security.h"
41 #include "lib/util_ea.h"
42 #include "librpc/gen_ndr/ndr_ioctl.h"
43 #include "ntioctl.h"
44 #include "librpc/gen_ndr/ndr_quota.h"
45
46 struct smb2_hnd {
47         uint64_t fid_persistent;
48         uint64_t fid_volatile;
49 };
50
51 /*
52  * Handle mapping code.
53  */
54
55 /***************************************************************
56  Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
57  Ensures handle is owned by cli struct.
58 ***************************************************************/
59
60 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
61                                 const struct smb2_hnd *ph,      /* In */
62                                 uint16_t *pfnum)                /* Out */
63 {
64         int ret;
65         struct idr_context *idp = cli->smb2.open_handles;
66         struct smb2_hnd *owned_h = talloc_memdup(cli,
67                                                 ph,
68                                                 sizeof(struct smb2_hnd));
69
70         if (owned_h == NULL) {
71                 return NT_STATUS_NO_MEMORY;
72         }
73
74         if (idp == NULL) {
75                 /* Lazy init */
76                 cli->smb2.open_handles = idr_init(cli);
77                 if (cli->smb2.open_handles == NULL) {
78                         TALLOC_FREE(owned_h);
79                         return NT_STATUS_NO_MEMORY;
80                 }
81                 idp = cli->smb2.open_handles;
82         }
83
84         ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
85         if (ret == -1) {
86                 TALLOC_FREE(owned_h);
87                 return NT_STATUS_NO_MEMORY;
88         }
89
90         *pfnum = (uint16_t)ret;
91         return NT_STATUS_OK;
92 }
93
94 /***************************************************************
95  Return the smb2_hnd pointer associated with the given fnum.
96 ***************************************************************/
97
98 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
99                                 uint16_t fnum,          /* In */
100                                 struct smb2_hnd **pph)  /* Out */
101 {
102         struct idr_context *idp = cli->smb2.open_handles;
103
104         if (idp == NULL) {
105                 return NT_STATUS_INVALID_PARAMETER;
106         }
107         *pph = (struct smb2_hnd *)idr_find(idp, fnum);
108         if (*pph == NULL) {
109                 return NT_STATUS_INVALID_HANDLE;
110         }
111         return NT_STATUS_OK;
112 }
113
114 /***************************************************************
115  Delete the fnum to smb2_hnd mapping. Zeros out handle on
116  successful return.
117 ***************************************************************/
118
119 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
120                                 struct smb2_hnd **pph,  /* In */
121                                 uint16_t fnum)                  /* In */
122 {
123         struct idr_context *idp = cli->smb2.open_handles;
124         struct smb2_hnd *ph;
125
126         if (idp == NULL) {
127                 return NT_STATUS_INVALID_PARAMETER;
128         }
129
130         ph = (struct smb2_hnd *)idr_find(idp, fnum);
131         if (ph != *pph) {
132                 return NT_STATUS_INVALID_PARAMETER;
133         }
134         idr_remove(idp, fnum);
135         TALLOC_FREE(*pph);
136         return NT_STATUS_OK;
137 }
138
139 /***************************************************************
140  Oplock mapping code.
141 ***************************************************************/
142
143 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
144 {
145         if (create_flags & REQUEST_BATCH_OPLOCK) {
146                 return SMB2_OPLOCK_LEVEL_BATCH;
147         } else if (create_flags & REQUEST_OPLOCK) {
148                 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
149         }
150
151         /* create_flags doesn't do a level2 request. */
152         return SMB2_OPLOCK_LEVEL_NONE;
153 }
154
155 /***************************************************************
156  Small wrapper that allows SMB2 create to return a uint16_t fnum.
157 ***************************************************************/
158
159 struct cli_smb2_create_fnum_state {
160         struct cli_state *cli;
161         struct smb_create_returns cr;
162         uint16_t fnum;
163         struct tevent_req *subreq;
164 };
165
166 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
167 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
168
169 struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
170                                              struct tevent_context *ev,
171                                              struct cli_state *cli,
172                                              const char *fname,
173                                              uint32_t create_flags,
174                                              uint32_t impersonation_level,
175                                              uint32_t desired_access,
176                                              uint32_t file_attributes,
177                                              uint32_t share_access,
178                                              uint32_t create_disposition,
179                                              uint32_t create_options)
180 {
181         struct tevent_req *req, *subreq;
182         struct cli_smb2_create_fnum_state *state;
183         size_t fname_len = 0;
184         const char *startp = NULL;
185         const char *endp = NULL;
186         time_t tstamp = (time_t)0;
187         struct smb2_create_blobs *cblobs = NULL;
188
189         req = tevent_req_create(mem_ctx, &state,
190                                 struct cli_smb2_create_fnum_state);
191         if (req == NULL) {
192                 return NULL;
193         }
194         state->cli = cli;
195
196         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
197                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
198                 return tevent_req_post(req, ev);
199         }
200
201         if (cli->backup_intent) {
202                 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
203         }
204
205         /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
206         fname_len = strlen(fname);
207         if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
208                 size_t len_before_gmt = startp - fname;
209                 size_t len_after_gmt = fname + fname_len - endp;
210                 DATA_BLOB twrp_blob;
211                 NTTIME ntt;
212                 NTSTATUS status;
213
214                 char *new_fname = talloc_array(state, char,
215                                 len_before_gmt + len_after_gmt + 1);
216
217                 if (tevent_req_nomem(new_fname, req)) {
218                         return tevent_req_post(req, ev);
219                 }
220
221                 memcpy(new_fname, fname, len_before_gmt);
222                 memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
223                 fname = new_fname;
224                 fname_len = len_before_gmt + len_after_gmt;
225
226                 unix_to_nt_time(&ntt, tstamp);
227                 twrp_blob = data_blob_const((const void *)&ntt, 8);
228
229                 cblobs = talloc_zero(state, struct smb2_create_blobs);
230                 if (tevent_req_nomem(cblobs, req)) {
231                         return tevent_req_post(req, ev);
232                 }
233
234                 status = smb2_create_blob_add(state, cblobs,
235                                 SMB2_CREATE_TAG_TWRP, twrp_blob);
236                 if (!NT_STATUS_IS_OK(status)) {
237                         tevent_req_nterror(req, status);
238                         return tevent_req_post(req, ev);
239                 }
240         }
241
242         /* SMB2 is pickier about pathnames. Ensure it doesn't
243            start in a '\' */
244         if (*fname == '\\') {
245                 fname++;
246                 fname_len--;
247         }
248
249         /* Or end in a '\' */
250         if (fname_len > 0 && fname[fname_len-1] == '\\') {
251                 char *new_fname = talloc_strdup(state, fname);
252                 if (tevent_req_nomem(new_fname, req)) {
253                         return tevent_req_post(req, ev);
254                 }
255                 new_fname[fname_len-1] = '\0';
256                 fname = new_fname;
257         }
258
259         subreq = smb2cli_create_send(state, ev,
260                                      cli->conn,
261                                      cli->timeout,
262                                      cli->smb2.session,
263                                      cli->smb2.tcon,
264                                      fname,
265                                      flags_to_smb2_oplock(create_flags),
266                                      impersonation_level,
267                                      desired_access,
268                                      file_attributes,
269                                      share_access,
270                                      create_disposition,
271                                      create_options,
272                                      cblobs);
273         if (tevent_req_nomem(subreq, req)) {
274                 return tevent_req_post(req, ev);
275         }
276         tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
277
278         state->subreq = subreq;
279         tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
280
281         return req;
282 }
283
284 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
285 {
286         struct tevent_req *req = tevent_req_callback_data(
287                 subreq, struct tevent_req);
288         struct cli_smb2_create_fnum_state *state = tevent_req_data(
289                 req, struct cli_smb2_create_fnum_state);
290         struct smb2_hnd h;
291         NTSTATUS status;
292
293         status = smb2cli_create_recv(subreq, &h.fid_persistent,
294                                      &h.fid_volatile, &state->cr, NULL, NULL);
295         TALLOC_FREE(subreq);
296         if (tevent_req_nterror(req, status)) {
297                 return;
298         }
299
300         status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
301         if (tevent_req_nterror(req, status)) {
302                 return;
303         }
304         tevent_req_done(req);
305 }
306
307 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
308 {
309         struct cli_smb2_create_fnum_state *state = tevent_req_data(
310                 req, struct cli_smb2_create_fnum_state);
311         return tevent_req_cancel(state->subreq);
312 }
313
314 NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum,
315                                    struct smb_create_returns *cr)
316 {
317         struct cli_smb2_create_fnum_state *state = tevent_req_data(
318                 req, struct cli_smb2_create_fnum_state);
319         NTSTATUS status;
320
321         if (tevent_req_is_nterror(req, &status)) {
322                 state->cli->raw_status = status;
323                 return status;
324         }
325         if (pfnum != NULL) {
326                 *pfnum = state->fnum;
327         }
328         if (cr != NULL) {
329                 *cr = state->cr;
330         }
331         state->cli->raw_status = NT_STATUS_OK;
332         return NT_STATUS_OK;
333 }
334
335 NTSTATUS cli_smb2_create_fnum(struct cli_state *cli,
336                         const char *fname,
337                         uint32_t create_flags,
338                         uint32_t desired_access,
339                         uint32_t file_attributes,
340                         uint32_t share_access,
341                         uint32_t create_disposition,
342                         uint32_t create_options,
343                         uint16_t *pfid,
344                         struct smb_create_returns *cr)
345 {
346         TALLOC_CTX *frame = talloc_stackframe();
347         struct tevent_context *ev;
348         struct tevent_req *req;
349         uint32_t impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
350         NTSTATUS status = NT_STATUS_NO_MEMORY;
351
352         if (smbXcli_conn_has_async_calls(cli->conn)) {
353                 /*
354                  * Can't use sync call while an async call is in flight
355                  */
356                 status = NT_STATUS_INVALID_PARAMETER;
357                 goto fail;
358         }
359         ev = samba_tevent_context_init(frame);
360         if (ev == NULL) {
361                 goto fail;
362         }
363         req = cli_smb2_create_fnum_send(frame, ev, cli, fname, create_flags,
364                                         impersonation_level,
365                                         desired_access, file_attributes,
366                                         share_access, create_disposition,
367                                         create_options);
368         if (req == NULL) {
369                 goto fail;
370         }
371         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
372                 goto fail;
373         }
374         status = cli_smb2_create_fnum_recv(req, pfid, cr);
375  fail:
376         TALLOC_FREE(frame);
377         return status;
378 }
379
380 /***************************************************************
381  Small wrapper that allows SMB2 close to use a uint16_t fnum.
382 ***************************************************************/
383
384 struct cli_smb2_close_fnum_state {
385         struct cli_state *cli;
386         uint16_t fnum;
387         struct smb2_hnd *ph;
388 };
389
390 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
391
392 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
393                                             struct tevent_context *ev,
394                                             struct cli_state *cli,
395                                             uint16_t fnum)
396 {
397         struct tevent_req *req, *subreq;
398         struct cli_smb2_close_fnum_state *state;
399         NTSTATUS status;
400
401         req = tevent_req_create(mem_ctx, &state,
402                                 struct cli_smb2_close_fnum_state);
403         if (req == NULL) {
404                 return NULL;
405         }
406         state->cli = cli;
407         state->fnum = fnum;
408
409         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
410                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
411                 return tevent_req_post(req, ev);
412         }
413
414         status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
415         if (tevent_req_nterror(req, status)) {
416                 return tevent_req_post(req, ev);
417         }
418
419         subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
420                                     cli->smb2.session, cli->smb2.tcon,
421                                     0, state->ph->fid_persistent,
422                                     state->ph->fid_volatile);
423         if (tevent_req_nomem(subreq, req)) {
424                 return tevent_req_post(req, ev);
425         }
426         tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
427         return req;
428 }
429
430 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
431 {
432         struct tevent_req *req = tevent_req_callback_data(
433                 subreq, struct tevent_req);
434         struct cli_smb2_close_fnum_state *state = tevent_req_data(
435                 req, struct cli_smb2_close_fnum_state);
436         NTSTATUS status;
437
438         status = smb2cli_close_recv(subreq);
439         if (tevent_req_nterror(req, status)) {
440                 return;
441         }
442
443         /* Delete the fnum -> handle mapping. */
444         status = delete_smb2_handle_mapping(state->cli, &state->ph,
445                                             state->fnum);
446         if (tevent_req_nterror(req, status)) {
447                 return;
448         }
449         tevent_req_done(req);
450 }
451
452 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
453 {
454         struct cli_smb2_close_fnum_state *state = tevent_req_data(
455                 req, struct cli_smb2_close_fnum_state);
456         NTSTATUS status = NT_STATUS_OK;
457
458         if (tevent_req_is_nterror(req, &status)) {
459                 state->cli->raw_status = status;
460         }
461         tevent_req_received(req);
462         return status;
463 }
464
465 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
466 {
467         TALLOC_CTX *frame = talloc_stackframe();
468         struct tevent_context *ev;
469         struct tevent_req *req;
470         NTSTATUS status = NT_STATUS_NO_MEMORY;
471
472         if (smbXcli_conn_has_async_calls(cli->conn)) {
473                 /*
474                  * Can't use sync call while an async call is in flight
475                  */
476                 status = NT_STATUS_INVALID_PARAMETER;
477                 goto fail;
478         }
479         ev = samba_tevent_context_init(frame);
480         if (ev == NULL) {
481                 goto fail;
482         }
483         req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
484         if (req == NULL) {
485                 goto fail;
486         }
487         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
488                 goto fail;
489         }
490         status = cli_smb2_close_fnum_recv(req);
491  fail:
492         TALLOC_FREE(frame);
493         return status;
494 }
495
496 struct cli_smb2_delete_on_close_state {
497         struct cli_state *cli;
498         uint16_t fnum;
499         struct smb2_hnd *ph;
500         uint8_t data[1];
501         DATA_BLOB inbuf;
502 };
503
504 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
505
506 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
507                                         struct tevent_context *ev,
508                                         struct cli_state *cli,
509                                         uint16_t fnum,
510                                         bool flag)
511 {
512         struct tevent_req *req = NULL;
513         struct cli_smb2_delete_on_close_state *state = NULL;
514         struct tevent_req *subreq = NULL;
515         uint8_t in_info_type;
516         uint8_t in_file_info_class;
517         NTSTATUS status;
518
519         req = tevent_req_create(mem_ctx, &state,
520                                 struct cli_smb2_delete_on_close_state);
521         if (req == NULL) {
522                 return NULL;
523         }
524         state->cli = cli;
525         state->fnum = fnum;
526
527         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
528                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
529                 return tevent_req_post(req, ev);
530         }
531
532         status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
533         if (tevent_req_nterror(req, status)) {
534                 return tevent_req_post(req, ev);
535         }
536
537         /*
538          * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
539          * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
540          */
541         in_info_type = 1;
542         in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
543         /* Setup data array. */
544         SCVAL(&state->data[0], 0, flag ? 1 : 0);
545         state->inbuf.data = &state->data[0];
546         state->inbuf.length = 1;
547
548         subreq = smb2cli_set_info_send(state, ev,
549                                        cli->conn,
550                                        cli->timeout,
551                                        cli->smb2.session,
552                                        cli->smb2.tcon,
553                                        in_info_type,
554                                        in_file_info_class,
555                                        &state->inbuf, /* in_input_buffer */
556                                        0, /* in_additional_info */
557                                        state->ph->fid_persistent,
558                                        state->ph->fid_volatile);
559         if (tevent_req_nomem(subreq, req)) {
560                 return tevent_req_post(req, ev);
561         }
562         tevent_req_set_callback(subreq,
563                                 cli_smb2_delete_on_close_done,
564                                 req);
565         return req;
566 }
567
568 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
569 {
570         NTSTATUS status = smb2cli_set_info_recv(subreq);
571         tevent_req_simple_finish_ntstatus(subreq, status);
572 }
573
574 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
575 {
576         struct cli_smb2_delete_on_close_state *state =
577                 tevent_req_data(req,
578                 struct cli_smb2_delete_on_close_state);
579         NTSTATUS status;
580
581         if (tevent_req_is_nterror(req, &status)) {
582                 state->cli->raw_status = status;
583                 tevent_req_received(req);
584                 return status;
585         }
586
587         state->cli->raw_status = NT_STATUS_OK;
588         tevent_req_received(req);
589         return NT_STATUS_OK;
590 }
591
592 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
593 {
594         TALLOC_CTX *frame = talloc_stackframe();
595         struct tevent_context *ev;
596         struct tevent_req *req;
597         NTSTATUS status = NT_STATUS_NO_MEMORY;
598
599         if (smbXcli_conn_has_async_calls(cli->conn)) {
600                 /*
601                  * Can't use sync call while an async call is in flight
602                  */
603                 status = NT_STATUS_INVALID_PARAMETER;
604                 goto fail;
605         }
606         ev = samba_tevent_context_init(frame);
607         if (ev == NULL) {
608                 goto fail;
609         }
610         req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
611         if (req == NULL) {
612                 goto fail;
613         }
614         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
615                 goto fail;
616         }
617         status = cli_smb2_delete_on_close_recv(req);
618  fail:
619         TALLOC_FREE(frame);
620         return status;
621 }
622
623 /***************************************************************
624  Small wrapper that allows SMB2 to create a directory
625  Synchronous only.
626 ***************************************************************/
627
628 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
629 {
630         NTSTATUS status;
631         uint16_t fnum;
632
633         if (smbXcli_conn_has_async_calls(cli->conn)) {
634                 /*
635                  * Can't use sync call while an async call is in flight
636                  */
637                 return NT_STATUS_INVALID_PARAMETER;
638         }
639
640         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
641                 return NT_STATUS_INVALID_PARAMETER;
642         }
643
644         status = cli_smb2_create_fnum(cli,
645                         dname,
646                         0,                      /* create_flags */
647                         FILE_READ_ATTRIBUTES,   /* desired_access */
648                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
649                         FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
650                         FILE_CREATE,            /* create_disposition */
651                         FILE_DIRECTORY_FILE,    /* create_options */
652                         &fnum,
653                         NULL);
654
655         if (!NT_STATUS_IS_OK(status)) {
656                 return status;
657         }
658         return cli_smb2_close_fnum(cli, fnum);
659 }
660
661 /***************************************************************
662  Small wrapper that allows SMB2 to delete a directory
663  Synchronous only.
664 ***************************************************************/
665
666 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
667 {
668         NTSTATUS status;
669         uint16_t fnum;
670
671         if (smbXcli_conn_has_async_calls(cli->conn)) {
672                 /*
673                  * Can't use sync call while an async call is in flight
674                  */
675                 return NT_STATUS_INVALID_PARAMETER;
676         }
677
678         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
679                 return NT_STATUS_INVALID_PARAMETER;
680         }
681
682         status = cli_smb2_create_fnum(cli,
683                         dname,
684                         0,                      /* create_flags */
685                         DELETE_ACCESS,          /* desired_access */
686                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
687                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
688                         FILE_OPEN,              /* create_disposition */
689                         FILE_DIRECTORY_FILE,    /* create_options */
690                         &fnum,
691                         NULL);
692
693         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
694                 /*
695                  * Naive option to match our SMB1 code. Assume the
696                  * symlink path that tripped us up was the last
697                  * component and try again. Eventually we will have to
698                  * deal with the returned path unprocessed component. JRA.
699                  */
700                 status = cli_smb2_create_fnum(cli,
701                         dname,
702                         0,                      /* create_flags */
703                         DELETE_ACCESS,          /* desired_access */
704                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
705                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
706                         FILE_OPEN,              /* create_disposition */
707                         FILE_DIRECTORY_FILE|
708                                 FILE_DELETE_ON_CLOSE|
709                                 FILE_OPEN_REPARSE_POINT, /* create_options */
710                         &fnum,
711                         NULL);
712         }
713
714         if (!NT_STATUS_IS_OK(status)) {
715                 return status;
716         }
717
718         status = cli_smb2_delete_on_close(cli, fnum, true);
719         if (!NT_STATUS_IS_OK(status)) {
720                 cli_smb2_close_fnum(cli, fnum);
721                 return status;
722         }
723
724         return cli_smb2_close_fnum(cli, fnum);
725 }
726
727 /***************************************************************
728  Small wrapper that allows SMB2 to unlink a pathname.
729  Synchronous only.
730 ***************************************************************/
731
732 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
733 {
734         NTSTATUS status;
735         uint16_t fnum;
736
737         if (smbXcli_conn_has_async_calls(cli->conn)) {
738                 /*
739                  * Can't use sync call while an async call is in flight
740                  */
741                 return NT_STATUS_INVALID_PARAMETER;
742         }
743
744         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
745                 return NT_STATUS_INVALID_PARAMETER;
746         }
747
748         status = cli_smb2_create_fnum(cli,
749                         fname,
750                         0,                      /* create_flags */
751                         DELETE_ACCESS,          /* desired_access */
752                         FILE_ATTRIBUTE_NORMAL, /* file attributes */
753                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
754                         FILE_OPEN,              /* create_disposition */
755                         FILE_DELETE_ON_CLOSE,   /* create_options */
756                         &fnum,
757                         NULL);
758
759         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
760                 /*
761                  * Naive option to match our SMB1 code. Assume the
762                  * symlink path that tripped us up was the last
763                  * component and try again. Eventually we will have to
764                  * deal with the returned path unprocessed component. JRA.
765                  */
766                 status = cli_smb2_create_fnum(cli,
767                         fname,
768                         0,                      /* create_flags */
769                         DELETE_ACCESS,          /* desired_access */
770                         FILE_ATTRIBUTE_NORMAL, /* file attributes */
771                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
772                         FILE_OPEN,              /* create_disposition */
773                         FILE_DELETE_ON_CLOSE|
774                                 FILE_OPEN_REPARSE_POINT, /* create_options */
775                         &fnum,
776                         NULL);
777         }
778
779         if (!NT_STATUS_IS_OK(status)) {
780                 return status;
781         }
782         return cli_smb2_close_fnum(cli, fnum);
783 }
784
785 /***************************************************************
786  Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
787 ***************************************************************/
788
789 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
790                                 uint32_t dir_data_length,
791                                 struct file_info *finfo,
792                                 uint32_t *next_offset)
793 {
794         size_t namelen = 0;
795         size_t slen = 0;
796         size_t ret = 0;
797
798         if (dir_data_length < 4) {
799                 return NT_STATUS_INFO_LENGTH_MISMATCH;
800         }
801
802         *next_offset = IVAL(dir_data, 0);
803
804         if (*next_offset > dir_data_length) {
805                 return NT_STATUS_INFO_LENGTH_MISMATCH;
806         }
807
808         if (*next_offset != 0) {
809                 /* Ensure we only read what in this record. */
810                 dir_data_length = *next_offset;
811         }
812
813         if (dir_data_length < 105) {
814                 return NT_STATUS_INFO_LENGTH_MISMATCH;
815         }
816
817         finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
818         finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
819         finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
820         finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
821         finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
822         finfo->mode = CVAL(dir_data + 56, 0);
823         namelen = IVAL(dir_data + 60,0);
824         if (namelen > (dir_data_length - 104)) {
825                 return NT_STATUS_INFO_LENGTH_MISMATCH;
826         }
827         slen = CVAL(dir_data + 68, 0);
828         if (slen > 24) {
829                 return NT_STATUS_INFO_LENGTH_MISMATCH;
830         }
831         ret = pull_string_talloc(finfo,
832                                 dir_data,
833                                 FLAGS2_UNICODE_STRINGS,
834                                 &finfo->short_name,
835                                 dir_data + 70,
836                                 slen,
837                                 STR_UNICODE);
838         if (ret == (size_t)-1) {
839                 /* Bad conversion. */
840                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
841         }
842
843         ret = pull_string_talloc(finfo,
844                                 dir_data,
845                                 FLAGS2_UNICODE_STRINGS,
846                                 &finfo->name,
847                                 dir_data + 104,
848                                 namelen,
849                                 STR_UNICODE);
850         if (ret == (size_t)-1) {
851                 /* Bad conversion. */
852                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
853         }
854         return NT_STATUS_OK;
855 }
856
857 /*******************************************************************
858  Given a filename - get its directory name
859 ********************************************************************/
860
861 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
862                                 const char *dir,
863                                 char **parent,
864                                 const char **name)
865 {
866         char *p;
867         ptrdiff_t len;
868
869         p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
870
871         if (p == NULL) {
872                 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
873                         return false;
874                 }
875                 if (name) {
876                         *name = dir;
877                 }
878                 return true;
879         }
880
881         len = p-dir;
882
883         if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
884                 return false;
885         }
886         (*parent)[len] = '\0';
887
888         if (name) {
889                 *name = p+1;
890         }
891         return true;
892 }
893
894 /***************************************************************
895  Wrapper that allows SMB2 to list a directory.
896  Synchronous only.
897 ***************************************************************/
898
899 NTSTATUS cli_smb2_list(struct cli_state *cli,
900                         const char *pathname,
901                         uint16_t attribute,
902                         NTSTATUS (*fn)(const char *,
903                                 struct file_info *,
904                                 const char *,
905                                 void *),
906                         void *state)
907 {
908         NTSTATUS status;
909         uint16_t fnum = 0xffff;
910         char *parent_dir = NULL;
911         const char *mask = NULL;
912         struct smb2_hnd *ph = NULL;
913         bool processed_file = false;
914         TALLOC_CTX *frame = talloc_stackframe();
915         TALLOC_CTX *subframe = NULL;
916         bool mask_has_wild;
917         uint32_t max_trans = smb2cli_conn_max_trans_size(cli->conn);
918
919         if (smbXcli_conn_has_async_calls(cli->conn)) {
920                 /*
921                  * Can't use sync call while an async call is in flight
922                  */
923                 status = NT_STATUS_INVALID_PARAMETER;
924                 goto fail;
925         }
926
927         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
928                 status = NT_STATUS_INVALID_PARAMETER;
929                 goto fail;
930         }
931
932         /* Get the directory name. */
933         if (!windows_parent_dirname(frame,
934                                 pathname,
935                                 &parent_dir,
936                                 &mask)) {
937                 status = NT_STATUS_NO_MEMORY;
938                 goto fail;
939         }
940
941         mask_has_wild = ms_has_wild(mask);
942
943         status = cli_smb2_create_fnum(cli,
944                         parent_dir,
945                         0,                      /* create_flags */
946                         SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
947                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
948                         FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
949                         FILE_OPEN,              /* create_disposition */
950                         FILE_DIRECTORY_FILE,    /* create_options */
951                         &fnum,
952                         NULL);
953
954         if (!NT_STATUS_IS_OK(status)) {
955                 goto fail;
956         }
957
958         status = map_fnum_to_smb2_handle(cli,
959                                         fnum,
960                                         &ph);
961         if (!NT_STATUS_IS_OK(status)) {
962                 goto fail;
963         }
964
965         do {
966                 uint8_t *dir_data = NULL;
967                 uint32_t dir_data_length = 0;
968                 uint32_t next_offset = 0;
969                 subframe = talloc_stackframe();
970
971                 status = smb2cli_query_directory(cli->conn,
972                                         cli->timeout,
973                                         cli->smb2.session,
974                                         cli->smb2.tcon,
975                                         SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
976                                         0,      /* flags */
977                                         0,      /* file_index */
978                                         ph->fid_persistent,
979                                         ph->fid_volatile,
980                                         mask,
981                                         max_trans,
982                                         subframe,
983                                         &dir_data,
984                                         &dir_data_length);
985
986                 if (!NT_STATUS_IS_OK(status)) {
987                         if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
988                                 break;
989                         }
990                         goto fail;
991                 }
992
993                 do {
994                         struct file_info *finfo = talloc_zero(subframe,
995                                                         struct file_info);
996
997                         if (finfo == NULL) {
998                                 status = NT_STATUS_NO_MEMORY;
999                                 goto fail;
1000                         }
1001
1002                         status = parse_finfo_id_both_directory_info(dir_data,
1003                                                 dir_data_length,
1004                                                 finfo,
1005                                                 &next_offset);
1006
1007                         if (!NT_STATUS_IS_OK(status)) {
1008                                 goto fail;
1009                         }
1010
1011                         if (dir_check_ftype((uint32_t)finfo->mode,
1012                                         (uint32_t)attribute)) {
1013                                 /*
1014                                  * Only process if attributes match.
1015                                  * On SMB1 server does this, so on
1016                                  * SMB2 we need to emulate in the
1017                                  * client.
1018                                  *
1019                                  * https://bugzilla.samba.org/show_bug.cgi?id=10260
1020                                  */
1021                                 processed_file = true;
1022
1023                                 status = fn(cli->dfs_mountpoint,
1024                                         finfo,
1025                                         pathname,
1026                                         state);
1027
1028                                 if (!NT_STATUS_IS_OK(status)) {
1029                                         break;
1030                                 }
1031                         }
1032
1033                         TALLOC_FREE(finfo);
1034
1035                         /* Move to next entry. */
1036                         if (next_offset) {
1037                                 dir_data += next_offset;
1038                                 dir_data_length -= next_offset;
1039                         }
1040                 } while (next_offset != 0);
1041
1042                 TALLOC_FREE(subframe);
1043
1044                 if (!mask_has_wild) {
1045                         /*
1046                          * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1047                          * when handed a non-wildcard path. Do it
1048                          * for the server (with a non-wildcard path
1049                          * there should only ever be one file returned.
1050                          */
1051                         status = STATUS_NO_MORE_FILES;
1052                         break;
1053                 }
1054
1055         } while (NT_STATUS_IS_OK(status));
1056
1057         if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1058                 status = NT_STATUS_OK;
1059         }
1060
1061         if (NT_STATUS_IS_OK(status) && !processed_file) {
1062                 /*
1063                  * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1064                  * if no files match. Emulate this in the client.
1065                  */
1066                 status = NT_STATUS_NO_SUCH_FILE;
1067         }
1068
1069   fail:
1070
1071         if (fnum != 0xffff) {
1072                 cli_smb2_close_fnum(cli, fnum);
1073         }
1074
1075         cli->raw_status = status;
1076
1077         TALLOC_FREE(subframe);
1078         TALLOC_FREE(frame);
1079         return status;
1080 }
1081
1082 /***************************************************************
1083  Wrapper that allows SMB2 to query a path info (basic level).
1084  Synchronous only.
1085 ***************************************************************/
1086
1087 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1088                                 const char *name,
1089                                 SMB_STRUCT_STAT *sbuf,
1090                                 uint32_t *attributes)
1091 {
1092         NTSTATUS status;
1093         struct smb_create_returns cr;
1094         uint16_t fnum = 0xffff;
1095         size_t namelen = strlen(name);
1096
1097         if (smbXcli_conn_has_async_calls(cli->conn)) {
1098                 /*
1099                  * Can't use sync call while an async call is in flight
1100                  */
1101                 return NT_STATUS_INVALID_PARAMETER;
1102         }
1103
1104         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1105                 return NT_STATUS_INVALID_PARAMETER;
1106         }
1107
1108         /* SMB2 is pickier about pathnames. Ensure it doesn't
1109            end in a '\' */
1110         if (namelen > 0 && name[namelen-1] == '\\') {
1111                 char *modname = talloc_strdup(talloc_tos(), name);
1112                 modname[namelen-1] = '\0';
1113                 name = modname;
1114         }
1115
1116         /* This is commonly used as a 'cd'. Try qpathinfo on
1117            a directory handle first. */
1118
1119         status = cli_smb2_create_fnum(cli,
1120                         name,
1121                         0,                      /* create_flags */
1122                         FILE_READ_ATTRIBUTES,   /* desired_access */
1123                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1124                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1125                         FILE_OPEN,              /* create_disposition */
1126                         FILE_DIRECTORY_FILE,    /* create_options */
1127                         &fnum,
1128                         &cr);
1129
1130         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1131                 /* Maybe a file ? */
1132                 status = cli_smb2_create_fnum(cli,
1133                         name,
1134                         0,                      /* create_flags */
1135                         FILE_READ_ATTRIBUTES,           /* desired_access */
1136                         0, /* file attributes */
1137                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1138                         FILE_OPEN,              /* create_disposition */
1139                         0,      /* create_options */
1140                         &fnum,
1141                         &cr);
1142         }
1143
1144         if (!NT_STATUS_IS_OK(status)) {
1145                 return status;
1146         }
1147
1148         status = cli_smb2_close_fnum(cli, fnum);
1149
1150         ZERO_STRUCTP(sbuf);
1151
1152         sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1153         sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1154         sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1155         sbuf->st_ex_size = cr.end_of_file;
1156         *attributes = cr.file_attributes;
1157
1158         return status;
1159 }
1160
1161 /***************************************************************
1162  Wrapper that allows SMB2 to check if a path is a directory.
1163  Synchronous only.
1164 ***************************************************************/
1165
1166 NTSTATUS cli_smb2_chkpath(struct cli_state *cli,
1167                                 const char *name)
1168 {
1169         NTSTATUS status;
1170         uint16_t fnum = 0xffff;
1171
1172         if (smbXcli_conn_has_async_calls(cli->conn)) {
1173                 /*
1174                  * Can't use sync call while an async call is in flight
1175                  */
1176                 return NT_STATUS_INVALID_PARAMETER;
1177         }
1178
1179         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1180                 return NT_STATUS_INVALID_PARAMETER;
1181         }
1182
1183         /* Ensure this is a directory. */
1184         status = cli_smb2_create_fnum(cli,
1185                         name,
1186                         0,                      /* create_flags */
1187                         FILE_READ_ATTRIBUTES,   /* desired_access */
1188                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1189                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1190                         FILE_OPEN,              /* create_disposition */
1191                         FILE_DIRECTORY_FILE,    /* create_options */
1192                         &fnum,
1193                         NULL);
1194
1195         if (!NT_STATUS_IS_OK(status)) {
1196                 return status;
1197         }
1198
1199         return cli_smb2_close_fnum(cli, fnum);
1200 }
1201
1202 /***************************************************************
1203  Helper function for pathname operations.
1204 ***************************************************************/
1205
1206 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1207                                 const char *name,
1208                                 uint32_t desired_access,
1209                                 uint16_t *pfnum)
1210 {
1211         NTSTATUS status;
1212         size_t namelen = strlen(name);
1213         TALLOC_CTX *frame = talloc_stackframe();
1214         uint32_t create_options = 0;
1215
1216         /* SMB2 is pickier about pathnames. Ensure it doesn't
1217            end in a '\' */
1218         if (namelen > 0 && name[namelen-1] == '\\') {
1219                 char *modname = talloc_strdup(frame, name);
1220                 if (modname == NULL) {
1221                         status = NT_STATUS_NO_MEMORY;
1222                         goto fail;
1223                 }
1224                 modname[namelen-1] = '\0';
1225                 name = modname;
1226         }
1227
1228         /* Try to open a file handle first. */
1229         status = cli_smb2_create_fnum(cli,
1230                         name,
1231                         0,                      /* create_flags */
1232                         desired_access,
1233                         0, /* file attributes */
1234                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1235                         FILE_OPEN,              /* create_disposition */
1236                         create_options,
1237                         pfnum,
1238                         NULL);
1239
1240         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1241                 /*
1242                  * Naive option to match our SMB1 code. Assume the
1243                  * symlink path that tripped us up was the last
1244                  * component and try again. Eventually we will have to
1245                  * deal with the returned path unprocessed component. JRA.
1246                  */
1247                 create_options |= FILE_OPEN_REPARSE_POINT;
1248                 status = cli_smb2_create_fnum(cli,
1249                         name,
1250                         0,                      /* create_flags */
1251                         desired_access,
1252                         0, /* file attributes */
1253                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1254                         FILE_OPEN,              /* create_disposition */
1255                         create_options,
1256                         pfnum,
1257                         NULL);
1258         }
1259
1260         if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1261                 create_options |= FILE_DIRECTORY_FILE;
1262                 status = cli_smb2_create_fnum(cli,
1263                         name,
1264                         0,                      /* create_flags */
1265                         desired_access,
1266                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1267                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1268                         FILE_OPEN,              /* create_disposition */
1269                         FILE_DIRECTORY_FILE,    /* create_options */
1270                         pfnum,
1271                         NULL);
1272         }
1273
1274   fail:
1275
1276         TALLOC_FREE(frame);
1277         return status;
1278 }
1279
1280 /***************************************************************
1281  Wrapper that allows SMB2 to query a path info (ALTNAME level).
1282  Synchronous only.
1283 ***************************************************************/
1284
1285 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1286                                 const char *name,
1287                                 fstring alt_name)
1288 {
1289         NTSTATUS status;
1290         DATA_BLOB outbuf = data_blob_null;
1291         uint16_t fnum = 0xffff;
1292         struct smb2_hnd *ph = NULL;
1293         uint32_t altnamelen = 0;
1294         TALLOC_CTX *frame = talloc_stackframe();
1295
1296         if (smbXcli_conn_has_async_calls(cli->conn)) {
1297                 /*
1298                  * Can't use sync call while an async call is in flight
1299                  */
1300                 status = NT_STATUS_INVALID_PARAMETER;
1301                 goto fail;
1302         }
1303
1304         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1305                 status = NT_STATUS_INVALID_PARAMETER;
1306                 goto fail;
1307         }
1308
1309         status = get_fnum_from_path(cli,
1310                                 name,
1311                                 FILE_READ_ATTRIBUTES,
1312                                 &fnum);
1313
1314         if (!NT_STATUS_IS_OK(status)) {
1315                 goto fail;
1316         }
1317
1318         status = map_fnum_to_smb2_handle(cli,
1319                                         fnum,
1320                                         &ph);
1321         if (!NT_STATUS_IS_OK(status)) {
1322                 goto fail;
1323         }
1324
1325         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1326            level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1327
1328         status = smb2cli_query_info(cli->conn,
1329                                 cli->timeout,
1330                                 cli->smb2.session,
1331                                 cli->smb2.tcon,
1332                                 1, /* in_info_type */
1333                                 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1334                                 0xFFFF, /* in_max_output_length */
1335                                 NULL, /* in_input_buffer */
1336                                 0, /* in_additional_info */
1337                                 0, /* in_flags */
1338                                 ph->fid_persistent,
1339                                 ph->fid_volatile,
1340                                 frame,
1341                                 &outbuf);
1342
1343         if (!NT_STATUS_IS_OK(status)) {
1344                 goto fail;
1345         }
1346
1347         /* Parse the reply. */
1348         if (outbuf.length < 4) {
1349                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1350                 goto fail;
1351         }
1352
1353         altnamelen = IVAL(outbuf.data, 0);
1354         if (altnamelen > outbuf.length - 4) {
1355                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1356                 goto fail;
1357         }
1358
1359         if (altnamelen > 0) {
1360                 size_t ret = 0;
1361                 char *short_name = NULL;
1362                 ret = pull_string_talloc(frame,
1363                                 outbuf.data,
1364                                 FLAGS2_UNICODE_STRINGS,
1365                                 &short_name,
1366                                 outbuf.data + 4,
1367                                 altnamelen,
1368                                 STR_UNICODE);
1369                 if (ret == (size_t)-1) {
1370                         /* Bad conversion. */
1371                         status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1372                         goto fail;
1373                 }
1374
1375                 fstrcpy(alt_name, short_name);
1376         } else {
1377                 alt_name[0] = '\0';
1378         }
1379
1380         status = NT_STATUS_OK;
1381
1382   fail:
1383
1384         if (fnum != 0xffff) {
1385                 cli_smb2_close_fnum(cli, fnum);
1386         }
1387
1388         cli->raw_status = status;
1389
1390         TALLOC_FREE(frame);
1391         return status;
1392 }
1393
1394
1395 /***************************************************************
1396  Wrapper that allows SMB2 to query a fnum info (basic level).
1397  Synchronous only.
1398 ***************************************************************/
1399
1400 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1401                         uint16_t fnum,
1402                         uint16_t *mode,
1403                         off_t *size,
1404                         struct timespec *create_time,
1405                         struct timespec *access_time,
1406                         struct timespec *write_time,
1407                         struct timespec *change_time,
1408                         SMB_INO_T *ino)
1409 {
1410         NTSTATUS status;
1411         DATA_BLOB outbuf = data_blob_null;
1412         struct smb2_hnd *ph = NULL;
1413         TALLOC_CTX *frame = talloc_stackframe();
1414
1415         if (smbXcli_conn_has_async_calls(cli->conn)) {
1416                 /*
1417                  * Can't use sync call while an async call is in flight
1418                  */
1419                 status = NT_STATUS_INVALID_PARAMETER;
1420                 goto fail;
1421         }
1422
1423         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1424                 status = NT_STATUS_INVALID_PARAMETER;
1425                 goto fail;
1426         }
1427
1428         status = map_fnum_to_smb2_handle(cli,
1429                                         fnum,
1430                                         &ph);
1431         if (!NT_STATUS_IS_OK(status)) {
1432                 goto fail;
1433         }
1434
1435         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1436            level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1437
1438         status = smb2cli_query_info(cli->conn,
1439                                 cli->timeout,
1440                                 cli->smb2.session,
1441                                 cli->smb2.tcon,
1442                                 1, /* in_info_type */
1443                                 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1444                                 0xFFFF, /* in_max_output_length */
1445                                 NULL, /* in_input_buffer */
1446                                 0, /* in_additional_info */
1447                                 0, /* in_flags */
1448                                 ph->fid_persistent,
1449                                 ph->fid_volatile,
1450                                 frame,
1451                                 &outbuf);
1452         if (!NT_STATUS_IS_OK(status)) {
1453                 goto fail;
1454         }
1455
1456         /* Parse the reply. */
1457         if (outbuf.length < 0x60) {
1458                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1459                 goto fail;
1460         }
1461
1462         if (create_time) {
1463                 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1464         }
1465         if (access_time) {
1466                 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1467         }
1468         if (write_time) {
1469                 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1470         }
1471         if (change_time) {
1472                 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1473         }
1474         if (mode) {
1475                 uint32_t attr = IVAL(outbuf.data, 0x20);
1476                 *mode = (uint16_t)attr;
1477         }
1478         if (size) {
1479                 uint64_t file_size = BVAL(outbuf.data, 0x30);
1480                 *size = (off_t)file_size;
1481         }
1482         if (ino) {
1483                 uint64_t file_index = BVAL(outbuf.data, 0x40);
1484                 *ino = (SMB_INO_T)file_index;
1485         }
1486
1487   fail:
1488
1489         cli->raw_status = status;
1490
1491         TALLOC_FREE(frame);
1492         return status;
1493 }
1494
1495 /***************************************************************
1496  Wrapper that allows SMB2 to query an fnum.
1497  Implement on top of cli_smb2_qfileinfo_basic().
1498  Synchronous only.
1499 ***************************************************************/
1500
1501 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1502                         uint16_t fnum,
1503                         uint16_t *attr,
1504                         off_t *size,
1505                         time_t *change_time,
1506                         time_t *access_time,
1507                         time_t *write_time)
1508 {
1509         struct timespec access_time_ts;
1510         struct timespec write_time_ts;
1511         struct timespec change_time_ts;
1512         NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1513                                         fnum,
1514                                         attr,
1515                                         size,
1516                                         NULL,
1517                                         &access_time_ts,
1518                                         &write_time_ts,
1519                                         &change_time_ts,
1520                                         NULL);
1521
1522         cli->raw_status = status;
1523
1524         if (!NT_STATUS_IS_OK(status)) {
1525                 return status;
1526         }
1527
1528         if (change_time) {
1529                 *change_time = change_time_ts.tv_sec;
1530         }
1531         if (access_time) {
1532                 *access_time = access_time_ts.tv_sec;
1533         }
1534         if (write_time) {
1535                 *write_time = write_time_ts.tv_sec;
1536         }
1537         return NT_STATUS_OK;
1538 }
1539
1540 /***************************************************************
1541  Wrapper that allows SMB2 to get pathname attributes.
1542  Synchronous only.
1543 ***************************************************************/
1544
1545 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1546                         const char *name,
1547                         uint16_t *attr,
1548                         off_t *size,
1549                         time_t *write_time)
1550 {
1551         NTSTATUS status;
1552         uint16_t fnum = 0xffff;
1553         struct smb2_hnd *ph = NULL;
1554         TALLOC_CTX *frame = talloc_stackframe();
1555
1556         if (smbXcli_conn_has_async_calls(cli->conn)) {
1557                 /*
1558                  * Can't use sync call while an async call is in flight
1559                  */
1560                 status = NT_STATUS_INVALID_PARAMETER;
1561                 goto fail;
1562         }
1563
1564         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1565                 status = NT_STATUS_INVALID_PARAMETER;
1566                 goto fail;
1567         }
1568
1569         status = get_fnum_from_path(cli,
1570                                 name,
1571                                 FILE_READ_ATTRIBUTES,
1572                                 &fnum);
1573
1574         if (!NT_STATUS_IS_OK(status)) {
1575                 goto fail;
1576         }
1577
1578         status = map_fnum_to_smb2_handle(cli,
1579                                         fnum,
1580                                         &ph);
1581         if (!NT_STATUS_IS_OK(status)) {
1582                 goto fail;
1583         }
1584         status = cli_smb2_getattrE(cli,
1585                                 fnum,
1586                                 attr,
1587                                 size,
1588                                 NULL,
1589                                 NULL,
1590                                 write_time);
1591         if (!NT_STATUS_IS_OK(status)) {
1592                 goto fail;
1593         }
1594
1595   fail:
1596
1597         if (fnum != 0xffff) {
1598                 cli_smb2_close_fnum(cli, fnum);
1599         }
1600
1601         cli->raw_status = status;
1602
1603         TALLOC_FREE(frame);
1604         return status;
1605 }
1606
1607 /***************************************************************
1608  Wrapper that allows SMB2 to query a pathname info (basic level).
1609  Implement on top of cli_smb2_qfileinfo_basic().
1610  Synchronous only.
1611 ***************************************************************/
1612
1613 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1614                         const char *name,
1615                         struct timespec *create_time,
1616                         struct timespec *access_time,
1617                         struct timespec *write_time,
1618                         struct timespec *change_time,
1619                         off_t *size,
1620                         uint16_t *mode,
1621                         SMB_INO_T *ino)
1622 {
1623         NTSTATUS status;
1624         struct smb2_hnd *ph = NULL;
1625         uint16_t fnum = 0xffff;
1626         TALLOC_CTX *frame = talloc_stackframe();
1627
1628         if (smbXcli_conn_has_async_calls(cli->conn)) {
1629                 /*
1630                  * Can't use sync call while an async call is in flight
1631                  */
1632                 status = NT_STATUS_INVALID_PARAMETER;
1633                 goto fail;
1634         }
1635
1636         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1637                 status = NT_STATUS_INVALID_PARAMETER;
1638                 goto fail;
1639         }
1640
1641         status = get_fnum_from_path(cli,
1642                                         name,
1643                                         FILE_READ_ATTRIBUTES,
1644                                         &fnum);
1645
1646         if (!NT_STATUS_IS_OK(status)) {
1647                 goto fail;
1648         }
1649
1650         status = map_fnum_to_smb2_handle(cli,
1651                                         fnum,
1652                                         &ph);
1653         if (!NT_STATUS_IS_OK(status)) {
1654                 goto fail;
1655         }
1656
1657         status = cli_smb2_qfileinfo_basic(cli,
1658                                         fnum,
1659                                         mode,
1660                                         size,
1661                                         create_time,
1662                                         access_time,
1663                                         write_time,
1664                                         change_time,
1665                                         ino);
1666
1667   fail:
1668
1669         if (fnum != 0xffff) {
1670                 cli_smb2_close_fnum(cli, fnum);
1671         }
1672
1673         cli->raw_status = status;
1674
1675         TALLOC_FREE(frame);
1676         return status;
1677 }
1678
1679 /***************************************************************
1680  Wrapper that allows SMB2 to query pathname streams.
1681  Synchronous only.
1682 ***************************************************************/
1683
1684 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1685                                 const char *name,
1686                                 TALLOC_CTX *mem_ctx,
1687                                 unsigned int *pnum_streams,
1688                                 struct stream_struct **pstreams)
1689 {
1690         NTSTATUS status;
1691         struct smb2_hnd *ph = NULL;
1692         uint16_t fnum = 0xffff;
1693         DATA_BLOB outbuf = data_blob_null;
1694         TALLOC_CTX *frame = talloc_stackframe();
1695
1696         if (smbXcli_conn_has_async_calls(cli->conn)) {
1697                 /*
1698                  * Can't use sync call while an async call is in flight
1699                  */
1700                 status = NT_STATUS_INVALID_PARAMETER;
1701                 goto fail;
1702         }
1703
1704         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1705                 status = NT_STATUS_INVALID_PARAMETER;
1706                 goto fail;
1707         }
1708
1709         status = get_fnum_from_path(cli,
1710                                 name,
1711                                 FILE_READ_ATTRIBUTES,
1712                                 &fnum);
1713
1714         if (!NT_STATUS_IS_OK(status)) {
1715                 goto fail;
1716         }
1717
1718         status = map_fnum_to_smb2_handle(cli,
1719                                         fnum,
1720                                         &ph);
1721         if (!NT_STATUS_IS_OK(status)) {
1722                 goto fail;
1723         }
1724
1725         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1726            level 22 (SMB2_FILE_STREAM_INFORMATION). */
1727
1728         status = smb2cli_query_info(cli->conn,
1729                                 cli->timeout,
1730                                 cli->smb2.session,
1731                                 cli->smb2.tcon,
1732                                 1, /* in_info_type */
1733                                 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1734                                 0xFFFF, /* in_max_output_length */
1735                                 NULL, /* in_input_buffer */
1736                                 0, /* in_additional_info */
1737                                 0, /* in_flags */
1738                                 ph->fid_persistent,
1739                                 ph->fid_volatile,
1740                                 frame,
1741                                 &outbuf);
1742
1743         if (!NT_STATUS_IS_OK(status)) {
1744                 goto fail;
1745         }
1746
1747         /* Parse the reply. */
1748         if (!parse_streams_blob(mem_ctx,
1749                                 outbuf.data,
1750                                 outbuf.length,
1751                                 pnum_streams,
1752                                 pstreams)) {
1753                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1754                 goto fail;
1755         }
1756
1757   fail:
1758
1759         if (fnum != 0xffff) {
1760                 cli_smb2_close_fnum(cli, fnum);
1761         }
1762
1763         cli->raw_status = status;
1764
1765         TALLOC_FREE(frame);
1766         return status;
1767 }
1768
1769 /***************************************************************
1770  Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
1771  a pathname.
1772  Synchronous only.
1773 ***************************************************************/
1774
1775 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
1776                         const char *name,
1777                         uint8_t in_info_type,
1778                         uint8_t in_file_info_class,
1779                         const DATA_BLOB *p_in_data)
1780 {
1781         NTSTATUS status;
1782         uint16_t fnum = 0xffff;
1783         struct smb2_hnd *ph = NULL;
1784         TALLOC_CTX *frame = talloc_stackframe();
1785
1786         if (smbXcli_conn_has_async_calls(cli->conn)) {
1787                 /*
1788                  * Can't use sync call while an async call is in flight
1789                  */
1790                 status = NT_STATUS_INVALID_PARAMETER;
1791                 goto fail;
1792         }
1793
1794         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1795                 status = NT_STATUS_INVALID_PARAMETER;
1796                 goto fail;
1797         }
1798
1799         status = get_fnum_from_path(cli,
1800                                 name,
1801                                 FILE_WRITE_ATTRIBUTES,
1802                                 &fnum);
1803
1804         if (!NT_STATUS_IS_OK(status)) {
1805                 goto fail;
1806         }
1807
1808         status = map_fnum_to_smb2_handle(cli,
1809                                         fnum,
1810                                         &ph);
1811         if (!NT_STATUS_IS_OK(status)) {
1812                 goto fail;
1813         }
1814
1815         status = smb2cli_set_info(cli->conn,
1816                                 cli->timeout,
1817                                 cli->smb2.session,
1818                                 cli->smb2.tcon,
1819                                 in_info_type,
1820                                 in_file_info_class,
1821                                 p_in_data, /* in_input_buffer */
1822                                 0, /* in_additional_info */
1823                                 ph->fid_persistent,
1824                                 ph->fid_volatile);
1825   fail:
1826
1827         if (fnum != 0xffff) {
1828                 cli_smb2_close_fnum(cli, fnum);
1829         }
1830
1831         cli->raw_status = status;
1832
1833         TALLOC_FREE(frame);
1834         return status;
1835 }
1836
1837
1838 /***************************************************************
1839  Wrapper that allows SMB2 to set pathname attributes.
1840  Synchronous only.
1841 ***************************************************************/
1842
1843 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1844                         const char *name,
1845                         uint16_t attr,
1846                         time_t mtime)
1847 {
1848         uint8_t inbuf_store[40];
1849         DATA_BLOB inbuf = data_blob_null;
1850
1851         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1852            level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1853
1854         inbuf.data = inbuf_store;
1855         inbuf.length = sizeof(inbuf_store);
1856         data_blob_clear(&inbuf);
1857
1858         /*
1859          * SMB1 uses attr == 0 to clear all attributes
1860          * on a file (end up with FILE_ATTRIBUTE_NORMAL),
1861          * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
1862          * request attribute change.
1863          *
1864          * SMB2 uses exactly the reverse. Unfortunately as the
1865          * cli_setatr() ABI is exposed inside libsmbclient,
1866          * we must make the SMB2 cli_smb2_setatr() call
1867          * export the same ABI as the SMB1 cli_setatr()
1868          * which calls it. This means reversing the sense
1869          * of the requested attr argument if it's zero
1870          * or FILE_ATTRIBUTE_NORMAL.
1871          *
1872          * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
1873          */
1874
1875         if (attr == 0) {
1876                 attr = FILE_ATTRIBUTE_NORMAL;
1877         } else if (attr == FILE_ATTRIBUTE_NORMAL) {
1878                 attr = 0;
1879         }
1880
1881         SSVAL(inbuf.data, 32, attr);
1882         if (mtime != 0) {
1883                 put_long_date((char *)inbuf.data + 16,mtime);
1884         }
1885         /* Set all the other times to -1. */
1886         SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1887         SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1888         SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1889
1890         return cli_smb2_setpathinfo(cli,
1891                                 name,
1892                                 1, /* in_info_type */
1893                                 /* in_file_info_class */
1894                                 SMB_FILE_BASIC_INFORMATION - 1000,
1895                                 &inbuf);
1896 }
1897
1898
1899 /***************************************************************
1900  Wrapper that allows SMB2 to set file handle times.
1901  Synchronous only.
1902 ***************************************************************/
1903
1904 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1905                         uint16_t fnum,
1906                         time_t change_time,
1907                         time_t access_time,
1908                         time_t write_time)
1909 {
1910         NTSTATUS status;
1911         struct smb2_hnd *ph = NULL;
1912         uint8_t inbuf_store[40];
1913         DATA_BLOB inbuf = data_blob_null;
1914
1915         if (smbXcli_conn_has_async_calls(cli->conn)) {
1916                 /*
1917                  * Can't use sync call while an async call is in flight
1918                  */
1919                 return NT_STATUS_INVALID_PARAMETER;
1920         }
1921
1922         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1923                 return NT_STATUS_INVALID_PARAMETER;
1924         }
1925
1926         status = map_fnum_to_smb2_handle(cli,
1927                                         fnum,
1928                                         &ph);
1929         if (!NT_STATUS_IS_OK(status)) {
1930                 return status;
1931         }
1932
1933         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1934            level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1935
1936         inbuf.data = inbuf_store;
1937         inbuf.length = sizeof(inbuf_store);
1938         data_blob_clear(&inbuf);
1939
1940         SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1941         if (change_time != 0) {
1942                 put_long_date((char *)inbuf.data + 24, change_time);
1943         }
1944         if (access_time != 0) {
1945                 put_long_date((char *)inbuf.data + 8, access_time);
1946         }
1947         if (write_time != 0) {
1948                 put_long_date((char *)inbuf.data + 16, write_time);
1949         }
1950
1951         cli->raw_status = smb2cli_set_info(cli->conn,
1952                                 cli->timeout,
1953                                 cli->smb2.session,
1954                                 cli->smb2.tcon,
1955                                 1, /* in_info_type */
1956                                 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1957                                 &inbuf, /* in_input_buffer */
1958                                 0, /* in_additional_info */
1959                                 ph->fid_persistent,
1960                                 ph->fid_volatile);
1961
1962         return cli->raw_status;
1963 }
1964
1965 /***************************************************************
1966  Wrapper that allows SMB2 to query disk attributes (size).
1967  Synchronous only.
1968 ***************************************************************/
1969
1970 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
1971                           uint64_t *bsize, uint64_t *total, uint64_t *avail)
1972 {
1973         NTSTATUS status;
1974         uint16_t fnum = 0xffff;
1975         DATA_BLOB outbuf = data_blob_null;
1976         struct smb2_hnd *ph = NULL;
1977         uint32_t sectors_per_unit = 0;
1978         uint32_t bytes_per_sector = 0;
1979         uint64_t total_size = 0;
1980         uint64_t size_free = 0;
1981         TALLOC_CTX *frame = talloc_stackframe();
1982
1983         if (smbXcli_conn_has_async_calls(cli->conn)) {
1984                 /*
1985                  * Can't use sync call while an async call is in flight
1986                  */
1987                 status = NT_STATUS_INVALID_PARAMETER;
1988                 goto fail;
1989         }
1990
1991         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1992                 status = NT_STATUS_INVALID_PARAMETER;
1993                 goto fail;
1994         }
1995
1996         /* First open the top level directory. */
1997         status = cli_smb2_create_fnum(cli,
1998                         path,
1999                         0,                      /* create_flags */
2000                         FILE_READ_ATTRIBUTES,   /* desired_access */
2001                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2002                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2003                         FILE_OPEN,              /* create_disposition */
2004                         FILE_DIRECTORY_FILE,    /* create_options */
2005                         &fnum,
2006                         NULL);
2007
2008         if (!NT_STATUS_IS_OK(status)) {
2009                 goto fail;
2010         }
2011
2012         status = map_fnum_to_smb2_handle(cli,
2013                                         fnum,
2014                                         &ph);
2015         if (!NT_STATUS_IS_OK(status)) {
2016                 goto fail;
2017         }
2018
2019         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2020            level 3 (SMB_FS_SIZE_INFORMATION). */
2021
2022         status = smb2cli_query_info(cli->conn,
2023                                 cli->timeout,
2024                                 cli->smb2.session,
2025                                 cli->smb2.tcon,
2026                                 2, /* in_info_type */
2027                                 3, /* in_file_info_class */
2028                                 0xFFFF, /* in_max_output_length */
2029                                 NULL, /* in_input_buffer */
2030                                 0, /* in_additional_info */
2031                                 0, /* in_flags */
2032                                 ph->fid_persistent,
2033                                 ph->fid_volatile,
2034                                 frame,
2035                                 &outbuf);
2036         if (!NT_STATUS_IS_OK(status)) {
2037                 goto fail;
2038         }
2039
2040         /* Parse the reply. */
2041         if (outbuf.length != 24) {
2042                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2043                 goto fail;
2044         }
2045
2046         total_size = BVAL(outbuf.data, 0);
2047         size_free = BVAL(outbuf.data, 8);
2048         sectors_per_unit = IVAL(outbuf.data, 16);
2049         bytes_per_sector = IVAL(outbuf.data, 20);
2050
2051         if (bsize) {
2052                 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2053         }
2054         if (total) {
2055                 *total = total_size;
2056         }
2057         if (avail) {
2058                 *avail = size_free;
2059         }
2060
2061         status = NT_STATUS_OK;
2062
2063   fail:
2064
2065         if (fnum != 0xffff) {
2066                 cli_smb2_close_fnum(cli, fnum);
2067         }
2068
2069         cli->raw_status = status;
2070
2071         TALLOC_FREE(frame);
2072         return status;
2073 }
2074
2075 /***************************************************************
2076  Wrapper that allows SMB2 to query file system sizes.
2077  Synchronous only.
2078 ***************************************************************/
2079
2080 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2081                                 uint64_t *total_allocation_units,
2082                                 uint64_t *caller_allocation_units,
2083                                 uint64_t *actual_allocation_units,
2084                                 uint64_t *sectors_per_allocation_unit,
2085                                 uint64_t *bytes_per_sector)
2086 {
2087         NTSTATUS status;
2088         uint16_t fnum = 0xffff;
2089         DATA_BLOB outbuf = data_blob_null;
2090         struct smb2_hnd *ph = NULL;
2091         TALLOC_CTX *frame = talloc_stackframe();
2092
2093         if (smbXcli_conn_has_async_calls(cli->conn)) {
2094                 /*
2095                  * Can't use sync call while an async call is in flight
2096                  */
2097                 status = NT_STATUS_INVALID_PARAMETER;
2098                 goto fail;
2099         }
2100
2101         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2102                 status = NT_STATUS_INVALID_PARAMETER;
2103                 goto fail;
2104         }
2105
2106         /* First open the top level directory. */
2107         status =
2108             cli_smb2_create_fnum(cli, "", 0,               /* create_flags */
2109                                  FILE_READ_ATTRIBUTES,     /* desired_access */
2110                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2111                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
2112                                      FILE_SHARE_DELETE, /* share_access */
2113                                  FILE_OPEN,             /* create_disposition */
2114                                  FILE_DIRECTORY_FILE,   /* create_options */
2115                                  &fnum,
2116                                  NULL);
2117
2118         if (!NT_STATUS_IS_OK(status)) {
2119                 goto fail;
2120         }
2121
2122         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2123         if (!NT_STATUS_IS_OK(status)) {
2124                 goto fail;
2125         }
2126
2127         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2128            level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2129
2130         status = smb2cli_query_info(cli->conn,
2131                                 cli->timeout,
2132                                 cli->smb2.session,
2133                                 cli->smb2.tcon,
2134                                 SMB2_GETINFO_FS, /* in_info_type */
2135                                 /* in_file_info_class */
2136                                 SMB_FS_FULL_SIZE_INFORMATION - 1000,
2137                                 0xFFFF, /* in_max_output_length */
2138                                 NULL, /* in_input_buffer */
2139                                 0, /* in_additional_info */
2140                                 0, /* in_flags */
2141                                 ph->fid_persistent,
2142                                 ph->fid_volatile,
2143                                 frame,
2144                                 &outbuf);
2145         if (!NT_STATUS_IS_OK(status)) {
2146                 goto fail;
2147         }
2148
2149         if (outbuf.length < 32) {
2150                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2151                 goto fail;
2152         }
2153
2154         *total_allocation_units = BIG_UINT(outbuf.data, 0);
2155         *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2156         *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2157         *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2158         *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2159
2160 fail:
2161
2162         if (fnum != 0xffff) {
2163                 cli_smb2_close_fnum(cli, fnum);
2164         }
2165
2166         cli->raw_status = status;
2167
2168         TALLOC_FREE(frame);
2169         return status;
2170 }
2171
2172 /***************************************************************
2173  Wrapper that allows SMB2 to query file system attributes.
2174  Synchronous only.
2175 ***************************************************************/
2176
2177 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2178 {
2179         NTSTATUS status;
2180         uint16_t fnum = 0xffff;
2181         DATA_BLOB outbuf = data_blob_null;
2182         struct smb2_hnd *ph = NULL;
2183         TALLOC_CTX *frame = talloc_stackframe();
2184
2185         if (smbXcli_conn_has_async_calls(cli->conn)) {
2186                 /*
2187                  * Can't use sync call while an async call is in flight
2188                  */
2189                 status = NT_STATUS_INVALID_PARAMETER;
2190                 goto fail;
2191         }
2192
2193         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2194                 status = NT_STATUS_INVALID_PARAMETER;
2195                 goto fail;
2196         }
2197
2198         /* First open the top level directory. */
2199         status =
2200             cli_smb2_create_fnum(cli, "", 0,               /* create_flags */
2201                                  FILE_READ_ATTRIBUTES,     /* desired_access */
2202                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2203                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
2204                                      FILE_SHARE_DELETE, /* share_access */
2205                                  FILE_OPEN,             /* create_disposition */
2206                                  FILE_DIRECTORY_FILE,   /* create_options */
2207                                  &fnum,
2208                                  NULL);
2209
2210         if (!NT_STATUS_IS_OK(status)) {
2211                 goto fail;
2212         }
2213
2214         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2215         if (!NT_STATUS_IS_OK(status)) {
2216                 goto fail;
2217         }
2218
2219         status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2220                                     cli->smb2.tcon, 2, /* in_info_type */
2221                                     5,                 /* in_file_info_class */
2222                                     0xFFFF, /* in_max_output_length */
2223                                     NULL,   /* in_input_buffer */
2224                                     0,      /* in_additional_info */
2225                                     0,      /* in_flags */
2226                                     ph->fid_persistent, ph->fid_volatile, frame,
2227                                     &outbuf);
2228         if (!NT_STATUS_IS_OK(status)) {
2229                 goto fail;
2230         }
2231
2232         if (outbuf.length < 12) {
2233                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2234                 goto fail;
2235         }
2236
2237         *fs_attr = IVAL(outbuf.data, 0);
2238
2239 fail:
2240
2241         if (fnum != 0xffff) {
2242                 cli_smb2_close_fnum(cli, fnum);
2243         }
2244
2245         cli->raw_status = status;
2246
2247         TALLOC_FREE(frame);
2248         return status;
2249 }
2250
2251 /***************************************************************
2252  Wrapper that allows SMB2 to query file system volume info.
2253  Synchronous only.
2254 ***************************************************************/
2255
2256 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2257                                 TALLOC_CTX *mem_ctx,
2258                                 char **_volume_name,
2259                                 uint32_t *pserial_number,
2260                                 time_t *pdate)
2261 {
2262         NTSTATUS status;
2263         uint16_t fnum = 0xffff;
2264         DATA_BLOB outbuf = data_blob_null;
2265         struct smb2_hnd *ph = NULL;
2266         uint32_t nlen;
2267         char *volume_name = NULL;
2268         TALLOC_CTX *frame = talloc_stackframe();
2269
2270         if (smbXcli_conn_has_async_calls(cli->conn)) {
2271                 /*
2272                  * Can't use sync call while an async call is in flight
2273                  */
2274                 status = NT_STATUS_INVALID_PARAMETER;
2275                 goto fail;
2276         }
2277
2278         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2279                 status = NT_STATUS_INVALID_PARAMETER;
2280                 goto fail;
2281         }
2282
2283         /* First open the top level directory. */
2284         status =
2285             cli_smb2_create_fnum(cli, "", 0,               /* create_flags */
2286                                  FILE_READ_ATTRIBUTES,     /* desired_access */
2287                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2288                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
2289                                      FILE_SHARE_DELETE, /* share_access */
2290                                  FILE_OPEN,             /* create_disposition */
2291                                  FILE_DIRECTORY_FILE,   /* create_options */
2292                                  &fnum,
2293                                  NULL);
2294
2295         if (!NT_STATUS_IS_OK(status)) {
2296                 goto fail;
2297         }
2298
2299         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2300         if (!NT_STATUS_IS_OK(status)) {
2301                 goto fail;
2302         }
2303
2304         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2305            level 1 (SMB_FS_VOLUME_INFORMATION). */
2306
2307         status = smb2cli_query_info(cli->conn,
2308                                 cli->timeout,
2309                                 cli->smb2.session,
2310                                 cli->smb2.tcon,
2311                                 SMB2_GETINFO_FS, /* in_info_type */
2312                                 /* in_file_info_class */
2313                                 SMB_FS_VOLUME_INFORMATION - 1000,
2314                                 0xFFFF, /* in_max_output_length */
2315                                 NULL, /* in_input_buffer */
2316                                 0, /* in_additional_info */
2317                                 0, /* in_flags */
2318                                 ph->fid_persistent,
2319                                 ph->fid_volatile,
2320                                 frame,
2321                                 &outbuf);
2322         if (!NT_STATUS_IS_OK(status)) {
2323                 goto fail;
2324         }
2325
2326         if (outbuf.length < 24) {
2327                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2328                 goto fail;
2329         }
2330
2331         if (pdate) {
2332                 struct timespec ts;
2333                 ts = interpret_long_date((char *)outbuf.data);
2334                 *pdate = ts.tv_sec;
2335         }
2336         if (pserial_number) {
2337                 *pserial_number = IVAL(outbuf.data,8);
2338         }
2339         nlen = IVAL(outbuf.data,12);
2340         if (nlen + 18 < 18) {
2341                 /* Integer wrap. */
2342                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2343                 goto fail;
2344         }
2345         /*
2346          * The next check is safe as we know outbuf.length >= 24
2347          * from above.
2348          */
2349         if (nlen > (outbuf.length - 18)) {
2350                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2351                 goto fail;
2352         }
2353
2354         clistr_pull_talloc(mem_ctx,
2355                         (const char *)outbuf.data,
2356                         0,
2357                         &volume_name,
2358                         outbuf.data + 18,
2359                         nlen,
2360                         STR_UNICODE);
2361         if (volume_name == NULL) {
2362                 status = map_nt_error_from_unix(errno);
2363                 goto fail;
2364         }
2365
2366         *_volume_name = volume_name;
2367
2368 fail:
2369
2370         if (fnum != 0xffff) {
2371                 cli_smb2_close_fnum(cli, fnum);
2372         }
2373
2374         cli->raw_status = status;
2375
2376         TALLOC_FREE(frame);
2377         return status;
2378 }
2379
2380
2381 /***************************************************************
2382  Wrapper that allows SMB2 to query a security descriptor.
2383  Synchronous only.
2384 ***************************************************************/
2385
2386 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2387                                         uint16_t fnum,
2388                                         uint32_t sec_info,
2389                                         TALLOC_CTX *mem_ctx,
2390                                         struct security_descriptor **ppsd)
2391 {
2392         NTSTATUS status;
2393         DATA_BLOB outbuf = data_blob_null;
2394         struct smb2_hnd *ph = NULL;
2395         struct security_descriptor *lsd = NULL;
2396         TALLOC_CTX *frame = talloc_stackframe();
2397
2398         if (smbXcli_conn_has_async_calls(cli->conn)) {
2399                 /*
2400                  * Can't use sync call while an async call is in flight
2401                  */
2402                 status = NT_STATUS_INVALID_PARAMETER;
2403                 goto fail;
2404         }
2405
2406         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2407                 status = NT_STATUS_INVALID_PARAMETER;
2408                 goto fail;
2409         }
2410
2411         status = map_fnum_to_smb2_handle(cli,
2412                                         fnum,
2413                                         &ph);
2414         if (!NT_STATUS_IS_OK(status)) {
2415                 goto fail;
2416         }
2417
2418         /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2419
2420         status = smb2cli_query_info(cli->conn,
2421                                 cli->timeout,
2422                                 cli->smb2.session,
2423                                 cli->smb2.tcon,
2424                                 3, /* in_info_type */
2425                                 0, /* in_file_info_class */
2426                                 0xFFFF, /* in_max_output_length */
2427                                 NULL, /* in_input_buffer */
2428                                 sec_info, /* in_additional_info */
2429                                 0, /* in_flags */
2430                                 ph->fid_persistent,
2431                                 ph->fid_volatile,
2432                                 frame,
2433                                 &outbuf);
2434
2435         if (!NT_STATUS_IS_OK(status)) {
2436                 goto fail;
2437         }
2438
2439         /* Parse the reply. */
2440         status = unmarshall_sec_desc(mem_ctx,
2441                                 outbuf.data,
2442                                 outbuf.length,
2443                                 &lsd);
2444
2445         if (!NT_STATUS_IS_OK(status)) {
2446                 goto fail;
2447         }
2448
2449         if (ppsd != NULL) {
2450                 *ppsd = lsd;
2451         } else {
2452                 TALLOC_FREE(lsd);
2453         }
2454
2455   fail:
2456
2457         cli->raw_status = status;
2458
2459         TALLOC_FREE(frame);
2460         return status;
2461 }
2462
2463 /***************************************************************
2464  Wrapper that allows SMB2 to set a security descriptor.
2465  Synchronous only.
2466 ***************************************************************/
2467
2468 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
2469                                         uint16_t fnum,
2470                                         uint32_t sec_info,
2471                                         const struct security_descriptor *sd)
2472 {
2473         NTSTATUS status;
2474         DATA_BLOB inbuf = data_blob_null;
2475         struct smb2_hnd *ph = NULL;
2476         TALLOC_CTX *frame = talloc_stackframe();
2477
2478         if (smbXcli_conn_has_async_calls(cli->conn)) {
2479                 /*
2480                  * Can't use sync call while an async call is in flight
2481                  */
2482                 status = NT_STATUS_INVALID_PARAMETER;
2483                 goto fail;
2484         }
2485
2486         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2487                 status = NT_STATUS_INVALID_PARAMETER;
2488                 goto fail;
2489         }
2490
2491         status = map_fnum_to_smb2_handle(cli,
2492                                         fnum,
2493                                         &ph);
2494         if (!NT_STATUS_IS_OK(status)) {
2495                 goto fail;
2496         }
2497
2498         status = marshall_sec_desc(frame,
2499                                 sd,
2500                                 &inbuf.data,
2501                                 &inbuf.length);
2502
2503         if (!NT_STATUS_IS_OK(status)) {
2504                 goto fail;
2505         }
2506
2507         /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2508
2509         status = smb2cli_set_info(cli->conn,
2510                                 cli->timeout,
2511                                 cli->smb2.session,
2512                                 cli->smb2.tcon,
2513                                 3, /* in_info_type */
2514                                 0, /* in_file_info_class */
2515                                 &inbuf, /* in_input_buffer */
2516                                 sec_info, /* in_additional_info */
2517                                 ph->fid_persistent,
2518                                 ph->fid_volatile);
2519
2520   fail:
2521
2522         cli->raw_status = status;
2523
2524         TALLOC_FREE(frame);
2525         return status;
2526 }
2527
2528 /***************************************************************
2529  Wrapper that allows SMB2 to rename a file.
2530  Synchronous only.
2531 ***************************************************************/
2532
2533 NTSTATUS cli_smb2_rename(struct cli_state *cli,
2534                          const char *fname_src,
2535                          const char *fname_dst,
2536                          bool replace)
2537 {
2538         NTSTATUS status;
2539         DATA_BLOB inbuf = data_blob_null;
2540         uint16_t fnum = 0xffff;
2541         struct smb2_hnd *ph = NULL;
2542         smb_ucs2_t *converted_str = NULL;
2543         size_t converted_size_bytes = 0;
2544         size_t namelen = 0;
2545         TALLOC_CTX *frame = talloc_stackframe();
2546
2547         if (smbXcli_conn_has_async_calls(cli->conn)) {
2548                 /*
2549                  * Can't use sync call while an async call is in flight
2550                  */
2551                 status = NT_STATUS_INVALID_PARAMETER;
2552                 goto fail;
2553         }
2554
2555         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2556                 status = NT_STATUS_INVALID_PARAMETER;
2557                 goto fail;
2558         }
2559
2560         status = get_fnum_from_path(cli,
2561                                 fname_src,
2562                                 DELETE_ACCESS,
2563                                 &fnum);
2564
2565         if (!NT_STATUS_IS_OK(status)) {
2566                 goto fail;
2567         }
2568
2569         status = map_fnum_to_smb2_handle(cli,
2570                                         fnum,
2571                                         &ph);
2572         if (!NT_STATUS_IS_OK(status)) {
2573                 goto fail;
2574         }
2575
2576         /* SMB2 is pickier about pathnames. Ensure it doesn't
2577            start in a '\' */
2578         if (*fname_dst == '\\') {
2579                 fname_dst++;
2580         }
2581
2582         /* SMB2 is pickier about pathnames. Ensure it doesn't
2583            end in a '\' */
2584         namelen = strlen(fname_dst);
2585         if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2586                 char *modname = talloc_strdup(frame, fname_dst);
2587                 modname[namelen-1] = '\0';
2588                 fname_dst = modname;
2589         }
2590
2591         if (!push_ucs2_talloc(frame,
2592                                 &converted_str,
2593                                 fname_dst,
2594                                 &converted_size_bytes)) {
2595                 status = NT_STATUS_INVALID_PARAMETER;
2596                 goto fail;
2597         }
2598
2599         /* W2K8 insists the dest name is not null
2600            terminated. Remove the last 2 zero bytes
2601            and reduce the name length. */
2602
2603         if (converted_size_bytes < 2) {
2604                 status = NT_STATUS_INVALID_PARAMETER;
2605                 goto fail;
2606         }
2607         converted_size_bytes -= 2;
2608
2609         inbuf = data_blob_talloc_zero(frame,
2610                                 20 + converted_size_bytes);
2611         if (inbuf.data == NULL) {
2612                 status = NT_STATUS_NO_MEMORY;
2613                 goto fail;
2614         }
2615
2616         if (replace) {
2617                 SCVAL(inbuf.data, 0, 1);
2618         }
2619
2620         SIVAL(inbuf.data, 16, converted_size_bytes);
2621         memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2622
2623         /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2624            level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2625
2626         status = smb2cli_set_info(cli->conn,
2627                                 cli->timeout,
2628                                 cli->smb2.session,
2629                                 cli->smb2.tcon,
2630                                 1, /* in_info_type */
2631                                 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2632                                 &inbuf, /* in_input_buffer */
2633                                 0, /* in_additional_info */
2634                                 ph->fid_persistent,
2635                                 ph->fid_volatile);
2636
2637   fail:
2638
2639         if (fnum != 0xffff) {
2640                 cli_smb2_close_fnum(cli, fnum);
2641         }
2642
2643         cli->raw_status = status;
2644
2645         TALLOC_FREE(frame);
2646         return status;
2647 }
2648
2649 /***************************************************************
2650  Wrapper that allows SMB2 to set an EA on a fnum.
2651  Synchronous only.
2652 ***************************************************************/
2653
2654 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2655                         uint16_t fnum,
2656                         const char *ea_name,
2657                         const char *ea_val,
2658                         size_t ea_len)
2659 {
2660         NTSTATUS status;
2661         DATA_BLOB inbuf = data_blob_null;
2662         size_t bloblen = 0;
2663         char *ea_name_ascii = NULL;
2664         size_t namelen = 0;
2665         struct smb2_hnd *ph = NULL;
2666         TALLOC_CTX *frame = talloc_stackframe();
2667
2668         if (smbXcli_conn_has_async_calls(cli->conn)) {
2669                 /*
2670                  * Can't use sync call while an async call is in flight
2671                  */
2672                 status = NT_STATUS_INVALID_PARAMETER;
2673                 goto fail;
2674         }
2675
2676         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2677                 status = NT_STATUS_INVALID_PARAMETER;
2678                 goto fail;
2679         }
2680
2681         status = map_fnum_to_smb2_handle(cli,
2682                                         fnum,
2683                                         &ph);
2684         if (!NT_STATUS_IS_OK(status)) {
2685                 goto fail;
2686         }
2687
2688         /* Marshall the SMB2 EA data. */
2689         if (ea_len > 0xFFFF) {
2690                 status = NT_STATUS_INVALID_PARAMETER;
2691                 goto fail;
2692         }
2693
2694         if (!push_ascii_talloc(frame,
2695                                 &ea_name_ascii,
2696                                 ea_name,
2697                                 &namelen)) {
2698                 status = NT_STATUS_INVALID_PARAMETER;
2699                 goto fail;
2700         }
2701
2702         if (namelen < 2 || namelen > 0xFF) {
2703                 status = NT_STATUS_INVALID_PARAMETER;
2704                 goto fail;
2705         }
2706
2707         bloblen = 8 + ea_len + namelen;
2708         /* Round up to a 4 byte boundary. */
2709         bloblen = ((bloblen + 3)&~3);
2710
2711         inbuf = data_blob_talloc_zero(frame, bloblen);
2712         if (inbuf.data == NULL) {
2713                 status = NT_STATUS_NO_MEMORY;
2714                 goto fail;
2715         }
2716         /* namelen doesn't include the NULL byte. */
2717         SCVAL(inbuf.data, 5, namelen - 1);
2718         SSVAL(inbuf.data, 6, ea_len);
2719         memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2720         memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2721
2722         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2723            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2724
2725         status = smb2cli_set_info(cli->conn,
2726                                 cli->timeout,
2727                                 cli->smb2.session,
2728                                 cli->smb2.tcon,
2729                                 1, /* in_info_type */
2730                                 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2731                                 &inbuf, /* in_input_buffer */
2732                                 0, /* in_additional_info */
2733                                 ph->fid_persistent,
2734                                 ph->fid_volatile);
2735
2736   fail:
2737
2738         cli->raw_status = status;
2739
2740         TALLOC_FREE(frame);
2741         return status;
2742 }
2743
2744 /***************************************************************
2745  Wrapper that allows SMB2 to set an EA on a pathname.
2746  Synchronous only.
2747 ***************************************************************/
2748
2749 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2750                         const char *name,
2751                         const char *ea_name,
2752                         const char *ea_val,
2753                         size_t ea_len)
2754 {
2755         NTSTATUS status;
2756         uint16_t fnum = 0xffff;
2757
2758         if (smbXcli_conn_has_async_calls(cli->conn)) {
2759                 /*
2760                  * Can't use sync call while an async call is in flight
2761                  */
2762                 status = NT_STATUS_INVALID_PARAMETER;
2763                 goto fail;
2764         }
2765
2766         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2767                 status = NT_STATUS_INVALID_PARAMETER;
2768                 goto fail;
2769         }
2770
2771         status = get_fnum_from_path(cli,
2772                                 name,
2773                                 FILE_WRITE_EA,
2774                                 &fnum);
2775
2776         if (!NT_STATUS_IS_OK(status)) {
2777                 goto fail;
2778         }
2779
2780         status = cli_set_ea_fnum(cli,
2781                                 fnum,
2782                                 ea_name,
2783                                 ea_val,
2784                                 ea_len);
2785         if (!NT_STATUS_IS_OK(status)) {
2786                 goto fail;
2787         }
2788
2789   fail:
2790
2791         if (fnum != 0xffff) {
2792                 cli_smb2_close_fnum(cli, fnum);
2793         }
2794
2795         cli->raw_status = status;
2796
2797         return status;
2798 }
2799
2800 /***************************************************************
2801  Wrapper that allows SMB2 to get an EA list on a pathname.
2802  Synchronous only.
2803 ***************************************************************/
2804
2805 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2806                                 const char *name,
2807                                 TALLOC_CTX *ctx,
2808                                 size_t *pnum_eas,
2809                                 struct ea_struct **pea_array)
2810 {
2811         NTSTATUS status;
2812         uint16_t fnum = 0xffff;
2813         DATA_BLOB outbuf = data_blob_null;
2814         struct smb2_hnd *ph = NULL;
2815         struct ea_list *ea_list = NULL;
2816         struct ea_list *eal = NULL;
2817         size_t ea_count = 0;
2818         TALLOC_CTX *frame = talloc_stackframe();
2819
2820         *pnum_eas = 0;
2821         *pea_array = NULL;
2822
2823         if (smbXcli_conn_has_async_calls(cli->conn)) {
2824                 /*
2825                  * Can't use sync call while an async call is in flight
2826                  */
2827                 status = NT_STATUS_INVALID_PARAMETER;
2828                 goto fail;
2829         }
2830
2831         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2832                 status = NT_STATUS_INVALID_PARAMETER;
2833                 goto fail;
2834         }
2835
2836         status = get_fnum_from_path(cli,
2837                                 name,
2838                                 FILE_READ_EA,
2839                                 &fnum);
2840
2841         if (!NT_STATUS_IS_OK(status)) {
2842                 goto fail;
2843         }
2844
2845         status = map_fnum_to_smb2_handle(cli,
2846                                         fnum,
2847                                         &ph);
2848         if (!NT_STATUS_IS_OK(status)) {
2849                 goto fail;
2850         }
2851
2852         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2853            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2854
2855         status = smb2cli_query_info(cli->conn,
2856                                 cli->timeout,
2857                                 cli->smb2.session,
2858                                 cli->smb2.tcon,
2859                                 1, /* in_info_type */
2860                                 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2861                                 0xFFFF, /* in_max_output_length */
2862                                 NULL, /* in_input_buffer */
2863                                 0, /* in_additional_info */
2864                                 0, /* in_flags */
2865                                 ph->fid_persistent,
2866                                 ph->fid_volatile,
2867                                 frame,
2868                                 &outbuf);
2869
2870         if (!NT_STATUS_IS_OK(status)) {
2871                 goto fail;
2872         }
2873
2874         /* Parse the reply. */
2875         ea_list = read_nttrans_ea_list(ctx,
2876                                 (const char *)outbuf.data,
2877                                 outbuf.length);
2878         if (ea_list == NULL) {
2879                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2880                 goto fail;
2881         }
2882
2883         /* Convert to an array. */
2884         for (eal = ea_list; eal; eal = eal->next) {
2885                 ea_count++;
2886         }
2887
2888         if (ea_count) {
2889                 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2890                 if (*pea_array == NULL) {
2891                         status = NT_STATUS_NO_MEMORY;
2892                         goto fail;
2893                 }
2894                 ea_count = 0;
2895                 for (eal = ea_list; eal; eal = eal->next) {
2896                         (*pea_array)[ea_count++] = eal->ea;
2897                 }
2898                 *pnum_eas = ea_count;
2899         }
2900
2901   fail:
2902
2903         if (fnum != 0xffff) {
2904                 cli_smb2_close_fnum(cli, fnum);
2905         }
2906
2907         cli->raw_status = status;
2908
2909         TALLOC_FREE(frame);
2910         return status;
2911 }
2912
2913 /***************************************************************
2914  Wrapper that allows SMB2 to get user quota.
2915  Synchronous only.
2916 ***************************************************************/
2917
2918 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
2919                                  int quota_fnum,
2920                                  SMB_NTQUOTA_STRUCT *pqt)
2921 {
2922         NTSTATUS status;
2923         DATA_BLOB inbuf = data_blob_null;
2924         DATA_BLOB info_blob = data_blob_null;
2925         DATA_BLOB outbuf = data_blob_null;
2926         struct smb2_hnd *ph = NULL;
2927         TALLOC_CTX *frame = talloc_stackframe();
2928         unsigned sid_len;
2929         unsigned int offset;
2930         struct smb2_query_quota_info query = {0};
2931         struct file_get_quota_info info = {0};
2932         enum ndr_err_code err;
2933         struct ndr_push *ndr_push = NULL;
2934
2935         if (smbXcli_conn_has_async_calls(cli->conn)) {
2936                 /*
2937                  * Can't use sync call while an async call is in flight
2938                  */
2939                 status = NT_STATUS_INVALID_PARAMETER;
2940                 goto fail;
2941         }
2942
2943         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2944                 status = NT_STATUS_INVALID_PARAMETER;
2945                 goto fail;
2946         }
2947
2948         status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2949         if (!NT_STATUS_IS_OK(status)) {
2950                 goto fail;
2951         }
2952
2953         sid_len = ndr_size_dom_sid(&pqt->sid, 0);
2954
2955         query.return_single = 1;
2956
2957         info.next_entry_offset = 0;
2958         info.sid_length = sid_len;
2959         info.sid = pqt->sid;
2960
2961         err = ndr_push_struct_blob(
2962                         &info_blob,
2963                         frame,
2964                         &info,
2965                         (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
2966
2967         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
2968                 status = NT_STATUS_INTERNAL_ERROR;