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
;
160 struct tevent_req
*subreq
;
163 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
);
164 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
);
166 struct tevent_req
*cli_smb2_create_fnum_send(TALLOC_CTX
*mem_ctx
,
167 struct tevent_context
*ev
,
168 struct cli_state
*cli
,
170 uint32_t create_flags
,
171 uint32_t desired_access
,
172 uint32_t file_attributes
,
173 uint32_t share_access
,
174 uint32_t create_disposition
,
175 uint32_t create_options
)
177 struct tevent_req
*req
, *subreq
;
178 struct cli_smb2_create_fnum_state
*state
;
180 req
= tevent_req_create(mem_ctx
, &state
,
181 struct cli_smb2_create_fnum_state
);
187 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
188 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
189 return tevent_req_post(req
, ev
);
192 if (cli
->backup_intent
) {
193 create_options
|= FILE_OPEN_FOR_BACKUP_INTENT
;
196 /* SMB2 is pickier about pathnames. Ensure it doesn't
198 if (*fname
== '\\') {
202 subreq
= smb2cli_create_send(state
, ev
,
208 flags_to_smb2_oplock(create_flags
),
209 SMB2_IMPERSONATION_IMPERSONATION
,
216 if (tevent_req_nomem(subreq
, req
)) {
217 return tevent_req_post(req
, ev
);
219 tevent_req_set_callback(subreq
, cli_smb2_create_fnum_done
, req
);
221 state
->subreq
= subreq
;
222 tevent_req_set_cancel_fn(req
, cli_smb2_create_fnum_cancel
);
227 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
)
229 struct tevent_req
*req
= tevent_req_callback_data(
230 subreq
, struct tevent_req
);
231 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
232 req
, struct cli_smb2_create_fnum_state
);
236 status
= smb2cli_create_recv(subreq
, &h
.fid_persistent
,
237 &h
.fid_volatile
, &state
->cr
);
239 if (tevent_req_nterror(req
, status
)) {
243 status
= map_smb2_handle_to_fnum(state
->cli
, &h
, &state
->fnum
);
244 if (tevent_req_nterror(req
, status
)) {
247 tevent_req_done(req
);
250 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
)
252 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
253 req
, struct cli_smb2_create_fnum_state
);
254 return tevent_req_cancel(state
->subreq
);
257 NTSTATUS
cli_smb2_create_fnum_recv(struct tevent_req
*req
, uint16_t *pfnum
,
258 struct smb_create_returns
*cr
)
260 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
261 req
, struct cli_smb2_create_fnum_state
);
264 if (tevent_req_is_nterror(req
, &status
)) {
268 *pfnum
= state
->fnum
;
276 NTSTATUS
cli_smb2_create_fnum(struct cli_state
*cli
,
278 uint32_t create_flags
,
279 uint32_t desired_access
,
280 uint32_t file_attributes
,
281 uint32_t share_access
,
282 uint32_t create_disposition
,
283 uint32_t create_options
,
285 struct smb_create_returns
*cr
)
287 TALLOC_CTX
*frame
= talloc_stackframe();
288 struct tevent_context
*ev
;
289 struct tevent_req
*req
;
290 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
292 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
294 * Can't use sync call while an async call is in flight
296 status
= NT_STATUS_INVALID_PARAMETER
;
299 ev
= samba_tevent_context_init(frame
);
303 req
= cli_smb2_create_fnum_send(frame
, ev
, cli
, fname
, create_flags
,
304 desired_access
, file_attributes
,
305 share_access
, create_disposition
,
310 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
313 status
= cli_smb2_create_fnum_recv(req
, pfid
, cr
);
319 /***************************************************************
320 Small wrapper that allows SMB2 close to use a uint16_t fnum.
322 ***************************************************************/
324 NTSTATUS
cli_smb2_close_fnum(struct cli_state
*cli
, uint16_t fnum
)
326 struct smb2_hnd
*ph
= NULL
;
329 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
331 * Can't use sync call while an async call is in flight
333 return NT_STATUS_INVALID_PARAMETER
;
336 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
337 return NT_STATUS_INVALID_PARAMETER
;
340 status
= map_fnum_to_smb2_handle(cli
,
343 if (!NT_STATUS_IS_OK(status
)) {
347 status
= smb2cli_close(cli
->conn
,
355 /* Delete the fnum -> handle mapping. */
356 if (NT_STATUS_IS_OK(status
)) {
357 status
= delete_smb2_handle_mapping(cli
, &ph
, fnum
);
363 /***************************************************************
364 Small wrapper that allows SMB2 to create a directory
366 ***************************************************************/
368 NTSTATUS
cli_smb2_mkdir(struct cli_state
*cli
, const char *dname
)
373 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
375 * Can't use sync call while an async call is in flight
377 return NT_STATUS_INVALID_PARAMETER
;
380 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
381 return NT_STATUS_INVALID_PARAMETER
;
384 status
= cli_smb2_create_fnum(cli
,
386 0, /* create_flags */
387 FILE_READ_ATTRIBUTES
, /* desired_access */
388 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
389 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
390 FILE_CREATE
, /* create_disposition */
391 FILE_DIRECTORY_FILE
, /* create_options */
395 if (!NT_STATUS_IS_OK(status
)) {
398 return cli_smb2_close_fnum(cli
, fnum
);
401 /***************************************************************
402 Small wrapper that allows SMB2 to delete a directory
404 ***************************************************************/
406 NTSTATUS
cli_smb2_rmdir(struct cli_state
*cli
, const char *dname
)
411 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
413 * Can't use sync call while an async call is in flight
415 return NT_STATUS_INVALID_PARAMETER
;
418 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
419 return NT_STATUS_INVALID_PARAMETER
;
422 status
= cli_smb2_create_fnum(cli
,
424 0, /* create_flags */
425 DELETE_ACCESS
, /* desired_access */
426 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
427 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
428 FILE_OPEN
, /* create_disposition */
429 FILE_DIRECTORY_FILE
|FILE_DELETE_ON_CLOSE
, /* create_options */
433 if (!NT_STATUS_IS_OK(status
)) {
436 return cli_smb2_close_fnum(cli
, fnum
);
439 /***************************************************************
440 Small wrapper that allows SMB2 to unlink a pathname.
442 ***************************************************************/
444 NTSTATUS
cli_smb2_unlink(struct cli_state
*cli
, const char *fname
)
449 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
451 * Can't use sync call while an async call is in flight
453 return NT_STATUS_INVALID_PARAMETER
;
456 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
457 return NT_STATUS_INVALID_PARAMETER
;
460 status
= cli_smb2_create_fnum(cli
,
462 0, /* create_flags */
463 DELETE_ACCESS
, /* desired_access */
464 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
465 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
466 FILE_OPEN
, /* create_disposition */
467 FILE_DELETE_ON_CLOSE
, /* create_options */
471 if (!NT_STATUS_IS_OK(status
)) {
474 return cli_smb2_close_fnum(cli
, fnum
);
477 /***************************************************************
478 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
479 ***************************************************************/
481 static NTSTATUS
parse_finfo_id_both_directory_info(uint8_t *dir_data
,
482 uint32_t dir_data_length
,
483 struct file_info
*finfo
,
484 uint32_t *next_offset
)
490 if (dir_data_length
< 4) {
491 return NT_STATUS_INFO_LENGTH_MISMATCH
;
494 *next_offset
= IVAL(dir_data
, 0);
496 if (*next_offset
> dir_data_length
) {
497 return NT_STATUS_INFO_LENGTH_MISMATCH
;
500 if (*next_offset
!= 0) {
501 /* Ensure we only read what in this record. */
502 dir_data_length
= *next_offset
;
505 if (dir_data_length
< 105) {
506 return NT_STATUS_INFO_LENGTH_MISMATCH
;
509 finfo
->atime_ts
= interpret_long_date((const char *)dir_data
+ 16);
510 finfo
->mtime_ts
= interpret_long_date((const char *)dir_data
+ 24);
511 finfo
->ctime_ts
= interpret_long_date((const char *)dir_data
+ 32);
512 finfo
->size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 40, 0);
513 finfo
->mode
= CVAL(dir_data
+ 56, 0);
514 namelen
= IVAL(dir_data
+ 60,0);
515 if (namelen
> (dir_data_length
- 104)) {
516 return NT_STATUS_INFO_LENGTH_MISMATCH
;
518 slen
= CVAL(dir_data
+ 68, 0);
520 return NT_STATUS_INFO_LENGTH_MISMATCH
;
522 ret
= pull_string_talloc(finfo
,
524 FLAGS2_UNICODE_STRINGS
,
529 if (ret
== (size_t)-1) {
530 /* Bad conversion. */
531 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
534 ret
= pull_string_talloc(finfo
,
536 FLAGS2_UNICODE_STRINGS
,
541 if (ret
== (size_t)-1) {
542 /* Bad conversion. */
543 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
548 /*******************************************************************
549 Given a filename - get its directory name
550 ********************************************************************/
552 static bool windows_parent_dirname(TALLOC_CTX
*mem_ctx
,
560 p
= strrchr_m(dir
, '\\'); /* Find final '\\', if any */
563 if (!(*parent
= talloc_strdup(mem_ctx
, "\\"))) {
574 if (!(*parent
= (char *)talloc_memdup(mem_ctx
, dir
, len
+1))) {
577 (*parent
)[len
] = '\0';
585 /***************************************************************
586 Wrapper that allows SMB2 to list a directory.
588 ***************************************************************/
590 NTSTATUS
cli_smb2_list(struct cli_state
*cli
,
591 const char *pathname
,
593 NTSTATUS (*fn
)(const char *,
600 uint16_t fnum
= 0xffff;
601 char *parent_dir
= NULL
;
602 const char *mask
= NULL
;
603 struct smb2_hnd
*ph
= NULL
;
604 bool processed_file
= false;
605 TALLOC_CTX
*frame
= talloc_stackframe();
606 TALLOC_CTX
*subframe
= NULL
;
608 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
610 * Can't use sync call while an async call is in flight
612 status
= NT_STATUS_INVALID_PARAMETER
;
616 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
617 status
= NT_STATUS_INVALID_PARAMETER
;
621 /* Get the directory name. */
622 if (!windows_parent_dirname(frame
,
626 status
= NT_STATUS_NO_MEMORY
;
630 status
= cli_smb2_create_fnum(cli
,
632 0, /* create_flags */
633 SEC_DIR_LIST
|SEC_DIR_READ_ATTRIBUTE
,/* desired_access */
634 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
635 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
636 FILE_OPEN
, /* create_disposition */
637 FILE_DIRECTORY_FILE
, /* create_options */
641 if (!NT_STATUS_IS_OK(status
)) {
645 status
= map_fnum_to_smb2_handle(cli
,
648 if (!NT_STATUS_IS_OK(status
)) {
653 uint8_t *dir_data
= NULL
;
654 uint32_t dir_data_length
= 0;
655 uint32_t next_offset
= 0;
656 subframe
= talloc_stackframe();
658 status
= smb2cli_query_directory(cli
->conn
,
662 SMB2_FIND_ID_BOTH_DIRECTORY_INFO
,
673 if (!NT_STATUS_IS_OK(status
)) {
674 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
681 struct file_info
*finfo
= talloc_zero(subframe
,
685 status
= NT_STATUS_NO_MEMORY
;
689 status
= parse_finfo_id_both_directory_info(dir_data
,
694 if (!NT_STATUS_IS_OK(status
)) {
698 if (dir_check_ftype((uint32_t)finfo
->mode
,
699 (uint32_t)attribute
)) {
701 * Only process if attributes match.
702 * On SMB1 server does this, so on
703 * SMB2 we need to emulate in the
706 * https://bugzilla.samba.org/show_bug.cgi?id=10260
708 processed_file
= true;
710 status
= fn(cli
->dfs_mountpoint
,
715 if (!NT_STATUS_IS_OK(status
)) {
722 /* Move to next entry. */
724 dir_data
+= next_offset
;
725 dir_data_length
-= next_offset
;
727 } while (next_offset
!= 0);
729 TALLOC_FREE(subframe
);
731 } while (NT_STATUS_IS_OK(status
));
733 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
734 status
= NT_STATUS_OK
;
737 if (NT_STATUS_IS_OK(status
) && !processed_file
) {
739 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
740 * if no files match. Emulate this in the client.
742 status
= NT_STATUS_NO_SUCH_FILE
;
747 if (fnum
!= 0xffff) {
748 cli_smb2_close_fnum(cli
, fnum
);
750 TALLOC_FREE(subframe
);
755 /***************************************************************
756 Wrapper that allows SMB2 to query a path info (basic level).
758 ***************************************************************/
760 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
762 SMB_STRUCT_STAT
*sbuf
,
763 uint32_t *attributes
)
766 struct smb_create_returns cr
;
767 uint16_t fnum
= 0xffff;
768 size_t namelen
= strlen(name
);
770 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
772 * Can't use sync call while an async call is in flight
774 return NT_STATUS_INVALID_PARAMETER
;
777 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
778 return NT_STATUS_INVALID_PARAMETER
;
781 /* SMB2 is pickier about pathnames. Ensure it doesn't
783 if (namelen
> 0 && name
[namelen
-1] == '\\') {
784 char *modname
= talloc_strdup(talloc_tos(), name
);
785 modname
[namelen
-1] = '\0';
789 /* This is commonly used as a 'cd'. Try qpathinfo on
790 a directory handle first. */
792 status
= cli_smb2_create_fnum(cli
,
794 0, /* create_flags */
795 FILE_READ_ATTRIBUTES
, /* desired_access */
796 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
797 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
798 FILE_OPEN
, /* create_disposition */
799 FILE_DIRECTORY_FILE
, /* create_options */
803 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
805 status
= cli_smb2_create_fnum(cli
,
807 0, /* create_flags */
808 FILE_READ_ATTRIBUTES
, /* desired_access */
809 0, /* file attributes */
810 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
811 FILE_OPEN
, /* create_disposition */
812 0, /* create_options */
817 if (!NT_STATUS_IS_OK(status
)) {
821 cli_smb2_close_fnum(cli
, fnum
);
825 sbuf
->st_ex_atime
= nt_time_to_unix_timespec(&cr
.last_access_time
);
826 sbuf
->st_ex_mtime
= nt_time_to_unix_timespec(&cr
.last_write_time
);
827 sbuf
->st_ex_ctime
= nt_time_to_unix_timespec(&cr
.change_time
);
828 sbuf
->st_ex_size
= cr
.end_of_file
;
829 *attributes
= cr
.file_attributes
;
834 /***************************************************************
835 Helper function for pathname operations.
836 ***************************************************************/
838 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
840 uint32_t desired_access
,
844 size_t namelen
= strlen(name
);
845 TALLOC_CTX
*frame
= talloc_stackframe();
847 /* SMB2 is pickier about pathnames. Ensure it doesn't
849 if (namelen
> 0 && name
[namelen
-1] == '\\') {
850 char *modname
= talloc_strdup(frame
, name
);
851 if (modname
== NULL
) {
852 status
= NT_STATUS_NO_MEMORY
;
855 modname
[namelen
-1] = '\0';
859 /* Try to open a file handle first. */
860 status
= cli_smb2_create_fnum(cli
,
862 0, /* create_flags */
864 0, /* file attributes */
865 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
866 FILE_OPEN
, /* create_disposition */
867 0, /* create_options */
871 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
872 status
= cli_smb2_create_fnum(cli
,
874 0, /* create_flags */
876 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
877 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
878 FILE_OPEN
, /* create_disposition */
879 FILE_DIRECTORY_FILE
, /* create_options */
890 /***************************************************************
891 Wrapper that allows SMB2 to query a path info (ALTNAME level).
893 ***************************************************************/
895 NTSTATUS
cli_smb2_qpathinfo_alt_name(struct cli_state
*cli
,
900 DATA_BLOB outbuf
= data_blob_null
;
901 uint16_t fnum
= 0xffff;
902 struct smb2_hnd
*ph
= NULL
;
903 uint32_t altnamelen
= 0;
904 TALLOC_CTX
*frame
= talloc_stackframe();
906 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
908 * Can't use sync call while an async call is in flight
910 status
= NT_STATUS_INVALID_PARAMETER
;
914 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
915 status
= NT_STATUS_INVALID_PARAMETER
;
919 status
= get_fnum_from_path(cli
,
921 FILE_READ_ATTRIBUTES
,
924 if (!NT_STATUS_IS_OK(status
)) {
928 status
= map_fnum_to_smb2_handle(cli
,
931 if (!NT_STATUS_IS_OK(status
)) {
935 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
936 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
938 status
= smb2cli_query_info(cli
->conn
,
942 1, /* in_info_type */
943 (SMB_FILE_ALTERNATE_NAME_INFORMATION
- 1000), /* in_file_info_class */
944 0xFFFF, /* in_max_output_length */
945 NULL
, /* in_input_buffer */
946 0, /* in_additional_info */
953 if (!NT_STATUS_IS_OK(status
)) {
957 /* Parse the reply. */
958 if (outbuf
.length
< 4) {
959 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
963 altnamelen
= IVAL(outbuf
.data
, 0);
964 if (altnamelen
> outbuf
.length
- 4) {
965 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
969 if (altnamelen
> 0) {
971 char *short_name
= NULL
;
972 ret
= pull_string_talloc(frame
,
974 FLAGS2_UNICODE_STRINGS
,
979 if (ret
== (size_t)-1) {
980 /* Bad conversion. */
981 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
985 fstrcpy(alt_name
, short_name
);
990 status
= NT_STATUS_OK
;
994 if (fnum
!= 0xffff) {
995 cli_smb2_close_fnum(cli
, fnum
);
1002 /***************************************************************
1003 Wrapper that allows SMB2 to query a fnum info (basic level).
1005 ***************************************************************/
1007 NTSTATUS
cli_smb2_qfileinfo_basic(struct cli_state
*cli
,
1011 struct timespec
*create_time
,
1012 struct timespec
*access_time
,
1013 struct timespec
*write_time
,
1014 struct timespec
*change_time
,
1018 DATA_BLOB outbuf
= data_blob_null
;
1019 struct smb2_hnd
*ph
= NULL
;
1020 TALLOC_CTX
*frame
= talloc_stackframe();
1022 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1024 * Can't use sync call while an async call is in flight
1026 status
= NT_STATUS_INVALID_PARAMETER
;
1030 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1031 status
= NT_STATUS_INVALID_PARAMETER
;
1035 status
= map_fnum_to_smb2_handle(cli
,
1038 if (!NT_STATUS_IS_OK(status
)) {
1042 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1043 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1045 status
= smb2cli_query_info(cli
->conn
,
1049 1, /* in_info_type */
1050 (SMB_FILE_ALL_INFORMATION
- 1000), /* in_file_info_class */
1051 0xFFFF, /* in_max_output_length */
1052 NULL
, /* in_input_buffer */
1053 0, /* in_additional_info */
1059 if (!NT_STATUS_IS_OK(status
)) {
1063 /* Parse the reply. */
1064 if (outbuf
.length
< 0x60) {
1065 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1070 *create_time
= interpret_long_date((const char *)outbuf
.data
+ 0x0);
1073 *access_time
= interpret_long_date((const char *)outbuf
.data
+ 0x8);
1076 *write_time
= interpret_long_date((const char *)outbuf
.data
+ 0x10);
1079 *change_time
= interpret_long_date((const char *)outbuf
.data
+ 0x18);
1082 uint32_t attr
= IVAL(outbuf
.data
, 0x20);
1083 *mode
= (uint16_t)attr
;
1086 uint64_t file_size
= BVAL(outbuf
.data
, 0x30);
1087 *size
= (off_t
)file_size
;
1090 uint64_t file_index
= BVAL(outbuf
.data
, 0x40);
1091 *ino
= (SMB_INO_T
)file_index
;
1100 /***************************************************************
1101 Wrapper that allows SMB2 to query an fnum.
1102 Implement on top of cli_smb2_qfileinfo_basic().
1104 ***************************************************************/
1106 NTSTATUS
cli_smb2_getattrE(struct cli_state
*cli
,
1110 time_t *change_time
,
1111 time_t *access_time
,
1114 struct timespec access_time_ts
;
1115 struct timespec write_time_ts
;
1116 struct timespec change_time_ts
;
1117 NTSTATUS status
= cli_smb2_qfileinfo_basic(cli
,
1127 if (!NT_STATUS_IS_OK(status
)) {
1132 *change_time
= change_time_ts
.tv_sec
;
1135 *access_time
= access_time_ts
.tv_sec
;
1138 *write_time
= write_time_ts
.tv_sec
;
1140 return NT_STATUS_OK
;
1143 /***************************************************************
1144 Wrapper that allows SMB2 to get pathname attributes.
1146 ***************************************************************/
1148 NTSTATUS
cli_smb2_getatr(struct cli_state
*cli
,
1155 uint16_t fnum
= 0xffff;
1156 struct smb2_hnd
*ph
= NULL
;
1157 TALLOC_CTX
*frame
= talloc_stackframe();
1159 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1161 * Can't use sync call while an async call is in flight
1163 status
= NT_STATUS_INVALID_PARAMETER
;
1167 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1168 status
= NT_STATUS_INVALID_PARAMETER
;
1172 status
= get_fnum_from_path(cli
,
1174 FILE_READ_ATTRIBUTES
,
1177 if (!NT_STATUS_IS_OK(status
)) {
1181 status
= map_fnum_to_smb2_handle(cli
,
1184 if (!NT_STATUS_IS_OK(status
)) {
1187 status
= cli_smb2_getattrE(cli
,
1194 if (!NT_STATUS_IS_OK(status
)) {
1200 if (fnum
!= 0xffff) {
1201 cli_smb2_close_fnum(cli
, fnum
);
1208 /***************************************************************
1209 Wrapper that allows SMB2 to query a pathname info (basic level).
1210 Implement on top of cli_smb2_qfileinfo_basic().
1212 ***************************************************************/
1214 NTSTATUS
cli_smb2_qpathinfo2(struct cli_state
*cli
,
1216 struct timespec
*create_time
,
1217 struct timespec
*access_time
,
1218 struct timespec
*write_time
,
1219 struct timespec
*change_time
,
1225 struct smb2_hnd
*ph
= NULL
;
1226 uint16_t fnum
= 0xffff;
1227 TALLOC_CTX
*frame
= talloc_stackframe();
1229 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1231 * Can't use sync call while an async call is in flight
1233 status
= NT_STATUS_INVALID_PARAMETER
;
1237 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1238 status
= NT_STATUS_INVALID_PARAMETER
;
1242 status
= get_fnum_from_path(cli
,
1244 FILE_READ_ATTRIBUTES
,
1247 if (!NT_STATUS_IS_OK(status
)) {
1251 status
= map_fnum_to_smb2_handle(cli
,
1254 if (!NT_STATUS_IS_OK(status
)) {
1258 status
= cli_smb2_qfileinfo_basic(cli
,
1270 if (fnum
!= 0xffff) {
1271 cli_smb2_close_fnum(cli
, fnum
);
1278 /***************************************************************
1279 Wrapper that allows SMB2 to query pathname streams.
1281 ***************************************************************/
1283 NTSTATUS
cli_smb2_qpathinfo_streams(struct cli_state
*cli
,
1285 TALLOC_CTX
*mem_ctx
,
1286 unsigned int *pnum_streams
,
1287 struct stream_struct
**pstreams
)
1290 struct smb2_hnd
*ph
= NULL
;
1291 uint16_t fnum
= 0xffff;
1292 DATA_BLOB outbuf
= data_blob_null
;
1293 TALLOC_CTX
*frame
= talloc_stackframe();
1295 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1297 * Can't use sync call while an async call is in flight
1299 status
= NT_STATUS_INVALID_PARAMETER
;
1303 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1304 status
= NT_STATUS_INVALID_PARAMETER
;
1308 status
= get_fnum_from_path(cli
,
1310 FILE_READ_ATTRIBUTES
,
1313 if (!NT_STATUS_IS_OK(status
)) {
1317 status
= map_fnum_to_smb2_handle(cli
,
1320 if (!NT_STATUS_IS_OK(status
)) {
1324 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1325 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1327 status
= smb2cli_query_info(cli
->conn
,
1331 1, /* in_info_type */
1332 (SMB_FILE_STREAM_INFORMATION
- 1000), /* in_file_info_class */
1333 0xFFFF, /* in_max_output_length */
1334 NULL
, /* in_input_buffer */
1335 0, /* in_additional_info */
1342 if (!NT_STATUS_IS_OK(status
)) {
1346 /* Parse the reply. */
1347 if (!parse_streams_blob(mem_ctx
,
1352 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1358 if (fnum
!= 0xffff) {
1359 cli_smb2_close_fnum(cli
, fnum
);
1366 /***************************************************************
1367 Wrapper that allows SMB2 to set pathname attributes.
1369 ***************************************************************/
1371 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
1377 uint16_t fnum
= 0xffff;
1378 struct smb2_hnd
*ph
= NULL
;
1379 uint8_t inbuf_store
[40];
1380 DATA_BLOB inbuf
= data_blob_null
;
1381 TALLOC_CTX
*frame
= talloc_stackframe();
1383 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1385 * Can't use sync call while an async call is in flight
1387 status
= NT_STATUS_INVALID_PARAMETER
;
1391 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1392 status
= NT_STATUS_INVALID_PARAMETER
;
1396 status
= get_fnum_from_path(cli
,
1398 FILE_WRITE_ATTRIBUTES
,
1401 if (!NT_STATUS_IS_OK(status
)) {
1405 status
= map_fnum_to_smb2_handle(cli
,
1408 if (!NT_STATUS_IS_OK(status
)) {
1412 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1413 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1415 inbuf
.data
= inbuf_store
;
1416 inbuf
.length
= sizeof(inbuf_store
);
1417 data_blob_clear(&inbuf
);
1419 SSVAL(inbuf
.data
, 32, attr
);
1421 put_long_date((char *)inbuf
.data
+ 16,mtime
);
1423 /* Set all the other times to -1. */
1424 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1425 SBVAL(inbuf
.data
, 8, 0xFFFFFFFFFFFFFFFFLL
);
1426 SBVAL(inbuf
.data
, 24, 0xFFFFFFFFFFFFFFFFLL
);
1428 status
= smb2cli_set_info(cli
->conn
,
1432 1, /* in_info_type */
1433 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1434 &inbuf
, /* in_input_buffer */
1435 0, /* in_additional_info */
1440 if (fnum
!= 0xffff) {
1441 cli_smb2_close_fnum(cli
, fnum
);
1448 /***************************************************************
1449 Wrapper that allows SMB2 to set file handle times.
1451 ***************************************************************/
1453 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
1460 struct smb2_hnd
*ph
= NULL
;
1461 uint8_t inbuf_store
[40];
1462 DATA_BLOB inbuf
= data_blob_null
;
1464 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1466 * Can't use sync call while an async call is in flight
1468 return NT_STATUS_INVALID_PARAMETER
;
1471 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1472 return NT_STATUS_INVALID_PARAMETER
;
1475 status
= map_fnum_to_smb2_handle(cli
,
1478 if (!NT_STATUS_IS_OK(status
)) {
1482 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1483 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1485 inbuf
.data
= inbuf_store
;
1486 inbuf
.length
= sizeof(inbuf_store
);
1487 data_blob_clear(&inbuf
);
1489 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1490 if (change_time
!= 0) {
1491 put_long_date((char *)inbuf
.data
+ 24, change_time
);
1493 if (access_time
!= 0) {
1494 put_long_date((char *)inbuf
.data
+ 8, access_time
);
1496 if (write_time
!= 0) {
1497 put_long_date((char *)inbuf
.data
+ 16, write_time
);
1500 return smb2cli_set_info(cli
->conn
,
1504 1, /* in_info_type */
1505 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1506 &inbuf
, /* in_input_buffer */
1507 0, /* in_additional_info */
1512 /***************************************************************
1513 Wrapper that allows SMB2 to query disk attributes (size).
1515 ***************************************************************/
1517 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, uint64_t *bsize
, uint64_t *total
, uint64_t *avail
)
1520 uint16_t fnum
= 0xffff;
1521 DATA_BLOB outbuf
= data_blob_null
;
1522 struct smb2_hnd
*ph
= NULL
;
1523 uint32_t sectors_per_unit
= 0;
1524 uint32_t bytes_per_sector
= 0;
1525 uint64_t total_size
= 0;
1526 uint64_t size_free
= 0;
1527 TALLOC_CTX
*frame
= talloc_stackframe();
1529 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1531 * Can't use sync call while an async call is in flight
1533 status
= NT_STATUS_INVALID_PARAMETER
;
1537 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1538 status
= NT_STATUS_INVALID_PARAMETER
;
1542 /* First open the top level directory. */
1543 status
= cli_smb2_create_fnum(cli
,
1545 0, /* create_flags */
1546 FILE_READ_ATTRIBUTES
, /* desired_access */
1547 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1548 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1549 FILE_OPEN
, /* create_disposition */
1550 FILE_DIRECTORY_FILE
, /* create_options */
1554 if (!NT_STATUS_IS_OK(status
)) {
1558 status
= map_fnum_to_smb2_handle(cli
,
1561 if (!NT_STATUS_IS_OK(status
)) {
1565 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1566 level 3 (SMB_FS_SIZE_INFORMATION). */
1568 status
= smb2cli_query_info(cli
->conn
,
1572 2, /* in_info_type */
1573 3, /* in_file_info_class */
1574 0xFFFF, /* in_max_output_length */
1575 NULL
, /* in_input_buffer */
1576 0, /* in_additional_info */
1582 if (!NT_STATUS_IS_OK(status
)) {
1586 /* Parse the reply. */
1587 if (outbuf
.length
!= 24) {
1588 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1592 total_size
= BVAL(outbuf
.data
, 0);
1593 size_free
= BVAL(outbuf
.data
, 8);
1594 sectors_per_unit
= IVAL(outbuf
.data
, 16);
1595 bytes_per_sector
= IVAL(outbuf
.data
, 20);
1598 *bsize
= (uint64_t)sectors_per_unit
* (uint64_t)bytes_per_sector
;
1601 *total
= total_size
;
1607 status
= NT_STATUS_OK
;
1611 if (fnum
!= 0xffff) {
1612 cli_smb2_close_fnum(cli
, fnum
);
1619 /***************************************************************
1620 Wrapper that allows SMB2 to query a security descriptor.
1622 ***************************************************************/
1624 NTSTATUS
cli_smb2_query_security_descriptor(struct cli_state
*cli
,
1627 TALLOC_CTX
*mem_ctx
,
1628 struct security_descriptor
**ppsd
)
1631 DATA_BLOB outbuf
= data_blob_null
;
1632 struct smb2_hnd
*ph
= NULL
;
1633 struct security_descriptor
*lsd
= NULL
;
1634 TALLOC_CTX
*frame
= talloc_stackframe();
1636 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1638 * Can't use sync call while an async call is in flight
1640 status
= NT_STATUS_INVALID_PARAMETER
;
1644 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1645 status
= NT_STATUS_INVALID_PARAMETER
;
1649 status
= map_fnum_to_smb2_handle(cli
,
1652 if (!NT_STATUS_IS_OK(status
)) {
1656 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1658 status
= smb2cli_query_info(cli
->conn
,
1662 3, /* in_info_type */
1663 0, /* in_file_info_class */
1664 0xFFFF, /* in_max_output_length */
1665 NULL
, /* in_input_buffer */
1666 sec_info
, /* in_additional_info */
1673 if (!NT_STATUS_IS_OK(status
)) {
1677 /* Parse the reply. */
1678 status
= unmarshall_sec_desc(mem_ctx
,
1683 if (!NT_STATUS_IS_OK(status
)) {
1699 /***************************************************************
1700 Wrapper that allows SMB2 to set a security descriptor.
1702 ***************************************************************/
1704 NTSTATUS
cli_smb2_set_security_descriptor(struct cli_state
*cli
,
1707 const struct security_descriptor
*sd
)
1710 DATA_BLOB inbuf
= data_blob_null
;
1711 struct smb2_hnd
*ph
= NULL
;
1712 TALLOC_CTX
*frame
= talloc_stackframe();
1714 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1716 * Can't use sync call while an async call is in flight
1718 status
= NT_STATUS_INVALID_PARAMETER
;
1722 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1723 status
= NT_STATUS_INVALID_PARAMETER
;
1727 status
= map_fnum_to_smb2_handle(cli
,
1730 if (!NT_STATUS_IS_OK(status
)) {
1734 status
= marshall_sec_desc(frame
,
1739 if (!NT_STATUS_IS_OK(status
)) {
1743 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1745 status
= smb2cli_set_info(cli
->conn
,
1749 3, /* in_info_type */
1750 0, /* in_file_info_class */
1751 &inbuf
, /* in_input_buffer */
1752 sec_info
, /* in_additional_info */
1762 /***************************************************************
1763 Wrapper that allows SMB2 to rename a file.
1765 ***************************************************************/
1767 NTSTATUS
cli_smb2_rename(struct cli_state
*cli
,
1768 const char *fname_src
,
1769 const char *fname_dst
)
1772 DATA_BLOB inbuf
= data_blob_null
;
1773 uint16_t fnum
= 0xffff;
1774 struct smb2_hnd
*ph
= NULL
;
1775 smb_ucs2_t
*converted_str
= NULL
;
1776 size_t converted_size_bytes
= 0;
1778 TALLOC_CTX
*frame
= talloc_stackframe();
1780 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1782 * Can't use sync call while an async call is in flight
1784 status
= NT_STATUS_INVALID_PARAMETER
;
1788 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1789 status
= NT_STATUS_INVALID_PARAMETER
;
1793 status
= get_fnum_from_path(cli
,
1798 if (!NT_STATUS_IS_OK(status
)) {
1802 status
= map_fnum_to_smb2_handle(cli
,
1805 if (!NT_STATUS_IS_OK(status
)) {
1809 /* SMB2 is pickier about pathnames. Ensure it doesn't
1811 if (*fname_dst
== '\\') {
1815 /* SMB2 is pickier about pathnames. Ensure it doesn't
1817 namelen
= strlen(fname_dst
);
1818 if (namelen
> 0 && fname_dst
[namelen
-1] == '\\') {
1819 char *modname
= talloc_strdup(frame
, fname_dst
);
1820 modname
[namelen
-1] = '\0';
1821 fname_dst
= modname
;
1824 if (!push_ucs2_talloc(frame
,
1827 &converted_size_bytes
)) {
1828 status
= NT_STATUS_INVALID_PARAMETER
;
1832 /* W2K8 insists the dest name is not null
1833 terminated. Remove the last 2 zero bytes
1834 and reduce the name length. */
1836 if (converted_size_bytes
< 2) {
1837 status
= NT_STATUS_INVALID_PARAMETER
;
1840 converted_size_bytes
-= 2;
1842 inbuf
= data_blob_talloc_zero(frame
,
1843 20 + converted_size_bytes
);
1844 if (inbuf
.data
== NULL
) {
1845 status
= NT_STATUS_NO_MEMORY
;
1849 SIVAL(inbuf
.data
, 16, converted_size_bytes
);
1850 memcpy(inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
1852 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
1853 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
1855 status
= smb2cli_set_info(cli
->conn
,
1859 1, /* in_info_type */
1860 SMB_FILE_RENAME_INFORMATION
- 1000, /* in_file_info_class */
1861 &inbuf
, /* in_input_buffer */
1862 0, /* in_additional_info */
1868 if (fnum
!= 0xffff) {
1869 cli_smb2_close_fnum(cli
, fnum
);
1876 /***************************************************************
1877 Wrapper that allows SMB2 to set an EA on a fnum.
1879 ***************************************************************/
1881 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
1883 const char *ea_name
,
1888 DATA_BLOB inbuf
= data_blob_null
;
1890 char *ea_name_ascii
= NULL
;
1892 struct smb2_hnd
*ph
= NULL
;
1893 TALLOC_CTX
*frame
= talloc_stackframe();
1895 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1897 * Can't use sync call while an async call is in flight
1899 status
= NT_STATUS_INVALID_PARAMETER
;
1903 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1904 status
= NT_STATUS_INVALID_PARAMETER
;
1908 status
= map_fnum_to_smb2_handle(cli
,
1911 if (!NT_STATUS_IS_OK(status
)) {
1915 /* Marshall the SMB2 EA data. */
1916 if (ea_len
> 0xFFFF) {
1917 status
= NT_STATUS_INVALID_PARAMETER
;
1921 if (!push_ascii_talloc(frame
,
1925 status
= NT_STATUS_INVALID_PARAMETER
;
1929 if (namelen
< 2 || namelen
> 0xFF) {
1930 status
= NT_STATUS_INVALID_PARAMETER
;
1934 bloblen
= 8 + ea_len
+ namelen
;
1935 /* Round up to a 4 byte boundary. */
1936 bloblen
= ((bloblen
+ 3)&~3);
1938 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
1939 if (inbuf
.data
== NULL
) {
1940 status
= NT_STATUS_NO_MEMORY
;
1943 /* namelen doesn't include the NULL byte. */
1944 SCVAL(inbuf
.data
, 5, namelen
- 1);
1945 SSVAL(inbuf
.data
, 6, ea_len
);
1946 memcpy(inbuf
.data
+ 8, ea_name_ascii
, namelen
);
1947 memcpy(inbuf
.data
+ 8 + namelen
, ea_val
, ea_len
);
1949 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1950 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
1952 status
= smb2cli_set_info(cli
->conn
,
1956 1, /* in_info_type */
1957 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
1958 &inbuf
, /* in_input_buffer */
1959 0, /* in_additional_info */
1969 /***************************************************************
1970 Wrapper that allows SMB2 to set an EA on a pathname.
1972 ***************************************************************/
1974 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
1976 const char *ea_name
,
1981 uint16_t fnum
= 0xffff;
1983 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1985 * Can't use sync call while an async call is in flight
1987 status
= NT_STATUS_INVALID_PARAMETER
;
1991 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1992 status
= NT_STATUS_INVALID_PARAMETER
;
1996 status
= get_fnum_from_path(cli
,
2001 if (!NT_STATUS_IS_OK(status
)) {
2005 status
= cli_set_ea_fnum(cli
,
2010 if (!NT_STATUS_IS_OK(status
)) {
2016 if (fnum
!= 0xffff) {
2017 cli_smb2_close_fnum(cli
, fnum
);
2023 /***************************************************************
2024 Wrapper that allows SMB2 to get an EA list on a pathname.
2026 ***************************************************************/
2028 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
2032 struct ea_struct
**pea_array
)
2035 uint16_t fnum
= 0xffff;
2036 DATA_BLOB outbuf
= data_blob_null
;
2037 struct smb2_hnd
*ph
= NULL
;
2038 struct ea_list
*ea_list
= NULL
;
2039 struct ea_list
*eal
= NULL
;
2040 size_t ea_count
= 0;
2041 TALLOC_CTX
*frame
= talloc_stackframe();
2046 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2048 * Can't use sync call while an async call is in flight
2050 status
= NT_STATUS_INVALID_PARAMETER
;
2054 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2055 status
= NT_STATUS_INVALID_PARAMETER
;
2059 status
= get_fnum_from_path(cli
,
2064 if (!NT_STATUS_IS_OK(status
)) {
2068 status
= map_fnum_to_smb2_handle(cli
,
2071 if (!NT_STATUS_IS_OK(status
)) {
2075 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2076 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2078 status
= smb2cli_query_info(cli
->conn
,
2082 1, /* in_info_type */
2083 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
2084 0xFFFF, /* in_max_output_length */
2085 NULL
, /* in_input_buffer */
2086 0, /* in_additional_info */
2093 if (!NT_STATUS_IS_OK(status
)) {
2097 /* Parse the reply. */
2098 ea_list
= read_nttrans_ea_list(ctx
,
2099 (const char *)outbuf
.data
,
2101 if (ea_list
== NULL
) {
2102 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2106 /* Convert to an array. */
2107 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2112 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
2113 if (*pea_array
== NULL
) {
2114 status
= NT_STATUS_NO_MEMORY
;
2118 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2119 (*pea_array
)[ea_count
++] = ea_list
->ea
;
2121 *pnum_eas
= ea_count
;
2126 if (fnum
!= 0xffff) {
2127 cli_smb2_close_fnum(cli
, fnum
);
2134 struct cli_smb2_read_state
{
2135 struct tevent_context
*ev
;
2136 struct cli_state
*cli
;
2137 struct smb2_hnd
*ph
;
2138 uint64_t start_offset
;
2144 static void cli_smb2_read_done(struct tevent_req
*subreq
);
2146 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
2147 struct tevent_context
*ev
,
2148 struct cli_state
*cli
,
2154 struct tevent_req
*req
, *subreq
;
2155 struct cli_smb2_read_state
*state
;
2157 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
2163 state
->start_offset
= (uint64_t)offset
;
2164 state
->size
= (uint32_t)size
;
2165 state
->received
= 0;
2168 status
= map_fnum_to_smb2_handle(cli
,
2171 if (tevent_req_nterror(req
, status
)) {
2172 return tevent_req_post(req
, ev
);
2175 subreq
= smb2cli_read_send(state
,
2178 state
->cli
->timeout
,
2179 state
->cli
->smb2
.session
,
2180 state
->cli
->smb2
.tcon
,
2182 state
->start_offset
,
2183 state
->ph
->fid_persistent
,
2184 state
->ph
->fid_volatile
,
2185 0, /* minimum_count */
2186 0); /* remaining_bytes */
2188 if (tevent_req_nomem(subreq
, req
)) {
2189 return tevent_req_post(req
, ev
);
2191 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
2195 static void cli_smb2_read_done(struct tevent_req
*subreq
)
2197 struct tevent_req
*req
= tevent_req_callback_data(
2198 subreq
, struct tevent_req
);
2199 struct cli_smb2_read_state
*state
= tevent_req_data(
2200 req
, struct cli_smb2_read_state
);
2203 status
= smb2cli_read_recv(subreq
, state
,
2204 &state
->buf
, &state
->received
);
2205 if (tevent_req_nterror(req
, status
)) {
2209 if (state
->received
> state
->size
) {
2210 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2214 tevent_req_done(req
);
2217 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
2222 struct cli_smb2_read_state
*state
= tevent_req_data(
2223 req
, struct cli_smb2_read_state
);
2225 if (tevent_req_is_nterror(req
, &status
)) {
2229 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2230 * better make sure that you copy it away before you talloc_free(req).
2231 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2233 *received
= (ssize_t
)state
->received
;
2234 *rcvbuf
= state
->buf
;
2235 return NT_STATUS_OK
;
2238 struct cli_smb2_write_state
{
2239 struct tevent_context
*ev
;
2240 struct cli_state
*cli
;
2241 struct smb2_hnd
*ph
;
2249 static void cli_smb2_write_written(struct tevent_req
*req
);
2251 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
2252 struct tevent_context
*ev
,
2253 struct cli_state
*cli
,
2261 struct tevent_req
*req
, *subreq
= NULL
;
2262 struct cli_smb2_write_state
*state
= NULL
;
2264 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
2270 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2271 state
->flags
= (uint32_t)mode
;
2273 state
->offset
= (uint64_t)offset
;
2274 state
->size
= (uint32_t)size
;
2277 status
= map_fnum_to_smb2_handle(cli
,
2280 if (tevent_req_nterror(req
, status
)) {
2281 return tevent_req_post(req
, ev
);
2284 subreq
= smb2cli_write_send(state
,
2287 state
->cli
->timeout
,
2288 state
->cli
->smb2
.session
,
2289 state
->cli
->smb2
.tcon
,
2292 state
->ph
->fid_persistent
,
2293 state
->ph
->fid_volatile
,
2294 0, /* remaining_bytes */
2295 state
->flags
, /* flags */
2298 if (tevent_req_nomem(subreq
, req
)) {
2299 return tevent_req_post(req
, ev
);
2301 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
2305 static void cli_smb2_write_written(struct tevent_req
*subreq
)
2307 struct tevent_req
*req
= tevent_req_callback_data(
2308 subreq
, struct tevent_req
);
2309 struct cli_smb2_write_state
*state
= tevent_req_data(
2310 req
, struct cli_smb2_write_state
);
2314 status
= smb2cli_write_recv(subreq
, &written
);
2315 TALLOC_FREE(subreq
);
2316 if (tevent_req_nterror(req
, status
)) {
2320 state
->written
= written
;
2322 tevent_req_done(req
);
2325 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
2328 struct cli_smb2_write_state
*state
= tevent_req_data(
2329 req
, struct cli_smb2_write_state
);
2332 if (tevent_req_is_nterror(req
, &status
)) {
2333 tevent_req_received(req
);
2337 if (pwritten
!= NULL
) {
2338 *pwritten
= (size_t)state
->written
;
2340 tevent_req_received(req
);
2341 return NT_STATUS_OK
;
2344 /***************************************************************
2345 Wrapper that allows SMB2 async write using an fnum.
2346 This is mostly cut-and-paste from Volker's code inside
2347 source3/libsmb/clireadwrite.c, adapted for SMB2.
2349 Done this way so I can reuse all the logic inside cli_push()
2351 ***************************************************************/
2353 struct cli_smb2_writeall_state
{
2354 struct tevent_context
*ev
;
2355 struct cli_state
*cli
;
2356 struct smb2_hnd
*ph
;
2364 static void cli_smb2_writeall_written(struct tevent_req
*req
);
2366 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
2367 struct tevent_context
*ev
,
2368 struct cli_state
*cli
,
2376 struct tevent_req
*req
, *subreq
= NULL
;
2377 struct cli_smb2_writeall_state
*state
= NULL
;
2382 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
2388 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2389 state
->flags
= (uint32_t)mode
;
2391 state
->offset
= (uint64_t)offset
;
2392 state
->size
= (uint32_t)size
;
2395 status
= map_fnum_to_smb2_handle(cli
,
2398 if (tevent_req_nterror(req
, status
)) {
2399 return tevent_req_post(req
, ev
);
2402 to_write
= state
->size
;
2403 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
2404 to_write
= MIN(max_size
, to_write
);
2405 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
2407 to_write
= MIN(max_size
, to_write
);
2410 subreq
= smb2cli_write_send(state
,
2413 state
->cli
->timeout
,
2414 state
->cli
->smb2
.session
,
2415 state
->cli
->smb2
.tcon
,
2418 state
->ph
->fid_persistent
,
2419 state
->ph
->fid_volatile
,
2420 0, /* remaining_bytes */
2421 state
->flags
, /* flags */
2422 state
->buf
+ state
->written
);
2424 if (tevent_req_nomem(subreq
, req
)) {
2425 return tevent_req_post(req
, ev
);
2427 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
2431 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
2433 struct tevent_req
*req
= tevent_req_callback_data(
2434 subreq
, struct tevent_req
);
2435 struct cli_smb2_writeall_state
*state
= tevent_req_data(
2436 req
, struct cli_smb2_writeall_state
);
2438 uint32_t written
, to_write
;
2442 status
= smb2cli_write_recv(subreq
, &written
);
2443 TALLOC_FREE(subreq
);
2444 if (tevent_req_nterror(req
, status
)) {
2448 state
->written
+= written
;
2450 if (state
->written
> state
->size
) {
2451 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2455 to_write
= state
->size
- state
->written
;
2457 if (to_write
== 0) {
2458 tevent_req_done(req
);
2462 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
2463 to_write
= MIN(max_size
, to_write
);
2464 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
2466 to_write
= MIN(max_size
, to_write
);
2469 subreq
= smb2cli_write_send(state
,
2472 state
->cli
->timeout
,
2473 state
->cli
->smb2
.session
,
2474 state
->cli
->smb2
.tcon
,
2476 state
->offset
+ state
->written
,
2477 state
->ph
->fid_persistent
,
2478 state
->ph
->fid_volatile
,
2479 0, /* remaining_bytes */
2480 state
->flags
, /* flags */
2481 state
->buf
+ state
->written
);
2483 if (tevent_req_nomem(subreq
, req
)) {
2486 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
2489 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
2492 struct cli_smb2_writeall_state
*state
= tevent_req_data(
2493 req
, struct cli_smb2_writeall_state
);
2496 if (tevent_req_is_nterror(req
, &status
)) {
2499 if (pwritten
!= NULL
) {
2500 *pwritten
= (size_t)state
->written
;
2502 return NT_STATUS_OK
;