2 Unix SMB/CIFS implementation.
4 Copyright (C) Jeremy Allison 2013
5 Copyright (C) Volker Lendecke 2013
6 Copyright (C) Stefan Metzmacher 2013
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.
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.
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/>.
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.
31 #include "async_smb.h"
32 #include "../libcli/smb/smbXcli_base.h"
34 #include "cli_smb2_fnum.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"
44 uint64_t fid_persistent
;
45 uint64_t fid_volatile
;
49 * Handle mapping code.
52 /***************************************************************
53 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
54 Ensures handle is owned by cli struct.
55 ***************************************************************/
57 static NTSTATUS
map_smb2_handle_to_fnum(struct cli_state
*cli
,
58 const struct smb2_hnd
*ph
, /* In */
59 uint16_t *pfnum
) /* Out */
62 struct idr_context
*idp
= cli
->smb2
.open_handles
;
63 struct smb2_hnd
*owned_h
= talloc_memdup(cli
,
65 sizeof(struct smb2_hnd
));
67 if (owned_h
== NULL
) {
68 return NT_STATUS_NO_MEMORY
;
73 cli
->smb2
.open_handles
= idr_init(cli
);
74 if (cli
->smb2
.open_handles
== NULL
) {
76 return NT_STATUS_NO_MEMORY
;
78 idp
= cli
->smb2
.open_handles
;
81 ret
= idr_get_new_above(idp
, owned_h
, 1, 0xFFFE);
84 return NT_STATUS_NO_MEMORY
;
87 *pfnum
= (uint16_t)ret
;
91 /***************************************************************
92 Return the smb2_hnd pointer associated with the given fnum.
93 ***************************************************************/
95 static NTSTATUS
map_fnum_to_smb2_handle(struct cli_state
*cli
,
96 uint16_t fnum
, /* In */
97 struct smb2_hnd
**pph
) /* Out */
99 struct idr_context
*idp
= cli
->smb2
.open_handles
;
102 return NT_STATUS_INVALID_PARAMETER
;
104 *pph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
106 return NT_STATUS_INVALID_HANDLE
;
111 /***************************************************************
112 Delete the fnum to smb2_hnd mapping. Zeros out handle on
114 ***************************************************************/
116 static NTSTATUS
delete_smb2_handle_mapping(struct cli_state
*cli
,
117 struct smb2_hnd
**pph
, /* In */
118 uint16_t fnum
) /* In */
120 struct idr_context
*idp
= cli
->smb2
.open_handles
;
124 return NT_STATUS_INVALID_PARAMETER
;
127 ph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
129 return NT_STATUS_INVALID_PARAMETER
;
131 idr_remove(idp
, fnum
);
136 /***************************************************************
138 ***************************************************************/
140 static uint8_t flags_to_smb2_oplock(uint32_t create_flags
)
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
;
148 /* create_flags doesn't do a level2 request. */
149 return SMB2_OPLOCK_LEVEL_NONE
;
152 /***************************************************************
153 Small wrapper that allows SMB2 create to return a uint16_t fnum.
155 ***************************************************************/
157 NTSTATUS
cli_smb2_create_fnum(struct cli_state
*cli
,
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
,
166 struct smb_create_returns
*cr
)
171 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
173 * Can't use sync call while an async call is in flight
175 return NT_STATUS_INVALID_PARAMETER
;
178 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
179 return NT_STATUS_INVALID_PARAMETER
;
182 if (cli
->backup_intent
) {
183 create_options
|= FILE_OPEN_FOR_BACKUP_INTENT
;
186 /* SMB2 is pickier about pathnames. Ensure it doesn't
188 if (*fname
== '\\') {
192 status
= smb2cli_create(cli
->conn
,
197 flags_to_smb2_oplock(create_flags
),
198 SMB2_IMPERSONATION_IMPERSONATION
,
209 if (NT_STATUS_IS_OK(status
)) {
210 status
= map_smb2_handle_to_fnum(cli
, &h
, pfid
);
216 /***************************************************************
217 Small wrapper that allows SMB2 close to use a uint16_t fnum.
219 ***************************************************************/
221 NTSTATUS
cli_smb2_close_fnum(struct cli_state
*cli
, uint16_t fnum
)
223 struct smb2_hnd
*ph
= NULL
;
226 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
228 * Can't use sync call while an async call is in flight
230 return NT_STATUS_INVALID_PARAMETER
;
233 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
234 return NT_STATUS_INVALID_PARAMETER
;
237 status
= map_fnum_to_smb2_handle(cli
,
240 if (!NT_STATUS_IS_OK(status
)) {
244 status
= smb2cli_close(cli
->conn
,
252 /* Delete the fnum -> handle mapping. */
253 if (NT_STATUS_IS_OK(status
)) {
254 status
= delete_smb2_handle_mapping(cli
, &ph
, fnum
);
260 /***************************************************************
261 Small wrapper that allows SMB2 to create a directory
263 ***************************************************************/
265 NTSTATUS
cli_smb2_mkdir(struct cli_state
*cli
, const char *dname
)
270 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
272 * Can't use sync call while an async call is in flight
274 return NT_STATUS_INVALID_PARAMETER
;
277 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
278 return NT_STATUS_INVALID_PARAMETER
;
281 status
= cli_smb2_create_fnum(cli
,
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 */
292 if (!NT_STATUS_IS_OK(status
)) {
295 return cli_smb2_close_fnum(cli
, fnum
);
298 /***************************************************************
299 Small wrapper that allows SMB2 to delete a directory
301 ***************************************************************/
303 NTSTATUS
cli_smb2_rmdir(struct cli_state
*cli
, const char *dname
)
308 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
310 * Can't use sync call while an async call is in flight
312 return NT_STATUS_INVALID_PARAMETER
;
315 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
316 return NT_STATUS_INVALID_PARAMETER
;
319 status
= cli_smb2_create_fnum(cli
,
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 */
330 if (!NT_STATUS_IS_OK(status
)) {
333 return cli_smb2_close_fnum(cli
, fnum
);
336 /***************************************************************
337 Small wrapper that allows SMB2 to unlink a pathname.
339 ***************************************************************/
341 NTSTATUS
cli_smb2_unlink(struct cli_state
*cli
, const char *fname
)
346 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
348 * Can't use sync call while an async call is in flight
350 return NT_STATUS_INVALID_PARAMETER
;
353 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
354 return NT_STATUS_INVALID_PARAMETER
;
357 status
= cli_smb2_create_fnum(cli
,
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 */
368 if (!NT_STATUS_IS_OK(status
)) {
371 return cli_smb2_close_fnum(cli
, fnum
);
374 /***************************************************************
375 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
376 ***************************************************************/
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
)
387 if (dir_data_length
< 4) {
388 return NT_STATUS_INFO_LENGTH_MISMATCH
;
391 *next_offset
= IVAL(dir_data
, 0);
393 if (*next_offset
> dir_data_length
) {
394 return NT_STATUS_INFO_LENGTH_MISMATCH
;
397 if (*next_offset
!= 0) {
398 /* Ensure we only read what in this record. */
399 dir_data_length
= *next_offset
;
402 if (dir_data_length
< 105) {
403 return NT_STATUS_INFO_LENGTH_MISMATCH
;
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
;
415 slen
= CVAL(dir_data
+ 68, 0);
417 return NT_STATUS_INFO_LENGTH_MISMATCH
;
419 ret
= pull_string_talloc(finfo
,
421 FLAGS2_UNICODE_STRINGS
,
426 if (ret
== (size_t)-1) {
427 /* Bad conversion. */
428 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
431 ret
= pull_string_talloc(finfo
,
433 FLAGS2_UNICODE_STRINGS
,
438 if (ret
== (size_t)-1) {
439 /* Bad conversion. */
440 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
445 /*******************************************************************
446 Given a filename - get its directory name
447 ********************************************************************/
449 static bool windows_parent_dirname(TALLOC_CTX
*mem_ctx
,
457 p
= strrchr_m(dir
, '\\'); /* Find final '\\', if any */
460 if (!(*parent
= talloc_strdup(mem_ctx
, "\\"))) {
471 if (!(*parent
= (char *)talloc_memdup(mem_ctx
, dir
, len
+1))) {
474 (*parent
)[len
] = '\0';
482 /***************************************************************
483 Wrapper that allows SMB2 to list a directory.
485 ***************************************************************/
487 NTSTATUS
cli_smb2_list(struct cli_state
*cli
,
488 const char *pathname
,
490 NTSTATUS (*fn
)(const char *,
497 uint16_t fnum
= 0xffff;
498 char *parent_dir
= NULL
;
499 const char *mask
= NULL
;
500 struct smb2_hnd
*ph
= NULL
;
501 bool processed_file
= false;
502 TALLOC_CTX
*frame
= talloc_stackframe();
503 TALLOC_CTX
*subframe
= NULL
;
506 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
508 * Can't use sync call while an async call is in flight
510 status
= NT_STATUS_INVALID_PARAMETER
;
514 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
515 status
= NT_STATUS_INVALID_PARAMETER
;
519 /* Get the directory name. */
520 if (!windows_parent_dirname(frame
,
524 status
= NT_STATUS_NO_MEMORY
;
528 mask_has_wild
= ms_has_wild(mask
);
530 status
= cli_smb2_create_fnum(cli
,
532 0, /* create_flags */
533 SEC_DIR_LIST
|SEC_DIR_READ_ATTRIBUTE
,/* desired_access */
534 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
535 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
536 FILE_OPEN
, /* create_disposition */
537 FILE_DIRECTORY_FILE
, /* create_options */
541 if (!NT_STATUS_IS_OK(status
)) {
545 status
= map_fnum_to_smb2_handle(cli
,
548 if (!NT_STATUS_IS_OK(status
)) {
553 uint8_t *dir_data
= NULL
;
554 uint32_t dir_data_length
= 0;
555 uint32_t next_offset
= 0;
556 subframe
= talloc_stackframe();
558 status
= smb2cli_query_directory(cli
->conn
,
562 SMB2_FIND_ID_BOTH_DIRECTORY_INFO
,
573 if (!NT_STATUS_IS_OK(status
)) {
574 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
581 struct file_info
*finfo
= talloc_zero(subframe
,
585 status
= NT_STATUS_NO_MEMORY
;
589 status
= parse_finfo_id_both_directory_info(dir_data
,
594 if (!NT_STATUS_IS_OK(status
)) {
598 if (dir_check_ftype((uint32_t)finfo
->mode
,
599 (uint32_t)attribute
)) {
601 * Only process if attributes match.
602 * On SMB1 server does this, so on
603 * SMB2 we need to emulate in the
606 * https://bugzilla.samba.org/show_bug.cgi?id=10260
608 processed_file
= true;
610 status
= fn(cli
->dfs_mountpoint
,
615 if (!NT_STATUS_IS_OK(status
)) {
622 /* Move to next entry. */
624 dir_data
+= next_offset
;
625 dir_data_length
-= next_offset
;
627 } while (next_offset
!= 0);
629 TALLOC_FREE(subframe
);
631 if (!mask_has_wild
) {
633 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
634 * when handed a non-wildcard path. Do it
635 * for the server (with a non-wildcard path
636 * there should only ever be one file returned.
638 status
= STATUS_NO_MORE_FILES
;
642 } while (NT_STATUS_IS_OK(status
));
644 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
645 status
= NT_STATUS_OK
;
648 if (NT_STATUS_IS_OK(status
) && !processed_file
) {
650 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
651 * if no files match. Emulate this in the client.
653 status
= NT_STATUS_NO_SUCH_FILE
;
658 if (fnum
!= 0xffff) {
659 cli_smb2_close_fnum(cli
, fnum
);
661 TALLOC_FREE(subframe
);
666 /***************************************************************
667 Wrapper that allows SMB2 to query a path info (basic level).
669 ***************************************************************/
671 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
673 SMB_STRUCT_STAT
*sbuf
,
674 uint32_t *attributes
)
677 struct smb_create_returns cr
;
678 uint16_t fnum
= 0xffff;
679 size_t namelen
= strlen(name
);
681 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
683 * Can't use sync call while an async call is in flight
685 return NT_STATUS_INVALID_PARAMETER
;
688 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
689 return NT_STATUS_INVALID_PARAMETER
;
692 /* SMB2 is pickier about pathnames. Ensure it doesn't
694 if (namelen
> 0 && name
[namelen
-1] == '\\') {
695 char *modname
= talloc_strdup(talloc_tos(), name
);
696 modname
[namelen
-1] = '\0';
700 /* This is commonly used as a 'cd'. Try qpathinfo on
701 a directory handle first. */
703 status
= cli_smb2_create_fnum(cli
,
705 0, /* create_flags */
706 FILE_READ_ATTRIBUTES
, /* desired_access */
707 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
708 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
709 FILE_OPEN
, /* create_disposition */
710 FILE_DIRECTORY_FILE
, /* create_options */
714 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
716 status
= cli_smb2_create_fnum(cli
,
718 0, /* create_flags */
719 FILE_READ_ATTRIBUTES
, /* desired_access */
720 0, /* file attributes */
721 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
722 FILE_OPEN
, /* create_disposition */
723 0, /* create_options */
728 if (!NT_STATUS_IS_OK(status
)) {
732 cli_smb2_close_fnum(cli
, fnum
);
736 sbuf
->st_ex_atime
= nt_time_to_unix_timespec(&cr
.last_access_time
);
737 sbuf
->st_ex_mtime
= nt_time_to_unix_timespec(&cr
.last_write_time
);
738 sbuf
->st_ex_ctime
= nt_time_to_unix_timespec(&cr
.change_time
);
739 sbuf
->st_ex_size
= cr
.end_of_file
;
740 *attributes
= cr
.file_attributes
;
745 /***************************************************************
746 Helper function for pathname operations.
747 ***************************************************************/
749 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
751 uint32_t desired_access
,
755 size_t namelen
= strlen(name
);
756 TALLOC_CTX
*frame
= talloc_stackframe();
758 /* SMB2 is pickier about pathnames. Ensure it doesn't
760 if (namelen
> 0 && name
[namelen
-1] == '\\') {
761 char *modname
= talloc_strdup(frame
, name
);
762 if (modname
== NULL
) {
763 status
= NT_STATUS_NO_MEMORY
;
766 modname
[namelen
-1] = '\0';
770 /* Try to open a file handle first. */
771 status
= cli_smb2_create_fnum(cli
,
773 0, /* create_flags */
775 0, /* file attributes */
776 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
777 FILE_OPEN
, /* create_disposition */
778 0, /* create_options */
782 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
783 status
= cli_smb2_create_fnum(cli
,
785 0, /* create_flags */
787 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
788 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
789 FILE_OPEN
, /* create_disposition */
790 FILE_DIRECTORY_FILE
, /* create_options */
801 /***************************************************************
802 Wrapper that allows SMB2 to query a path info (ALTNAME level).
804 ***************************************************************/
806 NTSTATUS
cli_smb2_qpathinfo_alt_name(struct cli_state
*cli
,
811 DATA_BLOB outbuf
= data_blob_null
;
812 uint16_t fnum
= 0xffff;
813 struct smb2_hnd
*ph
= NULL
;
814 uint32_t altnamelen
= 0;
815 TALLOC_CTX
*frame
= talloc_stackframe();
817 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
819 * Can't use sync call while an async call is in flight
821 status
= NT_STATUS_INVALID_PARAMETER
;
825 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
826 status
= NT_STATUS_INVALID_PARAMETER
;
830 status
= get_fnum_from_path(cli
,
832 FILE_READ_ATTRIBUTES
,
835 if (!NT_STATUS_IS_OK(status
)) {
839 status
= map_fnum_to_smb2_handle(cli
,
842 if (!NT_STATUS_IS_OK(status
)) {
846 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
847 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
849 status
= smb2cli_query_info(cli
->conn
,
853 1, /* in_info_type */
854 (SMB_FILE_ALTERNATE_NAME_INFORMATION
- 1000), /* in_file_info_class */
855 0xFFFF, /* in_max_output_length */
856 NULL
, /* in_input_buffer */
857 0, /* in_additional_info */
864 if (!NT_STATUS_IS_OK(status
)) {
868 /* Parse the reply. */
869 if (outbuf
.length
< 4) {
870 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
874 altnamelen
= IVAL(outbuf
.data
, 0);
875 if (altnamelen
> outbuf
.length
- 4) {
876 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
880 if (altnamelen
> 0) {
882 char *short_name
= NULL
;
883 ret
= pull_string_talloc(frame
,
885 FLAGS2_UNICODE_STRINGS
,
890 if (ret
== (size_t)-1) {
891 /* Bad conversion. */
892 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
896 fstrcpy(alt_name
, short_name
);
901 status
= NT_STATUS_OK
;
905 if (fnum
!= 0xffff) {
906 cli_smb2_close_fnum(cli
, fnum
);
913 /***************************************************************
914 Wrapper that allows SMB2 to query a fnum info (basic level).
916 ***************************************************************/
918 NTSTATUS
cli_smb2_qfileinfo_basic(struct cli_state
*cli
,
922 struct timespec
*create_time
,
923 struct timespec
*access_time
,
924 struct timespec
*write_time
,
925 struct timespec
*change_time
,
929 DATA_BLOB outbuf
= data_blob_null
;
930 struct smb2_hnd
*ph
= NULL
;
931 TALLOC_CTX
*frame
= talloc_stackframe();
933 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
935 * Can't use sync call while an async call is in flight
937 status
= NT_STATUS_INVALID_PARAMETER
;
941 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
942 status
= NT_STATUS_INVALID_PARAMETER
;
946 status
= map_fnum_to_smb2_handle(cli
,
949 if (!NT_STATUS_IS_OK(status
)) {
953 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
954 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
956 status
= smb2cli_query_info(cli
->conn
,
960 1, /* in_info_type */
961 (SMB_FILE_ALL_INFORMATION
- 1000), /* in_file_info_class */
962 0xFFFF, /* in_max_output_length */
963 NULL
, /* in_input_buffer */
964 0, /* in_additional_info */
970 if (!NT_STATUS_IS_OK(status
)) {
974 /* Parse the reply. */
975 if (outbuf
.length
< 0x60) {
976 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
981 *create_time
= interpret_long_date((const char *)outbuf
.data
+ 0x0);
984 *access_time
= interpret_long_date((const char *)outbuf
.data
+ 0x8);
987 *write_time
= interpret_long_date((const char *)outbuf
.data
+ 0x10);
990 *change_time
= interpret_long_date((const char *)outbuf
.data
+ 0x18);
993 uint32_t attr
= IVAL(outbuf
.data
, 0x20);
994 *mode
= (uint16_t)attr
;
997 uint64_t file_size
= BVAL(outbuf
.data
, 0x30);
998 *size
= (off_t
)file_size
;
1001 uint64_t file_index
= BVAL(outbuf
.data
, 0x40);
1002 *ino
= (SMB_INO_T
)file_index
;
1011 /***************************************************************
1012 Wrapper that allows SMB2 to query an fnum.
1013 Implement on top of cli_smb2_qfileinfo_basic().
1015 ***************************************************************/
1017 NTSTATUS
cli_smb2_getattrE(struct cli_state
*cli
,
1021 time_t *change_time
,
1022 time_t *access_time
,
1025 struct timespec access_time_ts
;
1026 struct timespec write_time_ts
;
1027 struct timespec change_time_ts
;
1028 NTSTATUS status
= cli_smb2_qfileinfo_basic(cli
,
1038 if (!NT_STATUS_IS_OK(status
)) {
1043 *change_time
= change_time_ts
.tv_sec
;
1046 *access_time
= access_time_ts
.tv_sec
;
1049 *write_time
= write_time_ts
.tv_sec
;
1051 return NT_STATUS_OK
;
1054 /***************************************************************
1055 Wrapper that allows SMB2 to get pathname attributes.
1057 ***************************************************************/
1059 NTSTATUS
cli_smb2_getatr(struct cli_state
*cli
,
1066 uint16_t fnum
= 0xffff;
1067 struct smb2_hnd
*ph
= NULL
;
1068 TALLOC_CTX
*frame
= talloc_stackframe();
1070 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1072 * Can't use sync call while an async call is in flight
1074 status
= NT_STATUS_INVALID_PARAMETER
;
1078 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1079 status
= NT_STATUS_INVALID_PARAMETER
;
1083 status
= get_fnum_from_path(cli
,
1085 FILE_READ_ATTRIBUTES
,
1088 if (!NT_STATUS_IS_OK(status
)) {
1092 status
= map_fnum_to_smb2_handle(cli
,
1095 if (!NT_STATUS_IS_OK(status
)) {
1098 status
= cli_smb2_getattrE(cli
,
1105 if (!NT_STATUS_IS_OK(status
)) {
1111 if (fnum
!= 0xffff) {
1112 cli_smb2_close_fnum(cli
, fnum
);
1119 /***************************************************************
1120 Wrapper that allows SMB2 to query a pathname info (basic level).
1121 Implement on top of cli_smb2_qfileinfo_basic().
1123 ***************************************************************/
1125 NTSTATUS
cli_smb2_qpathinfo2(struct cli_state
*cli
,
1127 struct timespec
*create_time
,
1128 struct timespec
*access_time
,
1129 struct timespec
*write_time
,
1130 struct timespec
*change_time
,
1136 struct smb2_hnd
*ph
= NULL
;
1137 uint16_t fnum
= 0xffff;
1138 TALLOC_CTX
*frame
= talloc_stackframe();
1140 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1142 * Can't use sync call while an async call is in flight
1144 status
= NT_STATUS_INVALID_PARAMETER
;
1148 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1149 status
= NT_STATUS_INVALID_PARAMETER
;
1153 status
= get_fnum_from_path(cli
,
1155 FILE_READ_ATTRIBUTES
,
1158 if (!NT_STATUS_IS_OK(status
)) {
1162 status
= map_fnum_to_smb2_handle(cli
,
1165 if (!NT_STATUS_IS_OK(status
)) {
1169 status
= cli_smb2_qfileinfo_basic(cli
,
1181 if (fnum
!= 0xffff) {
1182 cli_smb2_close_fnum(cli
, fnum
);
1189 /***************************************************************
1190 Wrapper that allows SMB2 to query pathname streams.
1192 ***************************************************************/
1194 NTSTATUS
cli_smb2_qpathinfo_streams(struct cli_state
*cli
,
1196 TALLOC_CTX
*mem_ctx
,
1197 unsigned int *pnum_streams
,
1198 struct stream_struct
**pstreams
)
1201 struct smb2_hnd
*ph
= NULL
;
1202 uint16_t fnum
= 0xffff;
1203 DATA_BLOB outbuf
= data_blob_null
;
1204 TALLOC_CTX
*frame
= talloc_stackframe();
1206 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1208 * Can't use sync call while an async call is in flight
1210 status
= NT_STATUS_INVALID_PARAMETER
;
1214 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1215 status
= NT_STATUS_INVALID_PARAMETER
;
1219 status
= get_fnum_from_path(cli
,
1221 FILE_READ_ATTRIBUTES
,
1224 if (!NT_STATUS_IS_OK(status
)) {
1228 status
= map_fnum_to_smb2_handle(cli
,
1231 if (!NT_STATUS_IS_OK(status
)) {
1235 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1236 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1238 status
= smb2cli_query_info(cli
->conn
,
1242 1, /* in_info_type */
1243 (SMB_FILE_STREAM_INFORMATION
- 1000), /* in_file_info_class */
1244 0xFFFF, /* in_max_output_length */
1245 NULL
, /* in_input_buffer */
1246 0, /* in_additional_info */
1253 if (!NT_STATUS_IS_OK(status
)) {
1257 /* Parse the reply. */
1258 if (!parse_streams_blob(mem_ctx
,
1263 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1269 if (fnum
!= 0xffff) {
1270 cli_smb2_close_fnum(cli
, fnum
);
1277 /***************************************************************
1278 Wrapper that allows SMB2 to set pathname attributes.
1280 ***************************************************************/
1282 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
1288 uint16_t fnum
= 0xffff;
1289 struct smb2_hnd
*ph
= NULL
;
1290 uint8_t inbuf_store
[40];
1291 DATA_BLOB inbuf
= data_blob_null
;
1292 TALLOC_CTX
*frame
= talloc_stackframe();
1294 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1296 * Can't use sync call while an async call is in flight
1298 status
= NT_STATUS_INVALID_PARAMETER
;
1302 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1303 status
= NT_STATUS_INVALID_PARAMETER
;
1307 status
= get_fnum_from_path(cli
,
1309 FILE_WRITE_ATTRIBUTES
,
1312 if (!NT_STATUS_IS_OK(status
)) {
1316 status
= map_fnum_to_smb2_handle(cli
,
1319 if (!NT_STATUS_IS_OK(status
)) {
1323 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1324 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1326 inbuf
.data
= inbuf_store
;
1327 inbuf
.length
= sizeof(inbuf_store
);
1328 data_blob_clear(&inbuf
);
1330 SSVAL(inbuf
.data
, 32, attr
);
1332 put_long_date((char *)inbuf
.data
+ 16,mtime
);
1334 /* Set all the other times to -1. */
1335 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1336 SBVAL(inbuf
.data
, 8, 0xFFFFFFFFFFFFFFFFLL
);
1337 SBVAL(inbuf
.data
, 24, 0xFFFFFFFFFFFFFFFFLL
);
1339 status
= smb2cli_set_info(cli
->conn
,
1343 1, /* in_info_type */
1344 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1345 &inbuf
, /* in_input_buffer */
1346 0, /* in_additional_info */
1351 if (fnum
!= 0xffff) {
1352 cli_smb2_close_fnum(cli
, fnum
);
1359 /***************************************************************
1360 Wrapper that allows SMB2 to set file handle times.
1362 ***************************************************************/
1364 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
1371 struct smb2_hnd
*ph
= NULL
;
1372 uint8_t inbuf_store
[40];
1373 DATA_BLOB inbuf
= data_blob_null
;
1375 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1377 * Can't use sync call while an async call is in flight
1379 return NT_STATUS_INVALID_PARAMETER
;
1382 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1383 return NT_STATUS_INVALID_PARAMETER
;
1386 status
= map_fnum_to_smb2_handle(cli
,
1389 if (!NT_STATUS_IS_OK(status
)) {
1393 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1394 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1396 inbuf
.data
= inbuf_store
;
1397 inbuf
.length
= sizeof(inbuf_store
);
1398 data_blob_clear(&inbuf
);
1400 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1401 if (change_time
!= 0) {
1402 put_long_date((char *)inbuf
.data
+ 24, change_time
);
1404 if (access_time
!= 0) {
1405 put_long_date((char *)inbuf
.data
+ 8, access_time
);
1407 if (write_time
!= 0) {
1408 put_long_date((char *)inbuf
.data
+ 16, write_time
);
1411 return smb2cli_set_info(cli
->conn
,
1415 1, /* in_info_type */
1416 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1417 &inbuf
, /* in_input_buffer */
1418 0, /* in_additional_info */
1423 /***************************************************************
1424 Wrapper that allows SMB2 to query disk attributes (size).
1426 ***************************************************************/
1428 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, int *bsize
, int *total
, int *avail
)
1431 uint16_t fnum
= 0xffff;
1432 DATA_BLOB outbuf
= data_blob_null
;
1433 struct smb2_hnd
*ph
= NULL
;
1434 uint32_t sectors_per_unit
= 0;
1435 uint32_t bytes_per_sector
= 0;
1436 uint64_t total_size
= 0;
1437 uint64_t size_free
= 0;
1438 TALLOC_CTX
*frame
= talloc_stackframe();
1440 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1442 * Can't use sync call while an async call is in flight
1444 status
= NT_STATUS_INVALID_PARAMETER
;
1448 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1449 status
= NT_STATUS_INVALID_PARAMETER
;
1453 /* First open the top level directory. */
1454 status
= cli_smb2_create_fnum(cli
,
1456 0, /* create_flags */
1457 FILE_READ_ATTRIBUTES
, /* desired_access */
1458 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1459 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1460 FILE_OPEN
, /* create_disposition */
1461 FILE_DIRECTORY_FILE
, /* create_options */
1465 if (!NT_STATUS_IS_OK(status
)) {
1469 status
= map_fnum_to_smb2_handle(cli
,
1472 if (!NT_STATUS_IS_OK(status
)) {
1476 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1477 level 3 (SMB_FS_SIZE_INFORMATION). */
1479 status
= smb2cli_query_info(cli
->conn
,
1483 2, /* in_info_type */
1484 3, /* in_file_info_class */
1485 0xFFFF, /* in_max_output_length */
1486 NULL
, /* in_input_buffer */
1487 0, /* in_additional_info */
1493 if (!NT_STATUS_IS_OK(status
)) {
1497 /* Parse the reply. */
1498 if (outbuf
.length
!= 24) {
1499 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1503 total_size
= BVAL(outbuf
.data
, 0);
1504 size_free
= BVAL(outbuf
.data
, 8);
1505 sectors_per_unit
= IVAL(outbuf
.data
, 16);
1506 bytes_per_sector
= IVAL(outbuf
.data
, 20);
1509 *bsize
= (int)(sectors_per_unit
* bytes_per_sector
);
1512 *total
= (int)total_size
;
1515 *avail
= (int)size_free
;
1518 status
= NT_STATUS_OK
;
1522 if (fnum
!= 0xffff) {
1523 cli_smb2_close_fnum(cli
, fnum
);
1530 /***************************************************************
1531 Wrapper that allows SMB2 to query a security descriptor.
1533 ***************************************************************/
1535 NTSTATUS
cli_smb2_query_security_descriptor(struct cli_state
*cli
,
1538 TALLOC_CTX
*mem_ctx
,
1539 struct security_descriptor
**ppsd
)
1542 DATA_BLOB outbuf
= data_blob_null
;
1543 struct smb2_hnd
*ph
= NULL
;
1544 struct security_descriptor
*lsd
= NULL
;
1545 TALLOC_CTX
*frame
= talloc_stackframe();
1547 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1549 * Can't use sync call while an async call is in flight
1551 status
= NT_STATUS_INVALID_PARAMETER
;
1555 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1556 status
= NT_STATUS_INVALID_PARAMETER
;
1560 status
= map_fnum_to_smb2_handle(cli
,
1563 if (!NT_STATUS_IS_OK(status
)) {
1567 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1569 status
= smb2cli_query_info(cli
->conn
,
1573 3, /* in_info_type */
1574 0, /* in_file_info_class */
1575 0xFFFF, /* in_max_output_length */
1576 NULL
, /* in_input_buffer */
1577 sec_info
, /* in_additional_info */
1584 if (!NT_STATUS_IS_OK(status
)) {
1588 /* Parse the reply. */
1589 status
= unmarshall_sec_desc(mem_ctx
,
1594 if (!NT_STATUS_IS_OK(status
)) {
1610 /***************************************************************
1611 Wrapper that allows SMB2 to set a security descriptor.
1613 ***************************************************************/
1615 NTSTATUS
cli_smb2_set_security_descriptor(struct cli_state
*cli
,
1618 const struct security_descriptor
*sd
)
1621 DATA_BLOB inbuf
= data_blob_null
;
1622 struct smb2_hnd
*ph
= NULL
;
1623 TALLOC_CTX
*frame
= talloc_stackframe();
1625 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1627 * Can't use sync call while an async call is in flight
1629 status
= NT_STATUS_INVALID_PARAMETER
;
1633 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1634 status
= NT_STATUS_INVALID_PARAMETER
;
1638 status
= map_fnum_to_smb2_handle(cli
,
1641 if (!NT_STATUS_IS_OK(status
)) {
1645 status
= marshall_sec_desc(frame
,
1650 if (!NT_STATUS_IS_OK(status
)) {
1654 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1656 status
= smb2cli_set_info(cli
->conn
,
1660 3, /* in_info_type */
1661 0, /* in_file_info_class */
1662 &inbuf
, /* in_input_buffer */
1663 sec_info
, /* in_additional_info */
1673 /***************************************************************
1674 Wrapper that allows SMB2 to rename a file.
1676 ***************************************************************/
1678 NTSTATUS
cli_smb2_rename(struct cli_state
*cli
,
1679 const char *fname_src
,
1680 const char *fname_dst
)
1683 DATA_BLOB inbuf
= data_blob_null
;
1684 uint16_t fnum
= 0xffff;
1685 struct smb2_hnd
*ph
= NULL
;
1686 smb_ucs2_t
*converted_str
= NULL
;
1687 size_t converted_size_bytes
= 0;
1689 TALLOC_CTX
*frame
= talloc_stackframe();
1691 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1693 * Can't use sync call while an async call is in flight
1695 status
= NT_STATUS_INVALID_PARAMETER
;
1699 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1700 status
= NT_STATUS_INVALID_PARAMETER
;
1704 status
= get_fnum_from_path(cli
,
1709 if (!NT_STATUS_IS_OK(status
)) {
1713 status
= map_fnum_to_smb2_handle(cli
,
1716 if (!NT_STATUS_IS_OK(status
)) {
1720 /* SMB2 is pickier about pathnames. Ensure it doesn't
1722 if (*fname_dst
== '\\') {
1726 /* SMB2 is pickier about pathnames. Ensure it doesn't
1728 namelen
= strlen(fname_dst
);
1729 if (namelen
> 0 && fname_dst
[namelen
-1] == '\\') {
1730 char *modname
= talloc_strdup(frame
, fname_dst
);
1731 modname
[namelen
-1] = '\0';
1732 fname_dst
= modname
;
1735 if (!push_ucs2_talloc(frame
,
1738 &converted_size_bytes
)) {
1739 status
= NT_STATUS_INVALID_PARAMETER
;
1743 /* W2K8 insists the dest name is not null
1744 terminated. Remove the last 2 zero bytes
1745 and reduce the name length. */
1747 if (converted_size_bytes
< 2) {
1748 status
= NT_STATUS_INVALID_PARAMETER
;
1751 converted_size_bytes
-= 2;
1753 inbuf
= data_blob_talloc_zero(frame
,
1754 20 + converted_size_bytes
);
1755 if (inbuf
.data
== NULL
) {
1756 status
= NT_STATUS_NO_MEMORY
;
1760 SIVAL(inbuf
.data
, 16, converted_size_bytes
);
1761 memcpy(inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
1763 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
1764 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
1766 status
= smb2cli_set_info(cli
->conn
,
1770 1, /* in_info_type */
1771 SMB_FILE_RENAME_INFORMATION
- 1000, /* in_file_info_class */
1772 &inbuf
, /* in_input_buffer */
1773 0, /* in_additional_info */
1779 if (fnum
!= 0xffff) {
1780 cli_smb2_close_fnum(cli
, fnum
);
1787 /***************************************************************
1788 Wrapper that allows SMB2 to set an EA on a fnum.
1790 ***************************************************************/
1792 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
1794 const char *ea_name
,
1799 DATA_BLOB inbuf
= data_blob_null
;
1801 char *ea_name_ascii
= NULL
;
1803 struct smb2_hnd
*ph
= NULL
;
1804 TALLOC_CTX
*frame
= talloc_stackframe();
1806 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1808 * Can't use sync call while an async call is in flight
1810 status
= NT_STATUS_INVALID_PARAMETER
;
1814 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1815 status
= NT_STATUS_INVALID_PARAMETER
;
1819 status
= map_fnum_to_smb2_handle(cli
,
1822 if (!NT_STATUS_IS_OK(status
)) {
1826 /* Marshall the SMB2 EA data. */
1827 if (ea_len
> 0xFFFF) {
1828 status
= NT_STATUS_INVALID_PARAMETER
;
1832 if (!push_ascii_talloc(frame
,
1836 status
= NT_STATUS_INVALID_PARAMETER
;
1840 if (namelen
< 2 || namelen
> 0xFF) {
1841 status
= NT_STATUS_INVALID_PARAMETER
;
1845 bloblen
= 8 + ea_len
+ namelen
;
1846 /* Round up to a 4 byte boundary. */
1847 bloblen
= ((bloblen
+ 3)&~3);
1849 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
1850 if (inbuf
.data
== NULL
) {
1851 status
= NT_STATUS_NO_MEMORY
;
1854 /* namelen doesn't include the NULL byte. */
1855 SCVAL(inbuf
.data
, 5, namelen
- 1);
1856 SSVAL(inbuf
.data
, 6, ea_len
);
1857 memcpy(inbuf
.data
+ 8, ea_name_ascii
, namelen
);
1858 memcpy(inbuf
.data
+ 8 + namelen
, ea_val
, ea_len
);
1860 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1861 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
1863 status
= smb2cli_set_info(cli
->conn
,
1867 1, /* in_info_type */
1868 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
1869 &inbuf
, /* in_input_buffer */
1870 0, /* in_additional_info */
1880 /***************************************************************
1881 Wrapper that allows SMB2 to set an EA on a pathname.
1883 ***************************************************************/
1885 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
1887 const char *ea_name
,
1892 uint16_t fnum
= 0xffff;
1894 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1896 * Can't use sync call while an async call is in flight
1898 status
= NT_STATUS_INVALID_PARAMETER
;
1902 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1903 status
= NT_STATUS_INVALID_PARAMETER
;
1907 status
= get_fnum_from_path(cli
,
1912 if (!NT_STATUS_IS_OK(status
)) {
1916 status
= cli_set_ea_fnum(cli
,
1921 if (!NT_STATUS_IS_OK(status
)) {
1927 if (fnum
!= 0xffff) {
1928 cli_smb2_close_fnum(cli
, fnum
);
1934 /***************************************************************
1935 Wrapper that allows SMB2 to get an EA list on a pathname.
1937 ***************************************************************/
1939 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
1943 struct ea_struct
**pea_array
)
1946 uint16_t fnum
= 0xffff;
1947 DATA_BLOB outbuf
= data_blob_null
;
1948 struct smb2_hnd
*ph
= NULL
;
1949 struct ea_list
*ea_list
= NULL
;
1950 struct ea_list
*eal
= NULL
;
1951 size_t ea_count
= 0;
1952 TALLOC_CTX
*frame
= talloc_stackframe();
1957 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1959 * Can't use sync call while an async call is in flight
1961 status
= NT_STATUS_INVALID_PARAMETER
;
1965 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1966 status
= NT_STATUS_INVALID_PARAMETER
;
1970 status
= get_fnum_from_path(cli
,
1975 if (!NT_STATUS_IS_OK(status
)) {
1979 status
= map_fnum_to_smb2_handle(cli
,
1982 if (!NT_STATUS_IS_OK(status
)) {
1986 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1987 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
1989 status
= smb2cli_query_info(cli
->conn
,
1993 1, /* in_info_type */
1994 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
1995 0xFFFF, /* in_max_output_length */
1996 NULL
, /* in_input_buffer */
1997 0, /* in_additional_info */
2004 if (!NT_STATUS_IS_OK(status
)) {
2008 /* Parse the reply. */
2009 ea_list
= read_nttrans_ea_list(ctx
,
2010 (const char *)outbuf
.data
,
2012 if (ea_list
== NULL
) {
2013 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2017 /* Convert to an array. */
2018 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2023 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
2024 if (*pea_array
== NULL
) {
2025 status
= NT_STATUS_NO_MEMORY
;
2029 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2030 (*pea_array
)[ea_count
++] = ea_list
->ea
;
2032 *pnum_eas
= ea_count
;
2037 if (fnum
!= 0xffff) {
2038 cli_smb2_close_fnum(cli
, fnum
);
2045 struct cli_smb2_read_state
{
2046 struct tevent_context
*ev
;
2047 struct cli_state
*cli
;
2048 struct smb2_hnd
*ph
;
2049 uint64_t start_offset
;
2055 static void cli_smb2_read_done(struct tevent_req
*subreq
);
2057 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
2058 struct tevent_context
*ev
,
2059 struct cli_state
*cli
,
2065 struct tevent_req
*req
, *subreq
;
2066 struct cli_smb2_read_state
*state
;
2068 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
2074 state
->start_offset
= (uint64_t)offset
;
2075 state
->size
= (uint32_t)size
;
2076 state
->received
= 0;
2079 status
= map_fnum_to_smb2_handle(cli
,
2082 if (tevent_req_nterror(req
, status
)) {
2083 return tevent_req_post(req
, ev
);
2086 subreq
= smb2cli_read_send(state
,
2089 state
->cli
->timeout
,
2090 state
->cli
->smb2
.session
,
2091 state
->cli
->smb2
.tcon
,
2093 state
->start_offset
,
2094 state
->ph
->fid_persistent
,
2095 state
->ph
->fid_volatile
,
2096 0, /* minimum_count */
2097 0); /* remaining_bytes */
2099 if (tevent_req_nomem(subreq
, req
)) {
2100 return tevent_req_post(req
, ev
);
2102 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
2106 static void cli_smb2_read_done(struct tevent_req
*subreq
)
2108 struct tevent_req
*req
= tevent_req_callback_data(
2109 subreq
, struct tevent_req
);
2110 struct cli_smb2_read_state
*state
= tevent_req_data(
2111 req
, struct cli_smb2_read_state
);
2114 status
= smb2cli_read_recv(subreq
, state
,
2115 &state
->buf
, &state
->received
);
2116 if (tevent_req_nterror(req
, status
)) {
2120 if (state
->received
> state
->size
) {
2121 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2125 tevent_req_done(req
);
2128 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
2133 struct cli_smb2_read_state
*state
= tevent_req_data(
2134 req
, struct cli_smb2_read_state
);
2136 if (tevent_req_is_nterror(req
, &status
)) {
2140 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2141 * better make sure that you copy it away before you talloc_free(req).
2142 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2144 *received
= (ssize_t
)state
->received
;
2145 *rcvbuf
= state
->buf
;
2146 return NT_STATUS_OK
;
2149 struct cli_smb2_write_state
{
2150 struct tevent_context
*ev
;
2151 struct cli_state
*cli
;
2152 struct smb2_hnd
*ph
;
2160 static void cli_smb2_write_written(struct tevent_req
*req
);
2162 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
2163 struct tevent_context
*ev
,
2164 struct cli_state
*cli
,
2172 struct tevent_req
*req
, *subreq
= NULL
;
2173 struct cli_smb2_write_state
*state
= NULL
;
2175 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
2181 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2182 state
->flags
= (uint32_t)mode
;
2184 state
->offset
= (uint64_t)offset
;
2185 state
->size
= (uint32_t)size
;
2188 status
= map_fnum_to_smb2_handle(cli
,
2191 if (tevent_req_nterror(req
, status
)) {
2192 return tevent_req_post(req
, ev
);
2195 subreq
= smb2cli_write_send(state
,
2198 state
->cli
->timeout
,
2199 state
->cli
->smb2
.session
,
2200 state
->cli
->smb2
.tcon
,
2203 state
->ph
->fid_persistent
,
2204 state
->ph
->fid_volatile
,
2205 0, /* remaining_bytes */
2206 state
->flags
, /* flags */
2209 if (tevent_req_nomem(subreq
, req
)) {
2210 return tevent_req_post(req
, ev
);
2212 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
2216 static void cli_smb2_write_written(struct tevent_req
*subreq
)
2218 struct tevent_req
*req
= tevent_req_callback_data(
2219 subreq
, struct tevent_req
);
2220 struct cli_smb2_write_state
*state
= tevent_req_data(
2221 req
, struct cli_smb2_write_state
);
2225 status
= smb2cli_write_recv(subreq
, &written
);
2226 TALLOC_FREE(subreq
);
2227 if (tevent_req_nterror(req
, status
)) {
2231 state
->written
= written
;
2233 tevent_req_done(req
);
2236 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
2239 struct cli_smb2_write_state
*state
= tevent_req_data(
2240 req
, struct cli_smb2_write_state
);
2243 if (tevent_req_is_nterror(req
, &status
)) {
2244 tevent_req_received(req
);
2248 if (pwritten
!= NULL
) {
2249 *pwritten
= (size_t)state
->written
;
2251 tevent_req_received(req
);
2252 return NT_STATUS_OK
;
2255 /***************************************************************
2256 Wrapper that allows SMB2 async write using an fnum.
2257 This is mostly cut-and-paste from Volker's code inside
2258 source3/libsmb/clireadwrite.c, adapted for SMB2.
2260 Done this way so I can reuse all the logic inside cli_push()
2262 ***************************************************************/
2264 struct cli_smb2_writeall_state
{
2265 struct tevent_context
*ev
;
2266 struct cli_state
*cli
;
2267 struct smb2_hnd
*ph
;
2275 static void cli_smb2_writeall_written(struct tevent_req
*req
);
2277 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
2278 struct tevent_context
*ev
,
2279 struct cli_state
*cli
,
2287 struct tevent_req
*req
, *subreq
= NULL
;
2288 struct cli_smb2_writeall_state
*state
= NULL
;
2293 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
2299 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2300 state
->flags
= (uint32_t)mode
;
2302 state
->offset
= (uint64_t)offset
;
2303 state
->size
= (uint32_t)size
;
2306 status
= map_fnum_to_smb2_handle(cli
,
2309 if (tevent_req_nterror(req
, status
)) {
2310 return tevent_req_post(req
, ev
);
2313 to_write
= state
->size
;
2314 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
2315 to_write
= MIN(max_size
, to_write
);
2316 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
2318 to_write
= MIN(max_size
, to_write
);
2321 subreq
= smb2cli_write_send(state
,
2324 state
->cli
->timeout
,
2325 state
->cli
->smb2
.session
,
2326 state
->cli
->smb2
.tcon
,
2329 state
->ph
->fid_persistent
,
2330 state
->ph
->fid_volatile
,
2331 0, /* remaining_bytes */
2332 state
->flags
, /* flags */
2333 state
->buf
+ state
->written
);
2335 if (tevent_req_nomem(subreq
, req
)) {
2336 return tevent_req_post(req
, ev
);
2338 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
2342 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
2344 struct tevent_req
*req
= tevent_req_callback_data(
2345 subreq
, struct tevent_req
);
2346 struct cli_smb2_writeall_state
*state
= tevent_req_data(
2347 req
, struct cli_smb2_writeall_state
);
2349 uint32_t written
, to_write
;
2353 status
= smb2cli_write_recv(subreq
, &written
);
2354 TALLOC_FREE(subreq
);
2355 if (tevent_req_nterror(req
, status
)) {
2359 state
->written
+= written
;
2361 if (state
->written
> state
->size
) {
2362 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2366 to_write
= state
->size
- state
->written
;
2368 if (to_write
== 0) {
2369 tevent_req_done(req
);
2373 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
2374 to_write
= MIN(max_size
, to_write
);
2375 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
2377 to_write
= MIN(max_size
, to_write
);
2380 subreq
= smb2cli_write_send(state
,
2383 state
->cli
->timeout
,
2384 state
->cli
->smb2
.session
,
2385 state
->cli
->smb2
.tcon
,
2387 state
->offset
+ state
->written
,
2388 state
->ph
->fid_persistent
,
2389 state
->ph
->fid_volatile
,
2390 0, /* remaining_bytes */
2391 state
->flags
, /* flags */
2392 state
->buf
+ state
->written
);
2394 if (tevent_req_nomem(subreq
, req
)) {
2397 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
2400 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
2403 struct cli_smb2_writeall_state
*state
= tevent_req_data(
2404 req
, struct cli_smb2_writeall_state
);
2407 if (tevent_req_is_nterror(req
, &status
)) {
2410 if (pwritten
!= NULL
) {
2411 *pwritten
= (size_t)state
->written
;
2413 return NT_STATUS_OK
;