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