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
= NT_STATUS_OK
;
454 if (tevent_req_is_nterror(req
, &status
)) {
455 state
->cli
->raw_status
= status
;
457 tevent_req_received(req
);
461 NTSTATUS
cli_smb2_close_fnum(struct cli_state
*cli
, uint16_t fnum
)
463 TALLOC_CTX
*frame
= talloc_stackframe();
464 struct tevent_context
*ev
;
465 struct tevent_req
*req
;
466 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
468 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
470 * Can't use sync call while an async call is in flight
472 status
= NT_STATUS_INVALID_PARAMETER
;
475 ev
= samba_tevent_context_init(frame
);
479 req
= cli_smb2_close_fnum_send(frame
, ev
, cli
, fnum
);
483 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
486 status
= cli_smb2_close_fnum_recv(req
);
492 struct cli_smb2_delete_on_close_state
{
493 struct cli_state
*cli
;
500 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
);
502 struct tevent_req
*cli_smb2_delete_on_close_send(TALLOC_CTX
*mem_ctx
,
503 struct tevent_context
*ev
,
504 struct cli_state
*cli
,
508 struct tevent_req
*req
= NULL
;
509 struct cli_smb2_delete_on_close_state
*state
= NULL
;
510 struct tevent_req
*subreq
= NULL
;
511 uint8_t in_info_type
;
512 uint8_t in_file_info_class
;
515 req
= tevent_req_create(mem_ctx
, &state
,
516 struct cli_smb2_delete_on_close_state
);
523 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
524 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
525 return tevent_req_post(req
, ev
);
528 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
529 if (tevent_req_nterror(req
, status
)) {
530 return tevent_req_post(req
, ev
);
534 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
535 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
538 in_file_info_class
= SMB_FILE_DISPOSITION_INFORMATION
- 1000;
539 /* Setup data array. */
540 SCVAL(&state
->data
[0], 0, flag
? 1 : 0);
541 state
->inbuf
.data
= &state
->data
[0];
542 state
->inbuf
.length
= 1;
544 subreq
= smb2cli_set_info_send(state
, ev
,
551 &state
->inbuf
, /* in_input_buffer */
552 0, /* in_additional_info */
553 state
->ph
->fid_persistent
,
554 state
->ph
->fid_volatile
);
555 if (tevent_req_nomem(subreq
, req
)) {
556 return tevent_req_post(req
, ev
);
558 tevent_req_set_callback(subreq
,
559 cli_smb2_delete_on_close_done
,
564 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
)
566 NTSTATUS status
= smb2cli_set_info_recv(subreq
);
567 tevent_req_simple_finish_ntstatus(subreq
, status
);
570 NTSTATUS
cli_smb2_delete_on_close_recv(struct tevent_req
*req
)
572 struct cli_smb2_delete_on_close_state
*state
=
574 struct cli_smb2_delete_on_close_state
);
577 if (tevent_req_is_nterror(req
, &status
)) {
578 state
->cli
->raw_status
= status
;
579 tevent_req_received(req
);
583 state
->cli
->raw_status
= NT_STATUS_OK
;
584 tevent_req_received(req
);
588 NTSTATUS
cli_smb2_delete_on_close(struct cli_state
*cli
, uint16_t fnum
, bool flag
)
590 TALLOC_CTX
*frame
= talloc_stackframe();
591 struct tevent_context
*ev
;
592 struct tevent_req
*req
;
593 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
595 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
597 * Can't use sync call while an async call is in flight
599 status
= NT_STATUS_INVALID_PARAMETER
;
602 ev
= samba_tevent_context_init(frame
);
606 req
= cli_smb2_delete_on_close_send(frame
, ev
, cli
, fnum
, flag
);
610 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
613 status
= cli_smb2_delete_on_close_recv(req
);
619 /***************************************************************
620 Small wrapper that allows SMB2 to create a directory
622 ***************************************************************/
624 NTSTATUS
cli_smb2_mkdir(struct cli_state
*cli
, const char *dname
)
629 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
631 * Can't use sync call while an async call is in flight
633 return NT_STATUS_INVALID_PARAMETER
;
636 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
637 return NT_STATUS_INVALID_PARAMETER
;
640 status
= cli_smb2_create_fnum(cli
,
642 0, /* create_flags */
643 FILE_READ_ATTRIBUTES
, /* desired_access */
644 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
645 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
646 FILE_CREATE
, /* create_disposition */
647 FILE_DIRECTORY_FILE
, /* create_options */
651 if (!NT_STATUS_IS_OK(status
)) {
654 return cli_smb2_close_fnum(cli
, fnum
);
657 /***************************************************************
658 Small wrapper that allows SMB2 to delete a directory
660 ***************************************************************/
662 NTSTATUS
cli_smb2_rmdir(struct cli_state
*cli
, const char *dname
)
667 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
669 * Can't use sync call while an async call is in flight
671 return NT_STATUS_INVALID_PARAMETER
;
674 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
675 return NT_STATUS_INVALID_PARAMETER
;
678 status
= cli_smb2_create_fnum(cli
,
680 0, /* create_flags */
681 DELETE_ACCESS
, /* desired_access */
682 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
683 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
684 FILE_OPEN
, /* create_disposition */
685 FILE_DIRECTORY_FILE
|FILE_DELETE_ON_CLOSE
, /* create_options */
689 if (!NT_STATUS_IS_OK(status
)) {
692 return cli_smb2_close_fnum(cli
, fnum
);
695 /***************************************************************
696 Small wrapper that allows SMB2 to unlink a pathname.
698 ***************************************************************/
700 NTSTATUS
cli_smb2_unlink(struct cli_state
*cli
, const char *fname
)
705 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
707 * Can't use sync call while an async call is in flight
709 return NT_STATUS_INVALID_PARAMETER
;
712 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
713 return NT_STATUS_INVALID_PARAMETER
;
716 status
= cli_smb2_create_fnum(cli
,
718 0, /* create_flags */
719 DELETE_ACCESS
, /* desired_access */
720 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
721 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
722 FILE_OPEN
, /* create_disposition */
723 FILE_DELETE_ON_CLOSE
, /* create_options */
727 if (!NT_STATUS_IS_OK(status
)) {
730 return cli_smb2_close_fnum(cli
, fnum
);
733 /***************************************************************
734 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
735 ***************************************************************/
737 static NTSTATUS
parse_finfo_id_both_directory_info(uint8_t *dir_data
,
738 uint32_t dir_data_length
,
739 struct file_info
*finfo
,
740 uint32_t *next_offset
)
746 if (dir_data_length
< 4) {
747 return NT_STATUS_INFO_LENGTH_MISMATCH
;
750 *next_offset
= IVAL(dir_data
, 0);
752 if (*next_offset
> dir_data_length
) {
753 return NT_STATUS_INFO_LENGTH_MISMATCH
;
756 if (*next_offset
!= 0) {
757 /* Ensure we only read what in this record. */
758 dir_data_length
= *next_offset
;
761 if (dir_data_length
< 105) {
762 return NT_STATUS_INFO_LENGTH_MISMATCH
;
765 finfo
->atime_ts
= interpret_long_date((const char *)dir_data
+ 16);
766 finfo
->mtime_ts
= interpret_long_date((const char *)dir_data
+ 24);
767 finfo
->ctime_ts
= interpret_long_date((const char *)dir_data
+ 32);
768 finfo
->size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 40, 0);
769 finfo
->mode
= CVAL(dir_data
+ 56, 0);
770 namelen
= IVAL(dir_data
+ 60,0);
771 if (namelen
> (dir_data_length
- 104)) {
772 return NT_STATUS_INFO_LENGTH_MISMATCH
;
774 slen
= CVAL(dir_data
+ 68, 0);
776 return NT_STATUS_INFO_LENGTH_MISMATCH
;
778 ret
= pull_string_talloc(finfo
,
780 FLAGS2_UNICODE_STRINGS
,
785 if (ret
== (size_t)-1) {
786 /* Bad conversion. */
787 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
790 ret
= pull_string_talloc(finfo
,
792 FLAGS2_UNICODE_STRINGS
,
797 if (ret
== (size_t)-1) {
798 /* Bad conversion. */
799 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
804 /*******************************************************************
805 Given a filename - get its directory name
806 ********************************************************************/
808 static bool windows_parent_dirname(TALLOC_CTX
*mem_ctx
,
816 p
= strrchr_m(dir
, '\\'); /* Find final '\\', if any */
819 if (!(*parent
= talloc_strdup(mem_ctx
, "\\"))) {
830 if (!(*parent
= (char *)talloc_memdup(mem_ctx
, dir
, len
+1))) {
833 (*parent
)[len
] = '\0';
841 /***************************************************************
842 Wrapper that allows SMB2 to list a directory.
844 ***************************************************************/
846 NTSTATUS
cli_smb2_list(struct cli_state
*cli
,
847 const char *pathname
,
849 NTSTATUS (*fn
)(const char *,
856 uint16_t fnum
= 0xffff;
857 char *parent_dir
= NULL
;
858 const char *mask
= NULL
;
859 struct smb2_hnd
*ph
= NULL
;
860 bool processed_file
= false;
861 TALLOC_CTX
*frame
= talloc_stackframe();
862 TALLOC_CTX
*subframe
= NULL
;
865 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
867 * Can't use sync call while an async call is in flight
869 status
= NT_STATUS_INVALID_PARAMETER
;
873 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
874 status
= NT_STATUS_INVALID_PARAMETER
;
878 /* Get the directory name. */
879 if (!windows_parent_dirname(frame
,
883 status
= NT_STATUS_NO_MEMORY
;
887 mask_has_wild
= ms_has_wild(mask
);
889 status
= cli_smb2_create_fnum(cli
,
891 0, /* create_flags */
892 SEC_DIR_LIST
|SEC_DIR_READ_ATTRIBUTE
,/* desired_access */
893 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
894 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
895 FILE_OPEN
, /* create_disposition */
896 FILE_DIRECTORY_FILE
, /* create_options */
900 if (!NT_STATUS_IS_OK(status
)) {
904 status
= map_fnum_to_smb2_handle(cli
,
907 if (!NT_STATUS_IS_OK(status
)) {
912 uint8_t *dir_data
= NULL
;
913 uint32_t dir_data_length
= 0;
914 uint32_t next_offset
= 0;
915 subframe
= talloc_stackframe();
917 status
= smb2cli_query_directory(cli
->conn
,
921 SMB2_FIND_ID_BOTH_DIRECTORY_INFO
,
932 if (!NT_STATUS_IS_OK(status
)) {
933 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
940 struct file_info
*finfo
= talloc_zero(subframe
,
944 status
= NT_STATUS_NO_MEMORY
;
948 status
= parse_finfo_id_both_directory_info(dir_data
,
953 if (!NT_STATUS_IS_OK(status
)) {
957 if (dir_check_ftype((uint32_t)finfo
->mode
,
958 (uint32_t)attribute
)) {
960 * Only process if attributes match.
961 * On SMB1 server does this, so on
962 * SMB2 we need to emulate in the
965 * https://bugzilla.samba.org/show_bug.cgi?id=10260
967 processed_file
= true;
969 status
= fn(cli
->dfs_mountpoint
,
974 if (!NT_STATUS_IS_OK(status
)) {
981 /* Move to next entry. */
983 dir_data
+= next_offset
;
984 dir_data_length
-= next_offset
;
986 } while (next_offset
!= 0);
988 TALLOC_FREE(subframe
);
990 if (!mask_has_wild
) {
992 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
993 * when handed a non-wildcard path. Do it
994 * for the server (with a non-wildcard path
995 * there should only ever be one file returned.
997 status
= STATUS_NO_MORE_FILES
;
1001 } while (NT_STATUS_IS_OK(status
));
1003 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
1004 status
= NT_STATUS_OK
;
1007 if (NT_STATUS_IS_OK(status
) && !processed_file
) {
1009 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1010 * if no files match. Emulate this in the client.
1012 status
= NT_STATUS_NO_SUCH_FILE
;
1017 if (fnum
!= 0xffff) {
1018 cli_smb2_close_fnum(cli
, fnum
);
1021 cli
->raw_status
= status
;
1023 TALLOC_FREE(subframe
);
1028 /***************************************************************
1029 Wrapper that allows SMB2 to query a path info (basic level).
1031 ***************************************************************/
1033 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
1035 SMB_STRUCT_STAT
*sbuf
,
1036 uint32_t *attributes
)
1039 struct smb_create_returns cr
;
1040 uint16_t fnum
= 0xffff;
1041 size_t namelen
= strlen(name
);
1043 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1045 * Can't use sync call while an async call is in flight
1047 return NT_STATUS_INVALID_PARAMETER
;
1050 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1051 return NT_STATUS_INVALID_PARAMETER
;
1054 /* SMB2 is pickier about pathnames. Ensure it doesn't
1056 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1057 char *modname
= talloc_strdup(talloc_tos(), name
);
1058 modname
[namelen
-1] = '\0';
1062 /* This is commonly used as a 'cd'. Try qpathinfo on
1063 a directory handle first. */
1065 status
= cli_smb2_create_fnum(cli
,
1067 0, /* create_flags */
1068 FILE_READ_ATTRIBUTES
, /* desired_access */
1069 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1070 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1071 FILE_OPEN
, /* create_disposition */
1072 FILE_DIRECTORY_FILE
, /* create_options */
1076 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
1077 /* Maybe a file ? */
1078 status
= cli_smb2_create_fnum(cli
,
1080 0, /* create_flags */
1081 FILE_READ_ATTRIBUTES
, /* desired_access */
1082 0, /* file attributes */
1083 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1084 FILE_OPEN
, /* create_disposition */
1085 0, /* create_options */
1090 if (!NT_STATUS_IS_OK(status
)) {
1094 status
= cli_smb2_close_fnum(cli
, fnum
);
1098 sbuf
->st_ex_atime
= nt_time_to_unix_timespec(cr
.last_access_time
);
1099 sbuf
->st_ex_mtime
= nt_time_to_unix_timespec(cr
.last_write_time
);
1100 sbuf
->st_ex_ctime
= nt_time_to_unix_timespec(cr
.change_time
);
1101 sbuf
->st_ex_size
= cr
.end_of_file
;
1102 *attributes
= cr
.file_attributes
;
1107 /***************************************************************
1108 Wrapper that allows SMB2 to check if a path is a directory.
1110 ***************************************************************/
1112 NTSTATUS
cli_smb2_chkpath(struct cli_state
*cli
,
1116 uint16_t fnum
= 0xffff;
1118 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1120 * Can't use sync call while an async call is in flight
1122 return NT_STATUS_INVALID_PARAMETER
;
1125 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1126 return NT_STATUS_INVALID_PARAMETER
;
1129 /* Ensure this is a directory. */
1130 status
= cli_smb2_create_fnum(cli
,
1132 0, /* create_flags */
1133 FILE_READ_ATTRIBUTES
, /* desired_access */
1134 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1135 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1136 FILE_OPEN
, /* create_disposition */
1137 FILE_DIRECTORY_FILE
, /* create_options */
1141 if (!NT_STATUS_IS_OK(status
)) {
1145 return cli_smb2_close_fnum(cli
, fnum
);
1148 /***************************************************************
1149 Helper function for pathname operations.
1150 ***************************************************************/
1152 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
1154 uint32_t desired_access
,
1158 size_t namelen
= strlen(name
);
1159 TALLOC_CTX
*frame
= talloc_stackframe();
1161 /* SMB2 is pickier about pathnames. Ensure it doesn't
1163 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1164 char *modname
= talloc_strdup(frame
, name
);
1165 if (modname
== NULL
) {
1166 status
= NT_STATUS_NO_MEMORY
;
1169 modname
[namelen
-1] = '\0';
1173 /* Try to open a file handle first. */
1174 status
= cli_smb2_create_fnum(cli
,
1176 0, /* create_flags */
1178 0, /* file attributes */
1179 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1180 FILE_OPEN
, /* create_disposition */
1181 0, /* create_options */
1185 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
1186 status
= cli_smb2_create_fnum(cli
,
1188 0, /* create_flags */
1190 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1191 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1192 FILE_OPEN
, /* create_disposition */
1193 FILE_DIRECTORY_FILE
, /* create_options */
1204 /***************************************************************
1205 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1207 ***************************************************************/
1209 NTSTATUS
cli_smb2_qpathinfo_alt_name(struct cli_state
*cli
,
1214 DATA_BLOB outbuf
= data_blob_null
;
1215 uint16_t fnum
= 0xffff;
1216 struct smb2_hnd
*ph
= NULL
;
1217 uint32_t altnamelen
= 0;
1218 TALLOC_CTX
*frame
= talloc_stackframe();
1220 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1222 * Can't use sync call while an async call is in flight
1224 status
= NT_STATUS_INVALID_PARAMETER
;
1228 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1229 status
= NT_STATUS_INVALID_PARAMETER
;
1233 status
= get_fnum_from_path(cli
,
1235 FILE_READ_ATTRIBUTES
,
1238 if (!NT_STATUS_IS_OK(status
)) {
1242 status
= map_fnum_to_smb2_handle(cli
,
1245 if (!NT_STATUS_IS_OK(status
)) {
1249 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1250 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1252 status
= smb2cli_query_info(cli
->conn
,
1256 1, /* in_info_type */
1257 (SMB_FILE_ALTERNATE_NAME_INFORMATION
- 1000), /* in_file_info_class */
1258 0xFFFF, /* in_max_output_length */
1259 NULL
, /* in_input_buffer */
1260 0, /* in_additional_info */
1267 if (!NT_STATUS_IS_OK(status
)) {
1271 /* Parse the reply. */
1272 if (outbuf
.length
< 4) {
1273 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1277 altnamelen
= IVAL(outbuf
.data
, 0);
1278 if (altnamelen
> outbuf
.length
- 4) {
1279 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1283 if (altnamelen
> 0) {
1285 char *short_name
= NULL
;
1286 ret
= pull_string_talloc(frame
,
1288 FLAGS2_UNICODE_STRINGS
,
1293 if (ret
== (size_t)-1) {
1294 /* Bad conversion. */
1295 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1299 fstrcpy(alt_name
, short_name
);
1304 status
= NT_STATUS_OK
;
1308 if (fnum
!= 0xffff) {
1309 cli_smb2_close_fnum(cli
, fnum
);
1312 cli
->raw_status
= status
;
1319 /***************************************************************
1320 Wrapper that allows SMB2 to query a fnum info (basic level).
1322 ***************************************************************/
1324 NTSTATUS
cli_smb2_qfileinfo_basic(struct cli_state
*cli
,
1328 struct timespec
*create_time
,
1329 struct timespec
*access_time
,
1330 struct timespec
*write_time
,
1331 struct timespec
*change_time
,
1335 DATA_BLOB outbuf
= data_blob_null
;
1336 struct smb2_hnd
*ph
= NULL
;
1337 TALLOC_CTX
*frame
= talloc_stackframe();
1339 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1341 * Can't use sync call while an async call is in flight
1343 status
= NT_STATUS_INVALID_PARAMETER
;
1347 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1348 status
= NT_STATUS_INVALID_PARAMETER
;
1352 status
= map_fnum_to_smb2_handle(cli
,
1355 if (!NT_STATUS_IS_OK(status
)) {
1359 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1360 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1362 status
= smb2cli_query_info(cli
->conn
,
1366 1, /* in_info_type */
1367 (SMB_FILE_ALL_INFORMATION
- 1000), /* in_file_info_class */
1368 0xFFFF, /* in_max_output_length */
1369 NULL
, /* in_input_buffer */
1370 0, /* in_additional_info */
1376 if (!NT_STATUS_IS_OK(status
)) {
1380 /* Parse the reply. */
1381 if (outbuf
.length
< 0x60) {
1382 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1387 *create_time
= interpret_long_date((const char *)outbuf
.data
+ 0x0);
1390 *access_time
= interpret_long_date((const char *)outbuf
.data
+ 0x8);
1393 *write_time
= interpret_long_date((const char *)outbuf
.data
+ 0x10);
1396 *change_time
= interpret_long_date((const char *)outbuf
.data
+ 0x18);
1399 uint32_t attr
= IVAL(outbuf
.data
, 0x20);
1400 *mode
= (uint16_t)attr
;
1403 uint64_t file_size
= BVAL(outbuf
.data
, 0x30);
1404 *size
= (off_t
)file_size
;
1407 uint64_t file_index
= BVAL(outbuf
.data
, 0x40);
1408 *ino
= (SMB_INO_T
)file_index
;
1413 cli
->raw_status
= status
;
1419 /***************************************************************
1420 Wrapper that allows SMB2 to query an fnum.
1421 Implement on top of cli_smb2_qfileinfo_basic().
1423 ***************************************************************/
1425 NTSTATUS
cli_smb2_getattrE(struct cli_state
*cli
,
1429 time_t *change_time
,
1430 time_t *access_time
,
1433 struct timespec access_time_ts
;
1434 struct timespec write_time_ts
;
1435 struct timespec change_time_ts
;
1436 NTSTATUS status
= cli_smb2_qfileinfo_basic(cli
,
1446 cli
->raw_status
= status
;
1448 if (!NT_STATUS_IS_OK(status
)) {
1453 *change_time
= change_time_ts
.tv_sec
;
1456 *access_time
= access_time_ts
.tv_sec
;
1459 *write_time
= write_time_ts
.tv_sec
;
1461 return NT_STATUS_OK
;
1464 /***************************************************************
1465 Wrapper that allows SMB2 to get pathname attributes.
1467 ***************************************************************/
1469 NTSTATUS
cli_smb2_getatr(struct cli_state
*cli
,
1476 uint16_t fnum
= 0xffff;
1477 struct smb2_hnd
*ph
= NULL
;
1478 TALLOC_CTX
*frame
= talloc_stackframe();
1480 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1482 * Can't use sync call while an async call is in flight
1484 status
= NT_STATUS_INVALID_PARAMETER
;
1488 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1489 status
= NT_STATUS_INVALID_PARAMETER
;
1493 status
= get_fnum_from_path(cli
,
1495 FILE_READ_ATTRIBUTES
,
1498 if (!NT_STATUS_IS_OK(status
)) {
1502 status
= map_fnum_to_smb2_handle(cli
,
1505 if (!NT_STATUS_IS_OK(status
)) {
1508 status
= cli_smb2_getattrE(cli
,
1515 if (!NT_STATUS_IS_OK(status
)) {
1521 if (fnum
!= 0xffff) {
1522 cli_smb2_close_fnum(cli
, fnum
);
1525 cli
->raw_status
= status
;
1531 /***************************************************************
1532 Wrapper that allows SMB2 to query a pathname info (basic level).
1533 Implement on top of cli_smb2_qfileinfo_basic().
1535 ***************************************************************/
1537 NTSTATUS
cli_smb2_qpathinfo2(struct cli_state
*cli
,
1539 struct timespec
*create_time
,
1540 struct timespec
*access_time
,
1541 struct timespec
*write_time
,
1542 struct timespec
*change_time
,
1548 struct smb2_hnd
*ph
= NULL
;
1549 uint16_t fnum
= 0xffff;
1550 TALLOC_CTX
*frame
= talloc_stackframe();
1552 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1554 * Can't use sync call while an async call is in flight
1556 status
= NT_STATUS_INVALID_PARAMETER
;
1560 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1561 status
= NT_STATUS_INVALID_PARAMETER
;
1565 status
= get_fnum_from_path(cli
,
1567 FILE_READ_ATTRIBUTES
,
1570 if (!NT_STATUS_IS_OK(status
)) {
1574 status
= map_fnum_to_smb2_handle(cli
,
1577 if (!NT_STATUS_IS_OK(status
)) {
1581 status
= cli_smb2_qfileinfo_basic(cli
,
1593 if (fnum
!= 0xffff) {
1594 cli_smb2_close_fnum(cli
, fnum
);
1597 cli
->raw_status
= status
;
1603 /***************************************************************
1604 Wrapper that allows SMB2 to query pathname streams.
1606 ***************************************************************/
1608 NTSTATUS
cli_smb2_qpathinfo_streams(struct cli_state
*cli
,
1610 TALLOC_CTX
*mem_ctx
,
1611 unsigned int *pnum_streams
,
1612 struct stream_struct
**pstreams
)
1615 struct smb2_hnd
*ph
= NULL
;
1616 uint16_t fnum
= 0xffff;
1617 DATA_BLOB outbuf
= data_blob_null
;
1618 TALLOC_CTX
*frame
= talloc_stackframe();
1620 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1622 * Can't use sync call while an async call is in flight
1624 status
= NT_STATUS_INVALID_PARAMETER
;
1628 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1629 status
= NT_STATUS_INVALID_PARAMETER
;
1633 status
= get_fnum_from_path(cli
,
1635 FILE_READ_ATTRIBUTES
,
1638 if (!NT_STATUS_IS_OK(status
)) {
1642 status
= map_fnum_to_smb2_handle(cli
,
1645 if (!NT_STATUS_IS_OK(status
)) {
1649 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1650 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1652 status
= smb2cli_query_info(cli
->conn
,
1656 1, /* in_info_type */
1657 (SMB_FILE_STREAM_INFORMATION
- 1000), /* in_file_info_class */
1658 0xFFFF, /* in_max_output_length */
1659 NULL
, /* in_input_buffer */
1660 0, /* in_additional_info */
1667 if (!NT_STATUS_IS_OK(status
)) {
1671 /* Parse the reply. */
1672 if (!parse_streams_blob(mem_ctx
,
1677 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1683 if (fnum
!= 0xffff) {
1684 cli_smb2_close_fnum(cli
, fnum
);
1687 cli
->raw_status
= status
;
1693 /***************************************************************
1694 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
1697 ***************************************************************/
1699 NTSTATUS
cli_smb2_setpathinfo(struct cli_state
*cli
,
1701 uint8_t in_info_type
,
1702 uint8_t in_file_info_class
,
1703 const DATA_BLOB
*p_in_data
)
1706 uint16_t fnum
= 0xffff;
1707 struct smb2_hnd
*ph
= NULL
;
1708 TALLOC_CTX
*frame
= talloc_stackframe();
1710 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1712 * Can't use sync call while an async call is in flight
1714 status
= NT_STATUS_INVALID_PARAMETER
;
1718 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1719 status
= NT_STATUS_INVALID_PARAMETER
;
1723 status
= get_fnum_from_path(cli
,
1725 FILE_WRITE_ATTRIBUTES
,
1728 if (!NT_STATUS_IS_OK(status
)) {
1732 status
= map_fnum_to_smb2_handle(cli
,
1735 if (!NT_STATUS_IS_OK(status
)) {
1739 status
= smb2cli_set_info(cli
->conn
,
1745 p_in_data
, /* in_input_buffer */
1746 0, /* in_additional_info */
1751 if (fnum
!= 0xffff) {
1752 cli_smb2_close_fnum(cli
, fnum
);
1755 cli
->raw_status
= status
;
1762 /***************************************************************
1763 Wrapper that allows SMB2 to set pathname attributes.
1765 ***************************************************************/
1767 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
1772 uint8_t inbuf_store
[40];
1773 DATA_BLOB inbuf
= data_blob_null
;
1775 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1776 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1778 inbuf
.data
= inbuf_store
;
1779 inbuf
.length
= sizeof(inbuf_store
);
1780 data_blob_clear(&inbuf
);
1783 * SMB1 uses attr == 0 to clear all attributes
1784 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
1785 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
1786 * request attribute change.
1788 * SMB2 uses exactly the reverse. Unfortunately as the
1789 * cli_setatr() ABI is exposed inside libsmbclient,
1790 * we must make the SMB2 cli_smb2_setatr() call
1791 * export the same ABI as the SMB1 cli_setatr()
1792 * which calls it. This means reversing the sense
1793 * of the requested attr argument if it's zero
1794 * or FILE_ATTRIBUTE_NORMAL.
1796 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
1800 attr
= FILE_ATTRIBUTE_NORMAL
;
1801 } else if (attr
== FILE_ATTRIBUTE_NORMAL
) {
1805 SSVAL(inbuf
.data
, 32, attr
);
1807 put_long_date((char *)inbuf
.data
+ 16,mtime
);
1809 /* Set all the other times to -1. */
1810 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1811 SBVAL(inbuf
.data
, 8, 0xFFFFFFFFFFFFFFFFLL
);
1812 SBVAL(inbuf
.data
, 24, 0xFFFFFFFFFFFFFFFFLL
);
1814 return cli_smb2_setpathinfo(cli
,
1816 1, /* in_info_type */
1817 /* in_file_info_class */
1818 SMB_FILE_BASIC_INFORMATION
- 1000,
1823 /***************************************************************
1824 Wrapper that allows SMB2 to set file handle times.
1826 ***************************************************************/
1828 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
1835 struct smb2_hnd
*ph
= NULL
;
1836 uint8_t inbuf_store
[40];
1837 DATA_BLOB inbuf
= data_blob_null
;
1839 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1841 * Can't use sync call while an async call is in flight
1843 return NT_STATUS_INVALID_PARAMETER
;
1846 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1847 return NT_STATUS_INVALID_PARAMETER
;
1850 status
= map_fnum_to_smb2_handle(cli
,
1853 if (!NT_STATUS_IS_OK(status
)) {
1857 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1858 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1860 inbuf
.data
= inbuf_store
;
1861 inbuf
.length
= sizeof(inbuf_store
);
1862 data_blob_clear(&inbuf
);
1864 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1865 if (change_time
!= 0) {
1866 put_long_date((char *)inbuf
.data
+ 24, change_time
);
1868 if (access_time
!= 0) {
1869 put_long_date((char *)inbuf
.data
+ 8, access_time
);
1871 if (write_time
!= 0) {
1872 put_long_date((char *)inbuf
.data
+ 16, write_time
);
1875 cli
->raw_status
= smb2cli_set_info(cli
->conn
,
1879 1, /* in_info_type */
1880 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1881 &inbuf
, /* in_input_buffer */
1882 0, /* in_additional_info */
1886 return cli
->raw_status
;
1889 /***************************************************************
1890 Wrapper that allows SMB2 to query disk attributes (size).
1892 ***************************************************************/
1894 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, const char *path
,
1895 uint64_t *bsize
, uint64_t *total
, uint64_t *avail
)
1898 uint16_t fnum
= 0xffff;
1899 DATA_BLOB outbuf
= data_blob_null
;
1900 struct smb2_hnd
*ph
= NULL
;
1901 uint32_t sectors_per_unit
= 0;
1902 uint32_t bytes_per_sector
= 0;
1903 uint64_t total_size
= 0;
1904 uint64_t size_free
= 0;
1905 TALLOC_CTX
*frame
= talloc_stackframe();
1907 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1909 * Can't use sync call while an async call is in flight
1911 status
= NT_STATUS_INVALID_PARAMETER
;
1915 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1916 status
= NT_STATUS_INVALID_PARAMETER
;
1920 /* First open the top level directory. */
1921 status
= cli_smb2_create_fnum(cli
,
1923 0, /* create_flags */
1924 FILE_READ_ATTRIBUTES
, /* desired_access */
1925 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1926 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1927 FILE_OPEN
, /* create_disposition */
1928 FILE_DIRECTORY_FILE
, /* create_options */
1932 if (!NT_STATUS_IS_OK(status
)) {
1936 status
= map_fnum_to_smb2_handle(cli
,
1939 if (!NT_STATUS_IS_OK(status
)) {
1943 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1944 level 3 (SMB_FS_SIZE_INFORMATION). */
1946 status
= smb2cli_query_info(cli
->conn
,
1950 2, /* in_info_type */
1951 3, /* in_file_info_class */
1952 0xFFFF, /* in_max_output_length */
1953 NULL
, /* in_input_buffer */
1954 0, /* in_additional_info */
1960 if (!NT_STATUS_IS_OK(status
)) {
1964 /* Parse the reply. */
1965 if (outbuf
.length
!= 24) {
1966 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1970 total_size
= BVAL(outbuf
.data
, 0);
1971 size_free
= BVAL(outbuf
.data
, 8);
1972 sectors_per_unit
= IVAL(outbuf
.data
, 16);
1973 bytes_per_sector
= IVAL(outbuf
.data
, 20);
1976 *bsize
= (uint64_t)sectors_per_unit
* (uint64_t)bytes_per_sector
;
1979 *total
= total_size
;
1985 status
= NT_STATUS_OK
;
1989 if (fnum
!= 0xffff) {
1990 cli_smb2_close_fnum(cli
, fnum
);
1993 cli
->raw_status
= status
;
1999 /***************************************************************
2000 Wrapper that allows SMB2 to query file system sizes.
2002 ***************************************************************/
2004 NTSTATUS
cli_smb2_get_fs_full_size_info(struct cli_state
*cli
,
2005 uint64_t *total_allocation_units
,
2006 uint64_t *caller_allocation_units
,
2007 uint64_t *actual_allocation_units
,
2008 uint64_t *sectors_per_allocation_unit
,
2009 uint64_t *bytes_per_sector
)
2012 uint16_t fnum
= 0xffff;
2013 DATA_BLOB outbuf
= data_blob_null
;
2014 struct smb2_hnd
*ph
= NULL
;
2015 TALLOC_CTX
*frame
= talloc_stackframe();
2017 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2019 * Can't use sync call while an async call is in flight
2021 status
= NT_STATUS_INVALID_PARAMETER
;
2025 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2026 status
= NT_STATUS_INVALID_PARAMETER
;
2030 /* First open the top level directory. */
2032 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2033 FILE_READ_ATTRIBUTES
, /* desired_access */
2034 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2035 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2036 FILE_SHARE_DELETE
, /* share_access */
2037 FILE_OPEN
, /* create_disposition */
2038 FILE_DIRECTORY_FILE
, /* create_options */
2042 if (!NT_STATUS_IS_OK(status
)) {
2046 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
2047 if (!NT_STATUS_IS_OK(status
)) {
2051 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2052 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2054 status
= smb2cli_query_info(cli
->conn
,
2058 SMB2_GETINFO_FS
, /* in_info_type */
2059 /* in_file_info_class */
2060 SMB_FS_FULL_SIZE_INFORMATION
- 1000,
2061 0xFFFF, /* in_max_output_length */
2062 NULL
, /* in_input_buffer */
2063 0, /* in_additional_info */
2069 if (!NT_STATUS_IS_OK(status
)) {
2073 if (outbuf
.length
< 32) {
2074 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2078 *total_allocation_units
= BIG_UINT(outbuf
.data
, 0);
2079 *caller_allocation_units
= BIG_UINT(outbuf
.data
, 8);
2080 *actual_allocation_units
= BIG_UINT(outbuf
.data
, 16);
2081 *sectors_per_allocation_unit
= (uint64_t)IVAL(outbuf
.data
, 24);
2082 *bytes_per_sector
= (uint64_t)IVAL(outbuf
.data
, 28);
2086 if (fnum
!= 0xffff) {
2087 cli_smb2_close_fnum(cli
, fnum
);
2090 cli
->raw_status
= status
;
2096 /***************************************************************
2097 Wrapper that allows SMB2 to query file system attributes.
2099 ***************************************************************/
2101 NTSTATUS
cli_smb2_get_fs_attr_info(struct cli_state
*cli
, uint32_t *fs_attr
)
2104 uint16_t fnum
= 0xffff;
2105 DATA_BLOB outbuf
= data_blob_null
;
2106 struct smb2_hnd
*ph
= NULL
;
2107 TALLOC_CTX
*frame
= talloc_stackframe();
2109 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2111 * Can't use sync call while an async call is in flight
2113 status
= NT_STATUS_INVALID_PARAMETER
;
2117 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2118 status
= NT_STATUS_INVALID_PARAMETER
;
2122 /* First open the top level directory. */
2124 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2125 FILE_READ_ATTRIBUTES
, /* desired_access */
2126 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2127 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2128 FILE_SHARE_DELETE
, /* share_access */
2129 FILE_OPEN
, /* create_disposition */
2130 FILE_DIRECTORY_FILE
, /* create_options */
2134 if (!NT_STATUS_IS_OK(status
)) {
2138 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
2139 if (!NT_STATUS_IS_OK(status
)) {
2143 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
2144 cli
->smb2
.tcon
, 2, /* in_info_type */
2145 5, /* in_file_info_class */
2146 0xFFFF, /* in_max_output_length */
2147 NULL
, /* in_input_buffer */
2148 0, /* in_additional_info */
2150 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
2152 if (!NT_STATUS_IS_OK(status
)) {
2156 if (outbuf
.length
< 12) {
2157 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2161 *fs_attr
= IVAL(outbuf
.data
, 0);
2165 if (fnum
!= 0xffff) {
2166 cli_smb2_close_fnum(cli
, fnum
);
2169 cli
->raw_status
= status
;
2175 /***************************************************************
2176 Wrapper that allows SMB2 to query file system volume info.
2178 ***************************************************************/
2180 NTSTATUS
cli_smb2_get_fs_volume_info(struct cli_state
*cli
,
2181 TALLOC_CTX
*mem_ctx
,
2182 char **_volume_name
,
2183 uint32_t *pserial_number
,
2187 uint16_t fnum
= 0xffff;
2188 DATA_BLOB outbuf
= data_blob_null
;
2189 struct smb2_hnd
*ph
= NULL
;
2191 char *volume_name
= NULL
;
2192 TALLOC_CTX
*frame
= talloc_stackframe();
2194 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2196 * Can't use sync call while an async call is in flight
2198 status
= NT_STATUS_INVALID_PARAMETER
;
2202 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2203 status
= NT_STATUS_INVALID_PARAMETER
;
2207 /* First open the top level directory. */
2209 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2210 FILE_READ_ATTRIBUTES
, /* desired_access */
2211 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2212 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2213 FILE_SHARE_DELETE
, /* share_access */
2214 FILE_OPEN
, /* create_disposition */
2215 FILE_DIRECTORY_FILE
, /* create_options */
2219 if (!NT_STATUS_IS_OK(status
)) {
2223 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
2224 if (!NT_STATUS_IS_OK(status
)) {
2228 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2229 level 1 (SMB_FS_VOLUME_INFORMATION). */
2231 status
= smb2cli_query_info(cli
->conn
,
2235 SMB2_GETINFO_FS
, /* in_info_type */
2236 /* in_file_info_class */
2237 SMB_FS_VOLUME_INFORMATION
- 1000,
2238 0xFFFF, /* in_max_output_length */
2239 NULL
, /* in_input_buffer */
2240 0, /* in_additional_info */
2246 if (!NT_STATUS_IS_OK(status
)) {
2250 if (outbuf
.length
< 24) {
2251 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2257 ts
= interpret_long_date((char *)outbuf
.data
);
2260 if (pserial_number
) {
2261 *pserial_number
= IVAL(outbuf
.data
,8);
2263 nlen
= IVAL(outbuf
.data
,12);
2264 if (nlen
+ 18 < 18) {
2266 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2270 * The next check is safe as we know outbuf.length >= 24
2273 if (nlen
> (outbuf
.length
- 18)) {
2274 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2278 clistr_pull_talloc(mem_ctx
,
2279 (const char *)outbuf
.data
,
2285 if (volume_name
== NULL
) {
2286 status
= map_nt_error_from_unix(errno
);
2290 *_volume_name
= volume_name
;
2294 if (fnum
!= 0xffff) {
2295 cli_smb2_close_fnum(cli
, fnum
);
2298 cli
->raw_status
= status
;
2305 /***************************************************************
2306 Wrapper that allows SMB2 to query a security descriptor.
2308 ***************************************************************/
2310 NTSTATUS
cli_smb2_query_security_descriptor(struct cli_state
*cli
,
2313 TALLOC_CTX
*mem_ctx
,
2314 struct security_descriptor
**ppsd
)
2317 DATA_BLOB outbuf
= data_blob_null
;
2318 struct smb2_hnd
*ph
= NULL
;
2319 struct security_descriptor
*lsd
= NULL
;
2320 TALLOC_CTX
*frame
= talloc_stackframe();
2322 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2324 * Can't use sync call while an async call is in flight
2326 status
= NT_STATUS_INVALID_PARAMETER
;
2330 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2331 status
= NT_STATUS_INVALID_PARAMETER
;
2335 status
= map_fnum_to_smb2_handle(cli
,
2338 if (!NT_STATUS_IS_OK(status
)) {
2342 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2344 status
= smb2cli_query_info(cli
->conn
,
2348 3, /* in_info_type */
2349 0, /* in_file_info_class */
2350 0xFFFF, /* in_max_output_length */
2351 NULL
, /* in_input_buffer */
2352 sec_info
, /* in_additional_info */
2359 if (!NT_STATUS_IS_OK(status
)) {
2363 /* Parse the reply. */
2364 status
= unmarshall_sec_desc(mem_ctx
,
2369 if (!NT_STATUS_IS_OK(status
)) {
2381 cli
->raw_status
= status
;
2387 /***************************************************************
2388 Wrapper that allows SMB2 to set a security descriptor.
2390 ***************************************************************/
2392 NTSTATUS
cli_smb2_set_security_descriptor(struct cli_state
*cli
,
2395 const struct security_descriptor
*sd
)
2398 DATA_BLOB inbuf
= data_blob_null
;
2399 struct smb2_hnd
*ph
= NULL
;
2400 TALLOC_CTX
*frame
= talloc_stackframe();
2402 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2404 * Can't use sync call while an async call is in flight
2406 status
= NT_STATUS_INVALID_PARAMETER
;
2410 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2411 status
= NT_STATUS_INVALID_PARAMETER
;
2415 status
= map_fnum_to_smb2_handle(cli
,
2418 if (!NT_STATUS_IS_OK(status
)) {
2422 status
= marshall_sec_desc(frame
,
2427 if (!NT_STATUS_IS_OK(status
)) {
2431 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2433 status
= smb2cli_set_info(cli
->conn
,
2437 3, /* in_info_type */
2438 0, /* in_file_info_class */
2439 &inbuf
, /* in_input_buffer */
2440 sec_info
, /* in_additional_info */
2446 cli
->raw_status
= status
;
2452 /***************************************************************
2453 Wrapper that allows SMB2 to rename a file.
2455 ***************************************************************/
2457 NTSTATUS
cli_smb2_rename(struct cli_state
*cli
,
2458 const char *fname_src
,
2459 const char *fname_dst
,
2463 DATA_BLOB inbuf
= data_blob_null
;
2464 uint16_t fnum
= 0xffff;
2465 struct smb2_hnd
*ph
= NULL
;
2466 smb_ucs2_t
*converted_str
= NULL
;
2467 size_t converted_size_bytes
= 0;
2469 TALLOC_CTX
*frame
= talloc_stackframe();
2471 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2473 * Can't use sync call while an async call is in flight
2475 status
= NT_STATUS_INVALID_PARAMETER
;
2479 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2480 status
= NT_STATUS_INVALID_PARAMETER
;
2484 status
= get_fnum_from_path(cli
,
2489 if (!NT_STATUS_IS_OK(status
)) {
2493 status
= map_fnum_to_smb2_handle(cli
,
2496 if (!NT_STATUS_IS_OK(status
)) {
2500 /* SMB2 is pickier about pathnames. Ensure it doesn't
2502 if (*fname_dst
== '\\') {
2506 /* SMB2 is pickier about pathnames. Ensure it doesn't
2508 namelen
= strlen(fname_dst
);
2509 if (namelen
> 0 && fname_dst
[namelen
-1] == '\\') {
2510 char *modname
= talloc_strdup(frame
, fname_dst
);
2511 modname
[namelen
-1] = '\0';
2512 fname_dst
= modname
;
2515 if (!push_ucs2_talloc(frame
,
2518 &converted_size_bytes
)) {
2519 status
= NT_STATUS_INVALID_PARAMETER
;
2523 /* W2K8 insists the dest name is not null
2524 terminated. Remove the last 2 zero bytes
2525 and reduce the name length. */
2527 if (converted_size_bytes
< 2) {
2528 status
= NT_STATUS_INVALID_PARAMETER
;
2531 converted_size_bytes
-= 2;
2533 inbuf
= data_blob_talloc_zero(frame
,
2534 20 + converted_size_bytes
);
2535 if (inbuf
.data
== NULL
) {
2536 status
= NT_STATUS_NO_MEMORY
;
2541 SCVAL(inbuf
.data
, 0, 1);
2544 SIVAL(inbuf
.data
, 16, converted_size_bytes
);
2545 memcpy(inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
2547 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2548 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2550 status
= smb2cli_set_info(cli
->conn
,
2554 1, /* in_info_type */
2555 SMB_FILE_RENAME_INFORMATION
- 1000, /* in_file_info_class */
2556 &inbuf
, /* in_input_buffer */
2557 0, /* in_additional_info */
2563 if (fnum
!= 0xffff) {
2564 cli_smb2_close_fnum(cli
, fnum
);
2567 cli
->raw_status
= status
;
2573 /***************************************************************
2574 Wrapper that allows SMB2 to set an EA on a fnum.
2576 ***************************************************************/
2578 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
2580 const char *ea_name
,
2585 DATA_BLOB inbuf
= data_blob_null
;
2587 char *ea_name_ascii
= NULL
;
2589 struct smb2_hnd
*ph
= NULL
;
2590 TALLOC_CTX
*frame
= talloc_stackframe();
2592 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2594 * Can't use sync call while an async call is in flight
2596 status
= NT_STATUS_INVALID_PARAMETER
;
2600 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2601 status
= NT_STATUS_INVALID_PARAMETER
;
2605 status
= map_fnum_to_smb2_handle(cli
,
2608 if (!NT_STATUS_IS_OK(status
)) {
2612 /* Marshall the SMB2 EA data. */
2613 if (ea_len
> 0xFFFF) {
2614 status
= NT_STATUS_INVALID_PARAMETER
;
2618 if (!push_ascii_talloc(frame
,
2622 status
= NT_STATUS_INVALID_PARAMETER
;
2626 if (namelen
< 2 || namelen
> 0xFF) {
2627 status
= NT_STATUS_INVALID_PARAMETER
;
2631 bloblen
= 8 + ea_len
+ namelen
;
2632 /* Round up to a 4 byte boundary. */
2633 bloblen
= ((bloblen
+ 3)&~3);
2635 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
2636 if (inbuf
.data
== NULL
) {
2637 status
= NT_STATUS_NO_MEMORY
;
2640 /* namelen doesn't include the NULL byte. */
2641 SCVAL(inbuf
.data
, 5, namelen
- 1);
2642 SSVAL(inbuf
.data
, 6, ea_len
);
2643 memcpy(inbuf
.data
+ 8, ea_name_ascii
, namelen
);
2644 memcpy(inbuf
.data
+ 8 + namelen
, ea_val
, ea_len
);
2646 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2647 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2649 status
= smb2cli_set_info(cli
->conn
,
2653 1, /* in_info_type */
2654 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
2655 &inbuf
, /* in_input_buffer */
2656 0, /* in_additional_info */
2662 cli
->raw_status
= status
;
2668 /***************************************************************
2669 Wrapper that allows SMB2 to set an EA on a pathname.
2671 ***************************************************************/
2673 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
2675 const char *ea_name
,
2680 uint16_t fnum
= 0xffff;
2682 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2684 * Can't use sync call while an async call is in flight
2686 status
= NT_STATUS_INVALID_PARAMETER
;
2690 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2691 status
= NT_STATUS_INVALID_PARAMETER
;
2695 status
= get_fnum_from_path(cli
,
2700 if (!NT_STATUS_IS_OK(status
)) {
2704 status
= cli_set_ea_fnum(cli
,
2709 if (!NT_STATUS_IS_OK(status
)) {
2715 if (fnum
!= 0xffff) {
2716 cli_smb2_close_fnum(cli
, fnum
);
2719 cli
->raw_status
= status
;
2724 /***************************************************************
2725 Wrapper that allows SMB2 to get an EA list on a pathname.
2727 ***************************************************************/
2729 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
2733 struct ea_struct
**pea_array
)
2736 uint16_t fnum
= 0xffff;
2737 DATA_BLOB outbuf
= data_blob_null
;
2738 struct smb2_hnd
*ph
= NULL
;
2739 struct ea_list
*ea_list
= NULL
;
2740 struct ea_list
*eal
= NULL
;
2741 size_t ea_count
= 0;
2742 TALLOC_CTX
*frame
= talloc_stackframe();
2747 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2749 * Can't use sync call while an async call is in flight
2751 status
= NT_STATUS_INVALID_PARAMETER
;
2755 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2756 status
= NT_STATUS_INVALID_PARAMETER
;
2760 status
= get_fnum_from_path(cli
,
2765 if (!NT_STATUS_IS_OK(status
)) {
2769 status
= map_fnum_to_smb2_handle(cli
,
2772 if (!NT_STATUS_IS_OK(status
)) {
2776 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2777 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2779 status
= smb2cli_query_info(cli
->conn
,
2783 1, /* in_info_type */
2784 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
2785 0xFFFF, /* in_max_output_length */
2786 NULL
, /* in_input_buffer */
2787 0, /* in_additional_info */
2794 if (!NT_STATUS_IS_OK(status
)) {
2798 /* Parse the reply. */
2799 ea_list
= read_nttrans_ea_list(ctx
,
2800 (const char *)outbuf
.data
,
2802 if (ea_list
== NULL
) {
2803 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2807 /* Convert to an array. */
2808 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2813 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
2814 if (*pea_array
== NULL
) {
2815 status
= NT_STATUS_NO_MEMORY
;
2819 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2820 (*pea_array
)[ea_count
++] = eal
->ea
;
2822 *pnum_eas
= ea_count
;
2827 if (fnum
!= 0xffff) {
2828 cli_smb2_close_fnum(cli
, fnum
);
2831 cli
->raw_status
= status
;
2837 /***************************************************************
2838 Wrapper that allows SMB2 to get user quota.
2840 ***************************************************************/
2842 NTSTATUS
cli_smb2_get_user_quota(struct cli_state
*cli
,
2844 SMB_NTQUOTA_STRUCT
*pqt
)
2847 DATA_BLOB inbuf
= data_blob_null
;
2848 DATA_BLOB outbuf
= data_blob_null
;
2849 struct smb2_hnd
*ph
= NULL
;
2850 TALLOC_CTX
*frame
= talloc_stackframe();
2852 unsigned int offset
;
2855 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2857 * Can't use sync call while an async call is in flight
2859 status
= NT_STATUS_INVALID_PARAMETER
;
2863 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2864 status
= NT_STATUS_INVALID_PARAMETER
;
2868 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
2869 if (!NT_STATUS_IS_OK(status
)) {
2873 sid_len
= ndr_size_dom_sid(&pqt
->sid
, 0);
2875 inbuf
= data_blob_talloc_zero(frame
, 24 + sid_len
);
2876 if (inbuf
.data
== NULL
) {
2877 status
= NT_STATUS_NO_MEMORY
;
2883 SCVAL(buf
, 0, 1); /* ReturnSingle */
2884 SCVAL(buf
, 1, 0); /* RestartScan */
2885 SSVAL(buf
, 2, 0); /* Reserved */
2886 if (8 + sid_len
< 8) {
2887 status
= NT_STATUS_INVALID_PARAMETER
;
2890 SIVAL(buf
, 4, 8 + sid_len
); /* SidListLength */
2891 SIVAL(buf
, 8, 0); /* StartSidLength */
2892 SIVAL(buf
, 12, 0); /* StartSidOffset */
2893 SIVAL(buf
, 16, 0); /* NextEntryOffset */
2894 SIVAL(buf
, 20, sid_len
); /* SidLength */
2895 sid_linearize(buf
+ 24, sid_len
, &pqt
->sid
);
2897 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
2898 cli
->smb2
.tcon
, 4, /* in_info_type */
2899 0, /* in_file_info_class */
2900 0xFFFF, /* in_max_output_length */
2901 &inbuf
, /* in_input_buffer */
2902 0, /* in_additional_info */
2904 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
2907 if (!NT_STATUS_IS_OK(status
)) {
2911 if (!parse_user_quota_record(outbuf
.data
, outbuf
.length
, &offset
,
2913 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2914 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
2918 cli
->raw_status
= status
;
2924 /***************************************************************
2925 Wrapper that allows SMB2 to list user quota.
2927 ***************************************************************/
2929 NTSTATUS
cli_smb2_list_user_quota_step(struct cli_state
*cli
,
2930 TALLOC_CTX
*mem_ctx
,
2932 SMB_NTQUOTA_LIST
**pqt_list
,
2936 DATA_BLOB inbuf
= data_blob_null
;
2937 DATA_BLOB outbuf
= data_blob_null
;
2938 struct smb2_hnd
*ph
= NULL
;
2939 TALLOC_CTX
*frame
= talloc_stackframe();
2942 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2944 * Can't use sync call while an async call is in flight
2946 status
= NT_STATUS_INVALID_PARAMETER
;
2950 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2951 status
= NT_STATUS_INVALID_PARAMETER
;
2955 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
2956 if (!NT_STATUS_IS_OK(status
)) {
2960 inbuf
= data_blob_talloc_zero(frame
, 16);
2961 if (inbuf
.data
== NULL
) {
2962 status
= NT_STATUS_NO_MEMORY
;
2968 SCVAL(buf
, 0, 0); /* ReturnSingle */
2969 SCVAL(buf
, 1, first
? 1 : 0); /* RestartScan */
2970 SSVAL(buf
, 2, 0); /* Reserved */
2971 SIVAL(buf
, 4, 0); /* SidListLength */
2972 SIVAL(buf
, 8, 0); /* StartSidLength */
2973 SIVAL(buf
, 12, 0); /* StartSidOffset */
2975 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
2976 cli
->smb2
.tcon
, 4, /* in_info_type */
2977 0, /* in_file_info_class */
2978 0xFFFF, /* in_max_output_length */
2979 &inbuf
, /* in_input_buffer */
2980 0, /* in_additional_info */
2982 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
2985 if (!NT_STATUS_IS_OK(status
)) {
2989 status
= parse_user_quota_list(outbuf
.data
, outbuf
.length
, mem_ctx
,
2993 cli
->raw_status
= status
;
2999 /***************************************************************
3000 Wrapper that allows SMB2 to get file system quota.
3002 ***************************************************************/
3004 NTSTATUS
cli_smb2_get_fs_quota_info(struct cli_state
*cli
,
3006 SMB_NTQUOTA_STRUCT
*pqt
)
3009 DATA_BLOB outbuf
= data_blob_null
;
3010 struct smb2_hnd
*ph
= NULL
;
3011 TALLOC_CTX
*frame
= talloc_stackframe();
3013 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3015 * Can't use sync call while an async call is in flight
3017 status
= NT_STATUS_INVALID_PARAMETER
;
3021 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3022 status
= NT_STATUS_INVALID_PARAMETER
;
3026 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
3027 if (!NT_STATUS_IS_OK(status
)) {
3031 status
= smb2cli_query_info(
3032 cli
->conn
, cli
->timeout
, cli
->smb2
.session
, cli
->smb2
.tcon
,
3033 2, /* in_info_type */
3034 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
3035 0xFFFF, /* in_max_output_length */
3036 NULL
, /* in_input_buffer */
3037 0, /* in_additional_info */
3039 ph
->fid_persistent
, ph
->fid_volatile
, frame
, &outbuf
);
3041 if (!NT_STATUS_IS_OK(status
)) {
3045 status
= parse_fs_quota_buffer(outbuf
.data
, outbuf
.length
, pqt
);
3048 cli
->raw_status
= status
;
3054 /***************************************************************
3055 Wrapper that allows SMB2 to set user quota.
3057 ***************************************************************/
3059 NTSTATUS
cli_smb2_set_user_quota(struct cli_state
*cli
,
3061 SMB_NTQUOTA_LIST
*qtl
)
3064 DATA_BLOB inbuf
= data_blob_null
;
3065 struct smb2_hnd
*ph
= NULL
;
3066 TALLOC_CTX
*frame
= talloc_stackframe();
3068 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3070 * Can't use sync call while an async call is in flight
3072 status
= NT_STATUS_INVALID_PARAMETER
;
3076 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3077 status
= NT_STATUS_INVALID_PARAMETER
;
3081 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
3082 if (!NT_STATUS_IS_OK(status
)) {
3086 status
= build_user_quota_buffer(qtl
, 0, talloc_tos(), &inbuf
, NULL
);
3087 if (!NT_STATUS_IS_OK(status
)) {
3091 status
= smb2cli_set_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
3092 cli
->smb2
.tcon
, 4, /* in_info_type */
3093 0, /* in_file_info_class */
3094 &inbuf
, /* in_input_buffer */
3095 0, /* in_additional_info */
3096 ph
->fid_persistent
, ph
->fid_volatile
);
3099 cli
->raw_status
= status
;
3106 NTSTATUS
cli_smb2_set_fs_quota_info(struct cli_state
*cli
,
3108 SMB_NTQUOTA_STRUCT
*pqt
)
3111 DATA_BLOB inbuf
= data_blob_null
;
3112 struct smb2_hnd
*ph
= NULL
;
3113 TALLOC_CTX
*frame
= talloc_stackframe();
3115 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3117 * Can't use sync call while an async call is in flight
3119 status
= NT_STATUS_INVALID_PARAMETER
;
3123 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3124 status
= NT_STATUS_INVALID_PARAMETER
;
3128 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
3129 if (!NT_STATUS_IS_OK(status
)) {
3133 status
= build_fs_quota_buffer(talloc_tos(), pqt
, &inbuf
, 0);
3134 if (!NT_STATUS_IS_OK(status
)) {
3138 status
= smb2cli_set_info(
3139 cli
->conn
, cli
->timeout
, cli
->smb2
.session
, cli
->smb2
.tcon
,
3140 2, /* in_info_type */
3141 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
3142 &inbuf
, /* in_input_buffer */
3143 0, /* in_additional_info */
3144 ph
->fid_persistent
, ph
->fid_volatile
);
3146 cli
->raw_status
= status
;
3152 struct cli_smb2_read_state
{
3153 struct tevent_context
*ev
;
3154 struct cli_state
*cli
;
3155 struct smb2_hnd
*ph
;
3156 uint64_t start_offset
;
3162 static void cli_smb2_read_done(struct tevent_req
*subreq
);
3164 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
3165 struct tevent_context
*ev
,
3166 struct cli_state
*cli
,
3172 struct tevent_req
*req
, *subreq
;
3173 struct cli_smb2_read_state
*state
;
3175 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
3181 state
->start_offset
= (uint64_t)offset
;
3182 state
->size
= (uint32_t)size
;
3183 state
->received
= 0;
3186 status
= map_fnum_to_smb2_handle(cli
,
3189 if (tevent_req_nterror(req
, status
)) {
3190 return tevent_req_post(req
, ev
);
3193 subreq
= smb2cli_read_send(state
,
3196 state
->cli
->timeout
,
3197 state
->cli
->smb2
.session
,
3198 state
->cli
->smb2
.tcon
,
3200 state
->start_offset
,
3201 state
->ph
->fid_persistent
,
3202 state
->ph
->fid_volatile
,
3203 0, /* minimum_count */
3204 0); /* remaining_bytes */
3206 if (tevent_req_nomem(subreq
, req
)) {
3207 return tevent_req_post(req
, ev
);
3209 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
3213 static void cli_smb2_read_done(struct tevent_req
*subreq
)
3215 struct tevent_req
*req
= tevent_req_callback_data(
3216 subreq
, struct tevent_req
);
3217 struct cli_smb2_read_state
*state
= tevent_req_data(
3218 req
, struct cli_smb2_read_state
);
3221 status
= smb2cli_read_recv(subreq
, state
,
3222 &state
->buf
, &state
->received
);
3223 if (tevent_req_nterror(req
, status
)) {
3227 if (state
->received
> state
->size
) {
3228 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3232 tevent_req_done(req
);
3235 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
3240 struct cli_smb2_read_state
*state
= tevent_req_data(
3241 req
, struct cli_smb2_read_state
);
3243 if (tevent_req_is_nterror(req
, &status
)) {
3244 state
->cli
->raw_status
= status
;
3248 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3249 * better make sure that you copy it away before you talloc_free(req).
3250 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3252 *received
= (ssize_t
)state
->received
;
3253 *rcvbuf
= state
->buf
;
3254 state
->cli
->raw_status
= NT_STATUS_OK
;
3255 return NT_STATUS_OK
;
3258 struct cli_smb2_write_state
{
3259 struct tevent_context
*ev
;
3260 struct cli_state
*cli
;
3261 struct smb2_hnd
*ph
;
3269 static void cli_smb2_write_written(struct tevent_req
*req
);
3271 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
3272 struct tevent_context
*ev
,
3273 struct cli_state
*cli
,
3281 struct tevent_req
*req
, *subreq
= NULL
;
3282 struct cli_smb2_write_state
*state
= NULL
;
3284 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
3290 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3291 state
->flags
= (uint32_t)mode
;
3293 state
->offset
= (uint64_t)offset
;
3294 state
->size
= (uint32_t)size
;
3297 status
= map_fnum_to_smb2_handle(cli
,
3300 if (tevent_req_nterror(req
, status
)) {
3301 return tevent_req_post(req
, ev
);
3304 subreq
= smb2cli_write_send(state
,
3307 state
->cli
->timeout
,
3308 state
->cli
->smb2
.session
,
3309 state
->cli
->smb2
.tcon
,
3312 state
->ph
->fid_persistent
,
3313 state
->ph
->fid_volatile
,
3314 0, /* remaining_bytes */
3315 state
->flags
, /* flags */
3318 if (tevent_req_nomem(subreq
, req
)) {
3319 return tevent_req_post(req
, ev
);
3321 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
3325 static void cli_smb2_write_written(struct tevent_req
*subreq
)
3327 struct tevent_req
*req
= tevent_req_callback_data(
3328 subreq
, struct tevent_req
);
3329 struct cli_smb2_write_state
*state
= tevent_req_data(
3330 req
, struct cli_smb2_write_state
);
3334 status
= smb2cli_write_recv(subreq
, &written
);
3335 TALLOC_FREE(subreq
);
3336 if (tevent_req_nterror(req
, status
)) {
3340 state
->written
= written
;
3342 tevent_req_done(req
);
3345 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
3348 struct cli_smb2_write_state
*state
= tevent_req_data(
3349 req
, struct cli_smb2_write_state
);
3352 if (tevent_req_is_nterror(req
, &status
)) {
3353 state
->cli
->raw_status
= status
;
3354 tevent_req_received(req
);
3358 if (pwritten
!= NULL
) {
3359 *pwritten
= (size_t)state
->written
;
3361 state
->cli
->raw_status
= NT_STATUS_OK
;
3362 tevent_req_received(req
);
3363 return NT_STATUS_OK
;
3366 /***************************************************************
3367 Wrapper that allows SMB2 async write using an fnum.
3368 This is mostly cut-and-paste from Volker's code inside
3369 source3/libsmb/clireadwrite.c, adapted for SMB2.
3371 Done this way so I can reuse all the logic inside cli_push()
3373 ***************************************************************/
3375 struct cli_smb2_writeall_state
{
3376 struct tevent_context
*ev
;
3377 struct cli_state
*cli
;
3378 struct smb2_hnd
*ph
;
3386 static void cli_smb2_writeall_written(struct tevent_req
*req
);
3388 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
3389 struct tevent_context
*ev
,
3390 struct cli_state
*cli
,
3398 struct tevent_req
*req
, *subreq
= NULL
;
3399 struct cli_smb2_writeall_state
*state
= NULL
;
3404 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
3410 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3411 state
->flags
= (uint32_t)mode
;
3413 state
->offset
= (uint64_t)offset
;
3414 state
->size
= (uint32_t)size
;
3417 status
= map_fnum_to_smb2_handle(cli
,
3420 if (tevent_req_nterror(req
, status
)) {
3421 return tevent_req_post(req
, ev
);
3424 to_write
= state
->size
;
3425 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
3426 to_write
= MIN(max_size
, to_write
);
3427 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
3429 to_write
= MIN(max_size
, to_write
);
3432 subreq
= smb2cli_write_send(state
,
3435 state
->cli
->timeout
,
3436 state
->cli
->smb2
.session
,
3437 state
->cli
->smb2
.tcon
,
3440 state
->ph
->fid_persistent
,
3441 state
->ph
->fid_volatile
,
3442 0, /* remaining_bytes */
3443 state
->flags
, /* flags */
3444 state
->buf
+ state
->written
);
3446 if (tevent_req_nomem(subreq
, req
)) {
3447 return tevent_req_post(req
, ev
);
3449 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
3453 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
3455 struct tevent_req
*req
= tevent_req_callback_data(
3456 subreq
, struct tevent_req
);
3457 struct cli_smb2_writeall_state
*state
= tevent_req_data(
3458 req
, struct cli_smb2_writeall_state
);
3460 uint32_t written
, to_write
;
3464 status
= smb2cli_write_recv(subreq
, &written
);
3465 TALLOC_FREE(subreq
);
3466 if (tevent_req_nterror(req
, status
)) {
3470 state
->written
+= written
;
3472 if (state
->written
> state
->size
) {
3473 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3477 to_write
= state
->size
- state
->written
;
3479 if (to_write
== 0) {
3480 tevent_req_done(req
);
3484 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
3485 to_write
= MIN(max_size
, to_write
);
3486 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
3488 to_write
= MIN(max_size
, to_write
);
3491 subreq
= smb2cli_write_send(state
,
3494 state
->cli
->timeout
,
3495 state
->cli
->smb2
.session
,
3496 state
->cli
->smb2
.tcon
,
3498 state
->offset
+ state
->written
,
3499 state
->ph
->fid_persistent
,
3500 state
->ph
->fid_volatile
,
3501 0, /* remaining_bytes */
3502 state
->flags
, /* flags */
3503 state
->buf
+ state
->written
);
3505 if (tevent_req_nomem(subreq
, req
)) {
3508 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
3511 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
3514 struct cli_smb2_writeall_state
*state
= tevent_req_data(
3515 req
, struct cli_smb2_writeall_state
);
3518 if (tevent_req_is_nterror(req
, &status
)) {
3519 state
->cli
->raw_status
= status
;
3522 if (pwritten
!= NULL
) {
3523 *pwritten
= (size_t)state
->written
;
3525 state
->cli
->raw_status
= NT_STATUS_OK
;
3526 return NT_STATUS_OK
;
3529 struct cli_smb2_splice_state
{
3530 struct tevent_context
*ev
;
3531 struct cli_state
*cli
;
3532 struct smb2_hnd
*src_ph
;
3533 struct smb2_hnd
*dst_ph
;
3534 int (*splice_cb
)(off_t n
, void *priv
);
3541 struct req_resume_key_rsp resume_rsp
;
3542 struct srv_copychunk_copy cc_copy
;
3545 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
3546 struct tevent_req
*req
);
3548 static void cli_splice_copychunk_done(struct tevent_req
*subreq
)
3550 struct tevent_req
*req
= tevent_req_callback_data(
3551 subreq
, struct tevent_req
);
3552 struct cli_smb2_splice_state
*state
=
3553 tevent_req_data(req
,
3554 struct cli_smb2_splice_state
);
3555 struct smbXcli_conn
*conn
= state
->cli
->conn
;
3556 DATA_BLOB out_input_buffer
= data_blob_null
;
3557 DATA_BLOB out_output_buffer
= data_blob_null
;
3558 struct srv_copychunk_rsp cc_copy_rsp
;
3559 enum ndr_err_code ndr_ret
;
3562 status
= smb2cli_ioctl_recv(subreq
, state
,
3564 &out_output_buffer
);
3565 TALLOC_FREE(subreq
);
3566 if ((!NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
) ||
3567 state
->resized
) && tevent_req_nterror(req
, status
)) {
3571 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
, state
, &cc_copy_rsp
,
3572 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
3573 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
3574 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3575 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3579 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
3580 uint32_t max_chunks
= MIN(cc_copy_rsp
.chunks_written
,
3581 cc_copy_rsp
.total_bytes_written
/ cc_copy_rsp
.chunk_bytes_written
);
3582 if ((cc_copy_rsp
.chunk_bytes_written
> smb2cli_conn_cc_chunk_len(conn
) ||
3583 max_chunks
> smb2cli_conn_cc_max_chunks(conn
)) &&
3584 tevent_req_nterror(req
, status
)) {
3588 state
->resized
= true;
3589 smb2cli_conn_set_cc_chunk_len(conn
, cc_copy_rsp
.chunk_bytes_written
);
3590 smb2cli_conn_set_cc_max_chunks(conn
, max_chunks
);
3592 if ((state
->src_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
3593 (state
->dst_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
3594 (state
->written
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
)) {
3595 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
3598 state
->src_offset
+= cc_copy_rsp
.total_bytes_written
;
3599 state
->dst_offset
+= cc_copy_rsp
.total_bytes_written
;
3600 state
->written
+= cc_copy_rsp
.total_bytes_written
;
3601 if (!state
->splice_cb(state
->written
, state
->priv
)) {
3602 tevent_req_nterror(req
, NT_STATUS_CANCELLED
);
3607 cli_splice_copychunk_send(state
, req
);
3610 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
3611 struct tevent_req
*req
)
3613 struct tevent_req
*subreq
;
3614 enum ndr_err_code ndr_ret
;
3615 struct smbXcli_conn
*conn
= state
->cli
->conn
;
3616 struct srv_copychunk_copy
*cc_copy
= &state
->cc_copy
;
3617 off_t src_offset
= state
->src_offset
;
3618 off_t dst_offset
= state
->dst_offset
;
3619 uint32_t req_len
= MIN(smb2cli_conn_cc_chunk_len(conn
) * smb2cli_conn_cc_max_chunks(conn
),
3620 state
->size
- state
->written
);
3621 DATA_BLOB in_input_buffer
= data_blob_null
;
3622 DATA_BLOB in_output_buffer
= data_blob_null
;
3624 if (state
->size
- state
->written
== 0) {
3625 tevent_req_done(req
);
3629 cc_copy
->chunk_count
= 0;
3631 cc_copy
->chunks
[cc_copy
->chunk_count
].source_off
= src_offset
;
3632 cc_copy
->chunks
[cc_copy
->chunk_count
].target_off
= dst_offset
;
3633 cc_copy
->chunks
[cc_copy
->chunk_count
].length
= MIN(req_len
,
3634 smb2cli_conn_cc_chunk_len(conn
));
3635 if (req_len
< cc_copy
->chunks
[cc_copy
->chunk_count
].length
) {
3636 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
3639 req_len
-= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
3640 if ((src_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
) ||
3641 (dst_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
)) {
3642 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
3645 src_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
3646 dst_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
3647 cc_copy
->chunk_count
++;
3650 ndr_ret
= ndr_push_struct_blob(&in_input_buffer
, state
, cc_copy
,
3651 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
3652 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
3653 DEBUG(0, ("failed to marshall copy chunk req\n"));
3654 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
3658 subreq
= smb2cli_ioctl_send(state
, state
->ev
, state
->cli
->conn
,
3659 state
->cli
->timeout
,
3660 state
->cli
->smb2
.session
,
3661 state
->cli
->smb2
.tcon
,
3662 state
->dst_ph
->fid_persistent
, /* in_fid_persistent */
3663 state
->dst_ph
->fid_volatile
, /* in_fid_volatile */
3664 FSCTL_SRV_COPYCHUNK_WRITE
,
3665 0, /* in_max_input_length */
3667 12, /* in_max_output_length */
3669 SMB2_IOCTL_FLAG_IS_FSCTL
);
3670 if (tevent_req_nomem(subreq
, req
)) {
3673 tevent_req_set_callback(subreq
,
3674 cli_splice_copychunk_done
,
3678 static void cli_splice_key_done(struct tevent_req
*subreq
)
3680 struct tevent_req
*req
= tevent_req_callback_data(
3681 subreq
, struct tevent_req
);
3682 struct cli_smb2_splice_state
*state
=
3683 tevent_req_data(req
,
3684 struct cli_smb2_splice_state
);
3685 enum ndr_err_code ndr_ret
;
3688 DATA_BLOB out_input_buffer
= data_blob_null
;
3689 DATA_BLOB out_output_buffer
= data_blob_null
;
3691 status
= smb2cli_ioctl_recv(subreq
, state
,
3693 &out_output_buffer
);
3694 TALLOC_FREE(subreq
);
3695 if (tevent_req_nterror(req
, status
)) {
3699 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
,
3700 state
, &state
->resume_rsp
,
3701 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
3702 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
3703 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3704 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3708 memcpy(&state
->cc_copy
.source_key
,
3709 &state
->resume_rsp
.resume_key
,
3710 sizeof state
->resume_rsp
.resume_key
);
3712 cli_splice_copychunk_send(state
, req
);
3715 struct tevent_req
*cli_smb2_splice_send(TALLOC_CTX
*mem_ctx
,
3716 struct tevent_context
*ev
,
3717 struct cli_state
*cli
,
3718 uint16_t src_fnum
, uint16_t dst_fnum
,
3719 off_t size
, off_t src_offset
, off_t dst_offset
,
3720 int (*splice_cb
)(off_t n
, void *priv
),
3723 struct tevent_req
*req
;
3724 struct tevent_req
*subreq
;
3725 struct cli_smb2_splice_state
*state
;
3727 DATA_BLOB in_input_buffer
= data_blob_null
;
3728 DATA_BLOB in_output_buffer
= data_blob_null
;
3730 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_splice_state
);
3736 state
->splice_cb
= splice_cb
;
3740 state
->src_offset
= src_offset
;
3741 state
->dst_offset
= dst_offset
;
3742 state
->cc_copy
.chunks
= talloc_array(state
,
3743 struct srv_copychunk
,
3744 smb2cli_conn_cc_max_chunks(cli
->conn
));
3745 if (state
->cc_copy
.chunks
== NULL
) {
3749 status
= map_fnum_to_smb2_handle(cli
, src_fnum
, &state
->src_ph
);
3750 if (tevent_req_nterror(req
, status
))
3751 return tevent_req_post(req
, ev
);
3753 status
= map_fnum_to_smb2_handle(cli
, dst_fnum
, &state
->dst_ph
);
3754 if (tevent_req_nterror(req
, status
))
3755 return tevent_req_post(req
, ev
);
3757 subreq
= smb2cli_ioctl_send(state
, ev
, cli
->conn
,
3761 state
->src_ph
->fid_persistent
, /* in_fid_persistent */
3762 state
->src_ph
->fid_volatile
, /* in_fid_volatile */
3763 FSCTL_SRV_REQUEST_RESUME_KEY
,
3764 0, /* in_max_input_length */
3766 32, /* in_max_output_length */
3768 SMB2_IOCTL_FLAG_IS_FSCTL
);
3769 if (tevent_req_nomem(subreq
, req
)) {
3772 tevent_req_set_callback(subreq
,
3773 cli_splice_key_done
,
3779 NTSTATUS
cli_smb2_splice_recv(struct tevent_req
*req
, off_t
*written
)
3781 struct cli_smb2_splice_state
*state
= tevent_req_data(
3782 req
, struct cli_smb2_splice_state
);
3785 if (tevent_req_is_nterror(req
, &status
)) {
3786 state
->cli
->raw_status
= status
;
3787 tevent_req_received(req
);
3790 if (written
!= NULL
) {
3791 *written
= state
->written
;
3793 state
->cli
->raw_status
= NT_STATUS_OK
;
3794 tevent_req_received(req
);
3795 return NT_STATUS_OK
;
3798 /***************************************************************
3799 SMB2 enum shadow copy data.
3800 ***************************************************************/
3802 struct cli_smb2_shadow_copy_data_fnum_state
{
3803 struct cli_state
*cli
;
3805 struct smb2_hnd
*ph
;
3806 DATA_BLOB out_input_buffer
;
3807 DATA_BLOB out_output_buffer
;
3810 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
);
3812 static struct tevent_req
*cli_smb2_shadow_copy_data_fnum_send(
3813 TALLOC_CTX
*mem_ctx
,
3814 struct tevent_context
*ev
,
3815 struct cli_state
*cli
,
3819 struct tevent_req
*req
, *subreq
;
3820 struct cli_smb2_shadow_copy_data_fnum_state
*state
;
3823 req
= tevent_req_create(mem_ctx
, &state
,
3824 struct cli_smb2_shadow_copy_data_fnum_state
);
3829 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3830 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3831 return tevent_req_post(req
, ev
);
3837 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
3838 if (tevent_req_nterror(req
, status
)) {
3839 return tevent_req_post(req
, ev
);
3843 * TODO. Under SMB2 we should send a zero max_output_length
3844 * ioctl to get the required size, then send another ioctl
3845 * to get the data, but the current SMB1 implementation just
3846 * does one roundtrip with a 64K buffer size. Do the same
3850 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
3851 state
->cli
->timeout
,
3852 state
->cli
->smb2
.session
,
3853 state
->cli
->smb2
.tcon
,
3854 state
->ph
->fid_persistent
, /* in_fid_persistent */
3855 state
->ph
->fid_volatile
, /* in_fid_volatile */
3856 FSCTL_GET_SHADOW_COPY_DATA
,
3857 0, /* in_max_input_length */
3858 NULL
, /* in_input_buffer */
3860 CLI_BUFFER_SIZE
: 16, /* in_max_output_length */
3861 NULL
, /* in_output_buffer */
3862 SMB2_IOCTL_FLAG_IS_FSCTL
);
3864 if (tevent_req_nomem(subreq
, req
)) {
3865 return tevent_req_post(req
, ev
);
3867 tevent_req_set_callback(subreq
,
3868 cli_smb2_shadow_copy_data_fnum_done
,
3874 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
)
3876 struct tevent_req
*req
= tevent_req_callback_data(
3877 subreq
, struct tevent_req
);
3878 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
3879 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
3882 status
= smb2cli_ioctl_recv(subreq
, state
,
3883 &state
->out_input_buffer
,
3884 &state
->out_output_buffer
);
3885 TALLOC_FREE(subreq
);
3886 if (tevent_req_nterror(req
, status
)) {
3889 tevent_req_done(req
);
3892 static NTSTATUS
cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req
*req
,
3893 TALLOC_CTX
*mem_ctx
,
3898 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
3899 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
3900 char **names
= NULL
;
3901 uint32_t num_names
= 0;
3902 uint32_t num_names_returned
= 0;
3903 uint32_t dlength
= 0;
3905 uint8_t *endp
= NULL
;
3908 if (tevent_req_is_nterror(req
, &status
)) {
3912 if (state
->out_output_buffer
.length
< 16) {
3913 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3916 num_names
= IVAL(state
->out_output_buffer
.data
, 0);
3917 num_names_returned
= IVAL(state
->out_output_buffer
.data
, 4);
3918 dlength
= IVAL(state
->out_output_buffer
.data
, 8);
3920 if (num_names
> 0x7FFFFFFF) {
3921 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3924 if (get_names
== false) {
3925 *pnum_names
= (int)num_names
;
3926 return NT_STATUS_OK
;
3928 if (num_names
!= num_names_returned
) {
3929 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3931 if (dlength
+ 12 < 12) {
3932 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3935 * NB. The below is an allowable return if there are
3936 * more snapshots than the buffer size we told the
3937 * server we can receive. We currently don't support
3940 if (dlength
+ 12 > state
->out_output_buffer
.length
) {
3941 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3943 if (state
->out_output_buffer
.length
+
3944 (2 * sizeof(SHADOW_COPY_LABEL
)) <
3945 state
->out_output_buffer
.length
) {
3946 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3949 names
= talloc_array(mem_ctx
, char *, num_names_returned
);
3950 if (names
== NULL
) {
3951 return NT_STATUS_NO_MEMORY
;
3954 endp
= state
->out_output_buffer
.data
+
3955 state
->out_output_buffer
.length
;
3957 for (i
=0; i
<num_names_returned
; i
++) {
3960 size_t converted_size
;
3962 src
= state
->out_output_buffer
.data
+ 12 +
3963 (i
* 2 * sizeof(SHADOW_COPY_LABEL
));
3965 if (src
+ (2 * sizeof(SHADOW_COPY_LABEL
)) > endp
) {
3966 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3968 ret
= convert_string_talloc(
3969 names
, CH_UTF16LE
, CH_UNIX
,
3970 src
, 2 * sizeof(SHADOW_COPY_LABEL
),
3971 &names
[i
], &converted_size
);
3974 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3977 *pnum_names
= num_names
;
3979 return NT_STATUS_OK
;
3982 NTSTATUS
cli_smb2_shadow_copy_data(TALLOC_CTX
*mem_ctx
,
3983 struct cli_state
*cli
,
3989 TALLOC_CTX
*frame
= talloc_stackframe();
3990 struct tevent_context
*ev
;
3991 struct tevent_req
*req
;
3992 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3994 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3996 * Can't use sync call while an async call is in flight
3998 status
= NT_STATUS_INVALID_PARAMETER
;
4001 ev
= samba_tevent_context_init(frame
);
4005 req
= cli_smb2_shadow_copy_data_fnum_send(frame
,
4013 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4016 status
= cli_smb2_shadow_copy_data_fnum_recv(req
,
4022 cli
->raw_status
= status
;
4028 /***************************************************************
4029 Wrapper that allows SMB2 to truncate a file.
4031 ***************************************************************/
4033 NTSTATUS
cli_smb2_ftruncate(struct cli_state
*cli
,
4038 DATA_BLOB inbuf
= data_blob_null
;
4039 struct smb2_hnd
*ph
= NULL
;
4040 TALLOC_CTX
*frame
= talloc_stackframe();
4042 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4044 * Can't use sync call while an async call is in flight
4046 status
= NT_STATUS_INVALID_PARAMETER
;
4050 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
4051 status
= NT_STATUS_INVALID_PARAMETER
;
4055 status
= map_fnum_to_smb2_handle(cli
,
4058 if (!NT_STATUS_IS_OK(status
)) {
4062 inbuf
= data_blob_talloc_zero(frame
, 8);
4063 if (inbuf
.data
== NULL
) {
4064 status
= NT_STATUS_NO_MEMORY
;
4068 SBVAL(inbuf
.data
, 0, newsize
);
4070 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4071 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4073 status
= smb2cli_set_info(cli
->conn
,
4077 1, /* in_info_type */
4078 /* in_file_info_class */
4079 SMB_FILE_END_OF_FILE_INFORMATION
- 1000,
4080 &inbuf
, /* in_input_buffer */
4081 0, /* in_additional_info */
4087 cli
->raw_status
= status
;