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"
33 #include "cli_smb2_fnum.h"
36 #include "../libcli/smb/smb2_create_blob.h"
37 #include "libsmb/proto.h"
38 #include "lib/util/tevent_ntstatus.h"
39 #include "../libcli/security/security.h"
40 #include "../librpc/gen_ndr/ndr_security.h"
41 #include "lib/util_ea.h"
42 #include "librpc/gen_ndr/ndr_ioctl.h"
46 uint64_t fid_persistent
;
47 uint64_t fid_volatile
;
51 * Handle mapping code.
54 /***************************************************************
55 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
56 Ensures handle is owned by cli struct.
57 ***************************************************************/
59 static NTSTATUS
map_smb2_handle_to_fnum(struct cli_state
*cli
,
60 const struct smb2_hnd
*ph
, /* In */
61 uint16_t *pfnum
) /* Out */
64 struct idr_context
*idp
= cli
->smb2
.open_handles
;
65 struct smb2_hnd
*owned_h
= talloc_memdup(cli
,
67 sizeof(struct smb2_hnd
));
69 if (owned_h
== NULL
) {
70 return NT_STATUS_NO_MEMORY
;
75 cli
->smb2
.open_handles
= idr_init(cli
);
76 if (cli
->smb2
.open_handles
== NULL
) {
78 return NT_STATUS_NO_MEMORY
;
80 idp
= cli
->smb2
.open_handles
;
83 ret
= idr_get_new_above(idp
, owned_h
, 1, 0xFFFE);
86 return NT_STATUS_NO_MEMORY
;
89 *pfnum
= (uint16_t)ret
;
93 /***************************************************************
94 Return the smb2_hnd pointer associated with the given fnum.
95 ***************************************************************/
97 static NTSTATUS
map_fnum_to_smb2_handle(struct cli_state
*cli
,
98 uint16_t fnum
, /* In */
99 struct smb2_hnd
**pph
) /* Out */
101 struct idr_context
*idp
= cli
->smb2
.open_handles
;
104 return NT_STATUS_INVALID_PARAMETER
;
106 *pph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
108 return NT_STATUS_INVALID_HANDLE
;
113 /***************************************************************
114 Delete the fnum to smb2_hnd mapping. Zeros out handle on
116 ***************************************************************/
118 static NTSTATUS
delete_smb2_handle_mapping(struct cli_state
*cli
,
119 struct smb2_hnd
**pph
, /* In */
120 uint16_t fnum
) /* In */
122 struct idr_context
*idp
= cli
->smb2
.open_handles
;
126 return NT_STATUS_INVALID_PARAMETER
;
129 ph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
131 return NT_STATUS_INVALID_PARAMETER
;
133 idr_remove(idp
, fnum
);
138 /***************************************************************
140 ***************************************************************/
142 static uint8_t flags_to_smb2_oplock(uint32_t create_flags
)
144 if (create_flags
& REQUEST_BATCH_OPLOCK
) {
145 return SMB2_OPLOCK_LEVEL_BATCH
;
146 } else if (create_flags
& REQUEST_OPLOCK
) {
147 return SMB2_OPLOCK_LEVEL_EXCLUSIVE
;
150 /* create_flags doesn't do a level2 request. */
151 return SMB2_OPLOCK_LEVEL_NONE
;
154 /***************************************************************
155 Small wrapper that allows SMB2 create to return a uint16_t fnum.
156 ***************************************************************/
158 struct cli_smb2_create_fnum_state
{
159 struct cli_state
*cli
;
160 struct smb_create_returns cr
;
162 struct tevent_req
*subreq
;
165 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
);
166 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
);
168 struct tevent_req
*cli_smb2_create_fnum_send(TALLOC_CTX
*mem_ctx
,
169 struct tevent_context
*ev
,
170 struct cli_state
*cli
,
172 uint32_t create_flags
,
173 uint32_t desired_access
,
174 uint32_t file_attributes
,
175 uint32_t share_access
,
176 uint32_t create_disposition
,
177 uint32_t create_options
)
179 struct tevent_req
*req
, *subreq
;
180 struct cli_smb2_create_fnum_state
*state
;
181 size_t fname_len
= 0;
182 const char *startp
= NULL
;
183 const char *endp
= NULL
;
184 time_t tstamp
= (time_t)0;
185 struct smb2_create_blobs
*cblobs
= NULL
;
187 req
= tevent_req_create(mem_ctx
, &state
,
188 struct cli_smb2_create_fnum_state
);
194 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
195 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
196 return tevent_req_post(req
, ev
);
199 if (cli
->backup_intent
) {
200 create_options
|= FILE_OPEN_FOR_BACKUP_INTENT
;
203 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
204 fname_len
= strlen(fname
);
205 if (clistr_is_previous_version_path(fname
, &startp
, &endp
, &tstamp
)) {
206 size_t len_before_gmt
= startp
- fname
;
207 size_t len_after_gmt
= fname
+ fname_len
- endp
;
212 char *new_fname
= talloc_array(state
, char,
213 len_before_gmt
+ len_after_gmt
+ 1);
215 if (tevent_req_nomem(new_fname
, req
)) {
216 return tevent_req_post(req
, ev
);
219 memcpy(new_fname
, fname
, len_before_gmt
);
220 memcpy(new_fname
+ len_before_gmt
, endp
, len_after_gmt
+ 1);
222 fname_len
= len_before_gmt
+ len_after_gmt
;
224 unix_to_nt_time(&ntt
, tstamp
);
225 twrp_blob
= data_blob_const((const void *)&ntt
, 8);
227 cblobs
= talloc_zero(state
, struct smb2_create_blobs
);
228 if (tevent_req_nomem(cblobs
, req
)) {
229 return tevent_req_post(req
, ev
);
232 status
= smb2_create_blob_add(state
, cblobs
,
233 SMB2_CREATE_TAG_TWRP
, twrp_blob
);
234 if (!NT_STATUS_IS_OK(status
)) {
235 tevent_req_nterror(req
, status
);
236 return tevent_req_post(req
, ev
);
240 /* SMB2 is pickier about pathnames. Ensure it doesn't
242 if (*fname
== '\\') {
247 /* Or end in a '\' */
248 if (fname_len
> 0 && fname
[fname_len
-1] == '\\') {
249 char *new_fname
= talloc_strdup(state
, fname
);
250 if (tevent_req_nomem(new_fname
, req
)) {
251 return tevent_req_post(req
, ev
);
253 new_fname
[fname_len
-1] = '\0';
257 subreq
= smb2cli_create_send(state
, ev
,
263 flags_to_smb2_oplock(create_flags
),
264 SMB2_IMPERSONATION_IMPERSONATION
,
271 if (tevent_req_nomem(subreq
, req
)) {
272 return tevent_req_post(req
, ev
);
274 tevent_req_set_callback(subreq
, cli_smb2_create_fnum_done
, req
);
276 state
->subreq
= subreq
;
277 tevent_req_set_cancel_fn(req
, cli_smb2_create_fnum_cancel
);
282 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
)
284 struct tevent_req
*req
= tevent_req_callback_data(
285 subreq
, struct tevent_req
);
286 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
287 req
, struct cli_smb2_create_fnum_state
);
291 status
= smb2cli_create_recv(subreq
, &h
.fid_persistent
,
292 &h
.fid_volatile
, &state
->cr
, NULL
, NULL
);
294 if (tevent_req_nterror(req
, status
)) {
298 status
= map_smb2_handle_to_fnum(state
->cli
, &h
, &state
->fnum
);
299 if (tevent_req_nterror(req
, status
)) {
302 tevent_req_done(req
);
305 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
)
307 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
308 req
, struct cli_smb2_create_fnum_state
);
309 return tevent_req_cancel(state
->subreq
);
312 NTSTATUS
cli_smb2_create_fnum_recv(struct tevent_req
*req
, uint16_t *pfnum
,
313 struct smb_create_returns
*cr
)
315 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
316 req
, struct cli_smb2_create_fnum_state
);
319 if (tevent_req_is_nterror(req
, &status
)) {
320 state
->cli
->raw_status
= status
;
324 *pfnum
= state
->fnum
;
329 state
->cli
->raw_status
= NT_STATUS_OK
;
333 NTSTATUS
cli_smb2_create_fnum(struct cli_state
*cli
,
335 uint32_t create_flags
,
336 uint32_t desired_access
,
337 uint32_t file_attributes
,
338 uint32_t share_access
,
339 uint32_t create_disposition
,
340 uint32_t create_options
,
342 struct smb_create_returns
*cr
)
344 TALLOC_CTX
*frame
= talloc_stackframe();
345 struct tevent_context
*ev
;
346 struct tevent_req
*req
;
347 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
349 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
351 * Can't use sync call while an async call is in flight
353 status
= NT_STATUS_INVALID_PARAMETER
;
356 ev
= samba_tevent_context_init(frame
);
360 req
= cli_smb2_create_fnum_send(frame
, ev
, cli
, fname
, create_flags
,
361 desired_access
, file_attributes
,
362 share_access
, create_disposition
,
367 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
370 status
= cli_smb2_create_fnum_recv(req
, pfid
, cr
);
376 /***************************************************************
377 Small wrapper that allows SMB2 close to use a uint16_t fnum.
378 ***************************************************************/
380 struct cli_smb2_close_fnum_state
{
381 struct cli_state
*cli
;
386 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
);
388 struct tevent_req
*cli_smb2_close_fnum_send(TALLOC_CTX
*mem_ctx
,
389 struct tevent_context
*ev
,
390 struct cli_state
*cli
,
393 struct tevent_req
*req
, *subreq
;
394 struct cli_smb2_close_fnum_state
*state
;
397 req
= tevent_req_create(mem_ctx
, &state
,
398 struct cli_smb2_close_fnum_state
);
405 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
406 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
407 return tevent_req_post(req
, ev
);
410 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
411 if (tevent_req_nterror(req
, status
)) {
412 return tevent_req_post(req
, ev
);
415 subreq
= smb2cli_close_send(state
, ev
, cli
->conn
, cli
->timeout
,
416 cli
->smb2
.session
, cli
->smb2
.tcon
,
417 0, state
->ph
->fid_persistent
,
418 state
->ph
->fid_volatile
);
419 if (tevent_req_nomem(subreq
, req
)) {
420 return tevent_req_post(req
, ev
);
422 tevent_req_set_callback(subreq
, cli_smb2_close_fnum_done
, req
);
426 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
)
428 struct tevent_req
*req
= tevent_req_callback_data(
429 subreq
, struct tevent_req
);
430 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
431 req
, struct cli_smb2_close_fnum_state
);
434 status
= smb2cli_close_recv(subreq
);
435 if (tevent_req_nterror(req
, status
)) {
439 /* Delete the fnum -> handle mapping. */
440 status
= delete_smb2_handle_mapping(state
->cli
, &state
->ph
,
442 if (tevent_req_nterror(req
, status
)) {
445 tevent_req_done(req
);
448 NTSTATUS
cli_smb2_close_fnum_recv(struct tevent_req
*req
)
450 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
451 req
, struct cli_smb2_close_fnum_state
);
452 NTSTATUS status
= tevent_req_simple_recv_ntstatus(req
);
453 state
->cli
->raw_status
= status
;
457 NTSTATUS
cli_smb2_close_fnum(struct cli_state
*cli
, uint16_t fnum
)
459 TALLOC_CTX
*frame
= talloc_stackframe();
460 struct tevent_context
*ev
;
461 struct tevent_req
*req
;
462 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
464 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
466 * Can't use sync call while an async call is in flight
468 status
= NT_STATUS_INVALID_PARAMETER
;
471 ev
= samba_tevent_context_init(frame
);
475 req
= cli_smb2_close_fnum_send(frame
, ev
, cli
, fnum
);
479 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
482 status
= cli_smb2_close_fnum_recv(req
);
488 /***************************************************************
489 Small wrapper that allows SMB2 to create a directory
491 ***************************************************************/
493 NTSTATUS
cli_smb2_mkdir(struct cli_state
*cli
, const char *dname
)
498 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
500 * Can't use sync call while an async call is in flight
502 return NT_STATUS_INVALID_PARAMETER
;
505 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
506 return NT_STATUS_INVALID_PARAMETER
;
509 status
= cli_smb2_create_fnum(cli
,
511 0, /* create_flags */
512 FILE_READ_ATTRIBUTES
, /* desired_access */
513 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
514 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
515 FILE_CREATE
, /* create_disposition */
516 FILE_DIRECTORY_FILE
, /* create_options */
520 if (!NT_STATUS_IS_OK(status
)) {
523 return cli_smb2_close_fnum(cli
, fnum
);
526 /***************************************************************
527 Small wrapper that allows SMB2 to delete a directory
529 ***************************************************************/
531 NTSTATUS
cli_smb2_rmdir(struct cli_state
*cli
, const char *dname
)
536 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
538 * Can't use sync call while an async call is in flight
540 return NT_STATUS_INVALID_PARAMETER
;
543 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
544 return NT_STATUS_INVALID_PARAMETER
;
547 status
= cli_smb2_create_fnum(cli
,
549 0, /* create_flags */
550 DELETE_ACCESS
, /* desired_access */
551 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
552 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
553 FILE_OPEN
, /* create_disposition */
554 FILE_DIRECTORY_FILE
|FILE_DELETE_ON_CLOSE
, /* create_options */
558 if (!NT_STATUS_IS_OK(status
)) {
561 return cli_smb2_close_fnum(cli
, fnum
);
564 /***************************************************************
565 Small wrapper that allows SMB2 to unlink a pathname.
567 ***************************************************************/
569 NTSTATUS
cli_smb2_unlink(struct cli_state
*cli
, const char *fname
)
574 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
576 * Can't use sync call while an async call is in flight
578 return NT_STATUS_INVALID_PARAMETER
;
581 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
582 return NT_STATUS_INVALID_PARAMETER
;
585 status
= cli_smb2_create_fnum(cli
,
587 0, /* create_flags */
588 DELETE_ACCESS
, /* desired_access */
589 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
590 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
591 FILE_OPEN
, /* create_disposition */
592 FILE_DELETE_ON_CLOSE
, /* create_options */
596 if (!NT_STATUS_IS_OK(status
)) {
599 return cli_smb2_close_fnum(cli
, fnum
);
602 /***************************************************************
603 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
604 ***************************************************************/
606 static NTSTATUS
parse_finfo_id_both_directory_info(uint8_t *dir_data
,
607 uint32_t dir_data_length
,
608 struct file_info
*finfo
,
609 uint32_t *next_offset
)
615 if (dir_data_length
< 4) {
616 return NT_STATUS_INFO_LENGTH_MISMATCH
;
619 *next_offset
= IVAL(dir_data
, 0);
621 if (*next_offset
> dir_data_length
) {
622 return NT_STATUS_INFO_LENGTH_MISMATCH
;
625 if (*next_offset
!= 0) {
626 /* Ensure we only read what in this record. */
627 dir_data_length
= *next_offset
;
630 if (dir_data_length
< 105) {
631 return NT_STATUS_INFO_LENGTH_MISMATCH
;
634 finfo
->atime_ts
= interpret_long_date((const char *)dir_data
+ 16);
635 finfo
->mtime_ts
= interpret_long_date((const char *)dir_data
+ 24);
636 finfo
->ctime_ts
= interpret_long_date((const char *)dir_data
+ 32);
637 finfo
->size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 40, 0);
638 finfo
->mode
= CVAL(dir_data
+ 56, 0);
639 namelen
= IVAL(dir_data
+ 60,0);
640 if (namelen
> (dir_data_length
- 104)) {
641 return NT_STATUS_INFO_LENGTH_MISMATCH
;
643 slen
= CVAL(dir_data
+ 68, 0);
645 return NT_STATUS_INFO_LENGTH_MISMATCH
;
647 ret
= pull_string_talloc(finfo
,
649 FLAGS2_UNICODE_STRINGS
,
654 if (ret
== (size_t)-1) {
655 /* Bad conversion. */
656 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
659 ret
= pull_string_talloc(finfo
,
661 FLAGS2_UNICODE_STRINGS
,
666 if (ret
== (size_t)-1) {
667 /* Bad conversion. */
668 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
673 /*******************************************************************
674 Given a filename - get its directory name
675 ********************************************************************/
677 static bool windows_parent_dirname(TALLOC_CTX
*mem_ctx
,
685 p
= strrchr_m(dir
, '\\'); /* Find final '\\', if any */
688 if (!(*parent
= talloc_strdup(mem_ctx
, "\\"))) {
699 if (!(*parent
= (char *)talloc_memdup(mem_ctx
, dir
, len
+1))) {
702 (*parent
)[len
] = '\0';
710 /***************************************************************
711 Wrapper that allows SMB2 to list a directory.
713 ***************************************************************/
715 NTSTATUS
cli_smb2_list(struct cli_state
*cli
,
716 const char *pathname
,
718 NTSTATUS (*fn
)(const char *,
725 uint16_t fnum
= 0xffff;
726 char *parent_dir
= NULL
;
727 const char *mask
= NULL
;
728 struct smb2_hnd
*ph
= NULL
;
729 bool processed_file
= false;
730 TALLOC_CTX
*frame
= talloc_stackframe();
731 TALLOC_CTX
*subframe
= NULL
;
734 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
736 * Can't use sync call while an async call is in flight
738 status
= NT_STATUS_INVALID_PARAMETER
;
742 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
743 status
= NT_STATUS_INVALID_PARAMETER
;
747 /* Get the directory name. */
748 if (!windows_parent_dirname(frame
,
752 status
= NT_STATUS_NO_MEMORY
;
756 mask_has_wild
= ms_has_wild(mask
);
758 status
= cli_smb2_create_fnum(cli
,
760 0, /* create_flags */
761 SEC_DIR_LIST
|SEC_DIR_READ_ATTRIBUTE
,/* desired_access */
762 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
763 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
764 FILE_OPEN
, /* create_disposition */
765 FILE_DIRECTORY_FILE
, /* create_options */
769 if (!NT_STATUS_IS_OK(status
)) {
773 status
= map_fnum_to_smb2_handle(cli
,
776 if (!NT_STATUS_IS_OK(status
)) {
781 uint8_t *dir_data
= NULL
;
782 uint32_t dir_data_length
= 0;
783 uint32_t next_offset
= 0;
784 subframe
= talloc_stackframe();
786 status
= smb2cli_query_directory(cli
->conn
,
790 SMB2_FIND_ID_BOTH_DIRECTORY_INFO
,
801 if (!NT_STATUS_IS_OK(status
)) {
802 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
809 struct file_info
*finfo
= talloc_zero(subframe
,
813 status
= NT_STATUS_NO_MEMORY
;
817 status
= parse_finfo_id_both_directory_info(dir_data
,
822 if (!NT_STATUS_IS_OK(status
)) {
826 if (dir_check_ftype((uint32_t)finfo
->mode
,
827 (uint32_t)attribute
)) {
829 * Only process if attributes match.
830 * On SMB1 server does this, so on
831 * SMB2 we need to emulate in the
834 * https://bugzilla.samba.org/show_bug.cgi?id=10260
836 processed_file
= true;
838 status
= fn(cli
->dfs_mountpoint
,
843 if (!NT_STATUS_IS_OK(status
)) {
850 /* Move to next entry. */
852 dir_data
+= next_offset
;
853 dir_data_length
-= next_offset
;
855 } while (next_offset
!= 0);
857 TALLOC_FREE(subframe
);
859 if (!mask_has_wild
) {
861 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
862 * when handed a non-wildcard path. Do it
863 * for the server (with a non-wildcard path
864 * there should only ever be one file returned.
866 status
= STATUS_NO_MORE_FILES
;
870 } while (NT_STATUS_IS_OK(status
));
872 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
873 status
= NT_STATUS_OK
;
876 if (NT_STATUS_IS_OK(status
) && !processed_file
) {
878 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
879 * if no files match. Emulate this in the client.
881 status
= NT_STATUS_NO_SUCH_FILE
;
886 if (fnum
!= 0xffff) {
887 cli_smb2_close_fnum(cli
, fnum
);
889 TALLOC_FREE(subframe
);
894 /***************************************************************
895 Wrapper that allows SMB2 to query a path info (basic level).
897 ***************************************************************/
899 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
901 SMB_STRUCT_STAT
*sbuf
,
902 uint32_t *attributes
)
905 struct smb_create_returns cr
;
906 uint16_t fnum
= 0xffff;
907 size_t namelen
= strlen(name
);
909 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
911 * Can't use sync call while an async call is in flight
913 return NT_STATUS_INVALID_PARAMETER
;
916 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
917 return NT_STATUS_INVALID_PARAMETER
;
920 /* SMB2 is pickier about pathnames. Ensure it doesn't
922 if (namelen
> 0 && name
[namelen
-1] == '\\') {
923 char *modname
= talloc_strdup(talloc_tos(), name
);
924 modname
[namelen
-1] = '\0';
928 /* This is commonly used as a 'cd'. Try qpathinfo on
929 a directory handle first. */
931 status
= cli_smb2_create_fnum(cli
,
933 0, /* create_flags */
934 FILE_READ_ATTRIBUTES
, /* desired_access */
935 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
936 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
937 FILE_OPEN
, /* create_disposition */
938 FILE_DIRECTORY_FILE
, /* create_options */
942 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
944 status
= cli_smb2_create_fnum(cli
,
946 0, /* create_flags */
947 FILE_READ_ATTRIBUTES
, /* desired_access */
948 0, /* file attributes */
949 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
950 FILE_OPEN
, /* create_disposition */
951 0, /* create_options */
956 if (!NT_STATUS_IS_OK(status
)) {
960 cli_smb2_close_fnum(cli
, fnum
);
964 sbuf
->st_ex_atime
= nt_time_to_unix_timespec(cr
.last_access_time
);
965 sbuf
->st_ex_mtime
= nt_time_to_unix_timespec(cr
.last_write_time
);
966 sbuf
->st_ex_ctime
= nt_time_to_unix_timespec(cr
.change_time
);
967 sbuf
->st_ex_size
= cr
.end_of_file
;
968 *attributes
= cr
.file_attributes
;
973 /***************************************************************
974 Helper function for pathname operations.
975 ***************************************************************/
977 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
979 uint32_t desired_access
,
983 size_t namelen
= strlen(name
);
984 TALLOC_CTX
*frame
= talloc_stackframe();
986 /* SMB2 is pickier about pathnames. Ensure it doesn't
988 if (namelen
> 0 && name
[namelen
-1] == '\\') {
989 char *modname
= talloc_strdup(frame
, name
);
990 if (modname
== NULL
) {
991 status
= NT_STATUS_NO_MEMORY
;
994 modname
[namelen
-1] = '\0';
998 /* Try to open a file handle first. */
999 status
= cli_smb2_create_fnum(cli
,
1001 0, /* create_flags */
1003 0, /* file attributes */
1004 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1005 FILE_OPEN
, /* create_disposition */
1006 0, /* create_options */
1010 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
1011 status
= cli_smb2_create_fnum(cli
,
1013 0, /* create_flags */
1015 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1016 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1017 FILE_OPEN
, /* create_disposition */
1018 FILE_DIRECTORY_FILE
, /* create_options */
1029 /***************************************************************
1030 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1032 ***************************************************************/
1034 NTSTATUS
cli_smb2_qpathinfo_alt_name(struct cli_state
*cli
,
1039 DATA_BLOB outbuf
= data_blob_null
;
1040 uint16_t fnum
= 0xffff;
1041 struct smb2_hnd
*ph
= NULL
;
1042 uint32_t altnamelen
= 0;
1043 TALLOC_CTX
*frame
= talloc_stackframe();
1045 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1047 * Can't use sync call while an async call is in flight
1049 status
= NT_STATUS_INVALID_PARAMETER
;
1053 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1054 status
= NT_STATUS_INVALID_PARAMETER
;
1058 status
= get_fnum_from_path(cli
,
1060 FILE_READ_ATTRIBUTES
,
1063 if (!NT_STATUS_IS_OK(status
)) {
1067 status
= map_fnum_to_smb2_handle(cli
,
1070 if (!NT_STATUS_IS_OK(status
)) {
1074 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1075 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1077 status
= smb2cli_query_info(cli
->conn
,
1081 1, /* in_info_type */
1082 (SMB_FILE_ALTERNATE_NAME_INFORMATION
- 1000), /* in_file_info_class */
1083 0xFFFF, /* in_max_output_length */
1084 NULL
, /* in_input_buffer */
1085 0, /* in_additional_info */
1092 if (!NT_STATUS_IS_OK(status
)) {
1096 /* Parse the reply. */
1097 if (outbuf
.length
< 4) {
1098 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1102 altnamelen
= IVAL(outbuf
.data
, 0);
1103 if (altnamelen
> outbuf
.length
- 4) {
1104 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1108 if (altnamelen
> 0) {
1110 char *short_name
= NULL
;
1111 ret
= pull_string_talloc(frame
,
1113 FLAGS2_UNICODE_STRINGS
,
1118 if (ret
== (size_t)-1) {
1119 /* Bad conversion. */
1120 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1124 fstrcpy(alt_name
, short_name
);
1129 status
= NT_STATUS_OK
;
1133 if (fnum
!= 0xffff) {
1134 cli_smb2_close_fnum(cli
, fnum
);
1141 /***************************************************************
1142 Wrapper that allows SMB2 to query a fnum info (basic level).
1144 ***************************************************************/
1146 NTSTATUS
cli_smb2_qfileinfo_basic(struct cli_state
*cli
,
1150 struct timespec
*create_time
,
1151 struct timespec
*access_time
,
1152 struct timespec
*write_time
,
1153 struct timespec
*change_time
,
1157 DATA_BLOB outbuf
= data_blob_null
;
1158 struct smb2_hnd
*ph
= NULL
;
1159 TALLOC_CTX
*frame
= talloc_stackframe();
1161 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1163 * Can't use sync call while an async call is in flight
1165 status
= NT_STATUS_INVALID_PARAMETER
;
1169 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1170 status
= NT_STATUS_INVALID_PARAMETER
;
1174 status
= map_fnum_to_smb2_handle(cli
,
1177 if (!NT_STATUS_IS_OK(status
)) {
1181 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1182 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1184 status
= smb2cli_query_info(cli
->conn
,
1188 1, /* in_info_type */
1189 (SMB_FILE_ALL_INFORMATION
- 1000), /* in_file_info_class */
1190 0xFFFF, /* in_max_output_length */
1191 NULL
, /* in_input_buffer */
1192 0, /* in_additional_info */
1198 if (!NT_STATUS_IS_OK(status
)) {
1202 /* Parse the reply. */
1203 if (outbuf
.length
< 0x60) {
1204 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1209 *create_time
= interpret_long_date((const char *)outbuf
.data
+ 0x0);
1212 *access_time
= interpret_long_date((const char *)outbuf
.data
+ 0x8);
1215 *write_time
= interpret_long_date((const char *)outbuf
.data
+ 0x10);
1218 *change_time
= interpret_long_date((const char *)outbuf
.data
+ 0x18);
1221 uint32_t attr
= IVAL(outbuf
.data
, 0x20);
1222 *mode
= (uint16_t)attr
;
1225 uint64_t file_size
= BVAL(outbuf
.data
, 0x30);
1226 *size
= (off_t
)file_size
;
1229 uint64_t file_index
= BVAL(outbuf
.data
, 0x40);
1230 *ino
= (SMB_INO_T
)file_index
;
1239 /***************************************************************
1240 Wrapper that allows SMB2 to query an fnum.
1241 Implement on top of cli_smb2_qfileinfo_basic().
1243 ***************************************************************/
1245 NTSTATUS
cli_smb2_getattrE(struct cli_state
*cli
,
1249 time_t *change_time
,
1250 time_t *access_time
,
1253 struct timespec access_time_ts
;
1254 struct timespec write_time_ts
;
1255 struct timespec change_time_ts
;
1256 NTSTATUS status
= cli_smb2_qfileinfo_basic(cli
,
1266 if (!NT_STATUS_IS_OK(status
)) {
1271 *change_time
= change_time_ts
.tv_sec
;
1274 *access_time
= access_time_ts
.tv_sec
;
1277 *write_time
= write_time_ts
.tv_sec
;
1279 return NT_STATUS_OK
;
1282 /***************************************************************
1283 Wrapper that allows SMB2 to get pathname attributes.
1285 ***************************************************************/
1287 NTSTATUS
cli_smb2_getatr(struct cli_state
*cli
,
1294 uint16_t fnum
= 0xffff;
1295 struct smb2_hnd
*ph
= NULL
;
1296 TALLOC_CTX
*frame
= talloc_stackframe();
1298 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1300 * Can't use sync call while an async call is in flight
1302 status
= NT_STATUS_INVALID_PARAMETER
;
1306 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1307 status
= NT_STATUS_INVALID_PARAMETER
;
1311 status
= get_fnum_from_path(cli
,
1313 FILE_READ_ATTRIBUTES
,
1316 if (!NT_STATUS_IS_OK(status
)) {
1320 status
= map_fnum_to_smb2_handle(cli
,
1323 if (!NT_STATUS_IS_OK(status
)) {
1326 status
= cli_smb2_getattrE(cli
,
1333 if (!NT_STATUS_IS_OK(status
)) {
1339 if (fnum
!= 0xffff) {
1340 cli_smb2_close_fnum(cli
, fnum
);
1347 /***************************************************************
1348 Wrapper that allows SMB2 to query a pathname info (basic level).
1349 Implement on top of cli_smb2_qfileinfo_basic().
1351 ***************************************************************/
1353 NTSTATUS
cli_smb2_qpathinfo2(struct cli_state
*cli
,
1355 struct timespec
*create_time
,
1356 struct timespec
*access_time
,
1357 struct timespec
*write_time
,
1358 struct timespec
*change_time
,
1364 struct smb2_hnd
*ph
= NULL
;
1365 uint16_t fnum
= 0xffff;
1366 TALLOC_CTX
*frame
= talloc_stackframe();
1368 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1370 * Can't use sync call while an async call is in flight
1372 status
= NT_STATUS_INVALID_PARAMETER
;
1376 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1377 status
= NT_STATUS_INVALID_PARAMETER
;
1381 status
= get_fnum_from_path(cli
,
1383 FILE_READ_ATTRIBUTES
,
1386 if (!NT_STATUS_IS_OK(status
)) {
1390 status
= map_fnum_to_smb2_handle(cli
,
1393 if (!NT_STATUS_IS_OK(status
)) {
1397 status
= cli_smb2_qfileinfo_basic(cli
,
1409 if (fnum
!= 0xffff) {
1410 cli_smb2_close_fnum(cli
, fnum
);
1417 /***************************************************************
1418 Wrapper that allows SMB2 to query pathname streams.
1420 ***************************************************************/
1422 NTSTATUS
cli_smb2_qpathinfo_streams(struct cli_state
*cli
,
1424 TALLOC_CTX
*mem_ctx
,
1425 unsigned int *pnum_streams
,
1426 struct stream_struct
**pstreams
)
1429 struct smb2_hnd
*ph
= NULL
;
1430 uint16_t fnum
= 0xffff;
1431 DATA_BLOB outbuf
= data_blob_null
;
1432 TALLOC_CTX
*frame
= talloc_stackframe();
1434 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1436 * Can't use sync call while an async call is in flight
1438 status
= NT_STATUS_INVALID_PARAMETER
;
1442 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1443 status
= NT_STATUS_INVALID_PARAMETER
;
1447 status
= get_fnum_from_path(cli
,
1449 FILE_READ_ATTRIBUTES
,
1452 if (!NT_STATUS_IS_OK(status
)) {
1456 status
= map_fnum_to_smb2_handle(cli
,
1459 if (!NT_STATUS_IS_OK(status
)) {
1463 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1464 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1466 status
= smb2cli_query_info(cli
->conn
,
1470 1, /* in_info_type */
1471 (SMB_FILE_STREAM_INFORMATION
- 1000), /* in_file_info_class */
1472 0xFFFF, /* in_max_output_length */
1473 NULL
, /* in_input_buffer */
1474 0, /* in_additional_info */
1481 if (!NT_STATUS_IS_OK(status
)) {
1485 /* Parse the reply. */
1486 if (!parse_streams_blob(mem_ctx
,
1491 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1497 if (fnum
!= 0xffff) {
1498 cli_smb2_close_fnum(cli
, fnum
);
1505 /***************************************************************
1506 Wrapper that allows SMB2 to set pathname attributes.
1508 ***************************************************************/
1510 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
1516 uint16_t fnum
= 0xffff;
1517 struct smb2_hnd
*ph
= NULL
;
1518 uint8_t inbuf_store
[40];
1519 DATA_BLOB inbuf
= data_blob_null
;
1520 TALLOC_CTX
*frame
= talloc_stackframe();
1522 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1524 * Can't use sync call while an async call is in flight
1526 status
= NT_STATUS_INVALID_PARAMETER
;
1530 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1531 status
= NT_STATUS_INVALID_PARAMETER
;
1535 status
= get_fnum_from_path(cli
,
1537 FILE_WRITE_ATTRIBUTES
,
1540 if (!NT_STATUS_IS_OK(status
)) {
1544 status
= map_fnum_to_smb2_handle(cli
,
1547 if (!NT_STATUS_IS_OK(status
)) {
1551 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1552 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1554 inbuf
.data
= inbuf_store
;
1555 inbuf
.length
= sizeof(inbuf_store
);
1556 data_blob_clear(&inbuf
);
1558 SSVAL(inbuf
.data
, 32, attr
);
1560 put_long_date((char *)inbuf
.data
+ 16,mtime
);
1562 /* Set all the other times to -1. */
1563 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1564 SBVAL(inbuf
.data
, 8, 0xFFFFFFFFFFFFFFFFLL
);
1565 SBVAL(inbuf
.data
, 24, 0xFFFFFFFFFFFFFFFFLL
);
1567 status
= smb2cli_set_info(cli
->conn
,
1571 1, /* in_info_type */
1572 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1573 &inbuf
, /* in_input_buffer */
1574 0, /* in_additional_info */
1579 if (fnum
!= 0xffff) {
1580 cli_smb2_close_fnum(cli
, fnum
);
1587 /***************************************************************
1588 Wrapper that allows SMB2 to set file handle times.
1590 ***************************************************************/
1592 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
1599 struct smb2_hnd
*ph
= NULL
;
1600 uint8_t inbuf_store
[40];
1601 DATA_BLOB inbuf
= data_blob_null
;
1603 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1605 * Can't use sync call while an async call is in flight
1607 return NT_STATUS_INVALID_PARAMETER
;
1610 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1611 return NT_STATUS_INVALID_PARAMETER
;
1614 status
= map_fnum_to_smb2_handle(cli
,
1617 if (!NT_STATUS_IS_OK(status
)) {
1621 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1622 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1624 inbuf
.data
= inbuf_store
;
1625 inbuf
.length
= sizeof(inbuf_store
);
1626 data_blob_clear(&inbuf
);
1628 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1629 if (change_time
!= 0) {
1630 put_long_date((char *)inbuf
.data
+ 24, change_time
);
1632 if (access_time
!= 0) {
1633 put_long_date((char *)inbuf
.data
+ 8, access_time
);
1635 if (write_time
!= 0) {
1636 put_long_date((char *)inbuf
.data
+ 16, write_time
);
1639 return smb2cli_set_info(cli
->conn
,
1643 1, /* in_info_type */
1644 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1645 &inbuf
, /* in_input_buffer */
1646 0, /* in_additional_info */
1651 /***************************************************************
1652 Wrapper that allows SMB2 to query disk attributes (size).
1654 ***************************************************************/
1656 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, const char *path
,
1657 uint64_t *bsize
, uint64_t *total
, uint64_t *avail
)
1660 uint16_t fnum
= 0xffff;
1661 DATA_BLOB outbuf
= data_blob_null
;
1662 struct smb2_hnd
*ph
= NULL
;
1663 uint32_t sectors_per_unit
= 0;
1664 uint32_t bytes_per_sector
= 0;
1665 uint64_t total_size
= 0;
1666 uint64_t size_free
= 0;
1667 TALLOC_CTX
*frame
= talloc_stackframe();
1669 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1671 * Can't use sync call while an async call is in flight
1673 status
= NT_STATUS_INVALID_PARAMETER
;
1677 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1678 status
= NT_STATUS_INVALID_PARAMETER
;
1682 /* First open the top level directory. */
1683 status
= cli_smb2_create_fnum(cli
,
1685 0, /* create_flags */
1686 FILE_READ_ATTRIBUTES
, /* desired_access */
1687 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1688 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1689 FILE_OPEN
, /* create_disposition */
1690 FILE_DIRECTORY_FILE
, /* create_options */
1694 if (!NT_STATUS_IS_OK(status
)) {
1698 status
= map_fnum_to_smb2_handle(cli
,
1701 if (!NT_STATUS_IS_OK(status
)) {
1705 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1706 level 3 (SMB_FS_SIZE_INFORMATION). */
1708 status
= smb2cli_query_info(cli
->conn
,
1712 2, /* in_info_type */
1713 3, /* in_file_info_class */
1714 0xFFFF, /* in_max_output_length */
1715 NULL
, /* in_input_buffer */
1716 0, /* in_additional_info */
1722 if (!NT_STATUS_IS_OK(status
)) {
1726 /* Parse the reply. */
1727 if (outbuf
.length
!= 24) {
1728 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1732 total_size
= BVAL(outbuf
.data
, 0);
1733 size_free
= BVAL(outbuf
.data
, 8);
1734 sectors_per_unit
= IVAL(outbuf
.data
, 16);
1735 bytes_per_sector
= IVAL(outbuf
.data
, 20);
1738 *bsize
= (uint64_t)sectors_per_unit
* (uint64_t)bytes_per_sector
;
1741 *total
= total_size
;
1747 status
= NT_STATUS_OK
;
1751 if (fnum
!= 0xffff) {
1752 cli_smb2_close_fnum(cli
, fnum
);
1759 /***************************************************************
1760 Wrapper that allows SMB2 to query file system attributes.
1762 ***************************************************************/
1764 NTSTATUS
cli_smb2_get_fs_attr_info(struct cli_state
*cli
, uint32_t *fs_attr
)
1767 uint16_t fnum
= 0xffff;
1768 DATA_BLOB outbuf
= data_blob_null
;
1769 struct smb2_hnd
*ph
= NULL
;
1770 TALLOC_CTX
*frame
= talloc_stackframe();
1772 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1774 * Can't use sync call while an async call is in flight
1776 status
= NT_STATUS_INVALID_PARAMETER
;
1780 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1781 status
= NT_STATUS_INVALID_PARAMETER
;
1785 /* First open the top level directory. */
1787 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
1788 FILE_READ_ATTRIBUTES
, /* desired_access */
1789 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1790 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
1791 FILE_SHARE_DELETE
, /* share_access */
1792 FILE_OPEN
, /* create_disposition */
1793 FILE_DIRECTORY_FILE
, /* create_options */
1797 if (!NT_STATUS_IS_OK(status
)) {
1801 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
1802 if (!NT_STATUS_IS_OK(status
)) {
1806 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
1807 cli
->smb2
.tcon
, 2, /* in_info_type */
1808 5, /* in_file_info_class */
1809 0xFFFF, /* in_max_output_length */
1810 NULL
, /* in_input_buffer */
1811 0, /* in_additional_info */
1813 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
1815 if (!NT_STATUS_IS_OK(status
)) {
1819 if (outbuf
.length
< 12) {
1820 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1824 *fs_attr
= IVAL(outbuf
.data
, 0);
1828 if (fnum
!= 0xffff) {
1829 cli_smb2_close_fnum(cli
, fnum
);
1836 /***************************************************************
1837 Wrapper that allows SMB2 to query a security descriptor.
1839 ***************************************************************/
1841 NTSTATUS
cli_smb2_query_security_descriptor(struct cli_state
*cli
,
1844 TALLOC_CTX
*mem_ctx
,
1845 struct security_descriptor
**ppsd
)
1848 DATA_BLOB outbuf
= data_blob_null
;
1849 struct smb2_hnd
*ph
= NULL
;
1850 struct security_descriptor
*lsd
= NULL
;
1851 TALLOC_CTX
*frame
= talloc_stackframe();
1853 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1855 * Can't use sync call while an async call is in flight
1857 status
= NT_STATUS_INVALID_PARAMETER
;
1861 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1862 status
= NT_STATUS_INVALID_PARAMETER
;
1866 status
= map_fnum_to_smb2_handle(cli
,
1869 if (!NT_STATUS_IS_OK(status
)) {
1873 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1875 status
= smb2cli_query_info(cli
->conn
,
1879 3, /* in_info_type */
1880 0, /* in_file_info_class */
1881 0xFFFF, /* in_max_output_length */
1882 NULL
, /* in_input_buffer */
1883 sec_info
, /* in_additional_info */
1890 if (!NT_STATUS_IS_OK(status
)) {
1894 /* Parse the reply. */
1895 status
= unmarshall_sec_desc(mem_ctx
,
1900 if (!NT_STATUS_IS_OK(status
)) {
1916 /***************************************************************
1917 Wrapper that allows SMB2 to set a security descriptor.
1919 ***************************************************************/
1921 NTSTATUS
cli_smb2_set_security_descriptor(struct cli_state
*cli
,
1924 const struct security_descriptor
*sd
)
1927 DATA_BLOB inbuf
= data_blob_null
;
1928 struct smb2_hnd
*ph
= NULL
;
1929 TALLOC_CTX
*frame
= talloc_stackframe();
1931 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1933 * Can't use sync call while an async call is in flight
1935 status
= NT_STATUS_INVALID_PARAMETER
;
1939 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1940 status
= NT_STATUS_INVALID_PARAMETER
;
1944 status
= map_fnum_to_smb2_handle(cli
,
1947 if (!NT_STATUS_IS_OK(status
)) {
1951 status
= marshall_sec_desc(frame
,
1956 if (!NT_STATUS_IS_OK(status
)) {
1960 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1962 status
= smb2cli_set_info(cli
->conn
,
1966 3, /* in_info_type */
1967 0, /* in_file_info_class */
1968 &inbuf
, /* in_input_buffer */
1969 sec_info
, /* in_additional_info */
1979 /***************************************************************
1980 Wrapper that allows SMB2 to rename a file.
1982 ***************************************************************/
1984 NTSTATUS
cli_smb2_rename(struct cli_state
*cli
,
1985 const char *fname_src
,
1986 const char *fname_dst
)
1989 DATA_BLOB inbuf
= data_blob_null
;
1990 uint16_t fnum
= 0xffff;
1991 struct smb2_hnd
*ph
= NULL
;
1992 smb_ucs2_t
*converted_str
= NULL
;
1993 size_t converted_size_bytes
= 0;
1995 TALLOC_CTX
*frame
= talloc_stackframe();
1997 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1999 * Can't use sync call while an async call is in flight
2001 status
= NT_STATUS_INVALID_PARAMETER
;
2005 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2006 status
= NT_STATUS_INVALID_PARAMETER
;
2010 status
= get_fnum_from_path(cli
,
2015 if (!NT_STATUS_IS_OK(status
)) {
2019 status
= map_fnum_to_smb2_handle(cli
,
2022 if (!NT_STATUS_IS_OK(status
)) {
2026 /* SMB2 is pickier about pathnames. Ensure it doesn't
2028 if (*fname_dst
== '\\') {
2032 /* SMB2 is pickier about pathnames. Ensure it doesn't
2034 namelen
= strlen(fname_dst
);
2035 if (namelen
> 0 && fname_dst
[namelen
-1] == '\\') {
2036 char *modname
= talloc_strdup(frame
, fname_dst
);
2037 modname
[namelen
-1] = '\0';
2038 fname_dst
= modname
;
2041 if (!push_ucs2_talloc(frame
,
2044 &converted_size_bytes
)) {
2045 status
= NT_STATUS_INVALID_PARAMETER
;
2049 /* W2K8 insists the dest name is not null
2050 terminated. Remove the last 2 zero bytes
2051 and reduce the name length. */
2053 if (converted_size_bytes
< 2) {
2054 status
= NT_STATUS_INVALID_PARAMETER
;
2057 converted_size_bytes
-= 2;
2059 inbuf
= data_blob_talloc_zero(frame
,
2060 20 + converted_size_bytes
);
2061 if (inbuf
.data
== NULL
) {
2062 status
= NT_STATUS_NO_MEMORY
;
2066 SIVAL(inbuf
.data
, 16, converted_size_bytes
);
2067 memcpy(inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
2069 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2070 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2072 status
= smb2cli_set_info(cli
->conn
,
2076 1, /* in_info_type */
2077 SMB_FILE_RENAME_INFORMATION
- 1000, /* in_file_info_class */
2078 &inbuf
, /* in_input_buffer */
2079 0, /* in_additional_info */
2085 if (fnum
!= 0xffff) {
2086 cli_smb2_close_fnum(cli
, fnum
);
2093 /***************************************************************
2094 Wrapper that allows SMB2 to set an EA on a fnum.
2096 ***************************************************************/
2098 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
2100 const char *ea_name
,
2105 DATA_BLOB inbuf
= data_blob_null
;
2107 char *ea_name_ascii
= NULL
;
2109 struct smb2_hnd
*ph
= NULL
;
2110 TALLOC_CTX
*frame
= talloc_stackframe();
2112 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2114 * Can't use sync call while an async call is in flight
2116 status
= NT_STATUS_INVALID_PARAMETER
;
2120 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2121 status
= NT_STATUS_INVALID_PARAMETER
;
2125 status
= map_fnum_to_smb2_handle(cli
,
2128 if (!NT_STATUS_IS_OK(status
)) {
2132 /* Marshall the SMB2 EA data. */
2133 if (ea_len
> 0xFFFF) {
2134 status
= NT_STATUS_INVALID_PARAMETER
;
2138 if (!push_ascii_talloc(frame
,
2142 status
= NT_STATUS_INVALID_PARAMETER
;
2146 if (namelen
< 2 || namelen
> 0xFF) {
2147 status
= NT_STATUS_INVALID_PARAMETER
;
2151 bloblen
= 8 + ea_len
+ namelen
;
2152 /* Round up to a 4 byte boundary. */
2153 bloblen
= ((bloblen
+ 3)&~3);
2155 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
2156 if (inbuf
.data
== NULL
) {
2157 status
= NT_STATUS_NO_MEMORY
;
2160 /* namelen doesn't include the NULL byte. */
2161 SCVAL(inbuf
.data
, 5, namelen
- 1);
2162 SSVAL(inbuf
.data
, 6, ea_len
);
2163 memcpy(inbuf
.data
+ 8, ea_name_ascii
, namelen
);
2164 memcpy(inbuf
.data
+ 8 + namelen
, ea_val
, ea_len
);
2166 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2167 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2169 status
= smb2cli_set_info(cli
->conn
,
2173 1, /* in_info_type */
2174 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
2175 &inbuf
, /* in_input_buffer */
2176 0, /* in_additional_info */
2186 /***************************************************************
2187 Wrapper that allows SMB2 to set an EA on a pathname.
2189 ***************************************************************/
2191 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
2193 const char *ea_name
,
2198 uint16_t fnum
= 0xffff;
2200 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2202 * Can't use sync call while an async call is in flight
2204 status
= NT_STATUS_INVALID_PARAMETER
;
2208 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2209 status
= NT_STATUS_INVALID_PARAMETER
;
2213 status
= get_fnum_from_path(cli
,
2218 if (!NT_STATUS_IS_OK(status
)) {
2222 status
= cli_set_ea_fnum(cli
,
2227 if (!NT_STATUS_IS_OK(status
)) {
2233 if (fnum
!= 0xffff) {
2234 cli_smb2_close_fnum(cli
, fnum
);
2240 /***************************************************************
2241 Wrapper that allows SMB2 to get an EA list on a pathname.
2243 ***************************************************************/
2245 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
2249 struct ea_struct
**pea_array
)
2252 uint16_t fnum
= 0xffff;
2253 DATA_BLOB outbuf
= data_blob_null
;
2254 struct smb2_hnd
*ph
= NULL
;
2255 struct ea_list
*ea_list
= NULL
;
2256 struct ea_list
*eal
= NULL
;
2257 size_t ea_count
= 0;
2258 TALLOC_CTX
*frame
= talloc_stackframe();
2263 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2265 * Can't use sync call while an async call is in flight
2267 status
= NT_STATUS_INVALID_PARAMETER
;
2271 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2272 status
= NT_STATUS_INVALID_PARAMETER
;
2276 status
= get_fnum_from_path(cli
,
2281 if (!NT_STATUS_IS_OK(status
)) {
2285 status
= map_fnum_to_smb2_handle(cli
,
2288 if (!NT_STATUS_IS_OK(status
)) {
2292 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2293 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2295 status
= smb2cli_query_info(cli
->conn
,
2299 1, /* in_info_type */
2300 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
2301 0xFFFF, /* in_max_output_length */
2302 NULL
, /* in_input_buffer */
2303 0, /* in_additional_info */
2310 if (!NT_STATUS_IS_OK(status
)) {
2314 /* Parse the reply. */
2315 ea_list
= read_nttrans_ea_list(ctx
,
2316 (const char *)outbuf
.data
,
2318 if (ea_list
== NULL
) {
2319 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2323 /* Convert to an array. */
2324 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2329 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
2330 if (*pea_array
== NULL
) {
2331 status
= NT_STATUS_NO_MEMORY
;
2335 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2336 (*pea_array
)[ea_count
++] = eal
->ea
;
2338 *pnum_eas
= ea_count
;
2343 if (fnum
!= 0xffff) {
2344 cli_smb2_close_fnum(cli
, fnum
);
2351 /***************************************************************
2352 Wrapper that allows SMB2 to get user quota.
2354 ***************************************************************/
2356 NTSTATUS
cli_smb2_get_user_quota(struct cli_state
*cli
,
2358 SMB_NTQUOTA_STRUCT
*pqt
)
2361 DATA_BLOB inbuf
= data_blob_null
;
2362 DATA_BLOB outbuf
= data_blob_null
;
2363 struct smb2_hnd
*ph
= NULL
;
2364 TALLOC_CTX
*frame
= talloc_stackframe();
2366 unsigned int offset
;
2369 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2371 * Can't use sync call while an async call is in flight
2373 status
= NT_STATUS_INVALID_PARAMETER
;
2377 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2378 status
= NT_STATUS_INVALID_PARAMETER
;
2382 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
2383 if (!NT_STATUS_IS_OK(status
)) {
2387 sid_len
= ndr_size_dom_sid(&pqt
->sid
, 0);
2389 inbuf
= data_blob_talloc_zero(frame
, 24 + sid_len
);
2390 if (inbuf
.data
== NULL
) {
2391 status
= NT_STATUS_NO_MEMORY
;
2397 SCVAL(buf
, 0, 1); /* ReturnSingle */
2398 SCVAL(buf
, 1, 0); /* RestartScan */
2399 SSVAL(buf
, 2, 0); /* Reserved */
2400 if (8 + sid_len
< 8) {
2401 status
= NT_STATUS_INVALID_PARAMETER
;
2404 SIVAL(buf
, 4, 8 + sid_len
); /* SidListLength */
2405 SIVAL(buf
, 8, 0); /* StartSidLength */
2406 SIVAL(buf
, 12, 0); /* StartSidOffset */
2407 SIVAL(buf
, 16, 0); /* NextEntryOffset */
2408 SIVAL(buf
, 20, sid_len
); /* SidLength */
2409 sid_linearize(buf
+ 24, sid_len
, &pqt
->sid
);
2411 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
2412 cli
->smb2
.tcon
, 4, /* in_info_type */
2413 0, /* in_file_info_class */
2414 0xFFFF, /* in_max_output_length */
2415 &inbuf
, /* in_input_buffer */
2416 0, /* in_additional_info */
2418 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
2421 if (!NT_STATUS_IS_OK(status
)) {
2425 if (!parse_user_quota_record(outbuf
.data
, outbuf
.length
, &offset
,
2427 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2428 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
2436 /***************************************************************
2437 Wrapper that allows SMB2 to list user quota.
2439 ***************************************************************/
2441 NTSTATUS
cli_smb2_list_user_quota_step(struct cli_state
*cli
,
2442 TALLOC_CTX
*mem_ctx
,
2444 SMB_NTQUOTA_LIST
**pqt_list
,
2448 DATA_BLOB inbuf
= data_blob_null
;
2449 DATA_BLOB outbuf
= data_blob_null
;
2450 struct smb2_hnd
*ph
= NULL
;
2451 TALLOC_CTX
*frame
= talloc_stackframe();
2454 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2456 * Can't use sync call while an async call is in flight
2458 status
= NT_STATUS_INVALID_PARAMETER
;
2462 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2463 status
= NT_STATUS_INVALID_PARAMETER
;
2467 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
2468 if (!NT_STATUS_IS_OK(status
)) {
2472 inbuf
= data_blob_talloc_zero(frame
, 16);
2473 if (inbuf
.data
== NULL
) {
2474 status
= NT_STATUS_NO_MEMORY
;
2480 SCVAL(buf
, 0, 0); /* ReturnSingle */
2481 SCVAL(buf
, 1, first
? 1 : 0); /* RestartScan */
2482 SSVAL(buf
, 2, 0); /* Reserved */
2483 SIVAL(buf
, 4, 0); /* SidListLength */
2484 SIVAL(buf
, 8, 0); /* StartSidLength */
2485 SIVAL(buf
, 12, 0); /* StartSidOffset */
2487 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
2488 cli
->smb2
.tcon
, 4, /* in_info_type */
2489 0, /* in_file_info_class */
2490 0xFFFF, /* in_max_output_length */
2491 &inbuf
, /* in_input_buffer */
2492 0, /* in_additional_info */
2494 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
2497 if (!NT_STATUS_IS_OK(status
)) {
2501 status
= parse_user_quota_list(outbuf
.data
, outbuf
.length
, mem_ctx
,
2509 /***************************************************************
2510 Wrapper that allows SMB2 to get file system quota.
2512 ***************************************************************/
2514 NTSTATUS
cli_smb2_get_fs_quota_info(struct cli_state
*cli
,
2516 SMB_NTQUOTA_STRUCT
*pqt
)
2519 DATA_BLOB outbuf
= data_blob_null
;
2520 struct smb2_hnd
*ph
= NULL
;
2521 TALLOC_CTX
*frame
= talloc_stackframe();
2523 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2525 * Can't use sync call while an async call is in flight
2527 status
= NT_STATUS_INVALID_PARAMETER
;
2531 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2532 status
= NT_STATUS_INVALID_PARAMETER
;
2536 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
2537 if (!NT_STATUS_IS_OK(status
)) {
2541 status
= smb2cli_query_info(
2542 cli
->conn
, cli
->timeout
, cli
->smb2
.session
, cli
->smb2
.tcon
,
2543 2, /* in_info_type */
2544 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
2545 0xFFFF, /* in_max_output_length */
2546 NULL
, /* in_input_buffer */
2547 0, /* in_additional_info */
2549 ph
->fid_persistent
, ph
->fid_volatile
, frame
, &outbuf
);
2551 if (!NT_STATUS_IS_OK(status
)) {
2555 status
= parse_fs_quota_buffer(outbuf
.data
, outbuf
.length
, pqt
);
2562 /***************************************************************
2563 Wrapper that allows SMB2 to set user quota.
2565 ***************************************************************/
2567 NTSTATUS
cli_smb2_set_user_quota(struct cli_state
*cli
,
2569 SMB_NTQUOTA_LIST
*qtl
)
2572 DATA_BLOB inbuf
= data_blob_null
;
2573 struct smb2_hnd
*ph
= NULL
;
2574 TALLOC_CTX
*frame
= talloc_stackframe();
2576 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2578 * Can't use sync call while an async call is in flight
2580 status
= NT_STATUS_INVALID_PARAMETER
;
2584 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2585 status
= NT_STATUS_INVALID_PARAMETER
;
2589 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
2590 if (!NT_STATUS_IS_OK(status
)) {
2594 status
= build_user_quota_buffer(qtl
, 0, talloc_tos(), &inbuf
, NULL
);
2595 if (!NT_STATUS_IS_OK(status
)) {
2599 status
= smb2cli_set_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
2600 cli
->smb2
.tcon
, 4, /* in_info_type */
2601 0, /* in_file_info_class */
2602 &inbuf
, /* in_input_buffer */
2603 0, /* in_additional_info */
2604 ph
->fid_persistent
, ph
->fid_volatile
);
2611 NTSTATUS
cli_smb2_set_fs_quota_info(struct cli_state
*cli
,
2613 SMB_NTQUOTA_STRUCT
*pqt
)
2616 DATA_BLOB inbuf
= data_blob_null
;
2617 struct smb2_hnd
*ph
= NULL
;
2618 TALLOC_CTX
*frame
= talloc_stackframe();
2620 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2622 * Can't use sync call while an async call is in flight
2624 status
= NT_STATUS_INVALID_PARAMETER
;
2628 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2629 status
= NT_STATUS_INVALID_PARAMETER
;
2633 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
2634 if (!NT_STATUS_IS_OK(status
)) {
2638 status
= build_fs_quota_buffer(talloc_tos(), pqt
, &inbuf
, 0);
2639 if (!NT_STATUS_IS_OK(status
)) {
2643 status
= smb2cli_set_info(
2644 cli
->conn
, cli
->timeout
, cli
->smb2
.session
, cli
->smb2
.tcon
,
2645 2, /* in_info_type */
2646 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
2647 &inbuf
, /* in_input_buffer */
2648 0, /* in_additional_info */
2649 ph
->fid_persistent
, ph
->fid_volatile
);
2655 struct cli_smb2_read_state
{
2656 struct tevent_context
*ev
;
2657 struct cli_state
*cli
;
2658 struct smb2_hnd
*ph
;
2659 uint64_t start_offset
;
2665 static void cli_smb2_read_done(struct tevent_req
*subreq
);
2667 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
2668 struct tevent_context
*ev
,
2669 struct cli_state
*cli
,
2675 struct tevent_req
*req
, *subreq
;
2676 struct cli_smb2_read_state
*state
;
2678 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
2684 state
->start_offset
= (uint64_t)offset
;
2685 state
->size
= (uint32_t)size
;
2686 state
->received
= 0;
2689 status
= map_fnum_to_smb2_handle(cli
,
2692 if (tevent_req_nterror(req
, status
)) {
2693 return tevent_req_post(req
, ev
);
2696 subreq
= smb2cli_read_send(state
,
2699 state
->cli
->timeout
,
2700 state
->cli
->smb2
.session
,
2701 state
->cli
->smb2
.tcon
,
2703 state
->start_offset
,
2704 state
->ph
->fid_persistent
,
2705 state
->ph
->fid_volatile
,
2706 0, /* minimum_count */
2707 0); /* remaining_bytes */
2709 if (tevent_req_nomem(subreq
, req
)) {
2710 return tevent_req_post(req
, ev
);
2712 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
2716 static void cli_smb2_read_done(struct tevent_req
*subreq
)
2718 struct tevent_req
*req
= tevent_req_callback_data(
2719 subreq
, struct tevent_req
);
2720 struct cli_smb2_read_state
*state
= tevent_req_data(
2721 req
, struct cli_smb2_read_state
);
2724 status
= smb2cli_read_recv(subreq
, state
,
2725 &state
->buf
, &state
->received
);
2726 if (tevent_req_nterror(req
, status
)) {
2730 if (state
->received
> state
->size
) {
2731 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2735 tevent_req_done(req
);
2738 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
2743 struct cli_smb2_read_state
*state
= tevent_req_data(
2744 req
, struct cli_smb2_read_state
);
2746 if (tevent_req_is_nterror(req
, &status
)) {
2747 state
->cli
->raw_status
= status
;
2751 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2752 * better make sure that you copy it away before you talloc_free(req).
2753 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2755 *received
= (ssize_t
)state
->received
;
2756 *rcvbuf
= state
->buf
;
2757 state
->cli
->raw_status
= NT_STATUS_OK
;
2758 return NT_STATUS_OK
;
2761 struct cli_smb2_write_state
{
2762 struct tevent_context
*ev
;
2763 struct cli_state
*cli
;
2764 struct smb2_hnd
*ph
;
2772 static void cli_smb2_write_written(struct tevent_req
*req
);
2774 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
2775 struct tevent_context
*ev
,
2776 struct cli_state
*cli
,
2784 struct tevent_req
*req
, *subreq
= NULL
;
2785 struct cli_smb2_write_state
*state
= NULL
;
2787 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
2793 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2794 state
->flags
= (uint32_t)mode
;
2796 state
->offset
= (uint64_t)offset
;
2797 state
->size
= (uint32_t)size
;
2800 status
= map_fnum_to_smb2_handle(cli
,
2803 if (tevent_req_nterror(req
, status
)) {
2804 return tevent_req_post(req
, ev
);
2807 subreq
= smb2cli_write_send(state
,
2810 state
->cli
->timeout
,
2811 state
->cli
->smb2
.session
,
2812 state
->cli
->smb2
.tcon
,
2815 state
->ph
->fid_persistent
,
2816 state
->ph
->fid_volatile
,
2817 0, /* remaining_bytes */
2818 state
->flags
, /* flags */
2821 if (tevent_req_nomem(subreq
, req
)) {
2822 return tevent_req_post(req
, ev
);
2824 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
2828 static void cli_smb2_write_written(struct tevent_req
*subreq
)
2830 struct tevent_req
*req
= tevent_req_callback_data(
2831 subreq
, struct tevent_req
);
2832 struct cli_smb2_write_state
*state
= tevent_req_data(
2833 req
, struct cli_smb2_write_state
);
2837 status
= smb2cli_write_recv(subreq
, &written
);
2838 TALLOC_FREE(subreq
);
2839 if (tevent_req_nterror(req
, status
)) {
2843 state
->written
= written
;
2845 tevent_req_done(req
);
2848 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
2851 struct cli_smb2_write_state
*state
= tevent_req_data(
2852 req
, struct cli_smb2_write_state
);
2855 if (tevent_req_is_nterror(req
, &status
)) {
2856 state
->cli
->raw_status
= status
;
2857 tevent_req_received(req
);
2861 if (pwritten
!= NULL
) {
2862 *pwritten
= (size_t)state
->written
;
2864 state
->cli
->raw_status
= NT_STATUS_OK
;
2865 tevent_req_received(req
);
2866 return NT_STATUS_OK
;
2869 /***************************************************************
2870 Wrapper that allows SMB2 async write using an fnum.
2871 This is mostly cut-and-paste from Volker's code inside
2872 source3/libsmb/clireadwrite.c, adapted for SMB2.
2874 Done this way so I can reuse all the logic inside cli_push()
2876 ***************************************************************/
2878 struct cli_smb2_writeall_state
{
2879 struct tevent_context
*ev
;
2880 struct cli_state
*cli
;
2881 struct smb2_hnd
*ph
;
2889 static void cli_smb2_writeall_written(struct tevent_req
*req
);
2891 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
2892 struct tevent_context
*ev
,
2893 struct cli_state
*cli
,
2901 struct tevent_req
*req
, *subreq
= NULL
;
2902 struct cli_smb2_writeall_state
*state
= NULL
;
2907 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
2913 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2914 state
->flags
= (uint32_t)mode
;
2916 state
->offset
= (uint64_t)offset
;
2917 state
->size
= (uint32_t)size
;
2920 status
= map_fnum_to_smb2_handle(cli
,
2923 if (tevent_req_nterror(req
, status
)) {
2924 return tevent_req_post(req
, ev
);
2927 to_write
= state
->size
;
2928 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
2929 to_write
= MIN(max_size
, to_write
);
2930 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
2932 to_write
= MIN(max_size
, to_write
);
2935 subreq
= smb2cli_write_send(state
,
2938 state
->cli
->timeout
,
2939 state
->cli
->smb2
.session
,
2940 state
->cli
->smb2
.tcon
,
2943 state
->ph
->fid_persistent
,
2944 state
->ph
->fid_volatile
,
2945 0, /* remaining_bytes */
2946 state
->flags
, /* flags */
2947 state
->buf
+ state
->written
);
2949 if (tevent_req_nomem(subreq
, req
)) {
2950 return tevent_req_post(req
, ev
);
2952 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
2956 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
2958 struct tevent_req
*req
= tevent_req_callback_data(
2959 subreq
, struct tevent_req
);
2960 struct cli_smb2_writeall_state
*state
= tevent_req_data(
2961 req
, struct cli_smb2_writeall_state
);
2963 uint32_t written
, to_write
;
2967 status
= smb2cli_write_recv(subreq
, &written
);
2968 TALLOC_FREE(subreq
);
2969 if (tevent_req_nterror(req
, status
)) {
2973 state
->written
+= written
;
2975 if (state
->written
> state
->size
) {
2976 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2980 to_write
= state
->size
- state
->written
;
2982 if (to_write
== 0) {
2983 tevent_req_done(req
);
2987 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
2988 to_write
= MIN(max_size
, to_write
);
2989 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
2991 to_write
= MIN(max_size
, to_write
);
2994 subreq
= smb2cli_write_send(state
,
2997 state
->cli
->timeout
,
2998 state
->cli
->smb2
.session
,
2999 state
->cli
->smb2
.tcon
,
3001 state
->offset
+ state
->written
,
3002 state
->ph
->fid_persistent
,
3003 state
->ph
->fid_volatile
,
3004 0, /* remaining_bytes */
3005 state
->flags
, /* flags */
3006 state
->buf
+ state
->written
);
3008 if (tevent_req_nomem(subreq
, req
)) {
3011 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
3014 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
3017 struct cli_smb2_writeall_state
*state
= tevent_req_data(
3018 req
, struct cli_smb2_writeall_state
);
3021 if (tevent_req_is_nterror(req
, &status
)) {
3022 state
->cli
->raw_status
= status
;
3025 if (pwritten
!= NULL
) {
3026 *pwritten
= (size_t)state
->written
;
3028 state
->cli
->raw_status
= NT_STATUS_OK
;
3029 return NT_STATUS_OK
;
3032 struct cli_smb2_splice_state
{
3033 struct tevent_context
*ev
;
3034 struct cli_state
*cli
;
3035 struct smb2_hnd
*src_ph
;
3036 struct smb2_hnd
*dst_ph
;
3037 int (*splice_cb
)(off_t n
, void *priv
);
3044 struct req_resume_key_rsp resume_rsp
;
3045 struct srv_copychunk_copy cc_copy
;
3048 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
3049 struct tevent_req
*req
);
3051 static void cli_splice_copychunk_done(struct tevent_req
*subreq
)
3053 struct tevent_req
*req
= tevent_req_callback_data(
3054 subreq
, struct tevent_req
);
3055 struct cli_smb2_splice_state
*state
=
3056 tevent_req_data(req
,
3057 struct cli_smb2_splice_state
);
3058 struct smbXcli_conn
*conn
= state
->cli
->conn
;
3059 DATA_BLOB out_input_buffer
= data_blob_null
;
3060 DATA_BLOB out_output_buffer
= data_blob_null
;
3061 struct srv_copychunk_rsp cc_copy_rsp
;
3062 enum ndr_err_code ndr_ret
;
3065 status
= smb2cli_ioctl_recv(subreq
, state
,
3067 &out_output_buffer
);
3068 TALLOC_FREE(subreq
);
3069 if ((!NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
) ||
3070 state
->resized
) && tevent_req_nterror(req
, status
)) {
3074 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
, state
, &cc_copy_rsp
,
3075 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
3076 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
3077 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3078 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3082 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
3083 uint32_t max_chunks
= MIN(cc_copy_rsp
.chunks_written
,
3084 cc_copy_rsp
.total_bytes_written
/ cc_copy_rsp
.chunk_bytes_written
);
3085 if ((cc_copy_rsp
.chunk_bytes_written
> smb2cli_conn_cc_chunk_len(conn
) ||
3086 max_chunks
> smb2cli_conn_cc_max_chunks(conn
)) &&
3087 tevent_req_nterror(req
, status
)) {
3091 state
->resized
= true;
3092 smb2cli_conn_set_cc_chunk_len(conn
, cc_copy_rsp
.chunk_bytes_written
);
3093 smb2cli_conn_set_cc_max_chunks(conn
, max_chunks
);
3095 if ((state
->src_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
3096 (state
->dst_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
3097 (state
->written
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
)) {
3098 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
3101 state
->src_offset
+= cc_copy_rsp
.total_bytes_written
;
3102 state
->dst_offset
+= cc_copy_rsp
.total_bytes_written
;
3103 state
->written
+= cc_copy_rsp
.total_bytes_written
;
3104 if (!state
->splice_cb(state
->written
, state
->priv
)) {
3105 tevent_req_nterror(req
, NT_STATUS_CANCELLED
);
3110 cli_splice_copychunk_send(state
, req
);
3113 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
3114 struct tevent_req
*req
)
3116 struct tevent_req
*subreq
;
3117 enum ndr_err_code ndr_ret
;
3118 struct smbXcli_conn
*conn
= state
->cli
->conn
;
3119 struct srv_copychunk_copy
*cc_copy
= &state
->cc_copy
;
3120 off_t src_offset
= state
->src_offset
;
3121 off_t dst_offset
= state
->dst_offset
;
3122 uint32_t req_len
= MIN(smb2cli_conn_cc_chunk_len(conn
) * smb2cli_conn_cc_max_chunks(conn
),
3123 state
->size
- state
->written
);
3124 DATA_BLOB in_input_buffer
= data_blob_null
;
3125 DATA_BLOB in_output_buffer
= data_blob_null
;
3127 if (state
->size
- state
->written
== 0) {
3128 tevent_req_done(req
);
3132 cc_copy
->chunk_count
= 0;
3134 cc_copy
->chunks
[cc_copy
->chunk_count
].source_off
= src_offset
;
3135 cc_copy
->chunks
[cc_copy
->chunk_count
].target_off
= dst_offset
;
3136 cc_copy
->chunks
[cc_copy
->chunk_count
].length
= MIN(req_len
,
3137 smb2cli_conn_cc_chunk_len(conn
));
3138 if (req_len
< cc_copy
->chunks
[cc_copy
->chunk_count
].length
) {
3139 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
3142 req_len
-= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
3143 if ((src_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
) ||
3144 (dst_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
)) {
3145 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
3148 src_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
3149 dst_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
3150 cc_copy
->chunk_count
++;
3153 ndr_ret
= ndr_push_struct_blob(&in_input_buffer
, state
, cc_copy
,
3154 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
3155 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
3156 DEBUG(0, ("failed to marshall copy chunk req\n"));
3157 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
3161 subreq
= smb2cli_ioctl_send(state
, state
->ev
, state
->cli
->conn
,
3162 state
->cli
->timeout
,
3163 state
->cli
->smb2
.session
,
3164 state
->cli
->smb2
.tcon
,
3165 state
->dst_ph
->fid_persistent
, /* in_fid_persistent */
3166 state
->dst_ph
->fid_volatile
, /* in_fid_volatile */
3167 FSCTL_SRV_COPYCHUNK_WRITE
,
3168 0, /* in_max_input_length */
3170 12, /* in_max_output_length */
3172 SMB2_IOCTL_FLAG_IS_FSCTL
);
3173 if (tevent_req_nomem(subreq
, req
)) {
3176 tevent_req_set_callback(subreq
,
3177 cli_splice_copychunk_done
,
3181 static void cli_splice_key_done(struct tevent_req
*subreq
)
3183 struct tevent_req
*req
= tevent_req_callback_data(
3184 subreq
, struct tevent_req
);
3185 struct cli_smb2_splice_state
*state
=
3186 tevent_req_data(req
,
3187 struct cli_smb2_splice_state
);
3188 enum ndr_err_code ndr_ret
;
3191 DATA_BLOB out_input_buffer
= data_blob_null
;
3192 DATA_BLOB out_output_buffer
= data_blob_null
;
3194 status
= smb2cli_ioctl_recv(subreq
, state
,
3196 &out_output_buffer
);
3197 TALLOC_FREE(subreq
);
3198 if (tevent_req_nterror(req
, status
)) {
3202 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
,
3203 state
, &state
->resume_rsp
,
3204 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
3205 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
3206 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3207 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3211 memcpy(&state
->cc_copy
.source_key
,
3212 &state
->resume_rsp
.resume_key
,
3213 sizeof state
->resume_rsp
.resume_key
);
3215 cli_splice_copychunk_send(state
, req
);
3218 struct tevent_req
*cli_smb2_splice_send(TALLOC_CTX
*mem_ctx
,
3219 struct tevent_context
*ev
,
3220 struct cli_state
*cli
,
3221 uint16_t src_fnum
, uint16_t dst_fnum
,
3222 off_t size
, off_t src_offset
, off_t dst_offset
,
3223 int (*splice_cb
)(off_t n
, void *priv
),
3226 struct tevent_req
*req
;
3227 struct tevent_req
*subreq
;
3228 struct cli_smb2_splice_state
*state
;
3230 DATA_BLOB in_input_buffer
= data_blob_null
;
3231 DATA_BLOB in_output_buffer
= data_blob_null
;
3233 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_splice_state
);
3239 state
->splice_cb
= splice_cb
;
3243 state
->src_offset
= src_offset
;
3244 state
->dst_offset
= dst_offset
;
3245 state
->cc_copy
.chunks
= talloc_array(state
,
3246 struct srv_copychunk
,
3247 smb2cli_conn_cc_max_chunks(cli
->conn
));
3248 if (state
->cc_copy
.chunks
== NULL
) {
3252 status
= map_fnum_to_smb2_handle(cli
, src_fnum
, &state
->src_ph
);
3253 if (tevent_req_nterror(req
, status
))
3254 return tevent_req_post(req
, ev
);
3256 status
= map_fnum_to_smb2_handle(cli
, dst_fnum
, &state
->dst_ph
);
3257 if (tevent_req_nterror(req
, status
))
3258 return tevent_req_post(req
, ev
);
3260 subreq
= smb2cli_ioctl_send(state
, ev
, cli
->conn
,
3264 state
->src_ph
->fid_persistent
, /* in_fid_persistent */
3265 state
->src_ph
->fid_volatile
, /* in_fid_volatile */
3266 FSCTL_SRV_REQUEST_RESUME_KEY
,
3267 0, /* in_max_input_length */
3269 32, /* in_max_output_length */
3271 SMB2_IOCTL_FLAG_IS_FSCTL
);
3272 if (tevent_req_nomem(subreq
, req
)) {
3275 tevent_req_set_callback(subreq
,
3276 cli_splice_key_done
,
3282 NTSTATUS
cli_smb2_splice_recv(struct tevent_req
*req
, off_t
*written
)
3284 struct cli_smb2_splice_state
*state
= tevent_req_data(
3285 req
, struct cli_smb2_splice_state
);
3288 if (tevent_req_is_nterror(req
, &status
)) {
3289 state
->cli
->raw_status
= status
;
3290 tevent_req_received(req
);
3293 if (written
!= NULL
) {
3294 *written
= state
->written
;
3296 state
->cli
->raw_status
= NT_STATUS_OK
;
3297 tevent_req_received(req
);
3298 return NT_STATUS_OK
;
3301 /***************************************************************
3302 SMB2 enum shadow copy data.
3303 ***************************************************************/
3305 struct cli_smb2_shadow_copy_data_fnum_state
{
3306 struct cli_state
*cli
;
3308 struct smb2_hnd
*ph
;
3309 DATA_BLOB out_input_buffer
;
3310 DATA_BLOB out_output_buffer
;
3313 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
);
3315 static struct tevent_req
*cli_smb2_shadow_copy_data_fnum_send(
3316 TALLOC_CTX
*mem_ctx
,
3317 struct tevent_context
*ev
,
3318 struct cli_state
*cli
,
3322 struct tevent_req
*req
, *subreq
;
3323 struct cli_smb2_shadow_copy_data_fnum_state
*state
;
3326 req
= tevent_req_create(mem_ctx
, &state
,
3327 struct cli_smb2_shadow_copy_data_fnum_state
);
3332 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3333 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3334 return tevent_req_post(req
, ev
);
3340 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
3341 if (tevent_req_nterror(req
, status
)) {
3342 return tevent_req_post(req
, ev
);
3346 * TODO. Under SMB2 we should send a zero max_output_length
3347 * ioctl to get the required size, then send another ioctl
3348 * to get the data, but the current SMB1 implementation just
3349 * does one roundtrip with a 64K buffer size. Do the same
3353 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
3354 state
->cli
->timeout
,
3355 state
->cli
->smb2
.session
,
3356 state
->cli
->smb2
.tcon
,
3357 state
->ph
->fid_persistent
, /* in_fid_persistent */
3358 state
->ph
->fid_volatile
, /* in_fid_volatile */
3359 FSCTL_GET_SHADOW_COPY_DATA
,
3360 0, /* in_max_input_length */
3361 NULL
, /* in_input_buffer */
3363 CLI_BUFFER_SIZE
: 16, /* in_max_output_length */
3364 NULL
, /* in_output_buffer */
3365 SMB2_IOCTL_FLAG_IS_FSCTL
);
3367 if (tevent_req_nomem(subreq
, req
)) {
3368 return tevent_req_post(req
, ev
);
3370 tevent_req_set_callback(subreq
,
3371 cli_smb2_shadow_copy_data_fnum_done
,
3377 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
)
3379 struct tevent_req
*req
= tevent_req_callback_data(
3380 subreq
, struct tevent_req
);
3381 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
3382 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
3385 status
= smb2cli_ioctl_recv(subreq
, state
,
3386 &state
->out_input_buffer
,
3387 &state
->out_output_buffer
);
3388 TALLOC_FREE(subreq
);
3389 if (tevent_req_nterror(req
, status
)) {
3392 tevent_req_done(req
);
3395 static NTSTATUS
cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req
*req
,
3396 TALLOC_CTX
*mem_ctx
,
3401 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
3402 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
3403 char **names
= NULL
;
3404 uint32_t num_names
= 0;
3405 uint32_t num_names_returned
= 0;
3406 uint32_t dlength
= 0;
3408 uint8_t *endp
= NULL
;
3411 if (tevent_req_is_nterror(req
, &status
)) {
3415 if (state
->out_output_buffer
.length
< 16) {
3416 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3419 num_names
= IVAL(state
->out_output_buffer
.data
, 0);
3420 num_names_returned
= IVAL(state
->out_output_buffer
.data
, 4);
3421 dlength
= IVAL(state
->out_output_buffer
.data
, 8);
3423 if (num_names
> 0x7FFFFFFF) {
3424 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3427 if (get_names
== false) {
3428 *pnum_names
= (int)num_names
;
3429 return NT_STATUS_OK
;
3431 if (num_names
!= num_names_returned
) {
3432 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3434 if (dlength
+ 12 < 12) {
3435 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3438 * NB. The below is an allowable return if there are
3439 * more snapshots than the buffer size we told the
3440 * server we can receive. We currently don't support
3443 if (dlength
+ 12 > state
->out_output_buffer
.length
) {
3444 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3446 if (state
->out_output_buffer
.length
+
3447 (2 * sizeof(SHADOW_COPY_LABEL
)) <
3448 state
->out_output_buffer
.length
) {
3449 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3452 names
= talloc_array(mem_ctx
, char *, num_names_returned
);
3453 if (names
== NULL
) {
3454 return NT_STATUS_NO_MEMORY
;
3457 endp
= state
->out_output_buffer
.data
+
3458 state
->out_output_buffer
.length
;
3460 for (i
=0; i
<num_names_returned
; i
++) {
3463 size_t converted_size
;
3465 src
= state
->out_output_buffer
.data
+ 12 +
3466 (i
* 2 * sizeof(SHADOW_COPY_LABEL
));
3468 if (src
+ (2 * sizeof(SHADOW_COPY_LABEL
)) > endp
) {
3469 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3471 ret
= convert_string_talloc(
3472 names
, CH_UTF16LE
, CH_UNIX
,
3473 src
, 2 * sizeof(SHADOW_COPY_LABEL
),
3474 &names
[i
], &converted_size
);
3477 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3480 *pnum_names
= num_names
;
3482 return NT_STATUS_OK
;
3485 NTSTATUS
cli_smb2_shadow_copy_data(TALLOC_CTX
*mem_ctx
,
3486 struct cli_state
*cli
,
3492 TALLOC_CTX
*frame
= talloc_stackframe();
3493 struct tevent_context
*ev
;
3494 struct tevent_req
*req
;
3495 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3497 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3499 * Can't use sync call while an async call is in flight
3501 status
= NT_STATUS_INVALID_PARAMETER
;
3504 ev
= samba_tevent_context_init(frame
);
3508 req
= cli_smb2_shadow_copy_data_fnum_send(frame
,
3516 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3519 status
= cli_smb2_shadow_copy_data_fnum_recv(req
,