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