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
,
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
;
505 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
507 * Can't use sync call while an async call is in flight
509 status
= NT_STATUS_INVALID_PARAMETER
;
513 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
514 status
= NT_STATUS_INVALID_PARAMETER
;
518 /* Get the directory name. */
519 if (!windows_parent_dirname(frame
,
523 status
= NT_STATUS_NO_MEMORY
;
527 status
= cli_smb2_create_fnum(cli
,
529 0, /* create_flags */
530 SEC_DIR_LIST
|SEC_DIR_READ_ATTRIBUTE
,/* desired_access */
531 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
532 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
533 FILE_OPEN
, /* create_disposition */
534 FILE_DIRECTORY_FILE
, /* create_options */
538 if (!NT_STATUS_IS_OK(status
)) {
542 status
= map_fnum_to_smb2_handle(cli
,
545 if (!NT_STATUS_IS_OK(status
)) {
550 uint8_t *dir_data
= NULL
;
551 uint32_t dir_data_length
= 0;
552 uint32_t next_offset
= 0;
553 subframe
= talloc_stackframe();
555 status
= smb2cli_query_directory(cli
->conn
,
559 SMB2_FIND_ID_BOTH_DIRECTORY_INFO
,
570 if (!NT_STATUS_IS_OK(status
)) {
571 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
578 struct file_info
*finfo
= talloc_zero(subframe
,
582 status
= NT_STATUS_NO_MEMORY
;
586 status
= parse_finfo_id_both_directory_info(dir_data
,
591 if (!NT_STATUS_IS_OK(status
)) {
595 if (dir_check_ftype((uint32_t)finfo
->mode
,
596 (uint32_t)attribute
)) {
598 * Only process if attributes match.
599 * On SMB1 server does this, so on
600 * SMB2 we need to emulate in the
603 * https://bugzilla.samba.org/show_bug.cgi?id=10260
605 processed_file
= true;
607 status
= fn(cli
->dfs_mountpoint
,
612 if (!NT_STATUS_IS_OK(status
)) {
619 /* Move to next entry. */
621 dir_data
+= next_offset
;
622 dir_data_length
-= next_offset
;
624 } while (next_offset
!= 0);
626 TALLOC_FREE(subframe
);
628 } while (NT_STATUS_IS_OK(status
));
630 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
631 status
= NT_STATUS_OK
;
634 if (NT_STATUS_IS_OK(status
) && !processed_file
) {
636 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
637 * if no files match. Emulate this in the client.
639 status
= NT_STATUS_NO_SUCH_FILE
;
644 if (fnum
!= 0xffff) {
645 cli_smb2_close_fnum(cli
, fnum
);
647 TALLOC_FREE(subframe
);
652 /***************************************************************
653 Wrapper that allows SMB2 to query a path info (basic level).
655 ***************************************************************/
657 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
659 SMB_STRUCT_STAT
*sbuf
,
660 uint32_t *attributes
)
663 struct smb2_create_returns cr
;
664 uint16_t fnum
= 0xffff;
665 size_t namelen
= strlen(name
);
667 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
669 * Can't use sync call while an async call is in flight
671 return NT_STATUS_INVALID_PARAMETER
;
674 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
675 return NT_STATUS_INVALID_PARAMETER
;
678 /* SMB2 is pickier about pathnames. Ensure it doesn't
680 if (namelen
> 0 && name
[namelen
-1] == '\\') {
681 char *modname
= talloc_strdup(talloc_tos(), name
);
682 modname
[namelen
-1] = '\0';
686 /* This is commonly used as a 'cd'. Try qpathinfo on
687 a directory handle first. */
689 status
= cli_smb2_create_fnum(cli
,
691 0, /* create_flags */
692 FILE_READ_ATTRIBUTES
, /* desired_access */
693 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
694 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
695 FILE_OPEN
, /* create_disposition */
696 FILE_DIRECTORY_FILE
, /* create_options */
700 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
702 status
= cli_smb2_create_fnum(cli
,
704 0, /* create_flags */
705 FILE_READ_ATTRIBUTES
, /* desired_access */
706 0, /* file attributes */
707 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
708 FILE_OPEN
, /* create_disposition */
709 0, /* create_options */
714 if (!NT_STATUS_IS_OK(status
)) {
718 cli_smb2_close_fnum(cli
, fnum
);
722 sbuf
->st_ex_atime
= nt_time_to_unix_timespec(&cr
.last_access_time
);
723 sbuf
->st_ex_mtime
= nt_time_to_unix_timespec(&cr
.last_write_time
);
724 sbuf
->st_ex_ctime
= nt_time_to_unix_timespec(&cr
.change_time
);
725 sbuf
->st_ex_size
= cr
.end_of_file
;
726 *attributes
= cr
.file_attributes
;
731 /***************************************************************
732 Helper function for pathname operations.
733 ***************************************************************/
735 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
737 uint32_t desired_access
,
741 size_t namelen
= strlen(name
);
742 TALLOC_CTX
*frame
= talloc_stackframe();
744 /* SMB2 is pickier about pathnames. Ensure it doesn't
746 if (namelen
> 0 && name
[namelen
-1] == '\\') {
747 char *modname
= talloc_strdup(frame
, name
);
748 if (modname
== NULL
) {
749 status
= NT_STATUS_NO_MEMORY
;
752 modname
[namelen
-1] = '\0';
756 /* Try to open a file handle first. */
757 status
= cli_smb2_create_fnum(cli
,
759 0, /* create_flags */
761 0, /* file attributes */
762 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
763 FILE_OPEN
, /* create_disposition */
764 0, /* create_options */
768 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
769 status
= cli_smb2_create_fnum(cli
,
771 0, /* create_flags */
773 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
774 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
775 FILE_OPEN
, /* create_disposition */
776 FILE_DIRECTORY_FILE
, /* create_options */
787 /***************************************************************
788 Wrapper that allows SMB2 to query a path info (ALTNAME level).
790 ***************************************************************/
792 NTSTATUS
cli_smb2_qpathinfo_alt_name(struct cli_state
*cli
,
797 DATA_BLOB outbuf
= data_blob_null
;
798 uint16_t fnum
= 0xffff;
799 struct smb2_hnd
*ph
= NULL
;
800 uint32_t altnamelen
= 0;
801 TALLOC_CTX
*frame
= talloc_stackframe();
803 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
805 * Can't use sync call while an async call is in flight
807 status
= NT_STATUS_INVALID_PARAMETER
;
811 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
812 status
= NT_STATUS_INVALID_PARAMETER
;
816 status
= get_fnum_from_path(cli
,
818 FILE_READ_ATTRIBUTES
,
821 if (!NT_STATUS_IS_OK(status
)) {
825 status
= map_fnum_to_smb2_handle(cli
,
828 if (!NT_STATUS_IS_OK(status
)) {
832 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
833 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
835 status
= smb2cli_query_info(cli
->conn
,
839 1, /* in_info_type */
840 (SMB_FILE_ALTERNATE_NAME_INFORMATION
- 1000), /* in_file_info_class */
841 0xFFFF, /* in_max_output_length */
842 NULL
, /* in_input_buffer */
843 0, /* in_additional_info */
850 if (!NT_STATUS_IS_OK(status
)) {
854 /* Parse the reply. */
855 if (outbuf
.length
< 4) {
856 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
860 altnamelen
= IVAL(outbuf
.data
, 0);
861 if (altnamelen
> outbuf
.length
- 4) {
862 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
866 if (altnamelen
> 0) {
868 char *short_name
= NULL
;
869 ret
= pull_string_talloc(frame
,
871 FLAGS2_UNICODE_STRINGS
,
876 if (ret
== (size_t)-1) {
877 /* Bad conversion. */
878 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
882 fstrcpy(alt_name
, short_name
);
887 status
= NT_STATUS_OK
;
891 if (fnum
!= 0xffff) {
892 cli_smb2_close_fnum(cli
, fnum
);
899 /***************************************************************
900 Wrapper that allows SMB2 to query a fnum info (basic level).
902 ***************************************************************/
904 NTSTATUS
cli_smb2_qfileinfo_basic(struct cli_state
*cli
,
908 struct timespec
*create_time
,
909 struct timespec
*access_time
,
910 struct timespec
*write_time
,
911 struct timespec
*change_time
,
915 DATA_BLOB outbuf
= data_blob_null
;
916 struct smb2_hnd
*ph
= NULL
;
917 TALLOC_CTX
*frame
= talloc_stackframe();
919 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
921 * Can't use sync call while an async call is in flight
923 status
= NT_STATUS_INVALID_PARAMETER
;
927 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
928 status
= NT_STATUS_INVALID_PARAMETER
;
932 status
= map_fnum_to_smb2_handle(cli
,
935 if (!NT_STATUS_IS_OK(status
)) {
939 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
940 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
942 status
= smb2cli_query_info(cli
->conn
,
946 1, /* in_info_type */
947 (SMB_FILE_ALL_INFORMATION
- 1000), /* in_file_info_class */
948 0xFFFF, /* in_max_output_length */
949 NULL
, /* in_input_buffer */
950 0, /* in_additional_info */
956 if (!NT_STATUS_IS_OK(status
)) {
960 /* Parse the reply. */
961 if (outbuf
.length
< 0x60) {
962 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
967 *create_time
= interpret_long_date((const char *)outbuf
.data
+ 0x0);
970 *access_time
= interpret_long_date((const char *)outbuf
.data
+ 0x8);
973 *write_time
= interpret_long_date((const char *)outbuf
.data
+ 0x10);
976 *change_time
= interpret_long_date((const char *)outbuf
.data
+ 0x18);
979 uint32_t attr
= IVAL(outbuf
.data
, 0x20);
980 *mode
= (uint16_t)attr
;
983 uint64_t file_size
= BVAL(outbuf
.data
, 0x30);
984 *size
= (off_t
)file_size
;
987 uint64_t file_index
= BVAL(outbuf
.data
, 0x40);
988 *ino
= (SMB_INO_T
)file_index
;
997 /***************************************************************
998 Wrapper that allows SMB2 to query an fnum.
999 Implement on top of cli_smb2_qfileinfo_basic().
1001 ***************************************************************/
1003 NTSTATUS
cli_smb2_getattrE(struct cli_state
*cli
,
1007 time_t *change_time
,
1008 time_t *access_time
,
1011 struct timespec access_time_ts
;
1012 struct timespec write_time_ts
;
1013 struct timespec change_time_ts
;
1014 NTSTATUS status
= cli_smb2_qfileinfo_basic(cli
,
1024 if (!NT_STATUS_IS_OK(status
)) {
1029 *change_time
= change_time_ts
.tv_sec
;
1032 *access_time
= access_time_ts
.tv_sec
;
1035 *write_time
= write_time_ts
.tv_sec
;
1037 return NT_STATUS_OK
;
1040 /***************************************************************
1041 Wrapper that allows SMB2 to get pathname attributes.
1043 ***************************************************************/
1045 NTSTATUS
cli_smb2_getatr(struct cli_state
*cli
,
1052 uint16_t fnum
= 0xffff;
1053 struct smb2_hnd
*ph
= NULL
;
1054 TALLOC_CTX
*frame
= talloc_stackframe();
1056 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1058 * Can't use sync call while an async call is in flight
1060 status
= NT_STATUS_INVALID_PARAMETER
;
1064 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1065 status
= NT_STATUS_INVALID_PARAMETER
;
1069 status
= get_fnum_from_path(cli
,
1071 FILE_READ_ATTRIBUTES
,
1074 if (!NT_STATUS_IS_OK(status
)) {
1078 status
= map_fnum_to_smb2_handle(cli
,
1081 if (!NT_STATUS_IS_OK(status
)) {
1084 status
= cli_smb2_getattrE(cli
,
1091 if (!NT_STATUS_IS_OK(status
)) {
1097 if (fnum
!= 0xffff) {
1098 cli_smb2_close_fnum(cli
, fnum
);
1105 /***************************************************************
1106 Wrapper that allows SMB2 to query a pathname info (basic level).
1107 Implement on top of cli_smb2_qfileinfo_basic().
1109 ***************************************************************/
1111 NTSTATUS
cli_smb2_qpathinfo2(struct cli_state
*cli
,
1113 struct timespec
*create_time
,
1114 struct timespec
*access_time
,
1115 struct timespec
*write_time
,
1116 struct timespec
*change_time
,
1122 struct smb2_hnd
*ph
= NULL
;
1123 uint16_t fnum
= 0xffff;
1124 TALLOC_CTX
*frame
= talloc_stackframe();
1126 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1128 * Can't use sync call while an async call is in flight
1130 status
= NT_STATUS_INVALID_PARAMETER
;
1134 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1135 status
= NT_STATUS_INVALID_PARAMETER
;
1139 status
= get_fnum_from_path(cli
,
1141 FILE_READ_ATTRIBUTES
,
1144 if (!NT_STATUS_IS_OK(status
)) {
1148 status
= map_fnum_to_smb2_handle(cli
,
1151 if (!NT_STATUS_IS_OK(status
)) {
1155 status
= cli_smb2_qfileinfo_basic(cli
,
1167 if (fnum
!= 0xffff) {
1168 cli_smb2_close_fnum(cli
, fnum
);
1175 /***************************************************************
1176 Wrapper that allows SMB2 to query pathname streams.
1178 ***************************************************************/
1180 NTSTATUS
cli_smb2_qpathinfo_streams(struct cli_state
*cli
,
1182 TALLOC_CTX
*mem_ctx
,
1183 unsigned int *pnum_streams
,
1184 struct stream_struct
**pstreams
)
1187 struct smb2_hnd
*ph
= NULL
;
1188 uint16_t fnum
= 0xffff;
1189 DATA_BLOB outbuf
= data_blob_null
;
1190 TALLOC_CTX
*frame
= talloc_stackframe();
1192 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1194 * Can't use sync call while an async call is in flight
1196 status
= NT_STATUS_INVALID_PARAMETER
;
1200 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1201 status
= NT_STATUS_INVALID_PARAMETER
;
1205 status
= get_fnum_from_path(cli
,
1207 FILE_READ_ATTRIBUTES
,
1210 if (!NT_STATUS_IS_OK(status
)) {
1214 status
= map_fnum_to_smb2_handle(cli
,
1217 if (!NT_STATUS_IS_OK(status
)) {
1221 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1222 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1224 status
= smb2cli_query_info(cli
->conn
,
1228 1, /* in_info_type */
1229 (SMB_FILE_STREAM_INFORMATION
- 1000), /* in_file_info_class */
1230 0xFFFF, /* in_max_output_length */
1231 NULL
, /* in_input_buffer */
1232 0, /* in_additional_info */
1239 if (!NT_STATUS_IS_OK(status
)) {
1243 /* Parse the reply. */
1244 if (!parse_streams_blob(mem_ctx
,
1249 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1255 if (fnum
!= 0xffff) {
1256 cli_smb2_close_fnum(cli
, fnum
);
1263 /***************************************************************
1264 Wrapper that allows SMB2 to set pathname attributes.
1266 ***************************************************************/
1268 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
1274 uint16_t fnum
= 0xffff;
1275 struct smb2_hnd
*ph
= NULL
;
1276 uint8_t inbuf_store
[40];
1277 DATA_BLOB inbuf
= data_blob_null
;
1278 TALLOC_CTX
*frame
= talloc_stackframe();
1280 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1282 * Can't use sync call while an async call is in flight
1284 status
= NT_STATUS_INVALID_PARAMETER
;
1288 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1289 status
= NT_STATUS_INVALID_PARAMETER
;
1293 status
= get_fnum_from_path(cli
,
1295 FILE_WRITE_ATTRIBUTES
,
1298 if (!NT_STATUS_IS_OK(status
)) {
1302 status
= map_fnum_to_smb2_handle(cli
,
1305 if (!NT_STATUS_IS_OK(status
)) {
1309 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1310 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1312 inbuf
.data
= inbuf_store
;
1313 inbuf
.length
= sizeof(inbuf_store
);
1314 data_blob_clear(&inbuf
);
1316 SSVAL(inbuf
.data
, 32, attr
);
1318 put_long_date((char *)inbuf
.data
+ 16,mtime
);
1320 /* Set all the other times to -1. */
1321 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1322 SBVAL(inbuf
.data
, 8, 0xFFFFFFFFFFFFFFFFLL
);
1323 SBVAL(inbuf
.data
, 24, 0xFFFFFFFFFFFFFFFFLL
);
1325 status
= smb2cli_set_info(cli
->conn
,
1329 1, /* in_info_type */
1330 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1331 &inbuf
, /* in_input_buffer */
1332 0, /* in_additional_info */
1337 if (fnum
!= 0xffff) {
1338 cli_smb2_close_fnum(cli
, fnum
);
1345 /***************************************************************
1346 Wrapper that allows SMB2 to set file handle times.
1348 ***************************************************************/
1350 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
1357 struct smb2_hnd
*ph
= NULL
;
1358 uint8_t inbuf_store
[40];
1359 DATA_BLOB inbuf
= data_blob_null
;
1361 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1363 * Can't use sync call while an async call is in flight
1365 return NT_STATUS_INVALID_PARAMETER
;
1368 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1369 return NT_STATUS_INVALID_PARAMETER
;
1372 status
= map_fnum_to_smb2_handle(cli
,
1375 if (!NT_STATUS_IS_OK(status
)) {
1379 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1380 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1382 inbuf
.data
= inbuf_store
;
1383 inbuf
.length
= sizeof(inbuf_store
);
1384 data_blob_clear(&inbuf
);
1386 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1387 if (change_time
!= 0) {
1388 put_long_date((char *)inbuf
.data
+ 24, change_time
);
1390 if (access_time
!= 0) {
1391 put_long_date((char *)inbuf
.data
+ 8, access_time
);
1393 if (write_time
!= 0) {
1394 put_long_date((char *)inbuf
.data
+ 16, write_time
);
1397 return smb2cli_set_info(cli
->conn
,
1401 1, /* in_info_type */
1402 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1403 &inbuf
, /* in_input_buffer */
1404 0, /* in_additional_info */
1409 /***************************************************************
1410 Wrapper that allows SMB2 to query disk attributes (size).
1412 ***************************************************************/
1414 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, int *bsize
, int *total
, int *avail
)
1417 uint16_t fnum
= 0xffff;
1418 DATA_BLOB outbuf
= data_blob_null
;
1419 struct smb2_hnd
*ph
= NULL
;
1420 uint32_t sectors_per_unit
= 0;
1421 uint32_t bytes_per_sector
= 0;
1422 uint64_t total_size
= 0;
1423 uint64_t size_free
= 0;
1424 TALLOC_CTX
*frame
= talloc_stackframe();
1426 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1428 * Can't use sync call while an async call is in flight
1430 status
= NT_STATUS_INVALID_PARAMETER
;
1434 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1435 status
= NT_STATUS_INVALID_PARAMETER
;
1439 /* First open the top level directory. */
1440 status
= cli_smb2_create_fnum(cli
,
1442 0, /* create_flags */
1443 FILE_READ_ATTRIBUTES
, /* desired_access */
1444 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1445 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1446 FILE_OPEN
, /* create_disposition */
1447 FILE_DIRECTORY_FILE
, /* create_options */
1451 if (!NT_STATUS_IS_OK(status
)) {
1455 status
= map_fnum_to_smb2_handle(cli
,
1458 if (!NT_STATUS_IS_OK(status
)) {
1462 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1463 level 3 (SMB_FS_SIZE_INFORMATION). */
1465 status
= smb2cli_query_info(cli
->conn
,
1469 2, /* in_info_type */
1470 3, /* in_file_info_class */
1471 0xFFFF, /* in_max_output_length */
1472 NULL
, /* in_input_buffer */
1473 0, /* in_additional_info */
1479 if (!NT_STATUS_IS_OK(status
)) {
1483 /* Parse the reply. */
1484 if (outbuf
.length
!= 24) {
1485 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1489 total_size
= BVAL(outbuf
.data
, 0);
1490 size_free
= BVAL(outbuf
.data
, 8);
1491 sectors_per_unit
= IVAL(outbuf
.data
, 16);
1492 bytes_per_sector
= IVAL(outbuf
.data
, 20);
1495 *bsize
= (int)(sectors_per_unit
* bytes_per_sector
);
1498 *total
= (int)total_size
;
1501 *avail
= (int)size_free
;
1504 status
= NT_STATUS_OK
;
1508 if (fnum
!= 0xffff) {
1509 cli_smb2_close_fnum(cli
, fnum
);
1516 /***************************************************************
1517 Wrapper that allows SMB2 to query a security descriptor.
1519 ***************************************************************/
1521 NTSTATUS
cli_smb2_query_security_descriptor(struct cli_state
*cli
,
1524 TALLOC_CTX
*mem_ctx
,
1525 struct security_descriptor
**ppsd
)
1528 DATA_BLOB outbuf
= data_blob_null
;
1529 struct smb2_hnd
*ph
= NULL
;
1530 struct security_descriptor
*lsd
= NULL
;
1531 TALLOC_CTX
*frame
= talloc_stackframe();
1533 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1535 * Can't use sync call while an async call is in flight
1537 status
= NT_STATUS_INVALID_PARAMETER
;
1541 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1542 status
= NT_STATUS_INVALID_PARAMETER
;
1546 status
= map_fnum_to_smb2_handle(cli
,
1549 if (!NT_STATUS_IS_OK(status
)) {
1553 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1555 status
= smb2cli_query_info(cli
->conn
,
1559 3, /* in_info_type */
1560 0, /* in_file_info_class */
1561 0xFFFF, /* in_max_output_length */
1562 NULL
, /* in_input_buffer */
1563 sec_info
, /* in_additional_info */
1570 if (!NT_STATUS_IS_OK(status
)) {
1574 /* Parse the reply. */
1575 status
= unmarshall_sec_desc(mem_ctx
,
1580 if (!NT_STATUS_IS_OK(status
)) {
1596 /***************************************************************
1597 Wrapper that allows SMB2 to set a security descriptor.
1599 ***************************************************************/
1601 NTSTATUS
cli_smb2_set_security_descriptor(struct cli_state
*cli
,
1604 const struct security_descriptor
*sd
)
1607 DATA_BLOB inbuf
= data_blob_null
;
1608 struct smb2_hnd
*ph
= NULL
;
1609 TALLOC_CTX
*frame
= talloc_stackframe();
1611 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1613 * Can't use sync call while an async call is in flight
1615 status
= NT_STATUS_INVALID_PARAMETER
;
1619 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1620 status
= NT_STATUS_INVALID_PARAMETER
;
1624 status
= map_fnum_to_smb2_handle(cli
,
1627 if (!NT_STATUS_IS_OK(status
)) {
1631 status
= marshall_sec_desc(frame
,
1636 if (!NT_STATUS_IS_OK(status
)) {
1640 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1642 status
= smb2cli_set_info(cli
->conn
,
1646 3, /* in_info_type */
1647 0, /* in_file_info_class */
1648 &inbuf
, /* in_input_buffer */
1649 sec_info
, /* in_additional_info */
1659 /***************************************************************
1660 Wrapper that allows SMB2 to rename a file.
1662 ***************************************************************/
1664 NTSTATUS
cli_smb2_rename(struct cli_state
*cli
,
1665 const char *fname_src
,
1666 const char *fname_dst
)
1669 DATA_BLOB inbuf
= data_blob_null
;
1670 uint16_t fnum
= 0xffff;
1671 struct smb2_hnd
*ph
= NULL
;
1672 smb_ucs2_t
*converted_str
= NULL
;
1673 size_t converted_size_bytes
= 0;
1675 TALLOC_CTX
*frame
= talloc_stackframe();
1677 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1679 * Can't use sync call while an async call is in flight
1681 status
= NT_STATUS_INVALID_PARAMETER
;
1685 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1686 status
= NT_STATUS_INVALID_PARAMETER
;
1690 status
= get_fnum_from_path(cli
,
1695 if (!NT_STATUS_IS_OK(status
)) {
1699 status
= map_fnum_to_smb2_handle(cli
,
1702 if (!NT_STATUS_IS_OK(status
)) {
1706 /* SMB2 is pickier about pathnames. Ensure it doesn't
1708 if (*fname_dst
== '\\') {
1712 /* SMB2 is pickier about pathnames. Ensure it doesn't
1714 namelen
= strlen(fname_dst
);
1715 if (namelen
> 0 && fname_dst
[namelen
-1] == '\\') {
1716 char *modname
= talloc_strdup(frame
, fname_dst
);
1717 modname
[namelen
-1] = '\0';
1718 fname_dst
= modname
;
1721 if (!push_ucs2_talloc(frame
,
1724 &converted_size_bytes
)) {
1725 status
= NT_STATUS_INVALID_PARAMETER
;
1729 /* W2K8 insists the dest name is not null
1730 terminated. Remove the last 2 zero bytes
1731 and reduce the name length. */
1733 if (converted_size_bytes
< 2) {
1734 status
= NT_STATUS_INVALID_PARAMETER
;
1737 converted_size_bytes
-= 2;
1739 inbuf
= data_blob_talloc_zero(frame
,
1740 20 + converted_size_bytes
);
1741 if (inbuf
.data
== NULL
) {
1742 status
= NT_STATUS_NO_MEMORY
;
1746 SIVAL(inbuf
.data
, 16, converted_size_bytes
);
1747 memcpy(inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
1749 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
1750 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
1752 status
= smb2cli_set_info(cli
->conn
,
1756 1, /* in_info_type */
1757 SMB_FILE_RENAME_INFORMATION
- 1000, /* in_file_info_class */
1758 &inbuf
, /* in_input_buffer */
1759 0, /* in_additional_info */
1765 if (fnum
!= 0xffff) {
1766 cli_smb2_close_fnum(cli
, fnum
);
1773 /***************************************************************
1774 Wrapper that allows SMB2 to set an EA on a fnum.
1776 ***************************************************************/
1778 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
1780 const char *ea_name
,
1785 DATA_BLOB inbuf
= data_blob_null
;
1787 char *ea_name_ascii
= NULL
;
1789 struct smb2_hnd
*ph
= NULL
;
1790 TALLOC_CTX
*frame
= talloc_stackframe();
1792 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1794 * Can't use sync call while an async call is in flight
1796 status
= NT_STATUS_INVALID_PARAMETER
;
1800 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1801 status
= NT_STATUS_INVALID_PARAMETER
;
1805 status
= map_fnum_to_smb2_handle(cli
,
1808 if (!NT_STATUS_IS_OK(status
)) {
1812 /* Marshall the SMB2 EA data. */
1813 if (ea_len
> 0xFFFF) {
1814 status
= NT_STATUS_INVALID_PARAMETER
;
1818 if (!push_ascii_talloc(frame
,
1822 status
= NT_STATUS_INVALID_PARAMETER
;
1826 if (namelen
< 2 || namelen
> 0xFF) {
1827 status
= NT_STATUS_INVALID_PARAMETER
;
1831 bloblen
= 8 + ea_len
+ namelen
;
1832 /* Round up to a 4 byte boundary. */
1833 bloblen
= ((bloblen
+ 3)&~3);
1835 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
1836 if (inbuf
.data
== NULL
) {
1837 status
= NT_STATUS_NO_MEMORY
;
1840 /* namelen doesn't include the NULL byte. */
1841 SCVAL(inbuf
.data
, 5, namelen
- 1);
1842 SSVAL(inbuf
.data
, 6, ea_len
);
1843 memcpy(inbuf
.data
+ 8, ea_name_ascii
, namelen
);
1844 memcpy(inbuf
.data
+ 8 + namelen
, ea_val
, ea_len
);
1846 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1847 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
1849 status
= smb2cli_set_info(cli
->conn
,
1853 1, /* in_info_type */
1854 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
1855 &inbuf
, /* in_input_buffer */
1856 0, /* in_additional_info */
1866 /***************************************************************
1867 Wrapper that allows SMB2 to set an EA on a pathname.
1869 ***************************************************************/
1871 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
1873 const char *ea_name
,
1878 uint16_t fnum
= 0xffff;
1880 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1882 * Can't use sync call while an async call is in flight
1884 status
= NT_STATUS_INVALID_PARAMETER
;
1888 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1889 status
= NT_STATUS_INVALID_PARAMETER
;
1893 status
= get_fnum_from_path(cli
,
1898 if (!NT_STATUS_IS_OK(status
)) {
1902 status
= cli_set_ea_fnum(cli
,
1907 if (!NT_STATUS_IS_OK(status
)) {
1913 if (fnum
!= 0xffff) {
1914 cli_smb2_close_fnum(cli
, fnum
);
1920 /***************************************************************
1921 Wrapper that allows SMB2 to get an EA list on a pathname.
1923 ***************************************************************/
1925 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
1929 struct ea_struct
**pea_array
)
1932 uint16_t fnum
= 0xffff;
1933 DATA_BLOB outbuf
= data_blob_null
;
1934 struct smb2_hnd
*ph
= NULL
;
1935 struct ea_list
*ea_list
= NULL
;
1936 struct ea_list
*eal
= NULL
;
1937 size_t ea_count
= 0;
1938 TALLOC_CTX
*frame
= talloc_stackframe();
1943 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1945 * Can't use sync call while an async call is in flight
1947 status
= NT_STATUS_INVALID_PARAMETER
;
1951 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1952 status
= NT_STATUS_INVALID_PARAMETER
;
1956 status
= get_fnum_from_path(cli
,
1961 if (!NT_STATUS_IS_OK(status
)) {
1965 status
= map_fnum_to_smb2_handle(cli
,
1968 if (!NT_STATUS_IS_OK(status
)) {
1972 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1973 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
1975 status
= smb2cli_query_info(cli
->conn
,
1979 1, /* in_info_type */
1980 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
1981 0xFFFF, /* in_max_output_length */
1982 NULL
, /* in_input_buffer */
1983 0, /* in_additional_info */
1990 if (!NT_STATUS_IS_OK(status
)) {
1994 /* Parse the reply. */
1995 ea_list
= read_nttrans_ea_list(ctx
,
1996 (const char *)outbuf
.data
,
1998 if (ea_list
== NULL
) {
1999 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2003 /* Convert to an array. */
2004 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2009 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
2010 if (*pea_array
== NULL
) {
2011 status
= NT_STATUS_NO_MEMORY
;
2015 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2016 (*pea_array
)[ea_count
++] = ea_list
->ea
;
2018 *pnum_eas
= ea_count
;
2023 if (fnum
!= 0xffff) {
2024 cli_smb2_close_fnum(cli
, fnum
);
2031 struct cli_smb2_read_state
{
2032 struct tevent_context
*ev
;
2033 struct cli_state
*cli
;
2034 struct smb2_hnd
*ph
;
2035 uint64_t start_offset
;
2041 static void cli_smb2_read_done(struct tevent_req
*subreq
);
2043 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
2044 struct tevent_context
*ev
,
2045 struct cli_state
*cli
,
2051 struct tevent_req
*req
, *subreq
;
2052 struct cli_smb2_read_state
*state
;
2054 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
2060 state
->start_offset
= (uint64_t)offset
;
2061 state
->size
= (uint32_t)size
;
2062 state
->received
= 0;
2065 status
= map_fnum_to_smb2_handle(cli
,
2068 if (tevent_req_nterror(req
, status
)) {
2069 return tevent_req_post(req
, ev
);
2072 subreq
= smb2cli_read_send(state
,
2075 state
->cli
->timeout
,
2076 state
->cli
->smb2
.session
,
2077 state
->cli
->smb2
.tcon
,
2079 state
->start_offset
,
2080 state
->ph
->fid_persistent
,
2081 state
->ph
->fid_volatile
,
2082 0, /* minimum_count */
2083 0); /* remaining_bytes */
2085 if (tevent_req_nomem(subreq
, req
)) {
2086 return tevent_req_post(req
, ev
);
2088 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
2092 static void cli_smb2_read_done(struct tevent_req
*subreq
)
2094 struct tevent_req
*req
= tevent_req_callback_data(
2095 subreq
, struct tevent_req
);
2096 struct cli_smb2_read_state
*state
= tevent_req_data(
2097 req
, struct cli_smb2_read_state
);
2100 status
= smb2cli_read_recv(subreq
, state
,
2101 &state
->buf
, &state
->received
);
2102 if (tevent_req_nterror(req
, status
)) {
2106 if (state
->received
> state
->size
) {
2107 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2111 tevent_req_done(req
);
2114 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
2119 struct cli_smb2_read_state
*state
= tevent_req_data(
2120 req
, struct cli_smb2_read_state
);
2122 if (tevent_req_is_nterror(req
, &status
)) {
2126 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2127 * better make sure that you copy it away before you talloc_free(req).
2128 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2130 *received
= (ssize_t
)state
->received
;
2131 *rcvbuf
= state
->buf
;
2132 return NT_STATUS_OK
;
2135 struct cli_smb2_write_state
{
2136 struct tevent_context
*ev
;
2137 struct cli_state
*cli
;
2138 struct smb2_hnd
*ph
;
2146 static void cli_smb2_write_written(struct tevent_req
*req
);
2148 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
2149 struct tevent_context
*ev
,
2150 struct cli_state
*cli
,
2158 struct tevent_req
*req
, *subreq
= NULL
;
2159 struct cli_smb2_write_state
*state
= NULL
;
2161 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
2167 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2168 state
->flags
= (uint32_t)mode
;
2170 state
->offset
= (uint64_t)offset
;
2171 state
->size
= (uint32_t)size
;
2174 status
= map_fnum_to_smb2_handle(cli
,
2177 if (tevent_req_nterror(req
, status
)) {
2178 return tevent_req_post(req
, ev
);
2181 subreq
= smb2cli_write_send(state
,
2184 state
->cli
->timeout
,
2185 state
->cli
->smb2
.session
,
2186 state
->cli
->smb2
.tcon
,
2189 state
->ph
->fid_persistent
,
2190 state
->ph
->fid_volatile
,
2191 0, /* remaining_bytes */
2192 state
->flags
, /* flags */
2195 if (tevent_req_nomem(subreq
, req
)) {
2196 return tevent_req_post(req
, ev
);
2198 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
2202 static void cli_smb2_write_written(struct tevent_req
*subreq
)
2204 struct tevent_req
*req
= tevent_req_callback_data(
2205 subreq
, struct tevent_req
);
2206 struct cli_smb2_write_state
*state
= tevent_req_data(
2207 req
, struct cli_smb2_write_state
);
2211 status
= smb2cli_write_recv(subreq
, &written
);
2212 TALLOC_FREE(subreq
);
2213 if (tevent_req_nterror(req
, status
)) {
2217 state
->written
= written
;
2219 tevent_req_done(req
);
2222 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
2225 struct cli_smb2_write_state
*state
= tevent_req_data(
2226 req
, struct cli_smb2_write_state
);
2229 if (tevent_req_is_nterror(req
, &status
)) {
2230 tevent_req_received(req
);
2234 if (pwritten
!= NULL
) {
2235 *pwritten
= (size_t)state
->written
;
2237 tevent_req_received(req
);
2238 return NT_STATUS_OK
;
2241 /***************************************************************
2242 Wrapper that allows SMB2 async write using an fnum.
2243 This is mostly cut-and-paste from Volker's code inside
2244 source3/libsmb/clireadwrite.c, adapted for SMB2.
2246 Done this way so I can reuse all the logic inside cli_push()
2248 ***************************************************************/
2250 struct cli_smb2_writeall_state
{
2251 struct tevent_context
*ev
;
2252 struct cli_state
*cli
;
2253 struct smb2_hnd
*ph
;
2261 static void cli_smb2_writeall_written(struct tevent_req
*req
);
2263 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
2264 struct tevent_context
*ev
,
2265 struct cli_state
*cli
,
2273 struct tevent_req
*req
, *subreq
= NULL
;
2274 struct cli_smb2_writeall_state
*state
= NULL
;
2279 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
2285 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2286 state
->flags
= (uint32_t)mode
;
2288 state
->offset
= (uint64_t)offset
;
2289 state
->size
= (uint32_t)size
;
2292 status
= map_fnum_to_smb2_handle(cli
,
2295 if (tevent_req_nterror(req
, status
)) {
2296 return tevent_req_post(req
, ev
);
2299 to_write
= state
->size
;
2300 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
2301 to_write
= MIN(max_size
, to_write
);
2302 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
2304 to_write
= MIN(max_size
, to_write
);
2307 subreq
= smb2cli_write_send(state
,
2310 state
->cli
->timeout
,
2311 state
->cli
->smb2
.session
,
2312 state
->cli
->smb2
.tcon
,
2315 state
->ph
->fid_persistent
,
2316 state
->ph
->fid_volatile
,
2317 0, /* remaining_bytes */
2318 state
->flags
, /* flags */
2319 state
->buf
+ state
->written
);
2321 if (tevent_req_nomem(subreq
, req
)) {
2322 return tevent_req_post(req
, ev
);
2324 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
2328 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
2330 struct tevent_req
*req
= tevent_req_callback_data(
2331 subreq
, struct tevent_req
);
2332 struct cli_smb2_writeall_state
*state
= tevent_req_data(
2333 req
, struct cli_smb2_writeall_state
);
2335 uint32_t written
, to_write
;
2339 status
= smb2cli_write_recv(subreq
, &written
);
2340 TALLOC_FREE(subreq
);
2341 if (tevent_req_nterror(req
, status
)) {
2345 state
->written
+= written
;
2347 if (state
->written
> state
->size
) {
2348 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2352 to_write
= state
->size
- state
->written
;
2354 if (to_write
== 0) {
2355 tevent_req_done(req
);
2359 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
2360 to_write
= MIN(max_size
, to_write
);
2361 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
2363 to_write
= MIN(max_size
, to_write
);
2366 subreq
= smb2cli_write_send(state
,
2369 state
->cli
->timeout
,
2370 state
->cli
->smb2
.session
,
2371 state
->cli
->smb2
.tcon
,
2373 state
->offset
+ state
->written
,
2374 state
->ph
->fid_persistent
,
2375 state
->ph
->fid_volatile
,
2376 0, /* remaining_bytes */
2377 state
->flags
, /* flags */
2378 state
->buf
+ state
->written
);
2380 if (tevent_req_nomem(subreq
, req
)) {
2383 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
2386 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
2389 struct cli_smb2_writeall_state
*state
= tevent_req_data(
2390 req
, struct cli_smb2_writeall_state
);
2393 if (tevent_req_is_nterror(req
, &status
)) {
2396 if (pwritten
!= NULL
) {
2397 *pwritten
= (size_t)state
->written
;
2399 return NT_STATUS_OK
;