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.
154 ***************************************************************/
156 struct cli_smb2_create_fnum_state
{
157 struct cli_state
*cli
;
158 struct smb_create_returns cr
;
162 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
);
164 struct tevent_req
*cli_smb2_create_fnum_send(TALLOC_CTX
*mem_ctx
,
165 struct tevent_context
*ev
,
166 struct cli_state
*cli
,
168 uint32_t create_flags
,
169 uint32_t desired_access
,
170 uint32_t file_attributes
,
171 uint32_t share_access
,
172 uint32_t create_disposition
,
173 uint32_t create_options
)
175 struct tevent_req
*req
, *subreq
;
176 struct cli_smb2_create_fnum_state
*state
;
178 req
= tevent_req_create(mem_ctx
, &state
,
179 struct cli_smb2_create_fnum_state
);
185 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
186 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
187 return tevent_req_post(req
, ev
);
190 if (cli
->backup_intent
) {
191 create_options
|= FILE_OPEN_FOR_BACKUP_INTENT
;
194 /* SMB2 is pickier about pathnames. Ensure it doesn't
196 if (*fname
== '\\') {
200 subreq
= smb2cli_create_send(state
, ev
,
206 flags_to_smb2_oplock(create_flags
),
207 SMB2_IMPERSONATION_IMPERSONATION
,
214 if (tevent_req_nomem(subreq
, req
)) {
215 return tevent_req_post(req
, ev
);
217 tevent_req_set_callback(subreq
, cli_smb2_create_fnum_done
, req
);
221 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
)
223 struct tevent_req
*req
= tevent_req_callback_data(
224 subreq
, struct tevent_req
);
225 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
226 req
, struct cli_smb2_create_fnum_state
);
230 status
= smb2cli_create_recv(subreq
, &h
.fid_persistent
,
231 &h
.fid_volatile
, &state
->cr
);
233 if (tevent_req_nterror(req
, status
)) {
237 status
= map_smb2_handle_to_fnum(state
->cli
, &h
, &state
->fnum
);
238 if (tevent_req_nterror(req
, status
)) {
241 tevent_req_done(req
);
244 NTSTATUS
cli_smb2_create_fnum_recv(struct tevent_req
*req
, uint16_t *pfnum
,
245 struct smb_create_returns
*cr
)
247 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
248 req
, struct cli_smb2_create_fnum_state
);
251 if (tevent_req_is_nterror(req
, &status
)) {
255 *pfnum
= state
->fnum
;
263 NTSTATUS
cli_smb2_create_fnum(struct cli_state
*cli
,
265 uint32_t create_flags
,
266 uint32_t desired_access
,
267 uint32_t file_attributes
,
268 uint32_t share_access
,
269 uint32_t create_disposition
,
270 uint32_t create_options
,
272 struct smb_create_returns
*cr
)
274 TALLOC_CTX
*frame
= talloc_stackframe();
275 struct tevent_context
*ev
;
276 struct tevent_req
*req
;
277 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
279 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
281 * Can't use sync call while an async call is in flight
283 status
= NT_STATUS_INVALID_PARAMETER
;
286 ev
= samba_tevent_context_init(frame
);
290 req
= cli_smb2_create_fnum_send(frame
, ev
, cli
, fname
, create_flags
,
291 desired_access
, file_attributes
,
292 share_access
, create_disposition
,
297 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
300 status
= cli_smb2_create_fnum_recv(req
, pfid
, cr
);
306 /***************************************************************
307 Small wrapper that allows SMB2 close to use a uint16_t fnum.
309 ***************************************************************/
311 NTSTATUS
cli_smb2_close_fnum(struct cli_state
*cli
, uint16_t fnum
)
313 struct smb2_hnd
*ph
= NULL
;
316 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
318 * Can't use sync call while an async call is in flight
320 return NT_STATUS_INVALID_PARAMETER
;
323 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
324 return NT_STATUS_INVALID_PARAMETER
;
327 status
= map_fnum_to_smb2_handle(cli
,
330 if (!NT_STATUS_IS_OK(status
)) {
334 status
= smb2cli_close(cli
->conn
,
342 /* Delete the fnum -> handle mapping. */
343 if (NT_STATUS_IS_OK(status
)) {
344 status
= delete_smb2_handle_mapping(cli
, &ph
, fnum
);
350 /***************************************************************
351 Small wrapper that allows SMB2 to create a directory
353 ***************************************************************/
355 NTSTATUS
cli_smb2_mkdir(struct cli_state
*cli
, const char *dname
)
360 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
362 * Can't use sync call while an async call is in flight
364 return NT_STATUS_INVALID_PARAMETER
;
367 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
368 return NT_STATUS_INVALID_PARAMETER
;
371 status
= cli_smb2_create_fnum(cli
,
373 0, /* create_flags */
374 FILE_READ_ATTRIBUTES
, /* desired_access */
375 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
376 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
377 FILE_CREATE
, /* create_disposition */
378 FILE_DIRECTORY_FILE
, /* create_options */
382 if (!NT_STATUS_IS_OK(status
)) {
385 return cli_smb2_close_fnum(cli
, fnum
);
388 /***************************************************************
389 Small wrapper that allows SMB2 to delete a directory
391 ***************************************************************/
393 NTSTATUS
cli_smb2_rmdir(struct cli_state
*cli
, const char *dname
)
398 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
400 * Can't use sync call while an async call is in flight
402 return NT_STATUS_INVALID_PARAMETER
;
405 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
406 return NT_STATUS_INVALID_PARAMETER
;
409 status
= cli_smb2_create_fnum(cli
,
411 0, /* create_flags */
412 DELETE_ACCESS
, /* desired_access */
413 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
414 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
415 FILE_OPEN
, /* create_disposition */
416 FILE_DIRECTORY_FILE
|FILE_DELETE_ON_CLOSE
, /* create_options */
420 if (!NT_STATUS_IS_OK(status
)) {
423 return cli_smb2_close_fnum(cli
, fnum
);
426 /***************************************************************
427 Small wrapper that allows SMB2 to unlink a pathname.
429 ***************************************************************/
431 NTSTATUS
cli_smb2_unlink(struct cli_state
*cli
, const char *fname
)
436 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
438 * Can't use sync call while an async call is in flight
440 return NT_STATUS_INVALID_PARAMETER
;
443 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
444 return NT_STATUS_INVALID_PARAMETER
;
447 status
= cli_smb2_create_fnum(cli
,
449 0, /* create_flags */
450 DELETE_ACCESS
, /* desired_access */
451 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
452 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
453 FILE_OPEN
, /* create_disposition */
454 FILE_DELETE_ON_CLOSE
, /* create_options */
458 if (!NT_STATUS_IS_OK(status
)) {
461 return cli_smb2_close_fnum(cli
, fnum
);
464 /***************************************************************
465 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
466 ***************************************************************/
468 static NTSTATUS
parse_finfo_id_both_directory_info(uint8_t *dir_data
,
469 uint32_t dir_data_length
,
470 struct file_info
*finfo
,
471 uint32_t *next_offset
)
477 if (dir_data_length
< 4) {
478 return NT_STATUS_INFO_LENGTH_MISMATCH
;
481 *next_offset
= IVAL(dir_data
, 0);
483 if (*next_offset
> dir_data_length
) {
484 return NT_STATUS_INFO_LENGTH_MISMATCH
;
487 if (*next_offset
!= 0) {
488 /* Ensure we only read what in this record. */
489 dir_data_length
= *next_offset
;
492 if (dir_data_length
< 105) {
493 return NT_STATUS_INFO_LENGTH_MISMATCH
;
496 finfo
->atime_ts
= interpret_long_date((const char *)dir_data
+ 16);
497 finfo
->mtime_ts
= interpret_long_date((const char *)dir_data
+ 24);
498 finfo
->ctime_ts
= interpret_long_date((const char *)dir_data
+ 32);
499 finfo
->size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 40, 0);
500 finfo
->mode
= CVAL(dir_data
+ 56, 0);
501 namelen
= IVAL(dir_data
+ 60,0);
502 if (namelen
> (dir_data_length
- 104)) {
503 return NT_STATUS_INFO_LENGTH_MISMATCH
;
505 slen
= CVAL(dir_data
+ 68, 0);
507 return NT_STATUS_INFO_LENGTH_MISMATCH
;
509 ret
= pull_string_talloc(finfo
,
511 FLAGS2_UNICODE_STRINGS
,
516 if (ret
== (size_t)-1) {
517 /* Bad conversion. */
518 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
521 ret
= pull_string_talloc(finfo
,
523 FLAGS2_UNICODE_STRINGS
,
528 if (ret
== (size_t)-1) {
529 /* Bad conversion. */
530 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
535 /*******************************************************************
536 Given a filename - get its directory name
537 ********************************************************************/
539 static bool windows_parent_dirname(TALLOC_CTX
*mem_ctx
,
547 p
= strrchr_m(dir
, '\\'); /* Find final '\\', if any */
550 if (!(*parent
= talloc_strdup(mem_ctx
, "\\"))) {
561 if (!(*parent
= (char *)talloc_memdup(mem_ctx
, dir
, len
+1))) {
564 (*parent
)[len
] = '\0';
572 /***************************************************************
573 Wrapper that allows SMB2 to list a directory.
575 ***************************************************************/
577 NTSTATUS
cli_smb2_list(struct cli_state
*cli
,
578 const char *pathname
,
580 NTSTATUS (*fn
)(const char *,
587 uint16_t fnum
= 0xffff;
588 char *parent_dir
= NULL
;
589 const char *mask
= NULL
;
590 struct smb2_hnd
*ph
= NULL
;
591 bool processed_file
= false;
592 TALLOC_CTX
*frame
= talloc_stackframe();
593 TALLOC_CTX
*subframe
= NULL
;
595 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
597 * Can't use sync call while an async call is in flight
599 status
= NT_STATUS_INVALID_PARAMETER
;
603 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
604 status
= NT_STATUS_INVALID_PARAMETER
;
608 /* Get the directory name. */
609 if (!windows_parent_dirname(frame
,
613 status
= NT_STATUS_NO_MEMORY
;
617 status
= cli_smb2_create_fnum(cli
,
619 0, /* create_flags */
620 SEC_DIR_LIST
|SEC_DIR_READ_ATTRIBUTE
,/* desired_access */
621 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
622 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
623 FILE_OPEN
, /* create_disposition */
624 FILE_DIRECTORY_FILE
, /* create_options */
628 if (!NT_STATUS_IS_OK(status
)) {
632 status
= map_fnum_to_smb2_handle(cli
,
635 if (!NT_STATUS_IS_OK(status
)) {
640 uint8_t *dir_data
= NULL
;
641 uint32_t dir_data_length
= 0;
642 uint32_t next_offset
= 0;
643 subframe
= talloc_stackframe();
645 status
= smb2cli_query_directory(cli
->conn
,
649 SMB2_FIND_ID_BOTH_DIRECTORY_INFO
,
660 if (!NT_STATUS_IS_OK(status
)) {
661 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
668 struct file_info
*finfo
= talloc_zero(subframe
,
672 status
= NT_STATUS_NO_MEMORY
;
676 status
= parse_finfo_id_both_directory_info(dir_data
,
681 if (!NT_STATUS_IS_OK(status
)) {
685 if (dir_check_ftype((uint32_t)finfo
->mode
,
686 (uint32_t)attribute
)) {
688 * Only process if attributes match.
689 * On SMB1 server does this, so on
690 * SMB2 we need to emulate in the
693 * https://bugzilla.samba.org/show_bug.cgi?id=10260
695 processed_file
= true;
697 status
= fn(cli
->dfs_mountpoint
,
702 if (!NT_STATUS_IS_OK(status
)) {
709 /* Move to next entry. */
711 dir_data
+= next_offset
;
712 dir_data_length
-= next_offset
;
714 } while (next_offset
!= 0);
716 TALLOC_FREE(subframe
);
718 } while (NT_STATUS_IS_OK(status
));
720 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
721 status
= NT_STATUS_OK
;
724 if (NT_STATUS_IS_OK(status
) && !processed_file
) {
726 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
727 * if no files match. Emulate this in the client.
729 status
= NT_STATUS_NO_SUCH_FILE
;
734 if (fnum
!= 0xffff) {
735 cli_smb2_close_fnum(cli
, fnum
);
737 TALLOC_FREE(subframe
);
742 /***************************************************************
743 Wrapper that allows SMB2 to query a path info (basic level).
745 ***************************************************************/
747 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
749 SMB_STRUCT_STAT
*sbuf
,
750 uint32_t *attributes
)
753 struct smb_create_returns cr
;
754 uint16_t fnum
= 0xffff;
755 size_t namelen
= strlen(name
);
757 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
759 * Can't use sync call while an async call is in flight
761 return NT_STATUS_INVALID_PARAMETER
;
764 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
765 return NT_STATUS_INVALID_PARAMETER
;
768 /* SMB2 is pickier about pathnames. Ensure it doesn't
770 if (namelen
> 0 && name
[namelen
-1] == '\\') {
771 char *modname
= talloc_strdup(talloc_tos(), name
);
772 modname
[namelen
-1] = '\0';
776 /* This is commonly used as a 'cd'. Try qpathinfo on
777 a directory handle first. */
779 status
= cli_smb2_create_fnum(cli
,
781 0, /* create_flags */
782 FILE_READ_ATTRIBUTES
, /* desired_access */
783 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
784 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
785 FILE_OPEN
, /* create_disposition */
786 FILE_DIRECTORY_FILE
, /* create_options */
790 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
792 status
= cli_smb2_create_fnum(cli
,
794 0, /* create_flags */
795 FILE_READ_ATTRIBUTES
, /* desired_access */
796 0, /* file attributes */
797 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
798 FILE_OPEN
, /* create_disposition */
799 0, /* create_options */
804 if (!NT_STATUS_IS_OK(status
)) {
808 cli_smb2_close_fnum(cli
, fnum
);
812 sbuf
->st_ex_atime
= nt_time_to_unix_timespec(&cr
.last_access_time
);
813 sbuf
->st_ex_mtime
= nt_time_to_unix_timespec(&cr
.last_write_time
);
814 sbuf
->st_ex_ctime
= nt_time_to_unix_timespec(&cr
.change_time
);
815 sbuf
->st_ex_size
= cr
.end_of_file
;
816 *attributes
= cr
.file_attributes
;
821 /***************************************************************
822 Helper function for pathname operations.
823 ***************************************************************/
825 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
827 uint32_t desired_access
,
831 size_t namelen
= strlen(name
);
832 TALLOC_CTX
*frame
= talloc_stackframe();
834 /* SMB2 is pickier about pathnames. Ensure it doesn't
836 if (namelen
> 0 && name
[namelen
-1] == '\\') {
837 char *modname
= talloc_strdup(frame
, name
);
838 if (modname
== NULL
) {
839 status
= NT_STATUS_NO_MEMORY
;
842 modname
[namelen
-1] = '\0';
846 /* Try to open a file handle first. */
847 status
= cli_smb2_create_fnum(cli
,
849 0, /* create_flags */
851 0, /* file attributes */
852 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
853 FILE_OPEN
, /* create_disposition */
854 0, /* create_options */
858 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
859 status
= cli_smb2_create_fnum(cli
,
861 0, /* create_flags */
863 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
864 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
865 FILE_OPEN
, /* create_disposition */
866 FILE_DIRECTORY_FILE
, /* create_options */
877 /***************************************************************
878 Wrapper that allows SMB2 to query a path info (ALTNAME level).
880 ***************************************************************/
882 NTSTATUS
cli_smb2_qpathinfo_alt_name(struct cli_state
*cli
,
887 DATA_BLOB outbuf
= data_blob_null
;
888 uint16_t fnum
= 0xffff;
889 struct smb2_hnd
*ph
= NULL
;
890 uint32_t altnamelen
= 0;
891 TALLOC_CTX
*frame
= talloc_stackframe();
893 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
895 * Can't use sync call while an async call is in flight
897 status
= NT_STATUS_INVALID_PARAMETER
;
901 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
902 status
= NT_STATUS_INVALID_PARAMETER
;
906 status
= get_fnum_from_path(cli
,
908 FILE_READ_ATTRIBUTES
,
911 if (!NT_STATUS_IS_OK(status
)) {
915 status
= map_fnum_to_smb2_handle(cli
,
918 if (!NT_STATUS_IS_OK(status
)) {
922 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
923 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
925 status
= smb2cli_query_info(cli
->conn
,
929 1, /* in_info_type */
930 (SMB_FILE_ALTERNATE_NAME_INFORMATION
- 1000), /* in_file_info_class */
931 0xFFFF, /* in_max_output_length */
932 NULL
, /* in_input_buffer */
933 0, /* in_additional_info */
940 if (!NT_STATUS_IS_OK(status
)) {
944 /* Parse the reply. */
945 if (outbuf
.length
< 4) {
946 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
950 altnamelen
= IVAL(outbuf
.data
, 0);
951 if (altnamelen
> outbuf
.length
- 4) {
952 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
956 if (altnamelen
> 0) {
958 char *short_name
= NULL
;
959 ret
= pull_string_talloc(frame
,
961 FLAGS2_UNICODE_STRINGS
,
966 if (ret
== (size_t)-1) {
967 /* Bad conversion. */
968 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
972 fstrcpy(alt_name
, short_name
);
977 status
= NT_STATUS_OK
;
981 if (fnum
!= 0xffff) {
982 cli_smb2_close_fnum(cli
, fnum
);
989 /***************************************************************
990 Wrapper that allows SMB2 to query a fnum info (basic level).
992 ***************************************************************/
994 NTSTATUS
cli_smb2_qfileinfo_basic(struct cli_state
*cli
,
998 struct timespec
*create_time
,
999 struct timespec
*access_time
,
1000 struct timespec
*write_time
,
1001 struct timespec
*change_time
,
1005 DATA_BLOB outbuf
= data_blob_null
;
1006 struct smb2_hnd
*ph
= NULL
;
1007 TALLOC_CTX
*frame
= talloc_stackframe();
1009 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1011 * Can't use sync call while an async call is in flight
1013 status
= NT_STATUS_INVALID_PARAMETER
;
1017 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1018 status
= NT_STATUS_INVALID_PARAMETER
;
1022 status
= map_fnum_to_smb2_handle(cli
,
1025 if (!NT_STATUS_IS_OK(status
)) {
1029 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1030 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1032 status
= smb2cli_query_info(cli
->conn
,
1036 1, /* in_info_type */
1037 (SMB_FILE_ALL_INFORMATION
- 1000), /* in_file_info_class */
1038 0xFFFF, /* in_max_output_length */
1039 NULL
, /* in_input_buffer */
1040 0, /* in_additional_info */
1046 if (!NT_STATUS_IS_OK(status
)) {
1050 /* Parse the reply. */
1051 if (outbuf
.length
< 0x60) {
1052 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1057 *create_time
= interpret_long_date((const char *)outbuf
.data
+ 0x0);
1060 *access_time
= interpret_long_date((const char *)outbuf
.data
+ 0x8);
1063 *write_time
= interpret_long_date((const char *)outbuf
.data
+ 0x10);
1066 *change_time
= interpret_long_date((const char *)outbuf
.data
+ 0x18);
1069 uint32_t attr
= IVAL(outbuf
.data
, 0x20);
1070 *mode
= (uint16_t)attr
;
1073 uint64_t file_size
= BVAL(outbuf
.data
, 0x30);
1074 *size
= (off_t
)file_size
;
1077 uint64_t file_index
= BVAL(outbuf
.data
, 0x40);
1078 *ino
= (SMB_INO_T
)file_index
;
1087 /***************************************************************
1088 Wrapper that allows SMB2 to query an fnum.
1089 Implement on top of cli_smb2_qfileinfo_basic().
1091 ***************************************************************/
1093 NTSTATUS
cli_smb2_getattrE(struct cli_state
*cli
,
1097 time_t *change_time
,
1098 time_t *access_time
,
1101 struct timespec access_time_ts
;
1102 struct timespec write_time_ts
;
1103 struct timespec change_time_ts
;
1104 NTSTATUS status
= cli_smb2_qfileinfo_basic(cli
,
1114 if (!NT_STATUS_IS_OK(status
)) {
1119 *change_time
= change_time_ts
.tv_sec
;
1122 *access_time
= access_time_ts
.tv_sec
;
1125 *write_time
= write_time_ts
.tv_sec
;
1127 return NT_STATUS_OK
;
1130 /***************************************************************
1131 Wrapper that allows SMB2 to get pathname attributes.
1133 ***************************************************************/
1135 NTSTATUS
cli_smb2_getatr(struct cli_state
*cli
,
1142 uint16_t fnum
= 0xffff;
1143 struct smb2_hnd
*ph
= NULL
;
1144 TALLOC_CTX
*frame
= talloc_stackframe();
1146 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1148 * Can't use sync call while an async call is in flight
1150 status
= NT_STATUS_INVALID_PARAMETER
;
1154 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1155 status
= NT_STATUS_INVALID_PARAMETER
;
1159 status
= get_fnum_from_path(cli
,
1161 FILE_READ_ATTRIBUTES
,
1164 if (!NT_STATUS_IS_OK(status
)) {
1168 status
= map_fnum_to_smb2_handle(cli
,
1171 if (!NT_STATUS_IS_OK(status
)) {
1174 status
= cli_smb2_getattrE(cli
,
1181 if (!NT_STATUS_IS_OK(status
)) {
1187 if (fnum
!= 0xffff) {
1188 cli_smb2_close_fnum(cli
, fnum
);
1195 /***************************************************************
1196 Wrapper that allows SMB2 to query a pathname info (basic level).
1197 Implement on top of cli_smb2_qfileinfo_basic().
1199 ***************************************************************/
1201 NTSTATUS
cli_smb2_qpathinfo2(struct cli_state
*cli
,
1203 struct timespec
*create_time
,
1204 struct timespec
*access_time
,
1205 struct timespec
*write_time
,
1206 struct timespec
*change_time
,
1212 struct smb2_hnd
*ph
= NULL
;
1213 uint16_t fnum
= 0xffff;
1214 TALLOC_CTX
*frame
= talloc_stackframe();
1216 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1218 * Can't use sync call while an async call is in flight
1220 status
= NT_STATUS_INVALID_PARAMETER
;
1224 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1225 status
= NT_STATUS_INVALID_PARAMETER
;
1229 status
= get_fnum_from_path(cli
,
1231 FILE_READ_ATTRIBUTES
,
1234 if (!NT_STATUS_IS_OK(status
)) {
1238 status
= map_fnum_to_smb2_handle(cli
,
1241 if (!NT_STATUS_IS_OK(status
)) {
1245 status
= cli_smb2_qfileinfo_basic(cli
,
1257 if (fnum
!= 0xffff) {
1258 cli_smb2_close_fnum(cli
, fnum
);
1265 /***************************************************************
1266 Wrapper that allows SMB2 to query pathname streams.
1268 ***************************************************************/
1270 NTSTATUS
cli_smb2_qpathinfo_streams(struct cli_state
*cli
,
1272 TALLOC_CTX
*mem_ctx
,
1273 unsigned int *pnum_streams
,
1274 struct stream_struct
**pstreams
)
1277 struct smb2_hnd
*ph
= NULL
;
1278 uint16_t fnum
= 0xffff;
1279 DATA_BLOB outbuf
= data_blob_null
;
1280 TALLOC_CTX
*frame
= talloc_stackframe();
1282 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1284 * Can't use sync call while an async call is in flight
1286 status
= NT_STATUS_INVALID_PARAMETER
;
1290 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1291 status
= NT_STATUS_INVALID_PARAMETER
;
1295 status
= get_fnum_from_path(cli
,
1297 FILE_READ_ATTRIBUTES
,
1300 if (!NT_STATUS_IS_OK(status
)) {
1304 status
= map_fnum_to_smb2_handle(cli
,
1307 if (!NT_STATUS_IS_OK(status
)) {
1311 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1312 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1314 status
= smb2cli_query_info(cli
->conn
,
1318 1, /* in_info_type */
1319 (SMB_FILE_STREAM_INFORMATION
- 1000), /* in_file_info_class */
1320 0xFFFF, /* in_max_output_length */
1321 NULL
, /* in_input_buffer */
1322 0, /* in_additional_info */
1329 if (!NT_STATUS_IS_OK(status
)) {
1333 /* Parse the reply. */
1334 if (!parse_streams_blob(mem_ctx
,
1339 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1345 if (fnum
!= 0xffff) {
1346 cli_smb2_close_fnum(cli
, fnum
);
1353 /***************************************************************
1354 Wrapper that allows SMB2 to set pathname attributes.
1356 ***************************************************************/
1358 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
1364 uint16_t fnum
= 0xffff;
1365 struct smb2_hnd
*ph
= NULL
;
1366 uint8_t inbuf_store
[40];
1367 DATA_BLOB inbuf
= data_blob_null
;
1368 TALLOC_CTX
*frame
= talloc_stackframe();
1370 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1372 * Can't use sync call while an async call is in flight
1374 status
= NT_STATUS_INVALID_PARAMETER
;
1378 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1379 status
= NT_STATUS_INVALID_PARAMETER
;
1383 status
= get_fnum_from_path(cli
,
1385 FILE_WRITE_ATTRIBUTES
,
1388 if (!NT_STATUS_IS_OK(status
)) {
1392 status
= map_fnum_to_smb2_handle(cli
,
1395 if (!NT_STATUS_IS_OK(status
)) {
1399 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1400 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1402 inbuf
.data
= inbuf_store
;
1403 inbuf
.length
= sizeof(inbuf_store
);
1404 data_blob_clear(&inbuf
);
1406 SSVAL(inbuf
.data
, 32, attr
);
1408 put_long_date((char *)inbuf
.data
+ 16,mtime
);
1410 /* Set all the other times to -1. */
1411 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1412 SBVAL(inbuf
.data
, 8, 0xFFFFFFFFFFFFFFFFLL
);
1413 SBVAL(inbuf
.data
, 24, 0xFFFFFFFFFFFFFFFFLL
);
1415 status
= smb2cli_set_info(cli
->conn
,
1419 1, /* in_info_type */
1420 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1421 &inbuf
, /* in_input_buffer */
1422 0, /* in_additional_info */
1427 if (fnum
!= 0xffff) {
1428 cli_smb2_close_fnum(cli
, fnum
);
1435 /***************************************************************
1436 Wrapper that allows SMB2 to set file handle times.
1438 ***************************************************************/
1440 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
1447 struct smb2_hnd
*ph
= NULL
;
1448 uint8_t inbuf_store
[40];
1449 DATA_BLOB inbuf
= data_blob_null
;
1451 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1453 * Can't use sync call while an async call is in flight
1455 return NT_STATUS_INVALID_PARAMETER
;
1458 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1459 return NT_STATUS_INVALID_PARAMETER
;
1462 status
= map_fnum_to_smb2_handle(cli
,
1465 if (!NT_STATUS_IS_OK(status
)) {
1469 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1470 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1472 inbuf
.data
= inbuf_store
;
1473 inbuf
.length
= sizeof(inbuf_store
);
1474 data_blob_clear(&inbuf
);
1476 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1477 if (change_time
!= 0) {
1478 put_long_date((char *)inbuf
.data
+ 24, change_time
);
1480 if (access_time
!= 0) {
1481 put_long_date((char *)inbuf
.data
+ 8, access_time
);
1483 if (write_time
!= 0) {
1484 put_long_date((char *)inbuf
.data
+ 16, write_time
);
1487 return smb2cli_set_info(cli
->conn
,
1491 1, /* in_info_type */
1492 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1493 &inbuf
, /* in_input_buffer */
1494 0, /* in_additional_info */
1499 /***************************************************************
1500 Wrapper that allows SMB2 to query disk attributes (size).
1502 ***************************************************************/
1504 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, uint64_t *bsize
, uint64_t *total
, uint64_t *avail
)
1507 uint16_t fnum
= 0xffff;
1508 DATA_BLOB outbuf
= data_blob_null
;
1509 struct smb2_hnd
*ph
= NULL
;
1510 uint32_t sectors_per_unit
= 0;
1511 uint32_t bytes_per_sector
= 0;
1512 uint64_t total_size
= 0;
1513 uint64_t size_free
= 0;
1514 TALLOC_CTX
*frame
= talloc_stackframe();
1516 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1518 * Can't use sync call while an async call is in flight
1520 status
= NT_STATUS_INVALID_PARAMETER
;
1524 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1525 status
= NT_STATUS_INVALID_PARAMETER
;
1529 /* First open the top level directory. */
1530 status
= cli_smb2_create_fnum(cli
,
1532 0, /* create_flags */
1533 FILE_READ_ATTRIBUTES
, /* desired_access */
1534 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1535 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1536 FILE_OPEN
, /* create_disposition */
1537 FILE_DIRECTORY_FILE
, /* create_options */
1541 if (!NT_STATUS_IS_OK(status
)) {
1545 status
= map_fnum_to_smb2_handle(cli
,
1548 if (!NT_STATUS_IS_OK(status
)) {
1552 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1553 level 3 (SMB_FS_SIZE_INFORMATION). */
1555 status
= smb2cli_query_info(cli
->conn
,
1559 2, /* in_info_type */
1560 3, /* in_file_info_class */
1561 0xFFFF, /* in_max_output_length */
1562 NULL
, /* in_input_buffer */
1563 0, /* in_additional_info */
1569 if (!NT_STATUS_IS_OK(status
)) {
1573 /* Parse the reply. */
1574 if (outbuf
.length
!= 24) {
1575 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1579 total_size
= BVAL(outbuf
.data
, 0);
1580 size_free
= BVAL(outbuf
.data
, 8);
1581 sectors_per_unit
= IVAL(outbuf
.data
, 16);
1582 bytes_per_sector
= IVAL(outbuf
.data
, 20);
1585 *bsize
= (uint64_t)sectors_per_unit
* (uint64_t)bytes_per_sector
;
1588 *total
= total_size
;
1594 status
= NT_STATUS_OK
;
1598 if (fnum
!= 0xffff) {
1599 cli_smb2_close_fnum(cli
, fnum
);
1606 /***************************************************************
1607 Wrapper that allows SMB2 to query a security descriptor.
1609 ***************************************************************/
1611 NTSTATUS
cli_smb2_query_security_descriptor(struct cli_state
*cli
,
1614 TALLOC_CTX
*mem_ctx
,
1615 struct security_descriptor
**ppsd
)
1618 DATA_BLOB outbuf
= data_blob_null
;
1619 struct smb2_hnd
*ph
= NULL
;
1620 struct security_descriptor
*lsd
= NULL
;
1621 TALLOC_CTX
*frame
= talloc_stackframe();
1623 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1625 * Can't use sync call while an async call is in flight
1627 status
= NT_STATUS_INVALID_PARAMETER
;
1631 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1632 status
= NT_STATUS_INVALID_PARAMETER
;
1636 status
= map_fnum_to_smb2_handle(cli
,
1639 if (!NT_STATUS_IS_OK(status
)) {
1643 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1645 status
= smb2cli_query_info(cli
->conn
,
1649 3, /* in_info_type */
1650 0, /* in_file_info_class */
1651 0xFFFF, /* in_max_output_length */
1652 NULL
, /* in_input_buffer */
1653 sec_info
, /* in_additional_info */
1660 if (!NT_STATUS_IS_OK(status
)) {
1664 /* Parse the reply. */
1665 status
= unmarshall_sec_desc(mem_ctx
,
1670 if (!NT_STATUS_IS_OK(status
)) {
1686 /***************************************************************
1687 Wrapper that allows SMB2 to set a security descriptor.
1689 ***************************************************************/
1691 NTSTATUS
cli_smb2_set_security_descriptor(struct cli_state
*cli
,
1694 const struct security_descriptor
*sd
)
1697 DATA_BLOB inbuf
= data_blob_null
;
1698 struct smb2_hnd
*ph
= NULL
;
1699 TALLOC_CTX
*frame
= talloc_stackframe();
1701 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1703 * Can't use sync call while an async call is in flight
1705 status
= NT_STATUS_INVALID_PARAMETER
;
1709 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1710 status
= NT_STATUS_INVALID_PARAMETER
;
1714 status
= map_fnum_to_smb2_handle(cli
,
1717 if (!NT_STATUS_IS_OK(status
)) {
1721 status
= marshall_sec_desc(frame
,
1726 if (!NT_STATUS_IS_OK(status
)) {
1730 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1732 status
= smb2cli_set_info(cli
->conn
,
1736 3, /* in_info_type */
1737 0, /* in_file_info_class */
1738 &inbuf
, /* in_input_buffer */
1739 sec_info
, /* in_additional_info */
1749 /***************************************************************
1750 Wrapper that allows SMB2 to rename a file.
1752 ***************************************************************/
1754 NTSTATUS
cli_smb2_rename(struct cli_state
*cli
,
1755 const char *fname_src
,
1756 const char *fname_dst
)
1759 DATA_BLOB inbuf
= data_blob_null
;
1760 uint16_t fnum
= 0xffff;
1761 struct smb2_hnd
*ph
= NULL
;
1762 smb_ucs2_t
*converted_str
= NULL
;
1763 size_t converted_size_bytes
= 0;
1765 TALLOC_CTX
*frame
= talloc_stackframe();
1767 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1769 * Can't use sync call while an async call is in flight
1771 status
= NT_STATUS_INVALID_PARAMETER
;
1775 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1776 status
= NT_STATUS_INVALID_PARAMETER
;
1780 status
= get_fnum_from_path(cli
,
1785 if (!NT_STATUS_IS_OK(status
)) {
1789 status
= map_fnum_to_smb2_handle(cli
,
1792 if (!NT_STATUS_IS_OK(status
)) {
1796 /* SMB2 is pickier about pathnames. Ensure it doesn't
1798 if (*fname_dst
== '\\') {
1802 /* SMB2 is pickier about pathnames. Ensure it doesn't
1804 namelen
= strlen(fname_dst
);
1805 if (namelen
> 0 && fname_dst
[namelen
-1] == '\\') {
1806 char *modname
= talloc_strdup(frame
, fname_dst
);
1807 modname
[namelen
-1] = '\0';
1808 fname_dst
= modname
;
1811 if (!push_ucs2_talloc(frame
,
1814 &converted_size_bytes
)) {
1815 status
= NT_STATUS_INVALID_PARAMETER
;
1819 /* W2K8 insists the dest name is not null
1820 terminated. Remove the last 2 zero bytes
1821 and reduce the name length. */
1823 if (converted_size_bytes
< 2) {
1824 status
= NT_STATUS_INVALID_PARAMETER
;
1827 converted_size_bytes
-= 2;
1829 inbuf
= data_blob_talloc_zero(frame
,
1830 20 + converted_size_bytes
);
1831 if (inbuf
.data
== NULL
) {
1832 status
= NT_STATUS_NO_MEMORY
;
1836 SIVAL(inbuf
.data
, 16, converted_size_bytes
);
1837 memcpy(inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
1839 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
1840 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
1842 status
= smb2cli_set_info(cli
->conn
,
1846 1, /* in_info_type */
1847 SMB_FILE_RENAME_INFORMATION
- 1000, /* in_file_info_class */
1848 &inbuf
, /* in_input_buffer */
1849 0, /* in_additional_info */
1855 if (fnum
!= 0xffff) {
1856 cli_smb2_close_fnum(cli
, fnum
);
1863 /***************************************************************
1864 Wrapper that allows SMB2 to set an EA on a fnum.
1866 ***************************************************************/
1868 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
1870 const char *ea_name
,
1875 DATA_BLOB inbuf
= data_blob_null
;
1877 char *ea_name_ascii
= NULL
;
1879 struct smb2_hnd
*ph
= NULL
;
1880 TALLOC_CTX
*frame
= talloc_stackframe();
1882 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1884 * Can't use sync call while an async call is in flight
1886 status
= NT_STATUS_INVALID_PARAMETER
;
1890 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1891 status
= NT_STATUS_INVALID_PARAMETER
;
1895 status
= map_fnum_to_smb2_handle(cli
,
1898 if (!NT_STATUS_IS_OK(status
)) {
1902 /* Marshall the SMB2 EA data. */
1903 if (ea_len
> 0xFFFF) {
1904 status
= NT_STATUS_INVALID_PARAMETER
;
1908 if (!push_ascii_talloc(frame
,
1912 status
= NT_STATUS_INVALID_PARAMETER
;
1916 if (namelen
< 2 || namelen
> 0xFF) {
1917 status
= NT_STATUS_INVALID_PARAMETER
;
1921 bloblen
= 8 + ea_len
+ namelen
;
1922 /* Round up to a 4 byte boundary. */
1923 bloblen
= ((bloblen
+ 3)&~3);
1925 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
1926 if (inbuf
.data
== NULL
) {
1927 status
= NT_STATUS_NO_MEMORY
;
1930 /* namelen doesn't include the NULL byte. */
1931 SCVAL(inbuf
.data
, 5, namelen
- 1);
1932 SSVAL(inbuf
.data
, 6, ea_len
);
1933 memcpy(inbuf
.data
+ 8, ea_name_ascii
, namelen
);
1934 memcpy(inbuf
.data
+ 8 + namelen
, ea_val
, ea_len
);
1936 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1937 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
1939 status
= smb2cli_set_info(cli
->conn
,
1943 1, /* in_info_type */
1944 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
1945 &inbuf
, /* in_input_buffer */
1946 0, /* in_additional_info */
1956 /***************************************************************
1957 Wrapper that allows SMB2 to set an EA on a pathname.
1959 ***************************************************************/
1961 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
1963 const char *ea_name
,
1968 uint16_t fnum
= 0xffff;
1970 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1972 * Can't use sync call while an async call is in flight
1974 status
= NT_STATUS_INVALID_PARAMETER
;
1978 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1979 status
= NT_STATUS_INVALID_PARAMETER
;
1983 status
= get_fnum_from_path(cli
,
1988 if (!NT_STATUS_IS_OK(status
)) {
1992 status
= cli_set_ea_fnum(cli
,
1997 if (!NT_STATUS_IS_OK(status
)) {
2003 if (fnum
!= 0xffff) {
2004 cli_smb2_close_fnum(cli
, fnum
);
2010 /***************************************************************
2011 Wrapper that allows SMB2 to get an EA list on a pathname.
2013 ***************************************************************/
2015 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
2019 struct ea_struct
**pea_array
)
2022 uint16_t fnum
= 0xffff;
2023 DATA_BLOB outbuf
= data_blob_null
;
2024 struct smb2_hnd
*ph
= NULL
;
2025 struct ea_list
*ea_list
= NULL
;
2026 struct ea_list
*eal
= NULL
;
2027 size_t ea_count
= 0;
2028 TALLOC_CTX
*frame
= talloc_stackframe();
2033 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2035 * Can't use sync call while an async call is in flight
2037 status
= NT_STATUS_INVALID_PARAMETER
;
2041 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2042 status
= NT_STATUS_INVALID_PARAMETER
;
2046 status
= get_fnum_from_path(cli
,
2051 if (!NT_STATUS_IS_OK(status
)) {
2055 status
= map_fnum_to_smb2_handle(cli
,
2058 if (!NT_STATUS_IS_OK(status
)) {
2062 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2063 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2065 status
= smb2cli_query_info(cli
->conn
,
2069 1, /* in_info_type */
2070 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
2071 0xFFFF, /* in_max_output_length */
2072 NULL
, /* in_input_buffer */
2073 0, /* in_additional_info */
2080 if (!NT_STATUS_IS_OK(status
)) {
2084 /* Parse the reply. */
2085 ea_list
= read_nttrans_ea_list(ctx
,
2086 (const char *)outbuf
.data
,
2088 if (ea_list
== NULL
) {
2089 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2093 /* Convert to an array. */
2094 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2099 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
2100 if (*pea_array
== NULL
) {
2101 status
= NT_STATUS_NO_MEMORY
;
2105 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2106 (*pea_array
)[ea_count
++] = ea_list
->ea
;
2108 *pnum_eas
= ea_count
;
2113 if (fnum
!= 0xffff) {
2114 cli_smb2_close_fnum(cli
, fnum
);
2121 struct cli_smb2_read_state
{
2122 struct tevent_context
*ev
;
2123 struct cli_state
*cli
;
2124 struct smb2_hnd
*ph
;
2125 uint64_t start_offset
;
2131 static void cli_smb2_read_done(struct tevent_req
*subreq
);
2133 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
2134 struct tevent_context
*ev
,
2135 struct cli_state
*cli
,
2141 struct tevent_req
*req
, *subreq
;
2142 struct cli_smb2_read_state
*state
;
2144 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
2150 state
->start_offset
= (uint64_t)offset
;
2151 state
->size
= (uint32_t)size
;
2152 state
->received
= 0;
2155 status
= map_fnum_to_smb2_handle(cli
,
2158 if (tevent_req_nterror(req
, status
)) {
2159 return tevent_req_post(req
, ev
);
2162 subreq
= smb2cli_read_send(state
,
2165 state
->cli
->timeout
,
2166 state
->cli
->smb2
.session
,
2167 state
->cli
->smb2
.tcon
,
2169 state
->start_offset
,
2170 state
->ph
->fid_persistent
,
2171 state
->ph
->fid_volatile
,
2172 0, /* minimum_count */
2173 0); /* remaining_bytes */
2175 if (tevent_req_nomem(subreq
, req
)) {
2176 return tevent_req_post(req
, ev
);
2178 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
2182 static void cli_smb2_read_done(struct tevent_req
*subreq
)
2184 struct tevent_req
*req
= tevent_req_callback_data(
2185 subreq
, struct tevent_req
);
2186 struct cli_smb2_read_state
*state
= tevent_req_data(
2187 req
, struct cli_smb2_read_state
);
2190 status
= smb2cli_read_recv(subreq
, state
,
2191 &state
->buf
, &state
->received
);
2192 if (tevent_req_nterror(req
, status
)) {
2196 if (state
->received
> state
->size
) {
2197 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2201 tevent_req_done(req
);
2204 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
2209 struct cli_smb2_read_state
*state
= tevent_req_data(
2210 req
, struct cli_smb2_read_state
);
2212 if (tevent_req_is_nterror(req
, &status
)) {
2216 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2217 * better make sure that you copy it away before you talloc_free(req).
2218 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2220 *received
= (ssize_t
)state
->received
;
2221 *rcvbuf
= state
->buf
;
2222 return NT_STATUS_OK
;
2225 struct cli_smb2_write_state
{
2226 struct tevent_context
*ev
;
2227 struct cli_state
*cli
;
2228 struct smb2_hnd
*ph
;
2236 static void cli_smb2_write_written(struct tevent_req
*req
);
2238 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
2239 struct tevent_context
*ev
,
2240 struct cli_state
*cli
,
2248 struct tevent_req
*req
, *subreq
= NULL
;
2249 struct cli_smb2_write_state
*state
= NULL
;
2251 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
2257 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2258 state
->flags
= (uint32_t)mode
;
2260 state
->offset
= (uint64_t)offset
;
2261 state
->size
= (uint32_t)size
;
2264 status
= map_fnum_to_smb2_handle(cli
,
2267 if (tevent_req_nterror(req
, status
)) {
2268 return tevent_req_post(req
, ev
);
2271 subreq
= smb2cli_write_send(state
,
2274 state
->cli
->timeout
,
2275 state
->cli
->smb2
.session
,
2276 state
->cli
->smb2
.tcon
,
2279 state
->ph
->fid_persistent
,
2280 state
->ph
->fid_volatile
,
2281 0, /* remaining_bytes */
2282 state
->flags
, /* flags */
2285 if (tevent_req_nomem(subreq
, req
)) {
2286 return tevent_req_post(req
, ev
);
2288 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
2292 static void cli_smb2_write_written(struct tevent_req
*subreq
)
2294 struct tevent_req
*req
= tevent_req_callback_data(
2295 subreq
, struct tevent_req
);
2296 struct cli_smb2_write_state
*state
= tevent_req_data(
2297 req
, struct cli_smb2_write_state
);
2301 status
= smb2cli_write_recv(subreq
, &written
);
2302 TALLOC_FREE(subreq
);
2303 if (tevent_req_nterror(req
, status
)) {
2307 state
->written
= written
;
2309 tevent_req_done(req
);
2312 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
2315 struct cli_smb2_write_state
*state
= tevent_req_data(
2316 req
, struct cli_smb2_write_state
);
2319 if (tevent_req_is_nterror(req
, &status
)) {
2320 tevent_req_received(req
);
2324 if (pwritten
!= NULL
) {
2325 *pwritten
= (size_t)state
->written
;
2327 tevent_req_received(req
);
2328 return NT_STATUS_OK
;
2331 /***************************************************************
2332 Wrapper that allows SMB2 async write using an fnum.
2333 This is mostly cut-and-paste from Volker's code inside
2334 source3/libsmb/clireadwrite.c, adapted for SMB2.
2336 Done this way so I can reuse all the logic inside cli_push()
2338 ***************************************************************/
2340 struct cli_smb2_writeall_state
{
2341 struct tevent_context
*ev
;
2342 struct cli_state
*cli
;
2343 struct smb2_hnd
*ph
;
2351 static void cli_smb2_writeall_written(struct tevent_req
*req
);
2353 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
2354 struct tevent_context
*ev
,
2355 struct cli_state
*cli
,
2363 struct tevent_req
*req
, *subreq
= NULL
;
2364 struct cli_smb2_writeall_state
*state
= NULL
;
2369 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
2375 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2376 state
->flags
= (uint32_t)mode
;
2378 state
->offset
= (uint64_t)offset
;
2379 state
->size
= (uint32_t)size
;
2382 status
= map_fnum_to_smb2_handle(cli
,
2385 if (tevent_req_nterror(req
, status
)) {
2386 return tevent_req_post(req
, ev
);
2389 to_write
= state
->size
;
2390 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
2391 to_write
= MIN(max_size
, to_write
);
2392 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
2394 to_write
= MIN(max_size
, to_write
);
2397 subreq
= smb2cli_write_send(state
,
2400 state
->cli
->timeout
,
2401 state
->cli
->smb2
.session
,
2402 state
->cli
->smb2
.tcon
,
2405 state
->ph
->fid_persistent
,
2406 state
->ph
->fid_volatile
,
2407 0, /* remaining_bytes */
2408 state
->flags
, /* flags */
2409 state
->buf
+ state
->written
);
2411 if (tevent_req_nomem(subreq
, req
)) {
2412 return tevent_req_post(req
, ev
);
2414 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
2418 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
2420 struct tevent_req
*req
= tevent_req_callback_data(
2421 subreq
, struct tevent_req
);
2422 struct cli_smb2_writeall_state
*state
= tevent_req_data(
2423 req
, struct cli_smb2_writeall_state
);
2425 uint32_t written
, to_write
;
2429 status
= smb2cli_write_recv(subreq
, &written
);
2430 TALLOC_FREE(subreq
);
2431 if (tevent_req_nterror(req
, status
)) {
2435 state
->written
+= written
;
2437 if (state
->written
> state
->size
) {
2438 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2442 to_write
= state
->size
- state
->written
;
2444 if (to_write
== 0) {
2445 tevent_req_done(req
);
2449 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
2450 to_write
= MIN(max_size
, to_write
);
2451 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
2453 to_write
= MIN(max_size
, to_write
);
2456 subreq
= smb2cli_write_send(state
,
2459 state
->cli
->timeout
,
2460 state
->cli
->smb2
.session
,
2461 state
->cli
->smb2
.tcon
,
2463 state
->offset
+ state
->written
,
2464 state
->ph
->fid_persistent
,
2465 state
->ph
->fid_volatile
,
2466 0, /* remaining_bytes */
2467 state
->flags
, /* flags */
2468 state
->buf
+ state
->written
);
2470 if (tevent_req_nomem(subreq
, req
)) {
2473 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
2476 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
2479 struct cli_smb2_writeall_state
*state
= tevent_req_data(
2480 req
, struct cli_smb2_writeall_state
);
2483 if (tevent_req_is_nterror(req
, &status
)) {
2486 if (pwritten
!= NULL
) {
2487 *pwritten
= (size_t)state
->written
;
2489 return NT_STATUS_OK
;