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 smb2_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
,
489 NTSTATUS (*fn
)(const char *,
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
;
503 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
505 * Can't use sync call while an async call is in flight
507 status
= NT_STATUS_INVALID_PARAMETER
;
511 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
512 status
= NT_STATUS_INVALID_PARAMETER
;
516 /* Get the directory name. */
517 if (!windows_parent_dirname(frame
,
521 status
= NT_STATUS_NO_MEMORY
;
525 status
= cli_smb2_create_fnum(cli
,
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 */
536 if (!NT_STATUS_IS_OK(status
)) {
540 status
= map_fnum_to_smb2_handle(cli
,
543 if (!NT_STATUS_IS_OK(status
)) {
548 uint8_t *dir_data
= NULL
;
549 uint32_t dir_data_length
= 0;
550 uint32_t next_offset
= 0;
551 subframe
= talloc_stackframe();
553 status
= smb2cli_query_directory(cli
->conn
,
557 SMB2_FIND_ID_BOTH_DIRECTORY_INFO
,
568 if (!NT_STATUS_IS_OK(status
)) {
569 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
576 struct file_info
*finfo
= talloc_zero(subframe
,
580 status
= NT_STATUS_NO_MEMORY
;
584 status
= parse_finfo_id_both_directory_info(dir_data
,
589 if (!NT_STATUS_IS_OK(status
)) {
593 status
= fn(cli
->dfs_mountpoint
,
598 if (!NT_STATUS_IS_OK(status
)) {
604 /* Move to next entry. */
606 dir_data
+= next_offset
;
607 dir_data_length
-= next_offset
;
609 } while (next_offset
!= 0);
611 TALLOC_FREE(subframe
);
613 } while (NT_STATUS_IS_OK(status
));
615 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
616 status
= NT_STATUS_OK
;
621 if (fnum
!= 0xffff) {
622 cli_smb2_close_fnum(cli
, fnum
);
624 TALLOC_FREE(subframe
);
629 /***************************************************************
630 Wrapper that allows SMB2 to query a path info (basic level).
632 ***************************************************************/
634 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
636 SMB_STRUCT_STAT
*sbuf
,
637 uint32_t *attributes
)
640 struct smb2_create_returns cr
;
641 uint16_t fnum
= 0xffff;
642 size_t namelen
= strlen(name
);
644 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
646 * Can't use sync call while an async call is in flight
648 return NT_STATUS_INVALID_PARAMETER
;
651 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
652 return NT_STATUS_INVALID_PARAMETER
;
655 /* SMB2 is pickier about pathnames. Ensure it doesn't
657 if (namelen
> 0 && name
[namelen
-1] == '\\') {
658 char *modname
= talloc_strdup(talloc_tos(), name
);
659 modname
[namelen
-1] = '\0';
663 /* This is commonly used as a 'cd'. Try qpathinfo on
664 a directory handle first. */
666 status
= cli_smb2_create_fnum(cli
,
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 */
677 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
679 status
= cli_smb2_create_fnum(cli
,
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 */
691 if (!NT_STATUS_IS_OK(status
)) {
695 cli_smb2_close_fnum(cli
, fnum
);
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
;
708 /***************************************************************
709 Helper function for pathname operations.
710 ***************************************************************/
712 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
714 uint32_t desired_access
,
718 size_t namelen
= strlen(name
);
719 TALLOC_CTX
*frame
= talloc_stackframe();
721 /* SMB2 is pickier about pathnames. Ensure it doesn't
723 if (namelen
> 0 && name
[namelen
-1] == '\\') {
724 char *modname
= talloc_strdup(frame
, name
);
725 if (modname
== NULL
) {
726 status
= NT_STATUS_NO_MEMORY
;
729 modname
[namelen
-1] = '\0';
733 /* Try to open a file handle first. */
734 status
= cli_smb2_create_fnum(cli
,
736 0, /* create_flags */
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 */
745 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
746 status
= cli_smb2_create_fnum(cli
,
748 0, /* create_flags */
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 */
764 /***************************************************************
765 Wrapper that allows SMB2 to query a path info (ALTNAME level).
767 ***************************************************************/
769 NTSTATUS
cli_smb2_qpathinfo_alt_name(struct cli_state
*cli
,
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();
780 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
782 * Can't use sync call while an async call is in flight
784 status
= NT_STATUS_INVALID_PARAMETER
;
788 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
789 status
= NT_STATUS_INVALID_PARAMETER
;
793 status
= get_fnum_from_path(cli
,
795 FILE_READ_ATTRIBUTES
,
798 if (!NT_STATUS_IS_OK(status
)) {
802 status
= map_fnum_to_smb2_handle(cli
,
805 if (!NT_STATUS_IS_OK(status
)) {
809 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
810 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
812 status
= smb2cli_query_info(cli
->conn
,
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 */
827 if (!NT_STATUS_IS_OK(status
)) {
831 /* Parse the reply. */
832 if (outbuf
.length
< 4) {
833 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
837 altnamelen
= IVAL(outbuf
.data
, 0);
838 if (altnamelen
> outbuf
.length
- 4) {
839 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
843 if (altnamelen
> 0) {
845 char *short_name
= NULL
;
846 ret
= pull_string_talloc(frame
,
848 FLAGS2_UNICODE_STRINGS
,
853 if (ret
== (size_t)-1) {
854 /* Bad conversion. */
855 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
859 fstrcpy(alt_name
, short_name
);
864 status
= NT_STATUS_OK
;
868 if (fnum
!= 0xffff) {
869 cli_smb2_close_fnum(cli
, fnum
);
876 /***************************************************************
877 Wrapper that allows SMB2 to query a fnum info (basic level).
879 ***************************************************************/
881 NTSTATUS
cli_smb2_qfileinfo_basic(struct cli_state
*cli
,
885 struct timespec
*create_time
,
886 struct timespec
*access_time
,
887 struct timespec
*write_time
,
888 struct timespec
*change_time
,
892 DATA_BLOB outbuf
= data_blob_null
;
893 struct smb2_hnd
*ph
= NULL
;
894 TALLOC_CTX
*frame
= talloc_stackframe();
896 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
898 * Can't use sync call while an async call is in flight
900 status
= NT_STATUS_INVALID_PARAMETER
;
904 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
905 status
= NT_STATUS_INVALID_PARAMETER
;
909 status
= map_fnum_to_smb2_handle(cli
,
912 if (!NT_STATUS_IS_OK(status
)) {
916 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
917 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
919 status
= smb2cli_query_info(cli
->conn
,
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 */
933 if (!NT_STATUS_IS_OK(status
)) {
937 /* Parse the reply. */
938 if (outbuf
.length
< 0x60) {
939 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
944 *create_time
= interpret_long_date((const char *)outbuf
.data
+ 0x0);
947 *access_time
= interpret_long_date((const char *)outbuf
.data
+ 0x8);
950 *write_time
= interpret_long_date((const char *)outbuf
.data
+ 0x10);
953 *change_time
= interpret_long_date((const char *)outbuf
.data
+ 0x18);
956 uint32_t attr
= IVAL(outbuf
.data
, 0x20);
957 *mode
= (uint16_t)attr
;
960 uint64_t file_size
= BVAL(outbuf
.data
, 0x30);
961 *size
= (off_t
)file_size
;
964 uint64_t file_index
= BVAL(outbuf
.data
, 0x40);
965 *ino
= (SMB_INO_T
)file_index
;
974 /***************************************************************
975 Wrapper that allows SMB2 to query an fnum.
976 Implement on top of cli_smb2_qfileinfo_basic().
978 ***************************************************************/
980 NTSTATUS
cli_smb2_getattrE(struct cli_state
*cli
,
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
,
1001 if (!NT_STATUS_IS_OK(status
)) {
1006 *change_time
= change_time_ts
.tv_sec
;
1009 *access_time
= access_time_ts
.tv_sec
;
1012 *write_time
= write_time_ts
.tv_sec
;
1014 return NT_STATUS_OK
;
1017 /***************************************************************
1018 Wrapper that allows SMB2 to get pathname attributes.
1020 ***************************************************************/
1022 NTSTATUS
cli_smb2_getatr(struct cli_state
*cli
,
1029 uint16_t fnum
= 0xffff;
1030 struct smb2_hnd
*ph
= NULL
;
1031 TALLOC_CTX
*frame
= talloc_stackframe();
1033 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1035 * Can't use sync call while an async call is in flight
1037 status
= NT_STATUS_INVALID_PARAMETER
;
1041 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1042 status
= NT_STATUS_INVALID_PARAMETER
;
1046 status
= get_fnum_from_path(cli
,
1048 FILE_READ_ATTRIBUTES
,
1051 if (!NT_STATUS_IS_OK(status
)) {
1055 status
= map_fnum_to_smb2_handle(cli
,
1058 if (!NT_STATUS_IS_OK(status
)) {
1061 status
= cli_smb2_getattrE(cli
,
1068 if (!NT_STATUS_IS_OK(status
)) {
1074 if (fnum
!= 0xffff) {
1075 cli_smb2_close_fnum(cli
, fnum
);
1082 /***************************************************************
1083 Wrapper that allows SMB2 to query a pathname info (basic level).
1084 Implement on top of cli_smb2_qfileinfo_basic().
1086 ***************************************************************/
1088 NTSTATUS
cli_smb2_qpathinfo2(struct cli_state
*cli
,
1090 struct timespec
*create_time
,
1091 struct timespec
*access_time
,
1092 struct timespec
*write_time
,
1093 struct timespec
*change_time
,
1099 struct smb2_hnd
*ph
= NULL
;
1100 uint16_t fnum
= 0xffff;
1101 TALLOC_CTX
*frame
= talloc_stackframe();
1103 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1105 * Can't use sync call while an async call is in flight
1107 status
= NT_STATUS_INVALID_PARAMETER
;
1111 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1112 status
= NT_STATUS_INVALID_PARAMETER
;
1116 status
= get_fnum_from_path(cli
,
1118 FILE_READ_ATTRIBUTES
,
1121 if (!NT_STATUS_IS_OK(status
)) {
1125 status
= map_fnum_to_smb2_handle(cli
,
1128 if (!NT_STATUS_IS_OK(status
)) {
1132 status
= cli_smb2_qfileinfo_basic(cli
,
1144 if (fnum
!= 0xffff) {
1145 cli_smb2_close_fnum(cli
, fnum
);
1152 /***************************************************************
1153 Wrapper that allows SMB2 to query pathname streams.
1155 ***************************************************************/
1157 NTSTATUS
cli_smb2_qpathinfo_streams(struct cli_state
*cli
,
1159 TALLOC_CTX
*mem_ctx
,
1160 unsigned int *pnum_streams
,
1161 struct stream_struct
**pstreams
)
1164 struct smb2_hnd
*ph
= NULL
;
1165 uint16_t fnum
= 0xffff;
1166 DATA_BLOB outbuf
= data_blob_null
;
1167 TALLOC_CTX
*frame
= talloc_stackframe();
1169 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1171 * Can't use sync call while an async call is in flight
1173 status
= NT_STATUS_INVALID_PARAMETER
;
1177 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1178 status
= NT_STATUS_INVALID_PARAMETER
;
1182 status
= get_fnum_from_path(cli
,
1184 FILE_READ_ATTRIBUTES
,
1187 if (!NT_STATUS_IS_OK(status
)) {
1191 status
= map_fnum_to_smb2_handle(cli
,
1194 if (!NT_STATUS_IS_OK(status
)) {
1198 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1199 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1201 status
= smb2cli_query_info(cli
->conn
,
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 */
1216 if (!NT_STATUS_IS_OK(status
)) {
1220 /* Parse the reply. */
1221 if (!parse_streams_blob(mem_ctx
,
1226 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1232 if (fnum
!= 0xffff) {
1233 cli_smb2_close_fnum(cli
, fnum
);
1240 /***************************************************************
1241 Wrapper that allows SMB2 to set pathname attributes.
1243 ***************************************************************/
1245 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
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();
1257 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1259 * Can't use sync call while an async call is in flight
1261 status
= NT_STATUS_INVALID_PARAMETER
;
1265 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1266 status
= NT_STATUS_INVALID_PARAMETER
;
1270 status
= get_fnum_from_path(cli
,
1272 FILE_WRITE_ATTRIBUTES
,
1275 if (!NT_STATUS_IS_OK(status
)) {
1279 status
= map_fnum_to_smb2_handle(cli
,
1282 if (!NT_STATUS_IS_OK(status
)) {
1286 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1287 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1289 inbuf
.data
= inbuf_store
;
1290 inbuf
.length
= sizeof(inbuf_store
);
1291 data_blob_clear(&inbuf
);
1293 SIVAL(inbuf
.data
,32,attr
);
1295 put_long_date((char *)inbuf
.data
+ 16,mtime
);
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
);
1302 status
= smb2cli_set_info(cli
->conn
,
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 */
1314 if (fnum
!= 0xffff) {
1315 cli_smb2_close_fnum(cli
, fnum
);
1322 /***************************************************************
1323 Wrapper that allows SMB2 to set file handle times.
1325 ***************************************************************/
1327 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
1334 struct smb2_hnd
*ph
= NULL
;
1335 uint8_t inbuf_store
[40];
1336 DATA_BLOB inbuf
= data_blob_null
;
1338 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1340 * Can't use sync call while an async call is in flight
1342 return NT_STATUS_INVALID_PARAMETER
;
1345 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1346 return NT_STATUS_INVALID_PARAMETER
;
1349 status
= map_fnum_to_smb2_handle(cli
,
1352 if (!NT_STATUS_IS_OK(status
)) {
1356 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1357 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1359 inbuf
.data
= inbuf_store
;
1360 inbuf
.length
= sizeof(inbuf_store
);
1361 data_blob_clear(&inbuf
);
1363 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1364 if (change_time
!= 0) {
1365 put_long_date((char *)inbuf
.data
+ 24, change_time
);
1367 if (access_time
!= 0) {
1368 put_long_date((char *)inbuf
.data
+ 8, access_time
);
1370 if (write_time
!= 0) {
1371 put_long_date((char *)inbuf
.data
+ 16, write_time
);
1374 return smb2cli_set_info(cli
->conn
,
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 */
1386 /***************************************************************
1387 Wrapper that allows SMB2 to query disk attributes (size).
1389 ***************************************************************/
1391 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, int *bsize
, int *total
, int *avail
)
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();
1403 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1405 * Can't use sync call while an async call is in flight
1407 status
= NT_STATUS_INVALID_PARAMETER
;
1411 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1412 status
= NT_STATUS_INVALID_PARAMETER
;
1416 /* First open the top level directory. */
1417 status
= cli_smb2_create_fnum(cli
,
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 */
1428 if (!NT_STATUS_IS_OK(status
)) {
1432 status
= map_fnum_to_smb2_handle(cli
,
1435 if (!NT_STATUS_IS_OK(status
)) {
1439 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1440 level 3 (SMB_FS_SIZE_INFORMATION). */
1442 status
= smb2cli_query_info(cli
->conn
,
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 */
1456 if (!NT_STATUS_IS_OK(status
)) {
1460 /* Parse the reply. */
1461 if (outbuf
.length
!= 24) {
1462 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
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);
1472 *bsize
= (int)(sectors_per_unit
* bytes_per_sector
);
1475 *total
= (int)total_size
;
1478 *avail
= (int)size_free
;
1481 status
= NT_STATUS_OK
;
1485 if (fnum
!= 0xffff) {
1486 cli_smb2_close_fnum(cli
, fnum
);
1493 /***************************************************************
1494 Wrapper that allows SMB2 to query a security descriptor.
1496 ***************************************************************/
1498 NTSTATUS
cli_smb2_query_security_descriptor(struct cli_state
*cli
,
1501 TALLOC_CTX
*mem_ctx
,
1502 struct security_descriptor
**ppsd
)
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();
1510 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1512 * Can't use sync call while an async call is in flight
1514 status
= NT_STATUS_INVALID_PARAMETER
;
1518 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1519 status
= NT_STATUS_INVALID_PARAMETER
;
1523 status
= map_fnum_to_smb2_handle(cli
,
1526 if (!NT_STATUS_IS_OK(status
)) {
1530 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1532 status
= smb2cli_query_info(cli
->conn
,
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 */
1547 if (!NT_STATUS_IS_OK(status
)) {
1551 /* Parse the reply. */
1552 status
= unmarshall_sec_desc(mem_ctx
,
1557 if (!NT_STATUS_IS_OK(status
)) {
1573 /***************************************************************
1574 Wrapper that allows SMB2 to set a security descriptor.
1576 ***************************************************************/
1578 NTSTATUS
cli_smb2_set_security_descriptor(struct cli_state
*cli
,
1581 const struct security_descriptor
*sd
)
1584 DATA_BLOB inbuf
= data_blob_null
;
1585 struct smb2_hnd
*ph
= NULL
;
1586 TALLOC_CTX
*frame
= talloc_stackframe();
1588 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1590 * Can't use sync call while an async call is in flight
1592 status
= NT_STATUS_INVALID_PARAMETER
;
1596 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1597 status
= NT_STATUS_INVALID_PARAMETER
;
1601 status
= map_fnum_to_smb2_handle(cli
,
1604 if (!NT_STATUS_IS_OK(status
)) {
1608 status
= marshall_sec_desc(frame
,
1613 if (!NT_STATUS_IS_OK(status
)) {
1617 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1619 status
= smb2cli_set_info(cli
->conn
,
1623 3, /* in_info_type */
1624 0, /* in_file_info_class */
1625 &inbuf
, /* in_input_buffer */
1626 sec_info
, /* in_additional_info */
1636 /***************************************************************
1637 Wrapper that allows SMB2 to rename a file.
1639 ***************************************************************/
1641 NTSTATUS
cli_smb2_rename(struct cli_state
*cli
,
1642 const char *fname_src
,
1643 const char *fname_dst
)
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;
1652 TALLOC_CTX
*frame
= talloc_stackframe();
1654 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1656 * Can't use sync call while an async call is in flight
1658 status
= NT_STATUS_INVALID_PARAMETER
;
1662 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1663 status
= NT_STATUS_INVALID_PARAMETER
;
1667 status
= get_fnum_from_path(cli
,
1672 if (!NT_STATUS_IS_OK(status
)) {
1676 status
= map_fnum_to_smb2_handle(cli
,
1679 if (!NT_STATUS_IS_OK(status
)) {
1683 /* SMB2 is pickier about pathnames. Ensure it doesn't
1685 if (*fname_dst
== '\\') {
1689 /* SMB2 is pickier about pathnames. Ensure it doesn't
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
;
1698 if (!push_ucs2_talloc(frame
,
1701 &converted_size_bytes
)) {
1702 status
= NT_STATUS_INVALID_PARAMETER
;
1706 /* W2K8 insists the dest name is not null
1707 terminated. Remove the last 2 zero bytes
1708 and reduce the name length. */
1710 if (converted_size_bytes
< 2) {
1711 status
= NT_STATUS_INVALID_PARAMETER
;
1714 converted_size_bytes
-= 2;
1716 inbuf
= data_blob_talloc_zero(frame
,
1717 20 + converted_size_bytes
);
1718 if (inbuf
.data
== NULL
) {
1719 status
= NT_STATUS_NO_MEMORY
;
1723 SIVAL(inbuf
.data
, 16, converted_size_bytes
);
1724 memcpy(inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
1726 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
1727 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
1729 status
= smb2cli_set_info(cli
->conn
,
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 */
1742 if (fnum
!= 0xffff) {
1743 cli_smb2_close_fnum(cli
, fnum
);
1750 /***************************************************************
1751 Wrapper that allows SMB2 to set an EA on a fnum.
1753 ***************************************************************/
1755 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
1757 const char *ea_name
,
1762 DATA_BLOB inbuf
= data_blob_null
;
1764 char *ea_name_ascii
= NULL
;
1766 struct smb2_hnd
*ph
= NULL
;
1767 TALLOC_CTX
*frame
= talloc_stackframe();
1769 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1771 * Can't use sync call while an async call is in flight
1773 status
= NT_STATUS_INVALID_PARAMETER
;
1777 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1778 status
= NT_STATUS_INVALID_PARAMETER
;
1782 status
= map_fnum_to_smb2_handle(cli
,
1785 if (!NT_STATUS_IS_OK(status
)) {
1789 /* Marshall the SMB2 EA data. */
1790 if (ea_len
> 0xFFFF) {
1791 status
= NT_STATUS_INVALID_PARAMETER
;
1795 if (!push_ascii_talloc(frame
,
1799 status
= NT_STATUS_INVALID_PARAMETER
;
1803 if (namelen
< 2 || namelen
> 0xFF) {
1804 status
= NT_STATUS_INVALID_PARAMETER
;
1808 bloblen
= 8 + ea_len
+ namelen
;
1809 /* Round up to a 4 byte boundary. */
1810 bloblen
= ((bloblen
+ 3)&~3);
1812 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
1813 if (inbuf
.data
== NULL
) {
1814 status
= NT_STATUS_NO_MEMORY
;
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
);
1823 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1824 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
1826 status
= smb2cli_set_info(cli
->conn
,
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 */
1843 /***************************************************************
1844 Wrapper that allows SMB2 to set an EA on a pathname.
1846 ***************************************************************/
1848 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
1850 const char *ea_name
,
1855 uint16_t fnum
= 0xffff;
1857 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1859 * Can't use sync call while an async call is in flight
1861 status
= NT_STATUS_INVALID_PARAMETER
;
1865 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1866 status
= NT_STATUS_INVALID_PARAMETER
;
1870 status
= get_fnum_from_path(cli
,
1875 if (!NT_STATUS_IS_OK(status
)) {
1879 status
= cli_set_ea_fnum(cli
,
1884 if (!NT_STATUS_IS_OK(status
)) {
1890 if (fnum
!= 0xffff) {
1891 cli_smb2_close_fnum(cli
, fnum
);
1897 /***************************************************************
1898 Wrapper that allows SMB2 to get an EA list on a pathname.
1900 ***************************************************************/
1902 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
1906 struct ea_struct
**pea_array
)
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();
1920 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1922 * Can't use sync call while an async call is in flight
1924 status
= NT_STATUS_INVALID_PARAMETER
;
1928 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1929 status
= NT_STATUS_INVALID_PARAMETER
;
1933 status
= get_fnum_from_path(cli
,
1938 if (!NT_STATUS_IS_OK(status
)) {
1942 status
= map_fnum_to_smb2_handle(cli
,
1945 if (!NT_STATUS_IS_OK(status
)) {
1949 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1950 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
1952 status
= smb2cli_query_info(cli
->conn
,
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 */
1967 if (!NT_STATUS_IS_OK(status
)) {
1971 /* Parse the reply. */
1972 ea_list
= read_nttrans_ea_list(ctx
,
1973 (const char *)outbuf
.data
,
1975 if (ea_list
== NULL
) {
1976 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1980 /* Convert to an array. */
1981 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
1986 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
1987 if (*pea_array
== NULL
) {
1988 status
= NT_STATUS_NO_MEMORY
;
1992 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
1993 (*pea_array
)[ea_count
++] = ea_list
->ea
;
1995 *pnum_eas
= ea_count
;
2004 struct cli_smb2_read_state
{
2005 struct tevent_context
*ev
;
2006 struct cli_state
*cli
;
2007 struct smb2_hnd
*ph
;
2008 uint64_t start_offset
;
2014 static void cli_smb2_read_done(struct tevent_req
*subreq
);
2016 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
2017 struct tevent_context
*ev
,
2018 struct cli_state
*cli
,
2024 struct tevent_req
*req
, *subreq
;
2025 struct cli_smb2_read_state
*state
;
2027 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
2033 state
->start_offset
= (uint64_t)offset
;
2034 state
->size
= (uint32_t)size
;
2035 state
->received
= 0;
2038 status
= map_fnum_to_smb2_handle(cli
,
2041 if (tevent_req_nterror(req
, status
)) {
2042 return tevent_req_post(req
, ev
);
2045 subreq
= smb2cli_read_send(state
,
2048 state
->cli
->timeout
,
2049 state
->cli
->smb2
.session
,
2050 state
->cli
->smb2
.tcon
,
2052 state
->start_offset
,
2053 state
->ph
->fid_persistent
,
2054 state
->ph
->fid_volatile
,
2055 0, /* minimum_count */
2056 0); /* remaining_bytes */
2058 if (tevent_req_nomem(subreq
, req
)) {
2059 return tevent_req_post(req
, ev
);
2061 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
2065 static void cli_smb2_read_done(struct tevent_req
*subreq
)
2067 struct tevent_req
*req
= tevent_req_callback_data(
2068 subreq
, struct tevent_req
);
2069 struct cli_smb2_read_state
*state
= tevent_req_data(
2070 req
, struct cli_smb2_read_state
);
2073 status
= smb2cli_read_recv(subreq
, state
,
2074 &state
->buf
, &state
->received
);
2075 if (tevent_req_nterror(req
, status
)) {
2079 if (state
->received
> state
->size
) {
2080 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2084 tevent_req_done(req
);
2087 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
2092 struct cli_smb2_read_state
*state
= tevent_req_data(
2093 req
, struct cli_smb2_read_state
);
2095 if (tevent_req_is_nterror(req
, &status
)) {
2099 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2100 * better make sure that you copy it away before you talloc_free(req).
2101 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2103 *received
= (ssize_t
)state
->received
;
2104 *rcvbuf
= state
->buf
;
2105 return NT_STATUS_OK
;
2108 struct cli_smb2_write_state
{
2109 struct tevent_context
*ev
;
2110 struct cli_state
*cli
;
2111 struct smb2_hnd
*ph
;
2119 static void cli_smb2_write_written(struct tevent_req
*req
);
2121 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
2122 struct tevent_context
*ev
,
2123 struct cli_state
*cli
,
2131 struct tevent_req
*req
, *subreq
= NULL
;
2132 struct cli_smb2_write_state
*state
= NULL
;
2134 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
2140 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2141 state
->flags
= (uint32_t)mode
;
2143 state
->offset
= (uint64_t)offset
;
2144 state
->size
= (uint32_t)size
;
2147 status
= map_fnum_to_smb2_handle(cli
,
2150 if (tevent_req_nterror(req
, status
)) {
2151 return tevent_req_post(req
, ev
);
2154 subreq
= smb2cli_write_send(state
,
2157 state
->cli
->timeout
,
2158 state
->cli
->smb2
.session
,
2159 state
->cli
->smb2
.tcon
,
2162 state
->ph
->fid_persistent
,
2163 state
->ph
->fid_volatile
,
2164 0, /* remaining_bytes */
2165 state
->flags
, /* flags */
2168 if (tevent_req_nomem(subreq
, req
)) {
2169 return tevent_req_post(req
, ev
);
2171 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
2175 static void cli_smb2_write_written(struct tevent_req
*subreq
)
2177 struct tevent_req
*req
= tevent_req_callback_data(
2178 subreq
, struct tevent_req
);
2179 struct cli_smb2_write_state
*state
= tevent_req_data(
2180 req
, struct cli_smb2_write_state
);
2184 status
= smb2cli_write_recv(subreq
, &written
);
2185 TALLOC_FREE(subreq
);
2186 if (tevent_req_nterror(req
, status
)) {
2190 state
->written
= written
;
2192 tevent_req_done(req
);
2195 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
2198 struct cli_smb2_write_state
*state
= tevent_req_data(
2199 req
, struct cli_smb2_write_state
);
2202 if (tevent_req_is_nterror(req
, &status
)) {
2203 tevent_req_received(req
);
2207 if (pwritten
!= NULL
) {
2208 *pwritten
= (size_t)state
->written
;
2210 tevent_req_received(req
);
2211 return NT_STATUS_OK
;
2214 /***************************************************************
2215 Wrapper that allows SMB2 async write using an fnum.
2216 This is mostly cut-and-paste from Volker's code inside
2217 source3/libsmb/clireadwrite.c, adapted for SMB2.
2219 Done this way so I can reuse all the logic inside cli_push()
2221 ***************************************************************/
2223 struct cli_smb2_writeall_state
{
2224 struct tevent_context
*ev
;
2225 struct cli_state
*cli
;
2226 struct smb2_hnd
*ph
;
2234 static void cli_smb2_writeall_written(struct tevent_req
*req
);
2236 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
2237 struct tevent_context
*ev
,
2238 struct cli_state
*cli
,
2246 struct tevent_req
*req
, *subreq
= NULL
;
2247 struct cli_smb2_writeall_state
*state
= NULL
;
2252 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
2258 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2259 state
->flags
= (uint32_t)mode
;
2261 state
->offset
= (uint64_t)offset
;
2262 state
->size
= (uint32_t)size
;
2265 status
= map_fnum_to_smb2_handle(cli
,
2268 if (tevent_req_nterror(req
, status
)) {
2269 return tevent_req_post(req
, ev
);
2272 to_write
= state
->size
;
2273 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
2274 to_write
= MIN(max_size
, to_write
);
2275 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
2277 to_write
= MIN(max_size
, to_write
);
2280 subreq
= smb2cli_write_send(state
,
2283 state
->cli
->timeout
,
2284 state
->cli
->smb2
.session
,
2285 state
->cli
->smb2
.tcon
,
2288 state
->ph
->fid_persistent
,
2289 state
->ph
->fid_volatile
,
2290 0, /* remaining_bytes */
2291 state
->flags
, /* flags */
2292 state
->buf
+ state
->written
);
2294 if (tevent_req_nomem(subreq
, req
)) {
2295 return tevent_req_post(req
, ev
);
2297 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
2301 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
2303 struct tevent_req
*req
= tevent_req_callback_data(
2304 subreq
, struct tevent_req
);
2305 struct cli_smb2_writeall_state
*state
= tevent_req_data(
2306 req
, struct cli_smb2_writeall_state
);
2308 uint32_t written
, to_write
;
2312 status
= smb2cli_write_recv(subreq
, &written
);
2313 TALLOC_FREE(subreq
);
2314 if (tevent_req_nterror(req
, status
)) {
2318 state
->written
+= written
;
2320 if (state
->written
> state
->size
) {
2321 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2325 to_write
= state
->size
- state
->written
;
2327 if (to_write
== 0) {
2328 tevent_req_done(req
);
2332 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
2333 to_write
= MIN(max_size
, to_write
);
2334 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
2336 to_write
= MIN(max_size
, to_write
);
2339 subreq
= smb2cli_write_send(state
,
2342 state
->cli
->timeout
,
2343 state
->cli
->smb2
.session
,
2344 state
->cli
->smb2
.tcon
,
2346 state
->offset
+ state
->written
,
2347 state
->ph
->fid_persistent
,
2348 state
->ph
->fid_volatile
,
2349 0, /* remaining_bytes */
2350 state
->flags
, /* flags */
2351 state
->buf
+ state
->written
);
2353 if (tevent_req_nomem(subreq
, req
)) {
2356 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
2359 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
2362 struct cli_smb2_writeall_state
*state
= tevent_req_data(
2363 req
, struct cli_smb2_writeall_state
);
2366 if (tevent_req_is_nterror(req
, &status
)) {
2369 if (pwritten
!= NULL
) {
2370 *pwritten
= (size_t)state
->written
;
2372 return NT_STATUS_OK
;