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