46a4ae95977d43a8fd65bf88f29f4d2d36abcdc7
[bbaumbach/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 smb2_create_blobs in_cblobs;
162         struct smb2_create_blobs out_cblobs;
163         struct smb_create_returns cr;
164         uint16_t fnum;
165         struct tevent_req *subreq;
166 };
167
168 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
169 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
170
171 struct tevent_req *cli_smb2_create_fnum_send(
172         TALLOC_CTX *mem_ctx,
173         struct tevent_context *ev,
174         struct cli_state *cli,
175         const char *fname,
176         uint32_t create_flags,
177         uint32_t impersonation_level,
178         uint32_t desired_access,
179         uint32_t file_attributes,
180         uint32_t share_access,
181         uint32_t create_disposition,
182         uint32_t create_options,
183         const struct smb2_create_blobs *in_cblobs)
184 {
185         struct tevent_req *req, *subreq;
186         struct cli_smb2_create_fnum_state *state;
187         size_t fname_len = 0;
188         const char *startp = NULL;
189         const char *endp = NULL;
190         time_t tstamp = (time_t)0;
191         NTSTATUS status;
192
193         req = tevent_req_create(mem_ctx, &state,
194                                 struct cli_smb2_create_fnum_state);
195         if (req == NULL) {
196                 return NULL;
197         }
198         state->cli = cli;
199
200         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
201                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
202                 return tevent_req_post(req, ev);
203         }
204
205         if (cli->backup_intent) {
206                 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
207         }
208
209         /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
210         fname_len = strlen(fname);
211         if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
212                 size_t len_before_gmt = startp - fname;
213                 size_t len_after_gmt = fname + fname_len - endp;
214                 DATA_BLOB twrp_blob;
215                 NTTIME ntt;
216
217                 char *new_fname = talloc_array(state, char,
218                                 len_before_gmt + len_after_gmt + 1);
219
220                 if (tevent_req_nomem(new_fname, req)) {
221                         return tevent_req_post(req, ev);
222                 }
223
224                 memcpy(new_fname, fname, len_before_gmt);
225                 memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
226                 fname = new_fname;
227                 fname_len = len_before_gmt + len_after_gmt;
228
229                 unix_to_nt_time(&ntt, tstamp);
230                 twrp_blob = data_blob_const((const void *)&ntt, 8);
231
232                 status = smb2_create_blob_add(
233                         state,
234                         &state->in_cblobs,
235                         SMB2_CREATE_TAG_TWRP,
236                         twrp_blob);
237                 if (!NT_STATUS_IS_OK(status)) {
238                         tevent_req_nterror(req, status);
239                         return tevent_req_post(req, ev);
240                 }
241         }
242
243         if (in_cblobs != NULL) {
244                 uint32_t i;
245                 for (i=0; i<in_cblobs->num_blobs; i++) {
246                         struct smb2_create_blob *b = &in_cblobs->blobs[i];
247                         status = smb2_create_blob_add(
248                                 state, &state->in_cblobs, b->tag, b->data);
249                         if (!NT_STATUS_IS_OK(status)) {
250                                 tevent_req_nterror(req, status);
251                                 return tevent_req_post(req, ev);
252                         }
253                 }
254         }
255
256         /* SMB2 is pickier about pathnames. Ensure it doesn't
257            start in a '\' */
258         if (*fname == '\\') {
259                 fname++;
260                 fname_len--;
261         }
262
263         /* Or end in a '\' */
264         if (fname_len > 0 && fname[fname_len-1] == '\\') {
265                 char *new_fname = talloc_strdup(state, fname);
266                 if (tevent_req_nomem(new_fname, req)) {
267                         return tevent_req_post(req, ev);
268                 }
269                 new_fname[fname_len-1] = '\0';
270                 fname = new_fname;
271         }
272
273         subreq = smb2cli_create_send(state, ev,
274                                      cli->conn,
275                                      cli->timeout,
276                                      cli->smb2.session,
277                                      cli->smb2.tcon,
278                                      fname,
279                                      flags_to_smb2_oplock(create_flags),
280                                      impersonation_level,
281                                      desired_access,
282                                      file_attributes,
283                                      share_access,
284                                      create_disposition,
285                                      create_options,
286                                      &state->in_cblobs);
287         if (tevent_req_nomem(subreq, req)) {
288                 return tevent_req_post(req, ev);
289         }
290         tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
291
292         state->subreq = subreq;
293         tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
294
295         return req;
296 }
297
298 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
299 {
300         struct tevent_req *req = tevent_req_callback_data(
301                 subreq, struct tevent_req);
302         struct cli_smb2_create_fnum_state *state = tevent_req_data(
303                 req, struct cli_smb2_create_fnum_state);
304         struct smb2_hnd h;
305         NTSTATUS status;
306
307         status = smb2cli_create_recv(
308                 subreq,
309                 &h.fid_persistent,
310                 &h.fid_volatile, &state->cr,
311                 state,
312                 &state->out_cblobs);
313         TALLOC_FREE(subreq);
314         if (tevent_req_nterror(req, status)) {
315                 return;
316         }
317
318         status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
319         if (tevent_req_nterror(req, status)) {
320                 return;
321         }
322         tevent_req_done(req);
323 }
324
325 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
326 {
327         struct cli_smb2_create_fnum_state *state = tevent_req_data(
328                 req, struct cli_smb2_create_fnum_state);
329         return tevent_req_cancel(state->subreq);
330 }
331
332 NTSTATUS cli_smb2_create_fnum_recv(
333         struct tevent_req *req,
334         uint16_t *pfnum,
335         struct smb_create_returns *cr,
336         TALLOC_CTX *mem_ctx,
337         struct smb2_create_blobs *out_cblobs)
338 {
339         struct cli_smb2_create_fnum_state *state = tevent_req_data(
340                 req, struct cli_smb2_create_fnum_state);
341         NTSTATUS status;
342
343         if (tevent_req_is_nterror(req, &status)) {
344                 state->cli->raw_status = status;
345                 return status;
346         }
347         if (pfnum != NULL) {
348                 *pfnum = state->fnum;
349         }
350         if (cr != NULL) {
351                 *cr = state->cr;
352         }
353         if (out_cblobs != NULL) {
354                 *out_cblobs = (struct smb2_create_blobs) {
355                         .num_blobs = state->out_cblobs.num_blobs,
356                         .blobs = talloc_move(
357                                 mem_ctx, &state->out_cblobs.blobs),
358                 };
359         }
360         state->cli->raw_status = NT_STATUS_OK;
361         return NT_STATUS_OK;
362 }
363
364 NTSTATUS cli_smb2_create_fnum(
365         struct cli_state *cli,
366         const char *fname,
367         uint32_t create_flags,
368         uint32_t impersonation_level,
369         uint32_t desired_access,
370         uint32_t file_attributes,
371         uint32_t share_access,
372         uint32_t create_disposition,
373         uint32_t create_options,
374         const struct smb2_create_blobs *in_cblobs,
375         uint16_t *pfid,
376         struct smb_create_returns *cr,
377         TALLOC_CTX *mem_ctx,
378         struct smb2_create_blobs *out_cblobs)
379 {
380         TALLOC_CTX *frame = talloc_stackframe();
381         struct tevent_context *ev;
382         struct tevent_req *req;
383         NTSTATUS status = NT_STATUS_NO_MEMORY;
384
385         if (smbXcli_conn_has_async_calls(cli->conn)) {
386                 /*
387                  * Can't use sync call while an async call is in flight
388                  */
389                 status = NT_STATUS_INVALID_PARAMETER;
390                 goto fail;
391         }
392         ev = samba_tevent_context_init(frame);
393         if (ev == NULL) {
394                 goto fail;
395         }
396         req = cli_smb2_create_fnum_send(
397                 frame,
398                 ev,
399                 cli,
400                 fname,
401                 create_flags,
402                 impersonation_level,
403                 desired_access,
404                 file_attributes,
405                 share_access,
406                 create_disposition,
407                 create_options,
408                 in_cblobs);
409         if (req == NULL) {
410                 goto fail;
411         }
412         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
413                 goto fail;
414         }
415         status = cli_smb2_create_fnum_recv(req, pfid, cr, mem_ctx, out_cblobs);
416  fail:
417         TALLOC_FREE(frame);
418         return status;
419 }
420
421 /***************************************************************
422  Small wrapper that allows SMB2 close to use a uint16_t fnum.
423 ***************************************************************/
424
425 struct cli_smb2_close_fnum_state {
426         struct cli_state *cli;
427         uint16_t fnum;
428         struct smb2_hnd *ph;
429 };
430
431 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
432
433 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
434                                             struct tevent_context *ev,
435                                             struct cli_state *cli,
436                                             uint16_t fnum)
437 {
438         struct tevent_req *req, *subreq;
439         struct cli_smb2_close_fnum_state *state;
440         NTSTATUS status;
441
442         req = tevent_req_create(mem_ctx, &state,
443                                 struct cli_smb2_close_fnum_state);
444         if (req == NULL) {
445                 return NULL;
446         }
447         state->cli = cli;
448         state->fnum = fnum;
449
450         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
451                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
452                 return tevent_req_post(req, ev);
453         }
454
455         status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
456         if (tevent_req_nterror(req, status)) {
457                 return tevent_req_post(req, ev);
458         }
459
460         subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
461                                     cli->smb2.session, cli->smb2.tcon,
462                                     0, state->ph->fid_persistent,
463                                     state->ph->fid_volatile);
464         if (tevent_req_nomem(subreq, req)) {
465                 return tevent_req_post(req, ev);
466         }
467         tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
468         return req;
469 }
470
471 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
472 {
473         struct tevent_req *req = tevent_req_callback_data(
474                 subreq, struct tevent_req);
475         struct cli_smb2_close_fnum_state *state = tevent_req_data(
476                 req, struct cli_smb2_close_fnum_state);
477         NTSTATUS status;
478
479         status = smb2cli_close_recv(subreq);
480         if (tevent_req_nterror(req, status)) {
481                 return;
482         }
483
484         /* Delete the fnum -> handle mapping. */
485         status = delete_smb2_handle_mapping(state->cli, &state->ph,
486                                             state->fnum);
487         if (tevent_req_nterror(req, status)) {
488                 return;
489         }
490         tevent_req_done(req);
491 }
492
493 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
494 {
495         struct cli_smb2_close_fnum_state *state = tevent_req_data(
496                 req, struct cli_smb2_close_fnum_state);
497         NTSTATUS status = NT_STATUS_OK;
498
499         if (tevent_req_is_nterror(req, &status)) {
500                 state->cli->raw_status = status;
501         }
502         tevent_req_received(req);
503         return status;
504 }
505
506 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
507 {
508         TALLOC_CTX *frame = talloc_stackframe();
509         struct tevent_context *ev;
510         struct tevent_req *req;
511         NTSTATUS status = NT_STATUS_NO_MEMORY;
512
513         if (smbXcli_conn_has_async_calls(cli->conn)) {
514                 /*
515                  * Can't use sync call while an async call is in flight
516                  */
517                 status = NT_STATUS_INVALID_PARAMETER;
518                 goto fail;
519         }
520         ev = samba_tevent_context_init(frame);
521         if (ev == NULL) {
522                 goto fail;
523         }
524         req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
525         if (req == NULL) {
526                 goto fail;
527         }
528         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
529                 goto fail;
530         }
531         status = cli_smb2_close_fnum_recv(req);
532  fail:
533         TALLOC_FREE(frame);
534         return status;
535 }
536
537 struct cli_smb2_set_info_fnum_state {
538         uint8_t dummy;
539 };
540
541 static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq);
542
543 struct tevent_req *cli_smb2_set_info_fnum_send(
544         TALLOC_CTX *mem_ctx,
545         struct tevent_context *ev,
546         struct cli_state *cli,
547         uint16_t fnum,
548         uint8_t in_info_type,
549         uint8_t in_info_class,
550         const DATA_BLOB *in_input_buffer,
551         uint32_t in_additional_info)
552 {
553         struct tevent_req *req = NULL, *subreq = NULL;
554         struct cli_smb2_set_info_fnum_state *state = NULL;
555         struct smb2_hnd *ph = NULL;
556         NTSTATUS status;
557
558         req = tevent_req_create(
559                 mem_ctx, &state, struct cli_smb2_set_info_fnum_state);
560         if (req == NULL) {
561                 return NULL;
562         }
563
564         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
565         if (tevent_req_nterror(req, status)) {
566                 return tevent_req_post(req, ev);
567         }
568
569         subreq = smb2cli_set_info_send(
570                 state,
571                 ev,
572                 cli->conn,
573                 cli->timeout,
574                 cli->smb2.session,
575                 cli->smb2.tcon,
576                 in_info_type,
577                 in_info_class,
578                 in_input_buffer,
579                 in_additional_info,
580                 ph->fid_persistent,
581                 ph->fid_volatile);
582         if (tevent_req_nomem(subreq, req)) {
583                 return tevent_req_post(req, ev);
584         }
585         tevent_req_set_callback(subreq, cli_smb2_set_info_fnum_done, req);
586         return req;
587 }
588
589 static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq)
590 {
591         NTSTATUS status = smb2cli_set_info_recv(subreq);
592         tevent_req_simple_finish_ntstatus(subreq, status);
593 }
594
595 NTSTATUS cli_smb2_set_info_fnum_recv(struct tevent_req *req)
596 {
597         return tevent_req_simple_recv_ntstatus(req);
598 }
599
600 NTSTATUS cli_smb2_set_info_fnum(
601         struct cli_state *cli,
602         uint16_t fnum,
603         uint8_t in_info_type,
604         uint8_t in_info_class,
605         const DATA_BLOB *in_input_buffer,
606         uint32_t in_additional_info)
607 {
608         TALLOC_CTX *frame = talloc_stackframe();
609         struct tevent_context *ev = NULL;
610         struct tevent_req *req = NULL;
611         NTSTATUS status = NT_STATUS_NO_MEMORY;
612         bool ok;
613
614         if (smbXcli_conn_has_async_calls(cli->conn)) {
615                 /*
616                  * Can't use sync call while an async call is in flight
617                  */
618                 status = NT_STATUS_INVALID_PARAMETER;
619                 goto fail;
620         }
621         ev = samba_tevent_context_init(frame);
622         if (ev == NULL) {
623                 goto fail;
624         }
625         req = cli_smb2_set_info_fnum_send(
626                 frame,
627                 ev,
628                 cli,
629                 fnum,
630                 in_info_type,
631                 in_info_class,
632                 in_input_buffer,
633                 in_additional_info);
634         if (req == NULL) {
635                 goto fail;
636         }
637         ok = tevent_req_poll_ntstatus(req, ev, &status);
638         if (!ok) {
639                 goto fail;
640         }
641         status = cli_smb2_set_info_fnum_recv(req);
642 fail:
643         TALLOC_FREE(frame);
644         return status;
645 }
646
647 struct cli_smb2_delete_on_close_state {
648         struct cli_state *cli;
649         uint8_t data[1];
650         DATA_BLOB inbuf;
651 };
652
653 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
654
655 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
656                                         struct tevent_context *ev,
657                                         struct cli_state *cli,
658                                         uint16_t fnum,
659                                         bool flag)
660 {
661         struct tevent_req *req = NULL;
662         struct cli_smb2_delete_on_close_state *state = NULL;
663         struct tevent_req *subreq = NULL;
664         uint8_t in_info_type;
665         uint8_t in_file_info_class;
666
667         req = tevent_req_create(mem_ctx, &state,
668                                 struct cli_smb2_delete_on_close_state);
669         if (req == NULL) {
670                 return NULL;
671         }
672         state->cli = cli;
673
674         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
675                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
676                 return tevent_req_post(req, ev);
677         }
678
679         /*
680          * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
681          * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
682          */
683         in_info_type = 1;
684         in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
685         /* Setup data array. */
686         SCVAL(&state->data[0], 0, flag ? 1 : 0);
687         state->inbuf.data = &state->data[0];
688         state->inbuf.length = 1;
689
690         subreq = cli_smb2_set_info_fnum_send(
691                 state,
692                 ev,
693                 cli,
694                 fnum,
695                 in_info_type,
696                 in_file_info_class,
697                 &state->inbuf,
698                 0);
699         if (tevent_req_nomem(subreq, req)) {
700                 return tevent_req_post(req, ev);
701         }
702         tevent_req_set_callback(subreq,
703                                 cli_smb2_delete_on_close_done,
704                                 req);
705         return req;
706 }
707
708 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
709 {
710         NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
711         tevent_req_simple_finish_ntstatus(subreq, status);
712 }
713
714 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
715 {
716         struct cli_smb2_delete_on_close_state *state =
717                 tevent_req_data(req,
718                 struct cli_smb2_delete_on_close_state);
719         NTSTATUS status;
720
721         if (tevent_req_is_nterror(req, &status)) {
722                 state->cli->raw_status = status;
723                 tevent_req_received(req);
724                 return status;
725         }
726
727         state->cli->raw_status = NT_STATUS_OK;
728         tevent_req_received(req);
729         return NT_STATUS_OK;
730 }
731
732 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
733 {
734         TALLOC_CTX *frame = talloc_stackframe();
735         struct tevent_context *ev;
736         struct tevent_req *req;
737         NTSTATUS status = NT_STATUS_NO_MEMORY;
738
739         if (smbXcli_conn_has_async_calls(cli->conn)) {
740                 /*
741                  * Can't use sync call while an async call is in flight
742                  */
743                 status = NT_STATUS_INVALID_PARAMETER;
744                 goto fail;
745         }
746         ev = samba_tevent_context_init(frame);
747         if (ev == NULL) {
748                 goto fail;
749         }
750         req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
751         if (req == NULL) {
752                 goto fail;
753         }
754         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
755                 goto fail;
756         }
757         status = cli_smb2_delete_on_close_recv(req);
758  fail:
759         TALLOC_FREE(frame);
760         return status;
761 }
762
763 struct cli_smb2_mkdir_state {
764         struct tevent_context *ev;
765         struct cli_state *cli;
766 };
767
768 static void cli_smb2_mkdir_opened(struct tevent_req *subreq);
769 static void cli_smb2_mkdir_closed(struct tevent_req *subreq);
770
771 struct tevent_req *cli_smb2_mkdir_send(
772         TALLOC_CTX *mem_ctx,
773         struct tevent_context *ev,
774         struct cli_state *cli,
775         const char *dname)
776 {
777         struct tevent_req *req = NULL, *subreq = NULL;
778         struct cli_smb2_mkdir_state *state = NULL;
779
780         req = tevent_req_create(
781                 mem_ctx, &state, struct cli_smb2_mkdir_state);
782         if (req == NULL) {
783                 return NULL;
784         }
785         state->ev = ev;
786         state->cli = cli;
787
788         /* Ensure this is a directory. */
789         subreq = cli_smb2_create_fnum_send(
790                 state,                             /* mem_ctx */
791                 ev,                                /* ev */
792                 cli,                               /* cli */
793                 dname,                             /* fname */
794                 0,                                 /* create_flags */
795                 SMB2_IMPERSONATION_IMPERSONATION,  /* impersonation_level */
796                 FILE_READ_ATTRIBUTES,              /* desired_access */
797                 FILE_ATTRIBUTE_DIRECTORY,          /* file_attributes */
798                 FILE_SHARE_READ|
799                 FILE_SHARE_WRITE,                  /* share_access */
800                 FILE_CREATE,                       /* create_disposition */
801                 FILE_DIRECTORY_FILE,               /* create_options */
802                 NULL);                             /* in_cblobs */
803         if (tevent_req_nomem(subreq, req)) {
804                 return tevent_req_post(req, ev);
805         }
806         tevent_req_set_callback(subreq, cli_smb2_mkdir_opened, req);
807         return req;
808 }
809
810 static void cli_smb2_mkdir_opened(struct tevent_req *subreq)
811 {
812         struct tevent_req *req = tevent_req_callback_data(
813                 subreq, struct tevent_req);
814         struct cli_smb2_mkdir_state *state = tevent_req_data(
815                 req, struct cli_smb2_mkdir_state);
816         NTSTATUS status;
817         uint16_t fnum;
818
819         status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
820         TALLOC_FREE(subreq);
821         if (tevent_req_nterror(req, status)) {
822                 return;
823         }
824
825         subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
826         if (tevent_req_nomem(subreq, req)) {
827                 return;
828         }
829         tevent_req_set_callback(subreq, cli_smb2_mkdir_closed, req);
830 }
831
832 static void cli_smb2_mkdir_closed(struct tevent_req *subreq)
833 {
834         NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
835         tevent_req_simple_finish_ntstatus(subreq, status);
836 }
837
838 NTSTATUS cli_smb2_mkdir_recv(struct tevent_req *req)
839 {
840         return tevent_req_simple_recv_ntstatus(req);
841 }
842
843 struct cli_smb2_rmdir_state {
844         struct tevent_context *ev;
845         struct cli_state *cli;
846         const char *dname;
847         const struct smb2_create_blobs *in_cblobs;
848         uint16_t fnum;
849         NTSTATUS status;
850 };
851
852 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq);
853 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq);
854 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq);
855 static void cli_smb2_rmdir_closed(struct tevent_req *subreq);
856
857 struct tevent_req *cli_smb2_rmdir_send(
858         TALLOC_CTX *mem_ctx,
859         struct tevent_context *ev,
860         struct cli_state *cli,
861         const char *dname,
862         const struct smb2_create_blobs *in_cblobs)
863 {
864         struct tevent_req *req = NULL, *subreq = NULL;
865         struct cli_smb2_rmdir_state *state = NULL;
866
867         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_rmdir_state);
868         if (req == NULL) {
869                 return NULL;
870         }
871         state->ev = ev;
872         state->cli = cli;
873         state->dname = dname;
874         state->in_cblobs = in_cblobs;
875
876         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
877                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
878                 return tevent_req_post(req, ev);
879         }
880
881         subreq = cli_smb2_create_fnum_send(
882                 state,
883                 state->ev,
884                 state->cli,
885                 state->dname,
886                 0,                      /* create_flags */
887                 SMB2_IMPERSONATION_IMPERSONATION,
888                 DELETE_ACCESS,          /* desired_access */
889                 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
890                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
891                 FILE_OPEN,              /* create_disposition */
892                 FILE_DIRECTORY_FILE,    /* create_options */
893                 state->in_cblobs);      /* in_cblobs */
894         if (tevent_req_nomem(subreq, req)) {
895                 return tevent_req_post(req, ev);
896         }
897         tevent_req_set_callback(subreq, cli_smb2_rmdir_opened1, req);
898         return req;
899 }
900
901 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq)
902 {
903         struct tevent_req *req = tevent_req_callback_data(
904                 subreq, struct tevent_req);
905         struct cli_smb2_rmdir_state *state = tevent_req_data(
906                 req, struct cli_smb2_rmdir_state);
907         NTSTATUS status;
908
909         status = cli_smb2_create_fnum_recv(
910                 subreq, &state->fnum, NULL, NULL, NULL);
911         TALLOC_FREE(subreq);
912
913         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
914                 /*
915                  * Naive option to match our SMB1 code. Assume the
916                  * symlink path that tripped us up was the last
917                  * component and try again. Eventually we will have to
918                  * deal with the returned path unprocessed component. JRA.
919                  */
920                 subreq = cli_smb2_create_fnum_send(
921                         state,
922                         state->ev,
923                         state->cli,
924                         state->dname,
925                         0,                      /* create_flags */
926                         SMB2_IMPERSONATION_IMPERSONATION,
927                         DELETE_ACCESS,          /* desired_access */
928                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
929                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
930                         FILE_OPEN,              /* create_disposition */
931                         FILE_DIRECTORY_FILE|
932                         FILE_DELETE_ON_CLOSE|
933                         FILE_OPEN_REPARSE_POINT, /* create_options */
934                         state->in_cblobs);       /* in_cblobs */
935                 if (tevent_req_nomem(subreq, req)) {
936                         return;
937                 }
938                 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened2, req);
939                 return;
940         }
941
942         if (tevent_req_nterror(req, status)) {
943                 return;
944         }
945
946         subreq = cli_smb2_delete_on_close_send(
947                 state, state->ev, state->cli, state->fnum, true);
948         if (tevent_req_nomem(subreq, req)) {
949                 return;
950         }
951         tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
952 }
953
954 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq)
955 {
956         struct tevent_req *req = tevent_req_callback_data(
957                 subreq, struct tevent_req);
958         struct cli_smb2_rmdir_state *state = tevent_req_data(
959                 req, struct cli_smb2_rmdir_state);
960         NTSTATUS status;
961
962         status = cli_smb2_create_fnum_recv(
963                 subreq, &state->fnum, NULL, NULL, NULL);
964         TALLOC_FREE(subreq);
965         if (tevent_req_nterror(req, status)) {
966                 return;
967         }
968
969         subreq = cli_smb2_delete_on_close_send(
970                 state, state->ev, state->cli, state->fnum, true);
971         if (tevent_req_nomem(subreq, req)) {
972                 return;
973         }
974         tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
975 }
976
977 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq)
978 {
979         struct tevent_req *req = tevent_req_callback_data(
980                 subreq, struct tevent_req);
981         struct cli_smb2_rmdir_state *state = tevent_req_data(
982                 req, struct cli_smb2_rmdir_state);
983
984         state->status = cli_smb2_delete_on_close_recv(subreq);
985         TALLOC_FREE(subreq);
986
987         /*
988          * Close the fd even if the set_disp failed
989          */
990
991         subreq = cli_smb2_close_fnum_send(
992                 state, state->ev, state->cli, state->fnum);
993         if (tevent_req_nomem(subreq, req)) {
994                 return;
995         }
996         tevent_req_set_callback(subreq, cli_smb2_rmdir_closed, req);
997 }
998
999 static void cli_smb2_rmdir_closed(struct tevent_req *subreq)
1000 {
1001         NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1002         tevent_req_simple_finish_ntstatus(subreq, status);
1003 }
1004
1005 NTSTATUS cli_smb2_rmdir_recv(struct tevent_req *req)
1006 {
1007         struct cli_smb2_rmdir_state *state = tevent_req_data(
1008                 req, struct cli_smb2_rmdir_state);
1009         NTSTATUS status;
1010
1011         if (tevent_req_is_nterror(req, &status)) {
1012                 return status;
1013         }
1014         return state->status;
1015 }
1016
1017 /***************************************************************
1018  Small wrapper that allows SMB2 to unlink a pathname.
1019 ***************************************************************/
1020
1021 struct cli_smb2_unlink_state {
1022         struct tevent_context *ev;
1023         struct cli_state *cli;
1024         const char *fname;
1025         const struct smb2_create_blobs *in_cblobs;
1026 };
1027
1028 static void cli_smb2_unlink_opened1(struct tevent_req *subreq);
1029 static void cli_smb2_unlink_opened2(struct tevent_req *subreq);
1030 static void cli_smb2_unlink_closed(struct tevent_req *subreq);
1031
1032 struct tevent_req *cli_smb2_unlink_send(
1033         TALLOC_CTX *mem_ctx,
1034         struct tevent_context *ev,
1035         struct cli_state *cli,
1036         const char *fname,
1037         const struct smb2_create_blobs *in_cblobs)
1038 {
1039         struct tevent_req *req = NULL, *subreq = NULL;
1040         struct cli_smb2_unlink_state *state = NULL;
1041
1042         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_unlink_state);
1043         if (req == NULL) {
1044                 return NULL;
1045         }
1046         state->ev = ev;
1047         state->cli = cli;
1048         state->fname = fname;
1049         state->in_cblobs = in_cblobs;
1050
1051         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1052                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1053                 return tevent_req_post(req, ev);
1054         }
1055
1056         subreq = cli_smb2_create_fnum_send(
1057                 state,          /* mem_ctx */
1058                 state->ev,      /* tevent_context */
1059                 state->cli,     /* cli_struct */
1060                 state->fname,   /* filename */
1061                 0,                      /* create_flags */
1062                 SMB2_IMPERSONATION_IMPERSONATION,
1063                 DELETE_ACCESS,          /* desired_access */
1064                 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1065                 FILE_SHARE_READ|
1066                 FILE_SHARE_WRITE|
1067                 FILE_SHARE_DELETE, /* share_access */
1068                 FILE_OPEN,              /* create_disposition */
1069                 FILE_DELETE_ON_CLOSE,   /* create_options */
1070                 state->in_cblobs);      /* in_cblobs */
1071         if (tevent_req_nomem(subreq, req)) {
1072                 return tevent_req_post(req, ev);
1073         }
1074         tevent_req_set_callback(subreq, cli_smb2_unlink_opened1, req);
1075         return req;
1076 }
1077
1078 static void cli_smb2_unlink_opened1(struct tevent_req *subreq)
1079 {
1080         struct tevent_req *req = tevent_req_callback_data(
1081                 subreq, struct tevent_req);
1082         struct cli_smb2_unlink_state *state = tevent_req_data(
1083                 req, struct cli_smb2_unlink_state);
1084         uint16_t fnum;
1085         NTSTATUS status;
1086
1087         status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1088         TALLOC_FREE(subreq);
1089
1090         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1091                 /*
1092                  * Naive option to match our SMB1 code. Assume the
1093                  * symlink path that tripped us up was the last
1094                  * component and try again. Eventually we will have to
1095                  * deal with the returned path unprocessed component. JRA.
1096                  */
1097                 subreq = cli_smb2_create_fnum_send(
1098                         state,          /* mem_ctx */
1099                         state->ev,      /* tevent_context */
1100                         state->cli,     /* cli_struct */
1101                         state->fname,   /* filename */
1102                         0,                      /* create_flags */
1103                         SMB2_IMPERSONATION_IMPERSONATION,
1104                         DELETE_ACCESS,          /* desired_access */
1105                         FILE_ATTRIBUTE_NORMAL, /* file attributes */
1106                         FILE_SHARE_READ|
1107                         FILE_SHARE_WRITE|
1108                         FILE_SHARE_DELETE, /* share_access */
1109                         FILE_OPEN,              /* create_disposition */
1110                         FILE_DELETE_ON_CLOSE|
1111                         FILE_OPEN_REPARSE_POINT, /* create_options */
1112                         state->in_cblobs);       /* in_cblobs */
1113                 if (tevent_req_nomem(subreq, req)) {
1114                         return;
1115                 }
1116                 tevent_req_set_callback(subreq, cli_smb2_unlink_opened2, req);
1117                 return;
1118         }
1119
1120         if (tevent_req_nterror(req, status)) {
1121                 return;
1122         }
1123
1124         subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1125         if (tevent_req_nomem(subreq, req)) {
1126                 return;
1127         }
1128         tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1129 }
1130
1131 static void cli_smb2_unlink_opened2(struct tevent_req *subreq)
1132 {
1133         struct tevent_req *req = tevent_req_callback_data(
1134                 subreq, struct tevent_req);
1135         struct cli_smb2_unlink_state *state = tevent_req_data(
1136                 req, struct cli_smb2_unlink_state);
1137         uint16_t fnum;
1138         NTSTATUS status;
1139
1140         status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1141         TALLOC_FREE(subreq);
1142         if (tevent_req_nterror(req, status)) {
1143                 return;
1144         }
1145
1146         subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1147         if (tevent_req_nomem(subreq, req)) {
1148                 return;
1149         }
1150         tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1151 }
1152
1153 static void cli_smb2_unlink_closed(struct tevent_req *subreq)
1154 {
1155         NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1156         tevent_req_simple_finish_ntstatus(subreq, status);
1157 }
1158
1159 NTSTATUS cli_smb2_unlink_recv(struct tevent_req *req)
1160 {
1161         return tevent_req_simple_recv_ntstatus(req);
1162 }
1163
1164 /***************************************************************
1165  Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1166 ***************************************************************/
1167
1168 static NTSTATUS parse_finfo_id_both_directory_info(const uint8_t *dir_data,
1169                                 uint32_t dir_data_length,
1170                                 struct file_info *finfo,
1171                                 uint32_t *next_offset)
1172 {
1173         size_t namelen = 0;
1174         size_t slen = 0;
1175         size_t ret = 0;
1176
1177         if (dir_data_length < 4) {
1178                 return NT_STATUS_INFO_LENGTH_MISMATCH;
1179         }
1180
1181         *next_offset = IVAL(dir_data, 0);
1182
1183         if (*next_offset > dir_data_length) {
1184                 return NT_STATUS_INFO_LENGTH_MISMATCH;
1185         }
1186
1187         if (*next_offset != 0) {
1188                 /* Ensure we only read what in this record. */
1189                 dir_data_length = *next_offset;
1190         }
1191
1192         if (dir_data_length < 105) {
1193                 return NT_STATUS_INFO_LENGTH_MISMATCH;
1194         }
1195
1196         finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
1197         finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
1198         finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
1199         finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
1200         finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
1201         finfo->allocated_size = IVAL2_TO_SMB_BIG_UINT(dir_data + 48, 0);
1202         /* NB. We need to enlarge finfo->mode to be 32-bits. */
1203         finfo->mode = (uint16_t)IVAL(dir_data + 56, 0);
1204         finfo->ino = IVAL2_TO_SMB_BIG_UINT(dir_data + 96, 0);
1205         namelen = IVAL(dir_data + 60,0);
1206         if (namelen > (dir_data_length - 104)) {
1207                 return NT_STATUS_INFO_LENGTH_MISMATCH;
1208         }
1209         slen = CVAL(dir_data + 68, 0);
1210         if (slen > 24) {
1211                 return NT_STATUS_INFO_LENGTH_MISMATCH;
1212         }
1213         ret = pull_string_talloc(finfo,
1214                                 dir_data,
1215                                 FLAGS2_UNICODE_STRINGS,
1216                                 &finfo->short_name,
1217                                 dir_data + 70,
1218                                 slen,
1219                                 STR_UNICODE);
1220         if (ret == (size_t)-1) {
1221                 /* Bad conversion. */
1222                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1223         }
1224
1225         ret = pull_string_talloc(finfo,
1226                                 dir_data,
1227                                 FLAGS2_UNICODE_STRINGS,
1228                                 &finfo->name,
1229                                 dir_data + 104,
1230                                 namelen,
1231                                 STR_UNICODE);
1232         if (ret == (size_t)-1) {
1233                 /* Bad conversion. */
1234                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1235         }
1236
1237         if (finfo->name == NULL) {
1238                 /* Bad conversion. */
1239                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1240         }
1241
1242         return NT_STATUS_OK;
1243 }
1244
1245 /*******************************************************************
1246  Given a filename - get its directory name
1247 ********************************************************************/
1248
1249 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
1250                                 const char *dir,
1251                                 char **parent,
1252                                 const char **name)
1253 {
1254         char *p;
1255         ptrdiff_t len;
1256
1257         p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
1258
1259         if (p == NULL) {
1260                 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
1261                         return false;
1262                 }
1263                 if (name) {
1264                         *name = dir;
1265                 }
1266                 return true;
1267         }
1268
1269         len = p-dir;
1270
1271         if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
1272                 return false;
1273         }
1274         (*parent)[len] = '\0';
1275
1276         if (name) {
1277                 *name = p+1;
1278         }
1279         return true;
1280 }
1281
1282 /***************************************************************
1283  Wrapper that allows SMB2 to list a directory.
1284  Synchronous only.
1285 ***************************************************************/
1286
1287 NTSTATUS cli_smb2_list(struct cli_state *cli,
1288                         const char *pathname,
1289                         uint16_t attribute,
1290                         NTSTATUS (*fn)(const char *,
1291                                 struct file_info *,
1292                                 const char *,
1293                                 void *),
1294                         void *state)
1295 {
1296         NTSTATUS status;
1297         uint16_t fnum = 0xffff;
1298         char *parent_dir = NULL;
1299         const char *mask = NULL;
1300         struct smb2_hnd *ph = NULL;
1301         bool processed_file = false;
1302         TALLOC_CTX *frame = talloc_stackframe();
1303         TALLOC_CTX *subframe = NULL;
1304         bool mask_has_wild;
1305         uint32_t max_trans;
1306         uint32_t max_avail_len;
1307         bool ok;
1308
1309         if (smbXcli_conn_has_async_calls(cli->conn)) {
1310                 /*
1311                  * Can't use sync call while an async call is in flight
1312                  */
1313                 status = NT_STATUS_INVALID_PARAMETER;
1314                 goto fail;
1315         }
1316
1317         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1318                 status = NT_STATUS_INVALID_PARAMETER;
1319                 goto fail;
1320         }
1321
1322         /* Get the directory name. */
1323         if (!windows_parent_dirname(frame,
1324                                 pathname,
1325                                 &parent_dir,
1326                                 &mask)) {
1327                 status = NT_STATUS_NO_MEMORY;
1328                 goto fail;
1329         }
1330
1331         mask_has_wild = ms_has_wild(mask);
1332
1333         status = cli_smb2_create_fnum(cli,
1334                         parent_dir,
1335                         0,                      /* create_flags */
1336                         SMB2_IMPERSONATION_IMPERSONATION,
1337                         SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
1338                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1339                         FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
1340                         FILE_OPEN,              /* create_disposition */
1341                         FILE_DIRECTORY_FILE,    /* create_options */
1342                         NULL,
1343                         &fnum,
1344                         NULL,
1345                         NULL,
1346                         NULL);
1347
1348         if (!NT_STATUS_IS_OK(status)) {
1349                 goto fail;
1350         }
1351
1352         status = map_fnum_to_smb2_handle(cli,
1353                                         fnum,
1354                                         &ph);
1355         if (!NT_STATUS_IS_OK(status)) {
1356                 goto fail;
1357         }
1358
1359         /*
1360          * ideally, use the max transaction size, but don't send a request
1361          * bigger than we have credits available for
1362          */
1363         max_trans = smb2cli_conn_max_trans_size(cli->conn);
1364         ok = smb2cli_conn_req_possible(cli->conn, &max_avail_len);
1365         if (ok) {
1366                 max_trans = MIN(max_trans, max_avail_len);
1367         }
1368
1369         do {
1370                 uint8_t *dir_data = NULL;
1371                 uint32_t dir_data_length = 0;
1372                 uint32_t next_offset = 0;
1373                 subframe = talloc_stackframe();
1374
1375                 status = smb2cli_query_directory(cli->conn,
1376                                         cli->timeout,
1377                                         cli->smb2.session,
1378                                         cli->smb2.tcon,
1379                                         SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
1380                                         0,      /* flags */
1381                                         0,      /* file_index */
1382                                         ph->fid_persistent,
1383                                         ph->fid_volatile,
1384                                         mask,
1385                                         max_trans,
1386                                         subframe,
1387                                         &dir_data,
1388                                         &dir_data_length);
1389
1390                 if (!NT_STATUS_IS_OK(status)) {
1391                         if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1392                                 break;
1393                         }
1394                         goto fail;
1395                 }
1396
1397                 do {
1398                         struct file_info *finfo = talloc_zero(subframe,
1399                                                         struct file_info);
1400
1401                         if (finfo == NULL) {
1402                                 status = NT_STATUS_NO_MEMORY;
1403                                 goto fail;
1404                         }
1405
1406                         status = parse_finfo_id_both_directory_info(dir_data,
1407                                                 dir_data_length,
1408                                                 finfo,
1409                                                 &next_offset);
1410
1411                         if (!NT_STATUS_IS_OK(status)) {
1412                                 goto fail;
1413                         }
1414
1415                         /* Protect against server attack. */
1416                         status = is_bad_finfo_name(cli, finfo);
1417                         if (!NT_STATUS_IS_OK(status)) {
1418                                 smbXcli_conn_disconnect(cli->conn, status);
1419                                 goto fail;
1420                         }
1421
1422                         if (dir_check_ftype((uint32_t)finfo->mode,
1423                                         (uint32_t)attribute)) {
1424                                 /*
1425                                  * Only process if attributes match.
1426                                  * On SMB1 server does this, so on
1427                                  * SMB2 we need to emulate in the
1428                                  * client.
1429                                  *
1430                                  * https://bugzilla.samba.org/show_bug.cgi?id=10260
1431                                  */
1432                                 processed_file = true;
1433
1434                                 status = fn(cli->dfs_mountpoint,
1435                                         finfo,
1436                                         pathname,
1437                                         state);
1438
1439                                 if (!NT_STATUS_IS_OK(status)) {
1440                                         break;
1441                                 }
1442                         }
1443
1444                         TALLOC_FREE(finfo);
1445
1446                         /* Move to next entry. */
1447                         if (next_offset) {
1448                                 dir_data += next_offset;
1449                                 dir_data_length -= next_offset;
1450                         }
1451                 } while (next_offset != 0);
1452
1453                 TALLOC_FREE(subframe);
1454
1455                 if (!mask_has_wild) {
1456                         /*
1457                          * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1458                          * when handed a non-wildcard path. Do it
1459                          * for the server (with a non-wildcard path
1460                          * there should only ever be one file returned.
1461                          */
1462                         status = STATUS_NO_MORE_FILES;
1463                         break;
1464                 }
1465
1466         } while (NT_STATUS_IS_OK(status));
1467
1468         if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1469                 status = NT_STATUS_OK;
1470         }
1471
1472         if (NT_STATUS_IS_OK(status) && !processed_file) {
1473                 /*
1474                  * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1475                  * if no files match. Emulate this in the client.
1476                  */
1477                 status = NT_STATUS_NO_SUCH_FILE;
1478         }
1479
1480   fail:
1481
1482         if (fnum != 0xffff) {
1483                 cli_smb2_close_fnum(cli, fnum);
1484         }
1485
1486         cli->raw_status = status;
1487
1488         TALLOC_FREE(subframe);
1489         TALLOC_FREE(frame);
1490         return status;
1491 }
1492
1493 /***************************************************************
1494  Wrapper that allows SMB2 to query a path info (basic level).
1495  Synchronous only.
1496 ***************************************************************/
1497
1498 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1499                                 const char *name,
1500                                 SMB_STRUCT_STAT *sbuf,
1501                                 uint32_t *attributes)
1502 {
1503         NTSTATUS status;
1504         struct smb_create_returns cr;
1505         uint16_t fnum = 0xffff;
1506         size_t namelen = strlen(name);
1507
1508         if (smbXcli_conn_has_async_calls(cli->conn)) {
1509                 /*
1510                  * Can't use sync call while an async call is in flight
1511                  */
1512                 return NT_STATUS_INVALID_PARAMETER;
1513         }
1514
1515         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1516                 return NT_STATUS_INVALID_PARAMETER;
1517         }
1518
1519         /* SMB2 is pickier about pathnames. Ensure it doesn't
1520            end in a '\' */
1521         if (namelen > 0 && name[namelen-1] == '\\') {
1522                 char *modname = talloc_strndup(talloc_tos(), name, namelen-1);
1523                 if (modname == NULL) {
1524                         return NT_STATUS_NO_MEMORY;
1525                 }
1526                 name = modname;
1527         }
1528
1529         /* This is commonly used as a 'cd'. Try qpathinfo on
1530            a directory handle first. */
1531
1532         status = cli_smb2_create_fnum(cli,
1533                         name,
1534                         0,                      /* create_flags */
1535                         SMB2_IMPERSONATION_IMPERSONATION,
1536                         FILE_READ_ATTRIBUTES,   /* desired_access */
1537                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1538                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1539                         FILE_OPEN,              /* create_disposition */
1540                         FILE_DIRECTORY_FILE,    /* create_options */
1541                         NULL,
1542                         &fnum,
1543                         &cr,
1544                         NULL,
1545                         NULL);
1546
1547         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1548                 /* Maybe a file ? */
1549                 status = cli_smb2_create_fnum(cli,
1550                         name,
1551                         0,                      /* create_flags */
1552                         SMB2_IMPERSONATION_IMPERSONATION,
1553                         FILE_READ_ATTRIBUTES,           /* desired_access */
1554                         0, /* file attributes */
1555                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1556                         FILE_OPEN,              /* create_disposition */
1557                         0,      /* create_options */
1558                         NULL,
1559                         &fnum,
1560                         &cr,
1561                         NULL,
1562                         NULL);
1563         }
1564
1565         if (!NT_STATUS_IS_OK(status)) {
1566                 return status;
1567         }
1568
1569         status = cli_smb2_close_fnum(cli, fnum);
1570
1571         ZERO_STRUCTP(sbuf);
1572
1573         sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1574         sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1575         sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1576         sbuf->st_ex_size = cr.end_of_file;
1577         *attributes = cr.file_attributes;
1578
1579         return status;
1580 }
1581
1582 struct cli_smb2_chkpath_state {
1583         struct tevent_context *ev;
1584         struct cli_state *cli;
1585 };
1586
1587 static void cli_smb2_chkpath_opened(struct tevent_req *subreq);
1588 static void cli_smb2_chkpath_closed(struct tevent_req *subreq);
1589
1590 struct tevent_req *cli_smb2_chkpath_send(
1591         TALLOC_CTX *mem_ctx,
1592         struct tevent_context *ev,
1593         struct cli_state *cli,
1594         const char *name)
1595 {
1596         struct tevent_req *req = NULL, *subreq = NULL;
1597         struct cli_smb2_chkpath_state *state = NULL;
1598
1599         req = tevent_req_create(
1600                 mem_ctx, &state, struct cli_smb2_chkpath_state);
1601         if (req == NULL) {
1602                 return NULL;
1603         }
1604         state->ev = ev;
1605         state->cli = cli;
1606
1607         /* Ensure this is a directory. */
1608         subreq = cli_smb2_create_fnum_send(
1609                 state,                             /* mem_ctx */
1610                 ev,                                /* ev */
1611                 cli,                               /* cli */
1612                 name,                              /* fname */
1613                 0,                                 /* create_flags */
1614                 SMB2_IMPERSONATION_IMPERSONATION,  /* impersonation_level */
1615                 FILE_READ_ATTRIBUTES,              /* desired_access */
1616                 FILE_ATTRIBUTE_DIRECTORY,          /* file_attributes */
1617                 FILE_SHARE_READ|
1618                 FILE_SHARE_WRITE|
1619                 FILE_SHARE_DELETE,                 /* share_access */
1620                 FILE_OPEN,                         /* create_disposition */
1621                 FILE_DIRECTORY_FILE,               /* create_options */
1622                 NULL);                             /* in_cblobs */
1623         if (tevent_req_nomem(subreq, req)) {
1624                 return tevent_req_post(req, ev);
1625         }
1626         tevent_req_set_callback(subreq, cli_smb2_chkpath_opened, req);
1627         return req;
1628 }
1629
1630 static void cli_smb2_chkpath_opened(struct tevent_req *subreq)
1631 {
1632         struct tevent_req *req = tevent_req_callback_data(
1633                 subreq, struct tevent_req);
1634         struct cli_smb2_chkpath_state *state = tevent_req_data(
1635                 req, struct cli_smb2_chkpath_state);
1636         NTSTATUS status;
1637         uint16_t fnum;
1638
1639         status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1640         TALLOC_FREE(subreq);
1641         if (tevent_req_nterror(req, status)) {
1642                 return;
1643         }
1644
1645         subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1646         if (tevent_req_nomem(subreq, req)) {
1647                 return;
1648         }
1649         tevent_req_set_callback(subreq, cli_smb2_chkpath_closed, req);
1650 }
1651
1652 static void cli_smb2_chkpath_closed(struct tevent_req *subreq)
1653 {
1654         NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1655         tevent_req_simple_finish_ntstatus(subreq, status);
1656 }
1657
1658 NTSTATUS cli_smb2_chkpath_recv(struct tevent_req *req)
1659 {
1660         return tevent_req_simple_recv_ntstatus(req);
1661 }
1662
1663 struct cli_smb2_query_info_fnum_state {
1664         DATA_BLOB outbuf;
1665 };
1666
1667 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq);
1668
1669 struct tevent_req *cli_smb2_query_info_fnum_send(
1670         TALLOC_CTX *mem_ctx,
1671         struct tevent_context *ev,
1672         struct cli_state *cli,
1673         uint16_t fnum,
1674         uint8_t in_info_type,
1675         uint8_t in_info_class,
1676         uint32_t in_max_output_length,
1677         const DATA_BLOB *in_input_buffer,
1678         uint32_t in_additional_info,
1679         uint32_t in_flags)
1680 {
1681         struct tevent_req *req = NULL, *subreq = NULL;
1682         struct cli_smb2_query_info_fnum_state *state = NULL;
1683         struct smb2_hnd *ph = NULL;
1684         NTSTATUS status;
1685
1686         req = tevent_req_create(
1687                 mem_ctx, &state, struct cli_smb2_query_info_fnum_state);
1688         if (req == NULL) {
1689                 return req;
1690         }
1691
1692         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1693         if (tevent_req_nterror(req, status)) {
1694                 return tevent_req_post(req, ev);
1695         }
1696
1697         subreq = smb2cli_query_info_send(
1698                 state,
1699                 ev,
1700                 cli->conn,
1701                 cli->timeout,
1702                 cli->smb2.session,
1703                 cli->smb2.tcon,
1704                 in_info_type,
1705                 in_info_class,
1706                 in_max_output_length,
1707                 in_input_buffer,
1708                 in_additional_info,
1709                 in_flags,
1710                 ph->fid_persistent,
1711                 ph->fid_volatile);
1712         if (tevent_req_nomem(subreq, req)) {
1713                 return tevent_req_post(req, ev);
1714         }
1715         tevent_req_set_callback(subreq, cli_smb2_query_info_fnum_done, req);
1716         return req;
1717 }
1718
1719 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq)
1720 {
1721         struct tevent_req *req = tevent_req_callback_data(
1722                 subreq, struct tevent_req);
1723         struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1724                 req, struct cli_smb2_query_info_fnum_state);
1725         DATA_BLOB outbuf;
1726         NTSTATUS status;
1727
1728         status = smb2cli_query_info_recv(subreq, state, &outbuf);
1729         TALLOC_FREE(subreq);
1730         if (tevent_req_nterror(req, status)) {
1731                 return;
1732         }
1733
1734         /*
1735          * We have to dup the memory here because outbuf.data is not
1736          * returned as a talloc object by smb2cli_query_info_recv.
1737          * It's a pointer into the received buffer.
1738          */
1739         state->outbuf = data_blob_dup_talloc(state, outbuf);
1740
1741         if ((outbuf.length != 0) &&
1742             tevent_req_nomem(state->outbuf.data, req)) {
1743                 return;
1744         }
1745         tevent_req_done(req);
1746 }
1747
1748 NTSTATUS cli_smb2_query_info_fnum_recv(
1749         struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *outbuf)
1750 {
1751         struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1752                 req, struct cli_smb2_query_info_fnum_state);
1753         NTSTATUS status;
1754
1755         if (tevent_req_is_nterror(req, &status)) {
1756                 return status;
1757         }
1758         *outbuf = (DATA_BLOB) {
1759                 .data = talloc_move(mem_ctx, &state->outbuf.data),
1760                 .length = state->outbuf.length,
1761         };
1762         return NT_STATUS_OK;
1763 }
1764
1765 NTSTATUS cli_smb2_query_info_fnum(
1766         struct cli_state *cli,
1767         uint16_t fnum,
1768         uint8_t in_info_type,
1769         uint8_t in_info_class,
1770         uint32_t in_max_output_length,
1771         const DATA_BLOB *in_input_buffer,
1772         uint32_t in_additional_info,
1773         uint32_t in_flags,
1774         TALLOC_CTX *mem_ctx,
1775         DATA_BLOB *outbuf)
1776 {
1777         TALLOC_CTX *frame = talloc_stackframe();
1778         struct tevent_context *ev = NULL;
1779         struct tevent_req *req = NULL;
1780         NTSTATUS status = NT_STATUS_NO_MEMORY;
1781         bool ok;
1782
1783         if (smbXcli_conn_has_async_calls(cli->conn)) {
1784                 /*
1785                  * Can't use sync call while an async call is in flight
1786                  */
1787                 status = NT_STATUS_INVALID_PARAMETER;
1788                 goto fail;
1789         }
1790         ev = samba_tevent_context_init(frame);
1791         if (ev == NULL) {
1792                 goto fail;
1793         }
1794         req = cli_smb2_query_info_fnum_send(
1795                 frame,
1796                 ev,
1797                 cli,
1798                 fnum,
1799                 in_info_type,
1800                 in_info_class,
1801                 in_max_output_length,
1802                 in_input_buffer,
1803                 in_additional_info,
1804                 in_flags);
1805         if (req == NULL) {
1806                 goto fail;
1807         }
1808         ok = tevent_req_poll_ntstatus(req, ev, &status);
1809         if (!ok) {
1810                 goto fail;
1811         }
1812         status = cli_smb2_query_info_fnum_recv(req, mem_ctx, outbuf);
1813 fail:
1814         TALLOC_FREE(frame);
1815         return status;
1816 }
1817
1818 /***************************************************************
1819  Helper function for pathname operations.
1820 ***************************************************************/
1821
1822 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1823                                 const char *name,
1824                                 uint32_t desired_access,
1825                                 uint16_t *pfnum)
1826 {
1827         NTSTATUS status;
1828         size_t namelen = strlen(name);
1829         TALLOC_CTX *frame = talloc_stackframe();
1830         uint32_t create_options = 0;
1831
1832         /* SMB2 is pickier about pathnames. Ensure it doesn't
1833            end in a '\' */
1834         if (namelen > 0 && name[namelen-1] == '\\') {
1835                 char *modname = talloc_strdup(frame, name);
1836                 if (modname == NULL) {
1837                         status = NT_STATUS_NO_MEMORY;
1838                         goto fail;
1839                 }
1840                 modname[namelen-1] = '\0';
1841                 name = modname;
1842         }
1843
1844         /* Try to open a file handle first. */
1845         status = cli_smb2_create_fnum(cli,
1846                         name,
1847                         0,                      /* create_flags */
1848                         SMB2_IMPERSONATION_IMPERSONATION,
1849                         desired_access,
1850                         0, /* file attributes */
1851                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1852                         FILE_OPEN,              /* create_disposition */
1853                         create_options,
1854                         NULL,
1855                         pfnum,
1856                         NULL,
1857                         NULL,
1858                         NULL);
1859
1860         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1861                 /*
1862                  * Naive option to match our SMB1 code. Assume the
1863                  * symlink path that tripped us up was the last
1864                  * component and try again. Eventually we will have to
1865                  * deal with the returned path unprocessed component. JRA.
1866                  */
1867                 create_options |= FILE_OPEN_REPARSE_POINT;
1868                 status = cli_smb2_create_fnum(cli,
1869                         name,
1870                         0,                      /* create_flags */
1871                         SMB2_IMPERSONATION_IMPERSONATION,
1872                         desired_access,
1873                         0, /* file attributes */
1874                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1875                         FILE_OPEN,              /* create_disposition */
1876                         create_options,
1877                         NULL,
1878                         pfnum,
1879                         NULL,
1880                         NULL,
1881                         NULL);
1882         }
1883
1884         if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1885                 create_options |= FILE_DIRECTORY_FILE;
1886                 status = cli_smb2_create_fnum(cli,
1887                         name,
1888                         0,                      /* create_flags */
1889                         SMB2_IMPERSONATION_IMPERSONATION,
1890                         desired_access,
1891                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1892                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1893                         FILE_OPEN,              /* create_disposition */
1894                         create_options,         /* create_options */
1895                         NULL,
1896                         pfnum,
1897                         NULL,
1898                         NULL,
1899                         NULL);
1900         }
1901
1902   fail:
1903
1904         TALLOC_FREE(frame);
1905         return status;
1906 }
1907
1908 /***************************************************************
1909  Wrapper that allows SMB2 to query a path info (ALTNAME level).
1910  Synchronous only.
1911 ***************************************************************/
1912
1913 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1914                                 const char *name,
1915                                 fstring alt_name)
1916 {
1917         NTSTATUS status;
1918         DATA_BLOB outbuf = data_blob_null;
1919         uint16_t fnum = 0xffff;
1920         uint32_t altnamelen = 0;
1921         TALLOC_CTX *frame = talloc_stackframe();
1922
1923         if (smbXcli_conn_has_async_calls(cli->conn)) {
1924                 /*
1925                  * Can't use sync call while an async call is in flight
1926                  */
1927                 status = NT_STATUS_INVALID_PARAMETER;
1928                 goto fail;
1929         }
1930
1931         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1932                 status = NT_STATUS_INVALID_PARAMETER;
1933                 goto fail;
1934         }
1935
1936         status = get_fnum_from_path(cli,
1937                                 name,
1938                                 FILE_READ_ATTRIBUTES,
1939                                 &fnum);
1940
1941         if (!NT_STATUS_IS_OK(status)) {
1942                 goto fail;
1943         }
1944
1945         status = cli_smb2_query_info_fnum(
1946                 cli,
1947                 fnum,
1948                 1, /* in_info_type */
1949                 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1950                 0xFFFF, /* in_max_output_length */
1951                 NULL, /* in_input_buffer */
1952                 0, /* in_additional_info */
1953                 0, /* in_flags */
1954                 frame,
1955                 &outbuf);
1956
1957         if (!NT_STATUS_IS_OK(status)) {
1958                 goto fail;
1959         }
1960
1961         /* Parse the reply. */
1962         if (outbuf.length < 4) {
1963                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1964                 goto fail;
1965         }
1966
1967         altnamelen = IVAL(outbuf.data, 0);
1968         if (altnamelen > outbuf.length - 4) {
1969                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1970                 goto fail;
1971         }
1972
1973         if (altnamelen > 0) {
1974                 size_t ret = 0;
1975                 char *short_name = NULL;
1976                 ret = pull_string_talloc(frame,
1977                                 outbuf.data,
1978                                 FLAGS2_UNICODE_STRINGS,
1979                                 &short_name,
1980                                 outbuf.data + 4,
1981                                 altnamelen,
1982                                 STR_UNICODE);
1983                 if (ret == (size_t)-1) {
1984                         /* Bad conversion. */
1985                         status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1986                         goto fail;
1987                 }
1988
1989                 fstrcpy(alt_name, short_name);
1990         } else {
1991                 alt_name[0] = '\0';
1992         }
1993
1994         status = NT_STATUS_OK;
1995
1996   fail:
1997
1998         if (fnum != 0xffff) {
1999                 cli_smb2_close_fnum(cli, fnum);
2000         }
2001
2002         cli->raw_status = status;
2003
2004         TALLOC_FREE(frame);
2005         return status;
2006 }
2007
2008
2009 /***************************************************************
2010  Wrapper that allows SMB2 to query a fnum info (basic level).
2011  Synchronous only.
2012 ***************************************************************/
2013
2014 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
2015                         uint16_t fnum,
2016                         uint16_t *mode,
2017                         off_t *size,
2018                         struct timespec *create_time,
2019                         struct timespec *access_time,
2020                         struct timespec *write_time,
2021                         struct timespec *change_time,
2022                         SMB_INO_T *ino)
2023 {
2024         NTSTATUS status;
2025         DATA_BLOB outbuf = data_blob_null;
2026         TALLOC_CTX *frame = talloc_stackframe();
2027
2028         if (smbXcli_conn_has_async_calls(cli->conn)) {
2029                 /*
2030                  * Can't use sync call while an async call is in flight
2031                  */
2032                 status = NT_STATUS_INVALID_PARAMETER;
2033                 goto fail;
2034         }
2035
2036         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2037                 status = NT_STATUS_INVALID_PARAMETER;
2038                 goto fail;
2039         }
2040
2041         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2042            level 0x12 (SMB2_FILE_ALL_INFORMATION). */
2043
2044         status = cli_smb2_query_info_fnum(
2045                 cli,
2046                 fnum,
2047                 1, /* in_info_type */
2048                 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
2049                 0xFFFF, /* in_max_output_length */
2050                 NULL, /* in_input_buffer */
2051                 0, /* in_additional_info */
2052                 0, /* in_flags */
2053                 frame,
2054                 &outbuf);
2055         if (!NT_STATUS_IS_OK(status)) {
2056                 goto fail;
2057         }
2058
2059         /* Parse the reply. */
2060         if (outbuf.length < 0x60) {
2061                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2062                 goto fail;
2063         }
2064
2065         if (create_time) {
2066                 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
2067         }
2068         if (access_time) {
2069                 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
2070         }
2071         if (write_time) {
2072                 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
2073         }
2074         if (change_time) {
2075                 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
2076         }
2077         if (mode) {
2078                 uint32_t attr = IVAL(outbuf.data, 0x20);
2079                 *mode = (uint16_t)attr;
2080         }
2081         if (size) {
2082                 uint64_t file_size = BVAL(outbuf.data, 0x30);
2083                 *size = (off_t)file_size;
2084         }
2085         if (ino) {
2086                 uint64_t file_index = BVAL(outbuf.data, 0x40);
2087                 *ino = (SMB_INO_T)file_index;
2088         }
2089
2090   fail:
2091
2092         cli->raw_status = status;
2093
2094         TALLOC_FREE(frame);
2095         return status;
2096 }
2097
2098 /***************************************************************
2099  Wrapper that allows SMB2 to query an fnum.
2100  Implement on top of cli_smb2_qfileinfo_basic().
2101  Synchronous only.
2102 ***************************************************************/
2103
2104 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
2105                         uint16_t fnum,
2106                         uint16_t *attr,
2107                         off_t *size,
2108                         time_t *change_time,
2109                         time_t *access_time,
2110                         time_t *write_time)
2111 {
2112         struct timespec access_time_ts;
2113         struct timespec write_time_ts;
2114         struct timespec change_time_ts;
2115         NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
2116                                         fnum,
2117                                         attr,
2118                                         size,
2119                                         NULL,
2120                                         &access_time_ts,
2121                                         &write_time_ts,
2122                                         &change_time_ts,
2123                                         NULL);
2124
2125         cli->raw_status = status;
2126
2127         if (!NT_STATUS_IS_OK(status)) {
2128                 return status;
2129         }
2130
2131         if (change_time) {
2132                 *change_time = change_time_ts.tv_sec;
2133         }
2134         if (access_time) {
2135                 *access_time = access_time_ts.tv_sec;
2136         }
2137         if (write_time) {
2138                 *write_time = write_time_ts.tv_sec;
2139         }
2140         return NT_STATUS_OK;
2141 }
2142
2143 /***************************************************************
2144  Wrapper that allows SMB2 to get pathname attributes.
2145  Synchronous only.
2146 ***************************************************************/
2147
2148 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
2149                         const char *name,
2150                         uint16_t *attr,
2151                         off_t *size,
2152                         time_t *write_time)
2153 {
2154         NTSTATUS status;
2155         uint16_t fnum = 0xffff;
2156         struct smb2_hnd *ph = NULL;
2157         TALLOC_CTX *frame = talloc_stackframe();
2158
2159         if (smbXcli_conn_has_async_calls(cli->conn)) {
2160                 /*
2161                  * Can't use sync call while an async call is in flight
2162                  */
2163                 status = NT_STATUS_INVALID_PARAMETER;
2164                 goto fail;
2165         }
2166
2167         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2168                 status = NT_STATUS_INVALID_PARAMETER;
2169                 goto fail;
2170         }
2171
2172         status = get_fnum_from_path(cli,
2173                                 name,
2174                                 FILE_READ_ATTRIBUTES,
2175                                 &fnum);
2176
2177         if (!NT_STATUS_IS_OK(status)) {
2178                 goto fail;
2179         }
2180
2181         status = map_fnum_to_smb2_handle(cli,
2182                                         fnum,
2183                                         &ph);
2184         if (!NT_STATUS_IS_OK(status)) {
2185                 goto fail;
2186         }
2187         status = cli_smb2_getattrE(cli,
2188                                 fnum,
2189                                 attr,
2190                                 size,
2191                                 NULL,
2192                                 NULL,
2193                                 write_time);
2194         if (!NT_STATUS_IS_OK(status)) {
2195                 goto fail;
2196         }
2197
2198   fail:
2199
2200         if (fnum != 0xffff) {
2201                 cli_smb2_close_fnum(cli, fnum);
2202         }
2203
2204         cli->raw_status = status;
2205
2206         TALLOC_FREE(frame);
2207         return status;
2208 }
2209
2210 /***************************************************************
2211  Wrapper that allows SMB2 to query a pathname info (basic level).
2212  Implement on top of cli_smb2_qfileinfo_basic().
2213  Synchronous only.
2214 ***************************************************************/
2215
2216 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
2217                         const char *name,
2218                         struct timespec *create_time,
2219                         struct timespec *access_time,
2220                         struct timespec *write_time,
2221                         struct timespec *change_time,
2222                         off_t *size,
2223                         uint16_t *mode,
2224                         SMB_INO_T *ino)
2225 {
2226         NTSTATUS status;
2227         struct smb2_hnd *ph = NULL;
2228         uint16_t fnum = 0xffff;
2229         TALLOC_CTX *frame = talloc_stackframe();
2230
2231         if (smbXcli_conn_has_async_calls(cli->conn)) {
2232                 /*
2233                  * Can't use sync call while an async call is in flight
2234                  */
2235                 status = NT_STATUS_INVALID_PARAMETER;
2236                 goto fail;
2237         }
2238
2239         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2240                 status = NT_STATUS_INVALID_PARAMETER;
2241                 goto fail;
2242         }
2243
2244         status = get_fnum_from_path(cli,
2245                                         name,
2246                                         FILE_READ_ATTRIBUTES,
2247                                         &fnum);
2248
2249         if (!NT_STATUS_IS_OK(status)) {
2250                 goto fail;
2251         }
2252
2253         status = map_fnum_to_smb2_handle(cli,
2254                                         fnum,
2255                                         &ph);
2256         if (!NT_STATUS_IS_OK(status)) {
2257                 goto fail;
2258         }
2259
2260         status = cli_smb2_qfileinfo_basic(cli,
2261                                         fnum,
2262                                         mode,
2263                                         size,
2264                                         create_time,
2265                                         access_time,
2266                                         write_time,
2267                                         change_time,
2268                                         ino);
2269
2270   fail:
2271
2272         if (fnum != 0xffff) {
2273                 cli_smb2_close_fnum(cli, fnum);
2274         }
2275
2276         cli->raw_status = status;
2277
2278         TALLOC_FREE(frame);
2279         return status;
2280 }
2281
2282 /***************************************************************
2283  Wrapper that allows SMB2 to query pathname streams.
2284  Synchronous only.
2285 ***************************************************************/
2286
2287 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
2288                                 const char *name,
2289                                 TALLOC_CTX *mem_ctx,
2290                                 unsigned int *pnum_streams,
2291                                 struct stream_struct **pstreams)
2292 {
2293         NTSTATUS status;
2294         uint16_t fnum = 0xffff;
2295         DATA_BLOB outbuf = data_blob_null;
2296         TALLOC_CTX *frame = talloc_stackframe();
2297
2298         if (smbXcli_conn_has_async_calls(cli->conn)) {
2299                 /*
2300                  * Can't use sync call while an async call is in flight
2301                  */
2302                 status = NT_STATUS_INVALID_PARAMETER;
2303                 goto fail;
2304         }
2305
2306         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2307                 status = NT_STATUS_INVALID_PARAMETER;
2308                 goto fail;
2309         }
2310
2311         status = get_fnum_from_path(cli,
2312                                 name,
2313                                 FILE_READ_ATTRIBUTES,
2314                                 &fnum);
2315
2316         if (!NT_STATUS_IS_OK(status)) {
2317                 goto fail;
2318         }
2319
2320         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2321            level 22 (SMB2_FILE_STREAM_INFORMATION). */
2322
2323         status = cli_smb2_query_info_fnum(
2324                 cli,
2325                 fnum,
2326                 1, /* in_info_type */
2327                 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
2328                 0xFFFF, /* in_max_output_length */
2329                 NULL, /* in_input_buffer */
2330                 0, /* in_additional_info */
2331                 0, /* in_flags */
2332                 frame,
2333                 &outbuf);
2334
2335         if (!NT_STATUS_IS_OK(status)) {
2336                 goto fail;
2337         }
2338
2339         /* Parse the reply. */
2340         if (!parse_streams_blob(mem_ctx,
2341                                 outbuf.data,
2342                                 outbuf.length,
2343                                 pnum_streams,
2344                                 pstreams)) {
2345                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2346                 goto fail;
2347         }
2348
2349   fail:
2350
2351         if (fnum != 0xffff) {
2352                 cli_smb2_close_fnum(cli, fnum);
2353         }
2354
2355         cli->raw_status = status;
2356
2357         TALLOC_FREE(frame);
2358         return status;
2359 }
2360
2361 /***************************************************************
2362  Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2363  a pathname.
2364  Synchronous only.
2365 ***************************************************************/
2366
2367 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
2368                         const char *name,
2369                         uint8_t in_info_type,
2370                         uint8_t in_file_info_class,
2371                         const DATA_BLOB *p_in_data)
2372 {
2373         NTSTATUS status;
2374         uint16_t fnum = 0xffff;
2375         TALLOC_CTX *frame = talloc_stackframe();
2376
2377         if (smbXcli_conn_has_async_calls(cli->conn)) {
2378                 /*
2379                  * Can't use sync call while an async call is in flight
2380                  */
2381                 status = NT_STATUS_INVALID_PARAMETER;
2382                 goto fail;
2383         }
2384
2385         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2386                 status = NT_STATUS_INVALID_PARAMETER;
2387                 goto fail;
2388         }
2389
2390         status = get_fnum_from_path(cli,
2391                                 name,
2392                                 FILE_WRITE_ATTRIBUTES,
2393                                 &fnum);
2394
2395         if (!NT_STATUS_IS_OK(status)) {
2396                 goto fail;
2397         }
2398
2399         status = cli_smb2_set_info_fnum(
2400                 cli,
2401                 fnum,
2402                 in_info_type,
2403                 in_file_info_class,
2404                 p_in_data,         /* in_input_buffer */
2405                 0);                /* in_additional_info */
2406   fail:
2407
2408         if (fnum != 0xffff) {
2409                 cli_smb2_close_fnum(cli, fnum);
2410         }
2411
2412         cli->raw_status = status;
2413
2414         TALLOC_FREE(frame);
2415         return status;
2416 }
2417
2418
2419 /***************************************************************
2420  Wrapper that allows SMB2 to set pathname attributes.
2421  Synchronous only.
2422 ***************************************************************/
2423
2424 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
2425                         const char *name,
2426                         uint16_t attr,
2427                         time_t mtime)
2428 {
2429         uint8_t inbuf_store[40];
2430         DATA_BLOB inbuf = data_blob_null;
2431
2432         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2433            level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2434
2435         inbuf.data = inbuf_store;
2436         inbuf.length = sizeof(inbuf_store);
2437         data_blob_clear(&inbuf);
2438
2439         /*
2440          * SMB1 uses attr == 0 to clear all attributes
2441          * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2442          * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2443          * request attribute change.
2444          *
2445          * SMB2 uses exactly the reverse. Unfortunately as the
2446          * cli_setatr() ABI is exposed inside libsmbclient,
2447          * we must make the SMB2 cli_smb2_setatr() call
2448          * export the same ABI as the SMB1 cli_setatr()
2449          * which calls it. This means reversing the sense
2450          * of the requested attr argument if it's zero
2451          * or FILE_ATTRIBUTE_NORMAL.
2452          *
2453          * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2454          */
2455
2456         if (attr == 0) {
2457                 attr = FILE_ATTRIBUTE_NORMAL;
2458         } else if (attr == FILE_ATTRIBUTE_NORMAL) {
2459                 attr = 0;
2460         }
2461
2462         SSVAL(inbuf.data, 32, attr);
2463         if (mtime != 0) {
2464                 put_long_date((char *)inbuf.data + 16,mtime);
2465         }
2466         /* Set all the other times to -1. */
2467         SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2468         SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
2469         SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
2470
2471         return cli_smb2_setpathinfo(cli,
2472                                 name,
2473                                 1, /* in_info_type */
2474                                 /* in_file_info_class */
2475                                 SMB_FILE_BASIC_INFORMATION - 1000,
2476                                 &inbuf);
2477 }
2478
2479
2480 /***************************************************************
2481  Wrapper that allows SMB2 to set file handle times.
2482  Synchronous only.
2483 ***************************************************************/
2484
2485 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
2486                         uint16_t fnum,
2487                         time_t change_time,
2488                         time_t access_time,
2489                         time_t write_time)
2490 {
2491         uint8_t inbuf_store[40];
2492         DATA_BLOB inbuf = data_blob_null;
2493
2494         if (smbXcli_conn_has_async_calls(cli->conn)) {
2495                 /*
2496                  * Can't use sync call while an async call is in flight
2497                  */
2498                 return NT_STATUS_INVALID_PARAMETER;
2499         }
2500
2501         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2502                 return NT_STATUS_INVALID_PARAMETER;
2503         }
2504
2505         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2506            level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2507
2508         inbuf.data = inbuf_store;
2509         inbuf.length = sizeof(inbuf_store);
2510         data_blob_clear(&inbuf);
2511
2512         SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2513         if (change_time != 0) {
2514                 put_long_date((char *)inbuf.data + 24, change_time);
2515         }
2516         if (access_time != 0) {
2517                 put_long_date((char *)inbuf.data + 8, access_time);
2518         }
2519         if (write_time != 0) {
2520                 put_long_date((char *)inbuf.data + 16, write_time);
2521         }
2522
2523         cli->raw_status = cli_smb2_set_info_fnum(
2524                 cli,
2525                 fnum,
2526                 1,              /* in_info_type */
2527                 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
2528                 &inbuf,            /* in_input_buffer */
2529                 0);                /* in_additional_info */
2530
2531         return cli->raw_status;
2532 }
2533
2534 /***************************************************************
2535  Wrapper that allows SMB2 to query disk attributes (size).
2536  Synchronous only.
2537 ***************************************************************/
2538
2539 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2540                           uint64_t *bsize, uint64_t *total, uint64_t *avail)
2541 {
2542         NTSTATUS status;
2543         uint16_t fnum = 0xffff;
2544         DATA_BLOB outbuf = data_blob_null;
2545         uint32_t sectors_per_unit = 0;
2546         uint32_t bytes_per_sector = 0;
2547         uint64_t total_size = 0;
2548         uint64_t size_free = 0;
2549         TALLOC_CTX *frame = talloc_stackframe();
2550
2551         if (smbXcli_conn_has_async_calls(cli->conn)) {
2552                 /*
2553                  * Can't use sync call while an async call is in flight
2554                  */
2555                 status = NT_STATUS_INVALID_PARAMETER;
2556                 goto fail;
2557         }
2558
2559         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2560                 status = NT_STATUS_INVALID_PARAMETER;
2561                 goto fail;
2562         }
2563
2564         /* First open the top level directory. */
2565         status = cli_smb2_create_fnum(cli,
2566                         path,
2567                         0,                      /* create_flags */
2568                         SMB2_IMPERSONATION_IMPERSONATION,
2569                         FILE_READ_ATTRIBUTES,   /* desired_access */
2570                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2571                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2572                         FILE_OPEN,              /* create_disposition */
2573                         FILE_DIRECTORY_FILE,    /* create_options */
2574                         NULL,
2575                         &fnum,
2576                         NULL,
2577                         NULL,
2578                         NULL);
2579
2580         if (!NT_STATUS_IS_OK(status)) {
2581                 goto fail;
2582         }
2583
2584         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2585            level 3 (SMB_FS_SIZE_INFORMATION). */
2586
2587         status = cli_smb2_query_info_fnum(
2588                 cli,
2589                 fnum,
2590                 2, /* in_info_type */
2591                 3, /* in_file_info_class */
2592                 0xFFFF, /* in_max_output_length */
2593                 NULL, /* in_input_buffer */
2594                 0, /* in_additional_info */
2595                 0, /* in_flags */
2596                 frame,
2597                 &outbuf);
2598         if (!NT_STATUS_IS_OK(status)) {
2599                 goto fail;
2600         }
2601
2602         /* Parse the reply. */
2603         if (outbuf.length != 24) {
2604                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2605                 goto fail;
2606         }
2607
2608         total_size = BVAL(outbuf.data, 0);
2609         size_free = BVAL(outbuf.data, 8);
2610         sectors_per_unit = IVAL(outbuf.data, 16);
2611         bytes_per_sector = IVAL(outbuf.data, 20);
2612
2613         if (bsize) {
2614                 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2615         }
2616         if (total) {
2617                 *total = total_size;
2618         }
2619         if (avail) {
2620                 *avail = size_free;
2621         }
2622
2623         status = NT_STATUS_OK;
2624
2625   fail:
2626
2627         if (fnum != 0xffff) {
2628                 cli_smb2_close_fnum(cli, fnum);
2629         }
2630
2631         cli->raw_status = status;
2632
2633         TALLOC_FREE(frame);
2634         return status;
2635 }
2636
2637 /***************************************************************
2638  Wrapper that allows SMB2 to query file system sizes.
2639  Synchronous only.
2640 ***************************************************************/
2641
2642 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2643                                 uint64_t *total_allocation_units,
2644                                 uint64_t *caller_allocation_units,
2645                                 uint64_t *actual_allocation_units,
2646                                 uint64_t *sectors_per_allocation_unit,
2647                                 uint64_t *bytes_per_sector)
2648 {
2649         NTSTATUS status;
2650         uint16_t fnum = 0xffff;
2651         DATA_BLOB outbuf = data_blob_null;
2652         TALLOC_CTX *frame = talloc_stackframe();
2653
2654         if (smbXcli_conn_has_async_calls(cli->conn)) {
2655                 /*
2656                  * Can't use sync call while an async call is in flight
2657                  */
2658                 status = NT_STATUS_INVALID_PARAMETER;
2659                 goto fail;
2660         }
2661
2662         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2663                 status = NT_STATUS_INVALID_PARAMETER;
2664                 goto fail;
2665         }
2666
2667         /* First open the top level directory. */
2668         status =
2669             cli_smb2_create_fnum(cli, "", 0,               /* create_flags */
2670                                  SMB2_IMPERSONATION_IMPERSONATION,
2671                                  FILE_READ_ATTRIBUTES,     /* desired_access */
2672                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2673                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
2674                                      FILE_SHARE_DELETE, /* share_access */
2675                                  FILE_OPEN,             /* create_disposition */
2676                                  FILE_DIRECTORY_FILE,   /* create_options */
2677                                  NULL,
2678                                  &fnum,
2679                                  NULL,
2680                                  NULL,
2681                                  NULL);
2682
2683         if (!NT_STATUS_IS_OK(status)) {
2684                 goto fail;
2685         }
2686
2687         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2688            level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2689
2690         status = cli_smb2_query_info_fnum(
2691                 cli,
2692                 fnum,
2693                 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2694                 SMB_FS_FULL_SIZE_INFORMATION - 1000, /* in_file_info_class */
2695                 0xFFFF, /* in_max_output_length */
2696                 NULL, /* in_input_buffer */
2697                 0, /* in_additional_info */
2698                 0, /* in_flags */
2699                 frame,
2700                 &outbuf);
2701         if (!NT_STATUS_IS_OK(status)) {
2702                 goto fail;
2703         }
2704
2705         if (outbuf.length < 32) {
2706                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2707                 goto fail;
2708         }
2709
2710         *total_allocation_units = BIG_UINT(outbuf.data, 0);
2711         *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2712         *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2713         *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2714         *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2715
2716 fail:
2717
2718         if (fnum != 0xffff) {
2719                 cli_smb2_close_fnum(cli, fnum);
2720         }
2721
2722         cli->raw_status = status;
2723
2724         TALLOC_FREE(frame);
2725         return status;
2726 }
2727
2728 /***************************************************************
2729  Wrapper that allows SMB2 to query file system attributes.
2730  Synchronous only.
2731 ***************************************************************/
2732
2733 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2734 {
2735         NTSTATUS status;
2736         uint16_t fnum = 0xffff;
2737         DATA_BLOB outbuf = data_blob_null;
2738         TALLOC_CTX *frame = talloc_stackframe();
2739
2740         if (smbXcli_conn_has_async_calls(cli->conn)) {
2741                 /*
2742                  * Can't use sync call while an async call is in flight
2743                  */
2744                 status = NT_STATUS_INVALID_PARAMETER;
2745                 goto fail;
2746         }
2747
2748         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2749                 status = NT_STATUS_INVALID_PARAMETER;
2750                 goto fail;
2751         }
2752
2753         /* First open the top level directory. */
2754         status =
2755             cli_smb2_create_fnum(cli, "", 0,               /* create_flags */
2756                                  SMB2_IMPERSONATION_IMPERSONATION,
2757                                  FILE_READ_ATTRIBUTES,     /* desired_access */
2758                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2759                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
2760                                      FILE_SHARE_DELETE, /* share_access */
2761                                  FILE_OPEN,             /* create_disposition */
2762                                  FILE_DIRECTORY_FILE,   /* create_options */
2763                                  NULL,
2764                                  &fnum,
2765                                  NULL,
2766                                  NULL,
2767                                  NULL);
2768
2769         if (!NT_STATUS_IS_OK(status)) {
2770                 goto fail;
2771         }
2772
2773         status = cli_smb2_query_info_fnum(
2774                 cli,
2775                 fnum,
2776                 2, /* in_info_type */
2777                 5,                     /* in_file_info_class */
2778                 0xFFFF, /* in_max_output_length */
2779                 NULL,   /* in_input_buffer */
2780                 0,      /* in_additional_info */
2781                 0,      /* in_flags */
2782                 frame,
2783                 &outbuf);
2784         if (!NT_STATUS_IS_OK(status)) {
2785                 goto fail;
2786         }
2787
2788         if (outbuf.length < 12) {
2789                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2790                 goto fail;
2791         }
2792
2793         *fs_attr = IVAL(outbuf.data, 0);
2794
2795 fail:
2796
2797         if (fnum != 0xffff) {
2798                 cli_smb2_close_fnum(cli, fnum);
2799         }
2800
2801         cli->raw_status = status;
2802
2803         TALLOC_FREE(frame);
2804         return status;
2805 }
2806
2807 /***************************************************************
2808  Wrapper that allows SMB2 to query file system volume info.
2809  Synchronous only.
2810 ***************************************************************/
2811
2812 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2813                                 TALLOC_CTX *mem_ctx,
2814                                 char **_volume_name,
2815                                 uint32_t *pserial_number,
2816                                 time_t *pdate)
2817 {
2818         NTSTATUS status;
2819         uint16_t fnum = 0xffff;
2820         DATA_BLOB outbuf = data_blob_null;
2821         uint32_t nlen;
2822         char *volume_name = NULL;
2823         TALLOC_CTX *frame = talloc_stackframe();
2824
2825         if (smbXcli_conn_has_async_calls(cli->conn)) {
2826                 /*
2827                  * Can't use sync call while an async call is in flight
2828                  */
2829                 status = NT_STATUS_INVALID_PARAMETER;
2830                 goto fail;
2831         }
2832
2833         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2834                 status = NT_STATUS_INVALID_PARAMETER;
2835                 goto fail;
2836         }
2837
2838         /* First open the top level directory. */
2839         status =
2840             cli_smb2_create_fnum(cli, "", 0,               /* create_flags */
2841                                  SMB2_IMPERSONATION_IMPERSONATION,
2842                                  FILE_READ_ATTRIBUTES,     /* desired_access */
2843                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2844                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
2845                                      FILE_SHARE_DELETE, /* share_access */
2846                                  FILE_OPEN,             /* create_disposition */
2847                                  FILE_DIRECTORY_FILE,   /* create_options */
2848                                  NULL,
2849                                  &fnum,
2850                                  NULL,
2851                                  NULL,
2852                                  NULL);
2853
2854         if (!NT_STATUS_IS_OK(status)) {
2855                 goto fail;
2856         }
2857
2858         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2859            level 1 (SMB_FS_VOLUME_INFORMATION). */
2860
2861         status = cli_smb2_query_info_fnum(
2862                 cli,
2863                 fnum,
2864                 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2865                 /* in_file_info_class */
2866                 SMB_FS_VOLUME_INFORMATION - 1000,
2867                 0xFFFF, /* in_max_output_length */
2868                 NULL, /* in_input_buffer */
2869                 0, /* in_additional_info */
2870                 0, /* in_flags */
2871                 frame,
2872                 &outbuf);
2873         if (!NT_STATUS_IS_OK(status)) {
2874                 goto fail;
2875         }
2876
2877         if (outbuf.length < 24) {
2878                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2879                 goto fail;
2880         }
2881
2882         if (pdate) {
2883                 struct timespec ts;
2884                 ts = interpret_long_date((char *)outbuf.data);
2885                 *pdate = ts.tv_sec;
2886         }
2887         if (pserial_number) {
2888                 *pserial_number = IVAL(outbuf.data,8);
2889         }
2890         nlen = IVAL(outbuf.data,12);
2891         if (nlen + 18 < 18) {
2892                 /* Integer wrap. */
2893                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2894                 goto fail;
2895         }
2896         /*
2897          * The next check is safe as we know outbuf.length >= 24
2898          * from above.
2899          */
2900         if (nlen > (outbuf.length - 18)) {
2901                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2902                 goto fail;
2903         }
2904
2905         pull_string_talloc(mem_ctx,
2906                            (const char *)outbuf.data,
2907                            0,
2908                            &volume_name,
2909                            outbuf.data + 18,
2910                            nlen,
2911                            STR_UNICODE);
2912         if (volume_name == NULL) {
2913                 status = map_nt_error_from_unix(errno);
2914                 goto fail;
2915         }
2916
2917         *_volume_name = volume_name;
2918
2919 fail:
2920
2921         if (fnum != 0xffff) {
2922                 cli_smb2_close_fnum(cli, fnum);
2923         }
2924
2925         cli->raw_status = status;
2926
2927         TALLOC_FREE(frame);
2928         return status;
2929 }
2930
2931
2932 /***************************************************************
2933  Wrapper that allows SMB2 to query a security descriptor.
2934  Synchronous only.
2935 ***************************************************************/
2936
2937 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2938                                         uint16_t fnum,
2939                                         uint32_t sec_info,
2940                                         TALLOC_CTX *mem_ctx,
2941                                         struct security_descriptor **ppsd)
2942 {
2943         NTSTATUS status;
2944         DATA_BLOB outbuf = data_blob_null;
2945         struct security_descriptor *lsd = NULL;
2946         TALLOC_CTX *frame = talloc_stackframe();
2947
2948         if (smbXcli_conn_has_async_calls(cli->conn)) {
2949                 /*
2950                  * Can't use sync call while an async call is in flight
2951                  */
2952                 status = NT_STATUS_INVALID_PARAMETER;
2953                 goto fail;
2954         }
2955
2956         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2957                 status = NT_STATUS_INVALID_PARAMETER;
2958                 goto fail;
2959         }
2960
2961         /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2962
2963         status = cli_smb2_query_info_fnum(
2964                 cli,
2965                 fnum,
2966                 3, /* in_info_type */
2967                 0, /* in_file_info_class */
2968                 0xFFFF, /* in_max_output_length */
2969                 NULL, /* in_input_buffer */
2970                 sec_info, /* in_additional_info */
2971                 0, /* in_flags */
2972                 frame,
2973                 &outbuf);
2974
2975         if (!NT_STATUS_IS_OK(status)) {
2976                 goto fail;
2977         }
2978
2979         /* Parse the reply. */
2980         status = unmarshall_sec_desc(mem_ctx,
2981                                 outbuf.data,
2982                                 outbuf.length,
2983                                 &lsd);
2984
2985         if (!NT_STATUS_IS_OK(status)) {
2986                 goto fail;
2987         }
2988
2989         if (ppsd != NULL) {
2990                 *ppsd = lsd;
2991         } else {
2992                 TALLOC_FREE(lsd);
2993         }
2994
2995   fail:
2996
2997         cli->raw_status = status;
2998
2999         TALLOC_FREE(frame);
3000         return status;
3001 }
3002
3003 /***************************************************************
3004  Wrapper that allows SMB2 to set a security descriptor.
3005  Synchronous only.
3006 ***************************************************************/
3007
3008 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
3009                                         uint16_t fnum,
3010                                         uint32_t sec_info,
3011                                         const struct security_descriptor *sd)
3012 {
3013         NTSTATUS status;
3014         DATA_BLOB inbuf = data_blob_null;
3015         TALLOC_CTX *frame = talloc_stackframe();
3016
3017         if (smbXcli_conn_has_async_calls(cli->conn)) {
3018                 /*
3019                  * Can't use sync call while an async call is in flight
3020                  */
3021                 status = NT_STATUS_INVALID_PARAMETER;
3022                 goto fail;
3023         }
3024
3025         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3026                 status = NT_STATUS_INVALID_PARAMETER;
3027                 goto fail;
3028         }
3029
3030         status = marshall_sec_desc(frame,
3031                                 sd,
3032                                 &inbuf.data,
3033                                 &inbuf.length);
3034
3035         if (!NT_STATUS_IS_OK(status)) {
3036                 goto fail;
3037         }
3038
3039         /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
3040
3041         status = cli_smb2_set_info_fnum(
3042                 cli,
3043                 fnum,
3044                 3,                        /* in_info_type */
3045                 0,                        /* in_file_info_class */
3046                 &inbuf,                   /* in_input_buffer */
3047                 sec_info);                /* in_additional_info */
3048
3049   fail:
3050
3051         cli->raw_status = status;
3052
3053         TALLOC_FREE(frame);
3054         return status;
3055 }
3056
3057 /***************************************************************
3058  Wrapper that allows SMB2 to query a security descriptor.
3059  Synchronous only.
3060
3061 ***************************************************************/
3062
3063 struct cli_smb2_mxac_state {
3064         struct tevent_context *ev;
3065         struct cli_state *cli;
3066         const char *fname;
3067         struct smb2_create_blobs in_cblobs;
3068         uint16_t fnum;
3069         NTSTATUS status;
3070         uint32_t mxac;
3071 };
3072
3073 static void cli_smb2_mxac_opened(struct tevent_req *subreq);
3074 static void cli_smb2_mxac_closed(struct tevent_req *subreq);
3075
3076 struct tevent_req *cli_smb2_query_mxac_send(TALLOC_CTX *mem_ctx,
3077                                             struct tevent_context *ev,
3078                                             struct cli_state *cli,
3079                                             const char *fname)
3080 {
3081         struct tevent_req *req = NULL, *subreq = NULL;
3082         struct cli_smb2_mxac_state *state = NULL;
3083         NTSTATUS status;
3084
3085         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_mxac_state);
3086         if (req == NULL) {
3087                 return NULL;
3088         }
3089         *state = (struct cli_smb2_mxac_state) {
3090                 .ev = ev,
3091                 .cli = cli,
3092                 .fname = fname,
3093         };
3094
3095         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3096                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3097                 return tevent_req_post(req, ev);
3098         }
3099
3100         status = smb2_create_blob_add(state,
3101                                       &state->in_cblobs,
3102                                       SMB2_CREATE_TAG_MXAC,
3103                                       data_blob(NULL, 0));
3104         if (tevent_req_nterror(req, status)) {
3105                 return tevent_req_post(req, ev);
3106         }
3107
3108         subreq = cli_smb2_create_fnum_send(
3109                 state,
3110                 state->ev,
3111                 state->cli,
3112                 state->fname,
3113                 0,                      /* create_flags */
3114                 SMB2_IMPERSONATION_IMPERSONATION,
3115                 FILE_READ_ATTRIBUTES,
3116                 0,                      /* file attributes */
3117                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
3118                 FILE_OPEN,
3119                 0,                      /* create_options */
3120                 &state->in_cblobs);
3121         if (tevent_req_nomem(subreq, req)) {
3122                 return tevent_req_post(req, ev);
3123         }
3124         tevent_req_set_callback(subreq, cli_smb2_mxac_opened, req);
3125         return req;
3126 }
3127
3128 static void cli_smb2_mxac_opened(struct tevent_req *subreq)
3129 {
3130         struct tevent_req *req = tevent_req_callback_data(
3131                 subreq, struct tevent_req);
3132         struct cli_smb2_mxac_state *state = tevent_req_data(
3133                 req, struct cli_smb2_mxac_state);
3134         struct smb2_create_blobs out_cblobs = {0};
3135         struct smb2_create_blob *mxac_blob = NULL;
3136         NTSTATUS status;
3137
3138         status = cli_smb2_create_fnum_recv(
3139                 subreq, &state->fnum, NULL, state, &out_cblobs);
3140         TALLOC_FREE(subreq);
3141
3142         if (tevent_req_nterror(req, status)) {
3143                 return;
3144         }
3145
3146         mxac_blob = smb2_create_blob_find(&out_cblobs, SMB2_CREATE_TAG_MXAC);
3147         if (mxac_blob == NULL) {
3148                 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3149                 goto close;
3150         }
3151         if (mxac_blob->data.length != 8) {
3152                 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3153                 goto close;
3154         }
3155
3156         state->status = NT_STATUS(IVAL(mxac_blob->data.data, 0));
3157         state->mxac = IVAL(mxac_blob->data.data, 4);
3158
3159 close:
3160         subreq = cli_smb2_close_fnum_send(
3161                 state, state->ev, state->cli, state->fnum);
3162         if (tevent_req_nomem(subreq, req)) {
3163                 return;
3164         }
3165         tevent_req_set_callback(subreq, cli_smb2_mxac_closed, req);
3166
3167         return;
3168 }
3169
3170 static void cli_smb2_mxac_closed(struct tevent_req *subreq)
3171 {
3172         struct tevent_req *req = tevent_req_callback_data(
3173                 subreq, struct tevent_req);
3174         NTSTATUS status;
3175
3176         status = cli_smb2_close_fnum_recv(subreq);
3177         if (tevent_req_nterror(req, status)) {
3178                 return;
3179         }
3180
3181         tevent_req_done(req);
3182 }
3183
3184 NTSTATUS cli_smb2_query_mxac_recv(struct tevent_req *req, uint32_t *mxac)
3185 {
3186         struct cli_smb2_mxac_state *state = tevent_req_data(
3187                 req, struct cli_smb2_mxac_state);
3188         NTSTATUS status;
3189
3190         if (tevent_req_is_nterror(req, &status)) {
3191                 return status;
3192         }
3193
3194         if (!NT_STATUS_IS_OK(state->status)) {
3195                 return state->status;
3196         }
3197
3198         *mxac = state->mxac;
3199         return NT_STATUS_OK;
3200 }
3201
3202 NTSTATUS cli_smb2_query_mxac(struct cli_state *cli,
3203                              const char *fname,
3204                              uint32_t *_mxac)
3205 {
3206         TALLOC_CTX *frame = talloc_stackframe();
3207         struct tevent_context *ev = NULL;
3208         struct tevent_req *req = NULL;
3209         NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
3210         bool ok;
3211
3212         if (smbXcli_conn_has_async_calls(cli->conn)) {
3213                 /*
3214                  * Can't use sync call while an async call is in flight
3215                  */
3216                 status = NT_STATUS_INVALID_PARAMETER;
3217                 goto fail;
3218         }
3219
3220         ev = samba_tevent_context_init(frame);
3221         if (ev == NULL) {
3222                 goto fail;
3223         }
3224         req = cli_smb2_query_mxac_send(frame, ev, cli, fname);
3225         if (req == NULL) {
3226                 goto fail;
3227         }
3228         ok = tevent_req_poll_ntstatus(req, ev, &status);
3229         if (!ok) {
3230                 goto fail;
3231         }
3232         status = cli_smb2_query_mxac_recv(req, _mxac);
3233
3234 fail:
3235         cli->raw_status = status;
3236         TALLOC_FREE(frame);
3237         return status;
3238 }
3239
3240 /***************************************************************
3241  Wrapper that allows SMB2 to rename a file.
3242  Synchronous only.
3243 ***************************************************************/
3244
3245 NTSTATUS cli_smb2_rename(struct cli_state *cli,
3246                          const char *fname_src,
3247                          const char *fname_dst,
3248                          bool replace)
3249 {
3250         NTSTATUS status;
3251         DATA_BLOB inbuf = data_blob_null;
3252         uint16_t fnum = 0xffff;
3253         smb_ucs2_t *converted_str = NULL;
3254         size_t converted_size_bytes = 0;
3255         size_t namelen = 0;
3256         TALLOC_CTX *frame = talloc_stackframe();
3257
3258         if (smbXcli_conn_has_async_calls(cli->conn)) {
3259                 /*
3260                  * Can't use sync call while an async call is in flight
3261                  */
3262                 status = NT_STATUS_INVALID_PARAMETER;
3263                 goto fail;
3264         }
3265
3266         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3267                 status = NT_STATUS_INVALID_PARAMETER;
3268                 goto fail;
3269         }
3270
3271         status = get_fnum_from_path(cli,
3272                                 fname_src,
3273                                 DELETE_ACCESS,
3274                                 &fnum);
3275
3276         if (!NT_STATUS_IS_OK(status)) {
3277                 goto fail;
3278         }
3279
3280         /* SMB2 is pickier about pathnames. Ensure it doesn't
3281            start in a '\' */
3282         if (*fname_dst == '\\') {
3283                 fname_dst++;
3284         }
3285
3286         /* SMB2 is pickier about pathnames. Ensure it doesn't
3287            end in a '\' */
3288         namelen = strlen(fname_dst);
3289         if (namelen > 0 && fname_dst[namelen-1] == '\\') {
3290                 char *modname = talloc_strdup(frame, fname_dst);
3291                 modname[namelen-1] = '\0';
3292                 fname_dst = modname;
3293         }
3294
3295         if (!push_ucs2_talloc(frame,
3296                                 &converted_str,
3297                                 fname_dst,
3298                                 &converted_size_bytes)) {
3299                 status = NT_STATUS_INVALID_PARAMETER;
3300                 goto fail;
3301         }
3302
3303         /* W2K8 insists the dest name is not null
3304            terminated. Remove the last 2 zero bytes
3305            and reduce the name length. */
3306
3307         if (converted_size_bytes < 2) {
3308                 status = NT_STATUS_INVALID_PARAMETER;
3309                 goto fail;
3310         }
3311         converted_size_bytes -= 2;
3312
3313         inbuf = data_blob_talloc_zero(frame,
3314                                 20 + converted_size_bytes);
3315         if (inbuf.data == NULL) {
3316                 status = NT_STATUS_NO_MEMORY;
3317                 goto fail;
3318         }
3319
3320         if (replace) {
3321                 SCVAL(inbuf.data, 0, 1);
3322         }
3323
3324         SIVAL(inbuf.data, 16, converted_size_bytes);
3325         memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
3326
3327         /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3328            level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3329
3330         status = cli_smb2_set_info_fnum(
3331                 cli,
3332                 fnum,
3333                 1,              /* in_info_type */
3334                 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
3335                 &inbuf,            /* in_input_buffer */
3336                 0);                /* in_additional_info */
3337
3338   fail:
3339
3340         if (fnum != 0xffff) {
3341                 cli_smb2_close_fnum(cli, fnum);
3342         }
3343
3344         cli->raw_status = status;
3345
3346         TALLOC_FREE(frame);
3347         return status;
3348 }
3349
3350 /***************************************************************
3351  Wrapper that allows SMB2 to set an EA on a fnum.
3352  Synchronous only.
3353 ***************************************************************/
3354
3355 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
3356                         uint16_t fnum,
3357                         const char *ea_name,
3358                         const char *ea_val,
3359                         size_t ea_len)
3360 {
3361         NTSTATUS status;
3362         DATA_BLOB inbuf = data_blob_null;
3363         size_t bloblen = 0;
3364         char *ea_name_ascii = NULL;
3365         size_t namelen = 0;
3366         TALLOC_CTX *frame = talloc_stackframe();
3367
3368         if (smbXcli_conn_has_async_calls(cli->conn)) {
3369                 /*
3370                  * Can't use sync call while an async call is in flight
3371                  */
3372                 status = NT_STATUS_INVALID_PARAMETER;
3373                 goto fail;
3374         }
3375
3376         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3377                 status = NT_STATUS_INVALID_PARAMETER;
3378                 goto fail;
3379         }
3380
3381         /* Marshall the SMB2 EA data. */
3382         if (ea_len > 0xFFFF) {
3383                 status = NT_STATUS_INVALID_PARAMETER;
3384                 goto fail;
3385         }
3386
3387         if (!push_ascii_talloc(frame,
3388                                 &ea_name_ascii,
3389                                 ea_name,
3390                                 &namelen)) {
3391                 status = NT_STATUS_INVALID_PARAMETER;
3392                 goto fail;
3393         }
3394
3395         if (namelen < 2 || namelen > 0xFF) {
3396                 status = NT_STATUS_INVALID_PARAMETER;
3397                 goto fail;
3398         }
3399
3400         bloblen = 8 + ea_len + namelen;
3401         /* Round up to a 4 byte boundary. */
3402         bloblen = ((bloblen + 3)&~3);
3403
3404         inbuf = data_blob_talloc_zero(frame, bloblen);
3405         if (inbuf.data == NULL) {
3406                 status = NT_STATUS_NO_MEMORY;
3407                 goto fail;
3408         }
3409         /* namelen doesn't include the NULL byte. */
3410         SCVAL(inbuf.data, 5, namelen - 1);
3411         SSVAL(inbuf.data, 6, ea_len);
3412         memcpy(inbuf.data + 8, ea_name_ascii, namelen);
3413         memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
3414
3415         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3416            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3417
3418         status = cli_smb2_set_info_fnum(
3419                 cli,
3420                 fnum,
3421                 1,              /* in_info_type */
3422                 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3423                 &inbuf,         /* in_input_buffer */
3424                 0);             /* in_additional_info */
3425
3426   fail:
3427
3428         cli->raw_status = status;
3429
3430         TALLOC_FREE(frame);
3431         return status;
3432 }
3433
3434 /***************************************************************
3435  Wrapper that allows SMB2 to set an EA on a pathname.
3436  Synchronous only.
3437 ***************************************************************/
3438
3439 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
3440                         const char *name,
3441                         const char *ea_name,
3442                         const char *ea_val,
3443                         size_t ea_len)
3444 {
3445         NTSTATUS status;
3446         uint16_t fnum = 0xffff;
3447
3448         if (smbXcli_conn_has_async_calls(cli->conn)) {
3449                 /*
3450                  * Can't use sync call while an async call is in flight
3451                  */
3452                 status = NT_STATUS_INVALID_PARAMETER;
3453                 goto fail;
3454         }
3455
3456         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3457                 status = NT_STATUS_INVALID_PARAMETER;
3458                 goto fail;
3459         }
3460
3461         status = get_fnum_from_path(cli,
3462                                 name,
3463                                 FILE_WRITE_EA,
3464                                 &fnum);
3465
3466         if (!NT_STATUS_IS_OK(status)) {
3467                 goto fail;
3468         }
3469
3470         status = cli_set_ea_fnum(cli,
3471                                 fnum,
3472                                 ea_name,
3473                                 ea_val,
3474                                 ea_len);
3475         if (!NT_STATUS_IS_OK(status)) {
3476                 goto fail;
3477