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 struct cli_smb2_delete_on_close_state
{
489 struct cli_state
*cli
;
496 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
);
498 struct tevent_req
*cli_smb2_delete_on_close_send(TALLOC_CTX
*mem_ctx
,
499 struct tevent_context
*ev
,
500 struct cli_state
*cli
,
504 struct tevent_req
*req
= NULL
;
505 struct cli_smb2_delete_on_close_state
*state
= NULL
;
506 struct tevent_req
*subreq
= NULL
;
507 uint8_t in_info_type
;
508 uint8_t in_file_info_class
;
511 req
= tevent_req_create(mem_ctx
, &state
,
512 struct cli_smb2_delete_on_close_state
);
519 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
520 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
521 return tevent_req_post(req
, ev
);
524 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
525 if (tevent_req_nterror(req
, status
)) {
526 return tevent_req_post(req
, ev
);
530 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
531 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
534 in_file_info_class
= SMB_FILE_DISPOSITION_INFORMATION
- 1000;
535 /* Setup data array. */
536 SCVAL(&state
->data
[0], 0, flag
? 1 : 0);
537 state
->inbuf
.data
= &state
->data
[0];
538 state
->inbuf
.length
= 1;
540 subreq
= smb2cli_set_info_send(state
, ev
,
547 &state
->inbuf
, /* in_input_buffer */
548 0, /* in_additional_info */
549 state
->ph
->fid_persistent
,
550 state
->ph
->fid_volatile
);
551 if (tevent_req_nomem(subreq
, req
)) {
552 return tevent_req_post(req
, ev
);
554 tevent_req_set_callback(subreq
,
555 cli_smb2_delete_on_close_done
,
560 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
)
562 NTSTATUS status
= smb2cli_set_info_recv(subreq
);
563 tevent_req_simple_finish_ntstatus(subreq
, status
);
566 NTSTATUS
cli_smb2_delete_on_close_recv(struct tevent_req
*req
)
568 struct cli_smb2_delete_on_close_state
*state
=
570 struct cli_smb2_delete_on_close_state
);
573 if (tevent_req_is_nterror(req
, &status
)) {
574 state
->cli
->raw_status
= status
;
575 tevent_req_received(req
);
579 state
->cli
->raw_status
= NT_STATUS_OK
;
580 tevent_req_received(req
);
584 NTSTATUS
cli_smb2_delete_on_close(struct cli_state
*cli
, uint16_t fnum
, bool flag
)
586 TALLOC_CTX
*frame
= talloc_stackframe();
587 struct tevent_context
*ev
;
588 struct tevent_req
*req
;
589 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
591 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
593 * Can't use sync call while an async call is in flight
595 status
= NT_STATUS_INVALID_PARAMETER
;
598 ev
= samba_tevent_context_init(frame
);
602 req
= cli_smb2_delete_on_close_send(frame
, ev
, cli
, fnum
, flag
);
606 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
609 status
= cli_smb2_delete_on_close_recv(req
);
615 /***************************************************************
616 Small wrapper that allows SMB2 to create a directory
618 ***************************************************************/
620 NTSTATUS
cli_smb2_mkdir(struct cli_state
*cli
, const char *dname
)
625 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
627 * Can't use sync call while an async call is in flight
629 return NT_STATUS_INVALID_PARAMETER
;
632 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
633 return NT_STATUS_INVALID_PARAMETER
;
636 status
= cli_smb2_create_fnum(cli
,
638 0, /* create_flags */
639 FILE_READ_ATTRIBUTES
, /* desired_access */
640 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
641 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
642 FILE_CREATE
, /* create_disposition */
643 FILE_DIRECTORY_FILE
, /* create_options */
647 if (!NT_STATUS_IS_OK(status
)) {
650 return cli_smb2_close_fnum(cli
, fnum
);
653 /***************************************************************
654 Small wrapper that allows SMB2 to delete a directory
656 ***************************************************************/
658 NTSTATUS
cli_smb2_rmdir(struct cli_state
*cli
, const char *dname
)
663 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
665 * Can't use sync call while an async call is in flight
667 return NT_STATUS_INVALID_PARAMETER
;
670 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
671 return NT_STATUS_INVALID_PARAMETER
;
674 status
= cli_smb2_create_fnum(cli
,
676 0, /* create_flags */
677 DELETE_ACCESS
, /* desired_access */
678 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
679 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
680 FILE_OPEN
, /* create_disposition */
681 FILE_DIRECTORY_FILE
|FILE_DELETE_ON_CLOSE
, /* create_options */
685 if (!NT_STATUS_IS_OK(status
)) {
688 return cli_smb2_close_fnum(cli
, fnum
);
691 /***************************************************************
692 Small wrapper that allows SMB2 to unlink a pathname.
694 ***************************************************************/
696 NTSTATUS
cli_smb2_unlink(struct cli_state
*cli
, const char *fname
)
701 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
703 * Can't use sync call while an async call is in flight
705 return NT_STATUS_INVALID_PARAMETER
;
708 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
709 return NT_STATUS_INVALID_PARAMETER
;
712 status
= cli_smb2_create_fnum(cli
,
714 0, /* create_flags */
715 DELETE_ACCESS
, /* desired_access */
716 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
717 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
718 FILE_OPEN
, /* create_disposition */
719 FILE_DELETE_ON_CLOSE
, /* create_options */
723 if (!NT_STATUS_IS_OK(status
)) {
726 return cli_smb2_close_fnum(cli
, fnum
);
729 /***************************************************************
730 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
731 ***************************************************************/
733 static NTSTATUS
parse_finfo_id_both_directory_info(uint8_t *dir_data
,
734 uint32_t dir_data_length
,
735 struct file_info
*finfo
,
736 uint32_t *next_offset
)
742 if (dir_data_length
< 4) {
743 return NT_STATUS_INFO_LENGTH_MISMATCH
;
746 *next_offset
= IVAL(dir_data
, 0);
748 if (*next_offset
> dir_data_length
) {
749 return NT_STATUS_INFO_LENGTH_MISMATCH
;
752 if (*next_offset
!= 0) {
753 /* Ensure we only read what in this record. */
754 dir_data_length
= *next_offset
;
757 if (dir_data_length
< 105) {
758 return NT_STATUS_INFO_LENGTH_MISMATCH
;
761 finfo
->atime_ts
= interpret_long_date((const char *)dir_data
+ 16);
762 finfo
->mtime_ts
= interpret_long_date((const char *)dir_data
+ 24);
763 finfo
->ctime_ts
= interpret_long_date((const char *)dir_data
+ 32);
764 finfo
->size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 40, 0);
765 finfo
->mode
= CVAL(dir_data
+ 56, 0);
766 namelen
= IVAL(dir_data
+ 60,0);
767 if (namelen
> (dir_data_length
- 104)) {
768 return NT_STATUS_INFO_LENGTH_MISMATCH
;
770 slen
= CVAL(dir_data
+ 68, 0);
772 return NT_STATUS_INFO_LENGTH_MISMATCH
;
774 ret
= pull_string_talloc(finfo
,
776 FLAGS2_UNICODE_STRINGS
,
781 if (ret
== (size_t)-1) {
782 /* Bad conversion. */
783 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
786 ret
= pull_string_talloc(finfo
,
788 FLAGS2_UNICODE_STRINGS
,
793 if (ret
== (size_t)-1) {
794 /* Bad conversion. */
795 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
800 /*******************************************************************
801 Given a filename - get its directory name
802 ********************************************************************/
804 static bool windows_parent_dirname(TALLOC_CTX
*mem_ctx
,
812 p
= strrchr_m(dir
, '\\'); /* Find final '\\', if any */
815 if (!(*parent
= talloc_strdup(mem_ctx
, "\\"))) {
826 if (!(*parent
= (char *)talloc_memdup(mem_ctx
, dir
, len
+1))) {
829 (*parent
)[len
] = '\0';
837 /***************************************************************
838 Wrapper that allows SMB2 to list a directory.
840 ***************************************************************/
842 NTSTATUS
cli_smb2_list(struct cli_state
*cli
,
843 const char *pathname
,
845 NTSTATUS (*fn
)(const char *,
852 uint16_t fnum
= 0xffff;
853 char *parent_dir
= NULL
;
854 const char *mask
= NULL
;
855 struct smb2_hnd
*ph
= NULL
;
856 bool processed_file
= false;
857 TALLOC_CTX
*frame
= talloc_stackframe();
858 TALLOC_CTX
*subframe
= NULL
;
861 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
863 * Can't use sync call while an async call is in flight
865 status
= NT_STATUS_INVALID_PARAMETER
;
869 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
870 status
= NT_STATUS_INVALID_PARAMETER
;
874 /* Get the directory name. */
875 if (!windows_parent_dirname(frame
,
879 status
= NT_STATUS_NO_MEMORY
;
883 mask_has_wild
= ms_has_wild(mask
);
885 status
= cli_smb2_create_fnum(cli
,
887 0, /* create_flags */
888 SEC_DIR_LIST
|SEC_DIR_READ_ATTRIBUTE
,/* desired_access */
889 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
890 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
891 FILE_OPEN
, /* create_disposition */
892 FILE_DIRECTORY_FILE
, /* create_options */
896 if (!NT_STATUS_IS_OK(status
)) {
900 status
= map_fnum_to_smb2_handle(cli
,
903 if (!NT_STATUS_IS_OK(status
)) {
908 uint8_t *dir_data
= NULL
;
909 uint32_t dir_data_length
= 0;
910 uint32_t next_offset
= 0;
911 subframe
= talloc_stackframe();
913 status
= smb2cli_query_directory(cli
->conn
,
917 SMB2_FIND_ID_BOTH_DIRECTORY_INFO
,
928 if (!NT_STATUS_IS_OK(status
)) {
929 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
936 struct file_info
*finfo
= talloc_zero(subframe
,
940 status
= NT_STATUS_NO_MEMORY
;
944 status
= parse_finfo_id_both_directory_info(dir_data
,
949 if (!NT_STATUS_IS_OK(status
)) {
953 if (dir_check_ftype((uint32_t)finfo
->mode
,
954 (uint32_t)attribute
)) {
956 * Only process if attributes match.
957 * On SMB1 server does this, so on
958 * SMB2 we need to emulate in the
961 * https://bugzilla.samba.org/show_bug.cgi?id=10260
963 processed_file
= true;
965 status
= fn(cli
->dfs_mountpoint
,
970 if (!NT_STATUS_IS_OK(status
)) {
977 /* Move to next entry. */
979 dir_data
+= next_offset
;
980 dir_data_length
-= next_offset
;
982 } while (next_offset
!= 0);
984 TALLOC_FREE(subframe
);
986 if (!mask_has_wild
) {
988 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
989 * when handed a non-wildcard path. Do it
990 * for the server (with a non-wildcard path
991 * there should only ever be one file returned.
993 status
= STATUS_NO_MORE_FILES
;
997 } while (NT_STATUS_IS_OK(status
));
999 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
1000 status
= NT_STATUS_OK
;
1003 if (NT_STATUS_IS_OK(status
) && !processed_file
) {
1005 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1006 * if no files match. Emulate this in the client.
1008 status
= NT_STATUS_NO_SUCH_FILE
;
1013 if (fnum
!= 0xffff) {
1014 cli_smb2_close_fnum(cli
, fnum
);
1017 cli
->raw_status
= status
;
1019 TALLOC_FREE(subframe
);
1024 /***************************************************************
1025 Wrapper that allows SMB2 to query a path info (basic level).
1027 ***************************************************************/
1029 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
1031 SMB_STRUCT_STAT
*sbuf
,
1032 uint32_t *attributes
)
1035 struct smb_create_returns cr
;
1036 uint16_t fnum
= 0xffff;
1037 size_t namelen
= strlen(name
);
1039 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1041 * Can't use sync call while an async call is in flight
1043 return NT_STATUS_INVALID_PARAMETER
;
1046 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1047 return NT_STATUS_INVALID_PARAMETER
;
1050 /* SMB2 is pickier about pathnames. Ensure it doesn't
1052 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1053 char *modname
= talloc_strdup(talloc_tos(), name
);
1054 modname
[namelen
-1] = '\0';
1058 /* This is commonly used as a 'cd'. Try qpathinfo on
1059 a directory handle first. */
1061 status
= cli_smb2_create_fnum(cli
,
1063 0, /* create_flags */
1064 FILE_READ_ATTRIBUTES
, /* desired_access */
1065 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1066 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1067 FILE_OPEN
, /* create_disposition */
1068 FILE_DIRECTORY_FILE
, /* create_options */
1072 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
1073 /* Maybe a file ? */
1074 status
= cli_smb2_create_fnum(cli
,
1076 0, /* create_flags */
1077 FILE_READ_ATTRIBUTES
, /* desired_access */
1078 0, /* file attributes */
1079 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1080 FILE_OPEN
, /* create_disposition */
1081 0, /* create_options */
1086 if (!NT_STATUS_IS_OK(status
)) {
1090 status
= cli_smb2_close_fnum(cli
, fnum
);
1094 sbuf
->st_ex_atime
= nt_time_to_unix_timespec(cr
.last_access_time
);
1095 sbuf
->st_ex_mtime
= nt_time_to_unix_timespec(cr
.last_write_time
);
1096 sbuf
->st_ex_ctime
= nt_time_to_unix_timespec(cr
.change_time
);
1097 sbuf
->st_ex_size
= cr
.end_of_file
;
1098 *attributes
= cr
.file_attributes
;
1103 /***************************************************************
1104 Helper function for pathname operations.
1105 ***************************************************************/
1107 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
1109 uint32_t desired_access
,
1113 size_t namelen
= strlen(name
);
1114 TALLOC_CTX
*frame
= talloc_stackframe();
1116 /* SMB2 is pickier about pathnames. Ensure it doesn't
1118 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1119 char *modname
= talloc_strdup(frame
, name
);
1120 if (modname
== NULL
) {
1121 status
= NT_STATUS_NO_MEMORY
;
1124 modname
[namelen
-1] = '\0';
1128 /* Try to open a file handle first. */
1129 status
= cli_smb2_create_fnum(cli
,
1131 0, /* create_flags */
1133 0, /* file attributes */
1134 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1135 FILE_OPEN
, /* create_disposition */
1136 0, /* create_options */
1140 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
1141 status
= cli_smb2_create_fnum(cli
,
1143 0, /* create_flags */
1145 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1146 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1147 FILE_OPEN
, /* create_disposition */
1148 FILE_DIRECTORY_FILE
, /* create_options */
1159 /***************************************************************
1160 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1162 ***************************************************************/
1164 NTSTATUS
cli_smb2_qpathinfo_alt_name(struct cli_state
*cli
,
1169 DATA_BLOB outbuf
= data_blob_null
;
1170 uint16_t fnum
= 0xffff;
1171 struct smb2_hnd
*ph
= NULL
;
1172 uint32_t altnamelen
= 0;
1173 TALLOC_CTX
*frame
= talloc_stackframe();
1175 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1177 * Can't use sync call while an async call is in flight
1179 status
= NT_STATUS_INVALID_PARAMETER
;
1183 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1184 status
= NT_STATUS_INVALID_PARAMETER
;
1188 status
= get_fnum_from_path(cli
,
1190 FILE_READ_ATTRIBUTES
,
1193 if (!NT_STATUS_IS_OK(status
)) {
1197 status
= map_fnum_to_smb2_handle(cli
,
1200 if (!NT_STATUS_IS_OK(status
)) {
1204 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1205 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1207 status
= smb2cli_query_info(cli
->conn
,
1211 1, /* in_info_type */
1212 (SMB_FILE_ALTERNATE_NAME_INFORMATION
- 1000), /* in_file_info_class */
1213 0xFFFF, /* in_max_output_length */
1214 NULL
, /* in_input_buffer */
1215 0, /* in_additional_info */
1222 if (!NT_STATUS_IS_OK(status
)) {
1226 /* Parse the reply. */
1227 if (outbuf
.length
< 4) {
1228 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1232 altnamelen
= IVAL(outbuf
.data
, 0);
1233 if (altnamelen
> outbuf
.length
- 4) {
1234 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1238 if (altnamelen
> 0) {
1240 char *short_name
= NULL
;
1241 ret
= pull_string_talloc(frame
,
1243 FLAGS2_UNICODE_STRINGS
,
1248 if (ret
== (size_t)-1) {
1249 /* Bad conversion. */
1250 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1254 fstrcpy(alt_name
, short_name
);
1259 status
= NT_STATUS_OK
;
1263 if (fnum
!= 0xffff) {
1264 cli_smb2_close_fnum(cli
, fnum
);
1267 cli
->raw_status
= status
;
1274 /***************************************************************
1275 Wrapper that allows SMB2 to query a fnum info (basic level).
1277 ***************************************************************/
1279 NTSTATUS
cli_smb2_qfileinfo_basic(struct cli_state
*cli
,
1283 struct timespec
*create_time
,
1284 struct timespec
*access_time
,
1285 struct timespec
*write_time
,
1286 struct timespec
*change_time
,
1290 DATA_BLOB outbuf
= data_blob_null
;
1291 struct smb2_hnd
*ph
= NULL
;
1292 TALLOC_CTX
*frame
= talloc_stackframe();
1294 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1296 * Can't use sync call while an async call is in flight
1298 status
= NT_STATUS_INVALID_PARAMETER
;
1302 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1303 status
= NT_STATUS_INVALID_PARAMETER
;
1307 status
= map_fnum_to_smb2_handle(cli
,
1310 if (!NT_STATUS_IS_OK(status
)) {
1314 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1315 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1317 status
= smb2cli_query_info(cli
->conn
,
1321 1, /* in_info_type */
1322 (SMB_FILE_ALL_INFORMATION
- 1000), /* in_file_info_class */
1323 0xFFFF, /* in_max_output_length */
1324 NULL
, /* in_input_buffer */
1325 0, /* in_additional_info */
1331 if (!NT_STATUS_IS_OK(status
)) {
1335 /* Parse the reply. */
1336 if (outbuf
.length
< 0x60) {
1337 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1342 *create_time
= interpret_long_date((const char *)outbuf
.data
+ 0x0);
1345 *access_time
= interpret_long_date((const char *)outbuf
.data
+ 0x8);
1348 *write_time
= interpret_long_date((const char *)outbuf
.data
+ 0x10);
1351 *change_time
= interpret_long_date((const char *)outbuf
.data
+ 0x18);
1354 uint32_t attr
= IVAL(outbuf
.data
, 0x20);
1355 *mode
= (uint16_t)attr
;
1358 uint64_t file_size
= BVAL(outbuf
.data
, 0x30);
1359 *size
= (off_t
)file_size
;
1362 uint64_t file_index
= BVAL(outbuf
.data
, 0x40);
1363 *ino
= (SMB_INO_T
)file_index
;
1368 cli
->raw_status
= status
;
1374 /***************************************************************
1375 Wrapper that allows SMB2 to query an fnum.
1376 Implement on top of cli_smb2_qfileinfo_basic().
1378 ***************************************************************/
1380 NTSTATUS
cli_smb2_getattrE(struct cli_state
*cli
,
1384 time_t *change_time
,
1385 time_t *access_time
,
1388 struct timespec access_time_ts
;
1389 struct timespec write_time_ts
;
1390 struct timespec change_time_ts
;
1391 NTSTATUS status
= cli_smb2_qfileinfo_basic(cli
,
1401 cli
->raw_status
= status
;
1403 if (!NT_STATUS_IS_OK(status
)) {
1408 *change_time
= change_time_ts
.tv_sec
;
1411 *access_time
= access_time_ts
.tv_sec
;
1414 *write_time
= write_time_ts
.tv_sec
;
1416 return NT_STATUS_OK
;
1419 /***************************************************************
1420 Wrapper that allows SMB2 to get pathname attributes.
1422 ***************************************************************/
1424 NTSTATUS
cli_smb2_getatr(struct cli_state
*cli
,
1431 uint16_t fnum
= 0xffff;
1432 struct smb2_hnd
*ph
= NULL
;
1433 TALLOC_CTX
*frame
= talloc_stackframe();
1435 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1437 * Can't use sync call while an async call is in flight
1439 status
= NT_STATUS_INVALID_PARAMETER
;
1443 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1444 status
= NT_STATUS_INVALID_PARAMETER
;
1448 status
= get_fnum_from_path(cli
,
1450 FILE_READ_ATTRIBUTES
,
1453 if (!NT_STATUS_IS_OK(status
)) {
1457 status
= map_fnum_to_smb2_handle(cli
,
1460 if (!NT_STATUS_IS_OK(status
)) {
1463 status
= cli_smb2_getattrE(cli
,
1470 if (!NT_STATUS_IS_OK(status
)) {
1476 if (fnum
!= 0xffff) {
1477 cli_smb2_close_fnum(cli
, fnum
);
1480 cli
->raw_status
= status
;
1486 /***************************************************************
1487 Wrapper that allows SMB2 to query a pathname info (basic level).
1488 Implement on top of cli_smb2_qfileinfo_basic().
1490 ***************************************************************/
1492 NTSTATUS
cli_smb2_qpathinfo2(struct cli_state
*cli
,
1494 struct timespec
*create_time
,
1495 struct timespec
*access_time
,
1496 struct timespec
*write_time
,
1497 struct timespec
*change_time
,
1503 struct smb2_hnd
*ph
= NULL
;
1504 uint16_t fnum
= 0xffff;
1505 TALLOC_CTX
*frame
= talloc_stackframe();
1507 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1509 * Can't use sync call while an async call is in flight
1511 status
= NT_STATUS_INVALID_PARAMETER
;
1515 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1516 status
= NT_STATUS_INVALID_PARAMETER
;
1520 status
= get_fnum_from_path(cli
,
1522 FILE_READ_ATTRIBUTES
,
1525 if (!NT_STATUS_IS_OK(status
)) {
1529 status
= map_fnum_to_smb2_handle(cli
,
1532 if (!NT_STATUS_IS_OK(status
)) {
1536 status
= cli_smb2_qfileinfo_basic(cli
,
1548 if (fnum
!= 0xffff) {
1549 cli_smb2_close_fnum(cli
, fnum
);
1552 cli
->raw_status
= status
;
1558 /***************************************************************
1559 Wrapper that allows SMB2 to query pathname streams.
1561 ***************************************************************/
1563 NTSTATUS
cli_smb2_qpathinfo_streams(struct cli_state
*cli
,
1565 TALLOC_CTX
*mem_ctx
,
1566 unsigned int *pnum_streams
,
1567 struct stream_struct
**pstreams
)
1570 struct smb2_hnd
*ph
= NULL
;
1571 uint16_t fnum
= 0xffff;
1572 DATA_BLOB outbuf
= data_blob_null
;
1573 TALLOC_CTX
*frame
= talloc_stackframe();
1575 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1577 * Can't use sync call while an async call is in flight
1579 status
= NT_STATUS_INVALID_PARAMETER
;
1583 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1584 status
= NT_STATUS_INVALID_PARAMETER
;
1588 status
= get_fnum_from_path(cli
,
1590 FILE_READ_ATTRIBUTES
,
1593 if (!NT_STATUS_IS_OK(status
)) {
1597 status
= map_fnum_to_smb2_handle(cli
,
1600 if (!NT_STATUS_IS_OK(status
)) {
1604 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1605 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1607 status
= smb2cli_query_info(cli
->conn
,
1611 1, /* in_info_type */
1612 (SMB_FILE_STREAM_INFORMATION
- 1000), /* in_file_info_class */
1613 0xFFFF, /* in_max_output_length */
1614 NULL
, /* in_input_buffer */
1615 0, /* in_additional_info */
1622 if (!NT_STATUS_IS_OK(status
)) {
1626 /* Parse the reply. */
1627 if (!parse_streams_blob(mem_ctx
,
1632 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1638 if (fnum
!= 0xffff) {
1639 cli_smb2_close_fnum(cli
, fnum
);
1642 cli
->raw_status
= status
;
1648 /***************************************************************
1649 Wrapper that allows SMB2 to set pathname attributes.
1651 ***************************************************************/
1653 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
1659 uint16_t fnum
= 0xffff;
1660 struct smb2_hnd
*ph
= NULL
;
1661 uint8_t inbuf_store
[40];
1662 DATA_BLOB inbuf
= data_blob_null
;
1663 TALLOC_CTX
*frame
= talloc_stackframe();
1665 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1667 * Can't use sync call while an async call is in flight
1669 status
= NT_STATUS_INVALID_PARAMETER
;
1673 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1674 status
= NT_STATUS_INVALID_PARAMETER
;
1678 status
= get_fnum_from_path(cli
,
1680 FILE_WRITE_ATTRIBUTES
,
1683 if (!NT_STATUS_IS_OK(status
)) {
1687 status
= map_fnum_to_smb2_handle(cli
,
1690 if (!NT_STATUS_IS_OK(status
)) {
1694 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1695 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1697 inbuf
.data
= inbuf_store
;
1698 inbuf
.length
= sizeof(inbuf_store
);
1699 data_blob_clear(&inbuf
);
1702 * SMB1 uses attr == 0 to clear all attributes
1703 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
1704 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
1705 * request attribute change.
1707 * SMB2 uses exactly the reverse. Unfortunately as the
1708 * cli_setatr() ABI is exposed inside libsmbclient,
1709 * we must make the SMB2 cli_smb2_setatr() call
1710 * export the same ABI as the SMB1 cli_setatr()
1711 * which calls it. This means reversing the sense
1712 * of the requested attr argument if it's zero
1713 * or FILE_ATTRIBUTE_NORMAL.
1715 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
1719 attr
= FILE_ATTRIBUTE_NORMAL
;
1720 } else if (attr
== FILE_ATTRIBUTE_NORMAL
) {
1724 SSVAL(inbuf
.data
, 32, attr
);
1726 put_long_date((char *)inbuf
.data
+ 16,mtime
);
1728 /* Set all the other times to -1. */
1729 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1730 SBVAL(inbuf
.data
, 8, 0xFFFFFFFFFFFFFFFFLL
);
1731 SBVAL(inbuf
.data
, 24, 0xFFFFFFFFFFFFFFFFLL
);
1733 status
= smb2cli_set_info(cli
->conn
,
1737 1, /* in_info_type */
1738 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1739 &inbuf
, /* in_input_buffer */
1740 0, /* in_additional_info */
1745 if (fnum
!= 0xffff) {
1746 cli_smb2_close_fnum(cli
, fnum
);
1749 cli
->raw_status
= status
;
1755 /***************************************************************
1756 Wrapper that allows SMB2 to set file handle times.
1758 ***************************************************************/
1760 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
1767 struct smb2_hnd
*ph
= NULL
;
1768 uint8_t inbuf_store
[40];
1769 DATA_BLOB inbuf
= data_blob_null
;
1771 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1773 * Can't use sync call while an async call is in flight
1775 return NT_STATUS_INVALID_PARAMETER
;
1778 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1779 return NT_STATUS_INVALID_PARAMETER
;
1782 status
= map_fnum_to_smb2_handle(cli
,
1785 if (!NT_STATUS_IS_OK(status
)) {
1789 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1790 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1792 inbuf
.data
= inbuf_store
;
1793 inbuf
.length
= sizeof(inbuf_store
);
1794 data_blob_clear(&inbuf
);
1796 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1797 if (change_time
!= 0) {
1798 put_long_date((char *)inbuf
.data
+ 24, change_time
);
1800 if (access_time
!= 0) {
1801 put_long_date((char *)inbuf
.data
+ 8, access_time
);
1803 if (write_time
!= 0) {
1804 put_long_date((char *)inbuf
.data
+ 16, write_time
);
1807 cli
->raw_status
= smb2cli_set_info(cli
->conn
,
1811 1, /* in_info_type */
1812 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1813 &inbuf
, /* in_input_buffer */
1814 0, /* in_additional_info */
1818 return cli
->raw_status
;
1821 /***************************************************************
1822 Wrapper that allows SMB2 to query disk attributes (size).
1824 ***************************************************************/
1826 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, const char *path
,
1827 uint64_t *bsize
, uint64_t *total
, uint64_t *avail
)
1830 uint16_t fnum
= 0xffff;
1831 DATA_BLOB outbuf
= data_blob_null
;
1832 struct smb2_hnd
*ph
= NULL
;
1833 uint32_t sectors_per_unit
= 0;
1834 uint32_t bytes_per_sector
= 0;
1835 uint64_t total_size
= 0;
1836 uint64_t size_free
= 0;
1837 TALLOC_CTX
*frame
= talloc_stackframe();
1839 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1841 * Can't use sync call while an async call is in flight
1843 status
= NT_STATUS_INVALID_PARAMETER
;
1847 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1848 status
= NT_STATUS_INVALID_PARAMETER
;
1852 /* First open the top level directory. */
1853 status
= cli_smb2_create_fnum(cli
,
1855 0, /* create_flags */
1856 FILE_READ_ATTRIBUTES
, /* desired_access */
1857 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1858 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1859 FILE_OPEN
, /* create_disposition */
1860 FILE_DIRECTORY_FILE
, /* create_options */
1864 if (!NT_STATUS_IS_OK(status
)) {
1868 status
= map_fnum_to_smb2_handle(cli
,
1871 if (!NT_STATUS_IS_OK(status
)) {
1875 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1876 level 3 (SMB_FS_SIZE_INFORMATION). */
1878 status
= smb2cli_query_info(cli
->conn
,
1882 2, /* in_info_type */
1883 3, /* in_file_info_class */
1884 0xFFFF, /* in_max_output_length */
1885 NULL
, /* in_input_buffer */
1886 0, /* in_additional_info */
1892 if (!NT_STATUS_IS_OK(status
)) {
1896 /* Parse the reply. */
1897 if (outbuf
.length
!= 24) {
1898 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1902 total_size
= BVAL(outbuf
.data
, 0);
1903 size_free
= BVAL(outbuf
.data
, 8);
1904 sectors_per_unit
= IVAL(outbuf
.data
, 16);
1905 bytes_per_sector
= IVAL(outbuf
.data
, 20);
1908 *bsize
= (uint64_t)sectors_per_unit
* (uint64_t)bytes_per_sector
;
1911 *total
= total_size
;
1917 status
= NT_STATUS_OK
;
1921 if (fnum
!= 0xffff) {
1922 cli_smb2_close_fnum(cli
, fnum
);
1925 cli
->raw_status
= status
;
1931 /***************************************************************
1932 Wrapper that allows SMB2 to query file system attributes.
1934 ***************************************************************/
1936 NTSTATUS
cli_smb2_get_fs_attr_info(struct cli_state
*cli
, uint32_t *fs_attr
)
1939 uint16_t fnum
= 0xffff;
1940 DATA_BLOB outbuf
= data_blob_null
;
1941 struct smb2_hnd
*ph
= NULL
;
1942 TALLOC_CTX
*frame
= talloc_stackframe();
1944 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1946 * Can't use sync call while an async call is in flight
1948 status
= NT_STATUS_INVALID_PARAMETER
;
1952 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1953 status
= NT_STATUS_INVALID_PARAMETER
;
1957 /* First open the top level directory. */
1959 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
1960 FILE_READ_ATTRIBUTES
, /* desired_access */
1961 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1962 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
1963 FILE_SHARE_DELETE
, /* share_access */
1964 FILE_OPEN
, /* create_disposition */
1965 FILE_DIRECTORY_FILE
, /* create_options */
1969 if (!NT_STATUS_IS_OK(status
)) {
1973 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
1974 if (!NT_STATUS_IS_OK(status
)) {
1978 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
1979 cli
->smb2
.tcon
, 2, /* in_info_type */
1980 5, /* in_file_info_class */
1981 0xFFFF, /* in_max_output_length */
1982 NULL
, /* in_input_buffer */
1983 0, /* in_additional_info */
1985 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
1987 if (!NT_STATUS_IS_OK(status
)) {
1991 if (outbuf
.length
< 12) {
1992 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1996 *fs_attr
= IVAL(outbuf
.data
, 0);
2000 if (fnum
!= 0xffff) {
2001 cli_smb2_close_fnum(cli
, fnum
);
2004 cli
->raw_status
= status
;
2010 /***************************************************************
2011 Wrapper that allows SMB2 to query a security descriptor.
2013 ***************************************************************/
2015 NTSTATUS
cli_smb2_query_security_descriptor(struct cli_state
*cli
,
2018 TALLOC_CTX
*mem_ctx
,
2019 struct security_descriptor
**ppsd
)
2022 DATA_BLOB outbuf
= data_blob_null
;
2023 struct smb2_hnd
*ph
= NULL
;
2024 struct security_descriptor
*lsd
= NULL
;
2025 TALLOC_CTX
*frame
= talloc_stackframe();
2027 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2029 * Can't use sync call while an async call is in flight
2031 status
= NT_STATUS_INVALID_PARAMETER
;
2035 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2036 status
= NT_STATUS_INVALID_PARAMETER
;
2040 status
= map_fnum_to_smb2_handle(cli
,
2043 if (!NT_STATUS_IS_OK(status
)) {
2047 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2049 status
= smb2cli_query_info(cli
->conn
,
2053 3, /* in_info_type */
2054 0, /* in_file_info_class */
2055 0xFFFF, /* in_max_output_length */
2056 NULL
, /* in_input_buffer */
2057 sec_info
, /* in_additional_info */
2064 if (!NT_STATUS_IS_OK(status
)) {
2068 /* Parse the reply. */
2069 status
= unmarshall_sec_desc(mem_ctx
,
2074 if (!NT_STATUS_IS_OK(status
)) {
2086 cli
->raw_status
= status
;
2092 /***************************************************************
2093 Wrapper that allows SMB2 to set a security descriptor.
2095 ***************************************************************/
2097 NTSTATUS
cli_smb2_set_security_descriptor(struct cli_state
*cli
,
2100 const struct security_descriptor
*sd
)
2103 DATA_BLOB inbuf
= data_blob_null
;
2104 struct smb2_hnd
*ph
= NULL
;
2105 TALLOC_CTX
*frame
= talloc_stackframe();
2107 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2109 * Can't use sync call while an async call is in flight
2111 status
= NT_STATUS_INVALID_PARAMETER
;
2115 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2116 status
= NT_STATUS_INVALID_PARAMETER
;
2120 status
= map_fnum_to_smb2_handle(cli
,
2123 if (!NT_STATUS_IS_OK(status
)) {
2127 status
= marshall_sec_desc(frame
,
2132 if (!NT_STATUS_IS_OK(status
)) {
2136 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2138 status
= smb2cli_set_info(cli
->conn
,
2142 3, /* in_info_type */
2143 0, /* in_file_info_class */
2144 &inbuf
, /* in_input_buffer */
2145 sec_info
, /* in_additional_info */
2151 cli
->raw_status
= status
;
2157 /***************************************************************
2158 Wrapper that allows SMB2 to rename a file.
2160 ***************************************************************/
2162 NTSTATUS
cli_smb2_rename(struct cli_state
*cli
,
2163 const char *fname_src
,
2164 const char *fname_dst
,
2168 DATA_BLOB inbuf
= data_blob_null
;
2169 uint16_t fnum
= 0xffff;
2170 struct smb2_hnd
*ph
= NULL
;
2171 smb_ucs2_t
*converted_str
= NULL
;
2172 size_t converted_size_bytes
= 0;
2174 TALLOC_CTX
*frame
= talloc_stackframe();
2176 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2178 * Can't use sync call while an async call is in flight
2180 status
= NT_STATUS_INVALID_PARAMETER
;
2184 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2185 status
= NT_STATUS_INVALID_PARAMETER
;
2189 status
= get_fnum_from_path(cli
,
2194 if (!NT_STATUS_IS_OK(status
)) {
2198 status
= map_fnum_to_smb2_handle(cli
,
2201 if (!NT_STATUS_IS_OK(status
)) {
2205 /* SMB2 is pickier about pathnames. Ensure it doesn't
2207 if (*fname_dst
== '\\') {
2211 /* SMB2 is pickier about pathnames. Ensure it doesn't
2213 namelen
= strlen(fname_dst
);
2214 if (namelen
> 0 && fname_dst
[namelen
-1] == '\\') {
2215 char *modname
= talloc_strdup(frame
, fname_dst
);
2216 modname
[namelen
-1] = '\0';
2217 fname_dst
= modname
;
2220 if (!push_ucs2_talloc(frame
,
2223 &converted_size_bytes
)) {
2224 status
= NT_STATUS_INVALID_PARAMETER
;
2228 /* W2K8 insists the dest name is not null
2229 terminated. Remove the last 2 zero bytes
2230 and reduce the name length. */
2232 if (converted_size_bytes
< 2) {
2233 status
= NT_STATUS_INVALID_PARAMETER
;
2236 converted_size_bytes
-= 2;
2238 inbuf
= data_blob_talloc_zero(frame
,
2239 20 + converted_size_bytes
);
2240 if (inbuf
.data
== NULL
) {
2241 status
= NT_STATUS_NO_MEMORY
;
2246 SCVAL(inbuf
.data
, 0, 1);
2249 SIVAL(inbuf
.data
, 16, converted_size_bytes
);
2250 memcpy(inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
2252 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2253 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2255 status
= smb2cli_set_info(cli
->conn
,
2259 1, /* in_info_type */
2260 SMB_FILE_RENAME_INFORMATION
- 1000, /* in_file_info_class */
2261 &inbuf
, /* in_input_buffer */
2262 0, /* in_additional_info */
2268 if (fnum
!= 0xffff) {
2269 cli_smb2_close_fnum(cli
, fnum
);
2272 cli
->raw_status
= status
;
2278 /***************************************************************
2279 Wrapper that allows SMB2 to set an EA on a fnum.
2281 ***************************************************************/
2283 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
2285 const char *ea_name
,
2290 DATA_BLOB inbuf
= data_blob_null
;
2292 char *ea_name_ascii
= NULL
;
2294 struct smb2_hnd
*ph
= NULL
;
2295 TALLOC_CTX
*frame
= talloc_stackframe();
2297 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2299 * Can't use sync call while an async call is in flight
2301 status
= NT_STATUS_INVALID_PARAMETER
;
2305 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2306 status
= NT_STATUS_INVALID_PARAMETER
;
2310 status
= map_fnum_to_smb2_handle(cli
,
2313 if (!NT_STATUS_IS_OK(status
)) {
2317 /* Marshall the SMB2 EA data. */
2318 if (ea_len
> 0xFFFF) {
2319 status
= NT_STATUS_INVALID_PARAMETER
;
2323 if (!push_ascii_talloc(frame
,
2327 status
= NT_STATUS_INVALID_PARAMETER
;
2331 if (namelen
< 2 || namelen
> 0xFF) {
2332 status
= NT_STATUS_INVALID_PARAMETER
;
2336 bloblen
= 8 + ea_len
+ namelen
;
2337 /* Round up to a 4 byte boundary. */
2338 bloblen
= ((bloblen
+ 3)&~3);
2340 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
2341 if (inbuf
.data
== NULL
) {
2342 status
= NT_STATUS_NO_MEMORY
;
2345 /* namelen doesn't include the NULL byte. */
2346 SCVAL(inbuf
.data
, 5, namelen
- 1);
2347 SSVAL(inbuf
.data
, 6, ea_len
);
2348 memcpy(inbuf
.data
+ 8, ea_name_ascii
, namelen
);
2349 memcpy(inbuf
.data
+ 8 + namelen
, ea_val
, ea_len
);
2351 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2352 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2354 status
= smb2cli_set_info(cli
->conn
,
2358 1, /* in_info_type */
2359 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
2360 &inbuf
, /* in_input_buffer */
2361 0, /* in_additional_info */
2367 cli
->raw_status
= status
;
2373 /***************************************************************
2374 Wrapper that allows SMB2 to set an EA on a pathname.
2376 ***************************************************************/
2378 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
2380 const char *ea_name
,
2385 uint16_t fnum
= 0xffff;
2387 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2389 * Can't use sync call while an async call is in flight
2391 status
= NT_STATUS_INVALID_PARAMETER
;
2395 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2396 status
= NT_STATUS_INVALID_PARAMETER
;
2400 status
= get_fnum_from_path(cli
,
2405 if (!NT_STATUS_IS_OK(status
)) {
2409 status
= cli_set_ea_fnum(cli
,
2414 if (!NT_STATUS_IS_OK(status
)) {
2420 if (fnum
!= 0xffff) {
2421 cli_smb2_close_fnum(cli
, fnum
);
2424 cli
->raw_status
= status
;
2429 /***************************************************************
2430 Wrapper that allows SMB2 to get an EA list on a pathname.
2432 ***************************************************************/
2434 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
2438 struct ea_struct
**pea_array
)
2441 uint16_t fnum
= 0xffff;
2442 DATA_BLOB outbuf
= data_blob_null
;
2443 struct smb2_hnd
*ph
= NULL
;
2444 struct ea_list
*ea_list
= NULL
;
2445 struct ea_list
*eal
= NULL
;
2446 size_t ea_count
= 0;
2447 TALLOC_CTX
*frame
= talloc_stackframe();
2452 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2454 * Can't use sync call while an async call is in flight
2456 status
= NT_STATUS_INVALID_PARAMETER
;
2460 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2461 status
= NT_STATUS_INVALID_PARAMETER
;
2465 status
= get_fnum_from_path(cli
,
2470 if (!NT_STATUS_IS_OK(status
)) {
2474 status
= map_fnum_to_smb2_handle(cli
,
2477 if (!NT_STATUS_IS_OK(status
)) {
2481 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2482 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2484 status
= smb2cli_query_info(cli
->conn
,
2488 1, /* in_info_type */
2489 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
2490 0xFFFF, /* in_max_output_length */
2491 NULL
, /* in_input_buffer */
2492 0, /* in_additional_info */
2499 if (!NT_STATUS_IS_OK(status
)) {
2503 /* Parse the reply. */
2504 ea_list
= read_nttrans_ea_list(ctx
,
2505 (const char *)outbuf
.data
,
2507 if (ea_list
== NULL
) {
2508 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2512 /* Convert to an array. */
2513 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2518 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
2519 if (*pea_array
== NULL
) {
2520 status
= NT_STATUS_NO_MEMORY
;
2524 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2525 (*pea_array
)[ea_count
++] = eal
->ea
;
2527 *pnum_eas
= ea_count
;
2532 if (fnum
!= 0xffff) {
2533 cli_smb2_close_fnum(cli
, fnum
);
2536 cli
->raw_status
= status
;
2542 /***************************************************************
2543 Wrapper that allows SMB2 to get user quota.
2545 ***************************************************************/
2547 NTSTATUS
cli_smb2_get_user_quota(struct cli_state
*cli
,
2549 SMB_NTQUOTA_STRUCT
*pqt
)
2552 DATA_BLOB inbuf
= data_blob_null
;
2553 DATA_BLOB outbuf
= data_blob_null
;
2554 struct smb2_hnd
*ph
= NULL
;
2555 TALLOC_CTX
*frame
= talloc_stackframe();
2557 unsigned int offset
;
2560 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2562 * Can't use sync call while an async call is in flight
2564 status
= NT_STATUS_INVALID_PARAMETER
;
2568 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2569 status
= NT_STATUS_INVALID_PARAMETER
;
2573 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
2574 if (!NT_STATUS_IS_OK(status
)) {
2578 sid_len
= ndr_size_dom_sid(&pqt
->sid
, 0);
2580 inbuf
= data_blob_talloc_zero(frame
, 24 + sid_len
);
2581 if (inbuf
.data
== NULL
) {
2582 status
= NT_STATUS_NO_MEMORY
;
2588 SCVAL(buf
, 0, 1); /* ReturnSingle */
2589 SCVAL(buf
, 1, 0); /* RestartScan */
2590 SSVAL(buf
, 2, 0); /* Reserved */
2591 if (8 + sid_len
< 8) {
2592 status
= NT_STATUS_INVALID_PARAMETER
;
2595 SIVAL(buf
, 4, 8 + sid_len
); /* SidListLength */
2596 SIVAL(buf
, 8, 0); /* StartSidLength */
2597 SIVAL(buf
, 12, 0); /* StartSidOffset */
2598 SIVAL(buf
, 16, 0); /* NextEntryOffset */
2599 SIVAL(buf
, 20, sid_len
); /* SidLength */
2600 sid_linearize(buf
+ 24, sid_len
, &pqt
->sid
);
2602 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
2603 cli
->smb2
.tcon
, 4, /* in_info_type */
2604 0, /* in_file_info_class */
2605 0xFFFF, /* in_max_output_length */
2606 &inbuf
, /* in_input_buffer */
2607 0, /* in_additional_info */
2609 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
2612 if (!NT_STATUS_IS_OK(status
)) {
2616 if (!parse_user_quota_record(outbuf
.data
, outbuf
.length
, &offset
,
2618 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2619 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
2623 cli
->raw_status
= status
;
2629 /***************************************************************
2630 Wrapper that allows SMB2 to list user quota.
2632 ***************************************************************/
2634 NTSTATUS
cli_smb2_list_user_quota_step(struct cli_state
*cli
,
2635 TALLOC_CTX
*mem_ctx
,
2637 SMB_NTQUOTA_LIST
**pqt_list
,
2641 DATA_BLOB inbuf
= data_blob_null
;
2642 DATA_BLOB outbuf
= data_blob_null
;
2643 struct smb2_hnd
*ph
= NULL
;
2644 TALLOC_CTX
*frame
= talloc_stackframe();
2647 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2649 * Can't use sync call while an async call is in flight
2651 status
= NT_STATUS_INVALID_PARAMETER
;
2655 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2656 status
= NT_STATUS_INVALID_PARAMETER
;
2660 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
2661 if (!NT_STATUS_IS_OK(status
)) {
2665 inbuf
= data_blob_talloc_zero(frame
, 16);
2666 if (inbuf
.data
== NULL
) {
2667 status
= NT_STATUS_NO_MEMORY
;
2673 SCVAL(buf
, 0, 0); /* ReturnSingle */
2674 SCVAL(buf
, 1, first
? 1 : 0); /* RestartScan */
2675 SSVAL(buf
, 2, 0); /* Reserved */
2676 SIVAL(buf
, 4, 0); /* SidListLength */
2677 SIVAL(buf
, 8, 0); /* StartSidLength */
2678 SIVAL(buf
, 12, 0); /* StartSidOffset */
2680 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
2681 cli
->smb2
.tcon
, 4, /* in_info_type */
2682 0, /* in_file_info_class */
2683 0xFFFF, /* in_max_output_length */
2684 &inbuf
, /* in_input_buffer */
2685 0, /* in_additional_info */
2687 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
2690 if (!NT_STATUS_IS_OK(status
)) {
2694 status
= parse_user_quota_list(outbuf
.data
, outbuf
.length
, mem_ctx
,
2698 cli
->raw_status
= status
;
2704 /***************************************************************
2705 Wrapper that allows SMB2 to get file system quota.
2707 ***************************************************************/
2709 NTSTATUS
cli_smb2_get_fs_quota_info(struct cli_state
*cli
,
2711 SMB_NTQUOTA_STRUCT
*pqt
)
2714 DATA_BLOB outbuf
= data_blob_null
;
2715 struct smb2_hnd
*ph
= NULL
;
2716 TALLOC_CTX
*frame
= talloc_stackframe();
2718 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2720 * Can't use sync call while an async call is in flight
2722 status
= NT_STATUS_INVALID_PARAMETER
;
2726 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2727 status
= NT_STATUS_INVALID_PARAMETER
;
2731 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
2732 if (!NT_STATUS_IS_OK(status
)) {
2736 status
= smb2cli_query_info(
2737 cli
->conn
, cli
->timeout
, cli
->smb2
.session
, cli
->smb2
.tcon
,
2738 2, /* in_info_type */
2739 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
2740 0xFFFF, /* in_max_output_length */
2741 NULL
, /* in_input_buffer */
2742 0, /* in_additional_info */
2744 ph
->fid_persistent
, ph
->fid_volatile
, frame
, &outbuf
);
2746 if (!NT_STATUS_IS_OK(status
)) {
2750 status
= parse_fs_quota_buffer(outbuf
.data
, outbuf
.length
, pqt
);
2753 cli
->raw_status
= status
;
2759 /***************************************************************
2760 Wrapper that allows SMB2 to set user quota.
2762 ***************************************************************/
2764 NTSTATUS
cli_smb2_set_user_quota(struct cli_state
*cli
,
2766 SMB_NTQUOTA_LIST
*qtl
)
2769 DATA_BLOB inbuf
= data_blob_null
;
2770 struct smb2_hnd
*ph
= NULL
;
2771 TALLOC_CTX
*frame
= talloc_stackframe();
2773 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2775 * Can't use sync call while an async call is in flight
2777 status
= NT_STATUS_INVALID_PARAMETER
;
2781 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2782 status
= NT_STATUS_INVALID_PARAMETER
;
2786 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
2787 if (!NT_STATUS_IS_OK(status
)) {
2791 status
= build_user_quota_buffer(qtl
, 0, talloc_tos(), &inbuf
, NULL
);
2792 if (!NT_STATUS_IS_OK(status
)) {
2796 status
= smb2cli_set_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
2797 cli
->smb2
.tcon
, 4, /* in_info_type */
2798 0, /* in_file_info_class */
2799 &inbuf
, /* in_input_buffer */
2800 0, /* in_additional_info */
2801 ph
->fid_persistent
, ph
->fid_volatile
);
2804 cli
->raw_status
= status
;
2811 NTSTATUS
cli_smb2_set_fs_quota_info(struct cli_state
*cli
,
2813 SMB_NTQUOTA_STRUCT
*pqt
)
2816 DATA_BLOB inbuf
= data_blob_null
;
2817 struct smb2_hnd
*ph
= NULL
;
2818 TALLOC_CTX
*frame
= talloc_stackframe();
2820 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2822 * Can't use sync call while an async call is in flight
2824 status
= NT_STATUS_INVALID_PARAMETER
;
2828 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2829 status
= NT_STATUS_INVALID_PARAMETER
;
2833 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
2834 if (!NT_STATUS_IS_OK(status
)) {
2838 status
= build_fs_quota_buffer(talloc_tos(), pqt
, &inbuf
, 0);
2839 if (!NT_STATUS_IS_OK(status
)) {
2843 status
= smb2cli_set_info(
2844 cli
->conn
, cli
->timeout
, cli
->smb2
.session
, cli
->smb2
.tcon
,
2845 2, /* in_info_type */
2846 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
2847 &inbuf
, /* in_input_buffer */
2848 0, /* in_additional_info */
2849 ph
->fid_persistent
, ph
->fid_volatile
);
2851 cli
->raw_status
= status
;
2857 struct cli_smb2_read_state
{
2858 struct tevent_context
*ev
;
2859 struct cli_state
*cli
;
2860 struct smb2_hnd
*ph
;
2861 uint64_t start_offset
;
2867 static void cli_smb2_read_done(struct tevent_req
*subreq
);
2869 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
2870 struct tevent_context
*ev
,
2871 struct cli_state
*cli
,
2877 struct tevent_req
*req
, *subreq
;
2878 struct cli_smb2_read_state
*state
;
2880 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
2886 state
->start_offset
= (uint64_t)offset
;
2887 state
->size
= (uint32_t)size
;
2888 state
->received
= 0;
2891 status
= map_fnum_to_smb2_handle(cli
,
2894 if (tevent_req_nterror(req
, status
)) {
2895 return tevent_req_post(req
, ev
);
2898 subreq
= smb2cli_read_send(state
,
2901 state
->cli
->timeout
,
2902 state
->cli
->smb2
.session
,
2903 state
->cli
->smb2
.tcon
,
2905 state
->start_offset
,
2906 state
->ph
->fid_persistent
,
2907 state
->ph
->fid_volatile
,
2908 0, /* minimum_count */
2909 0); /* remaining_bytes */
2911 if (tevent_req_nomem(subreq
, req
)) {
2912 return tevent_req_post(req
, ev
);
2914 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
2918 static void cli_smb2_read_done(struct tevent_req
*subreq
)
2920 struct tevent_req
*req
= tevent_req_callback_data(
2921 subreq
, struct tevent_req
);
2922 struct cli_smb2_read_state
*state
= tevent_req_data(
2923 req
, struct cli_smb2_read_state
);
2926 status
= smb2cli_read_recv(subreq
, state
,
2927 &state
->buf
, &state
->received
);
2928 if (tevent_req_nterror(req
, status
)) {
2932 if (state
->received
> state
->size
) {
2933 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2937 tevent_req_done(req
);
2940 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
2945 struct cli_smb2_read_state
*state
= tevent_req_data(
2946 req
, struct cli_smb2_read_state
);
2948 if (tevent_req_is_nterror(req
, &status
)) {
2949 state
->cli
->raw_status
= status
;
2953 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2954 * better make sure that you copy it away before you talloc_free(req).
2955 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2957 *received
= (ssize_t
)state
->received
;
2958 *rcvbuf
= state
->buf
;
2959 state
->cli
->raw_status
= NT_STATUS_OK
;
2960 return NT_STATUS_OK
;
2963 struct cli_smb2_write_state
{
2964 struct tevent_context
*ev
;
2965 struct cli_state
*cli
;
2966 struct smb2_hnd
*ph
;
2974 static void cli_smb2_write_written(struct tevent_req
*req
);
2976 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
2977 struct tevent_context
*ev
,
2978 struct cli_state
*cli
,
2986 struct tevent_req
*req
, *subreq
= NULL
;
2987 struct cli_smb2_write_state
*state
= NULL
;
2989 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
2995 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2996 state
->flags
= (uint32_t)mode
;
2998 state
->offset
= (uint64_t)offset
;
2999 state
->size
= (uint32_t)size
;
3002 status
= map_fnum_to_smb2_handle(cli
,
3005 if (tevent_req_nterror(req
, status
)) {
3006 return tevent_req_post(req
, ev
);
3009 subreq
= smb2cli_write_send(state
,
3012 state
->cli
->timeout
,
3013 state
->cli
->smb2
.session
,
3014 state
->cli
->smb2
.tcon
,
3017 state
->ph
->fid_persistent
,
3018 state
->ph
->fid_volatile
,
3019 0, /* remaining_bytes */
3020 state
->flags
, /* flags */
3023 if (tevent_req_nomem(subreq
, req
)) {
3024 return tevent_req_post(req
, ev
);
3026 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
3030 static void cli_smb2_write_written(struct tevent_req
*subreq
)
3032 struct tevent_req
*req
= tevent_req_callback_data(
3033 subreq
, struct tevent_req
);
3034 struct cli_smb2_write_state
*state
= tevent_req_data(
3035 req
, struct cli_smb2_write_state
);
3039 status
= smb2cli_write_recv(subreq
, &written
);
3040 TALLOC_FREE(subreq
);
3041 if (tevent_req_nterror(req
, status
)) {
3045 state
->written
= written
;
3047 tevent_req_done(req
);
3050 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
3053 struct cli_smb2_write_state
*state
= tevent_req_data(
3054 req
, struct cli_smb2_write_state
);
3057 if (tevent_req_is_nterror(req
, &status
)) {
3058 state
->cli
->raw_status
= status
;
3059 tevent_req_received(req
);
3063 if (pwritten
!= NULL
) {
3064 *pwritten
= (size_t)state
->written
;
3066 state
->cli
->raw_status
= NT_STATUS_OK
;
3067 tevent_req_received(req
);
3068 return NT_STATUS_OK
;
3071 /***************************************************************
3072 Wrapper that allows SMB2 async write using an fnum.
3073 This is mostly cut-and-paste from Volker's code inside
3074 source3/libsmb/clireadwrite.c, adapted for SMB2.
3076 Done this way so I can reuse all the logic inside cli_push()
3078 ***************************************************************/
3080 struct cli_smb2_writeall_state
{
3081 struct tevent_context
*ev
;
3082 struct cli_state
*cli
;
3083 struct smb2_hnd
*ph
;
3091 static void cli_smb2_writeall_written(struct tevent_req
*req
);
3093 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
3094 struct tevent_context
*ev
,
3095 struct cli_state
*cli
,
3103 struct tevent_req
*req
, *subreq
= NULL
;
3104 struct cli_smb2_writeall_state
*state
= NULL
;
3109 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
3115 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3116 state
->flags
= (uint32_t)mode
;
3118 state
->offset
= (uint64_t)offset
;
3119 state
->size
= (uint32_t)size
;
3122 status
= map_fnum_to_smb2_handle(cli
,
3125 if (tevent_req_nterror(req
, status
)) {
3126 return tevent_req_post(req
, ev
);
3129 to_write
= state
->size
;
3130 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
3131 to_write
= MIN(max_size
, to_write
);
3132 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
3134 to_write
= MIN(max_size
, to_write
);
3137 subreq
= smb2cli_write_send(state
,
3140 state
->cli
->timeout
,
3141 state
->cli
->smb2
.session
,
3142 state
->cli
->smb2
.tcon
,
3145 state
->ph
->fid_persistent
,
3146 state
->ph
->fid_volatile
,
3147 0, /* remaining_bytes */
3148 state
->flags
, /* flags */
3149 state
->buf
+ state
->written
);
3151 if (tevent_req_nomem(subreq
, req
)) {
3152 return tevent_req_post(req
, ev
);
3154 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
3158 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
3160 struct tevent_req
*req
= tevent_req_callback_data(
3161 subreq
, struct tevent_req
);
3162 struct cli_smb2_writeall_state
*state
= tevent_req_data(
3163 req
, struct cli_smb2_writeall_state
);
3165 uint32_t written
, to_write
;
3169 status
= smb2cli_write_recv(subreq
, &written
);
3170 TALLOC_FREE(subreq
);
3171 if (tevent_req_nterror(req
, status
)) {
3175 state
->written
+= written
;
3177 if (state
->written
> state
->size
) {
3178 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3182 to_write
= state
->size
- state
->written
;
3184 if (to_write
== 0) {
3185 tevent_req_done(req
);
3189 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
3190 to_write
= MIN(max_size
, to_write
);
3191 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
3193 to_write
= MIN(max_size
, to_write
);
3196 subreq
= smb2cli_write_send(state
,
3199 state
->cli
->timeout
,
3200 state
->cli
->smb2
.session
,
3201 state
->cli
->smb2
.tcon
,
3203 state
->offset
+ state
->written
,
3204 state
->ph
->fid_persistent
,
3205 state
->ph
->fid_volatile
,
3206 0, /* remaining_bytes */
3207 state
->flags
, /* flags */
3208 state
->buf
+ state
->written
);
3210 if (tevent_req_nomem(subreq
, req
)) {
3213 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
3216 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
3219 struct cli_smb2_writeall_state
*state
= tevent_req_data(
3220 req
, struct cli_smb2_writeall_state
);
3223 if (tevent_req_is_nterror(req
, &status
)) {
3224 state
->cli
->raw_status
= status
;
3227 if (pwritten
!= NULL
) {
3228 *pwritten
= (size_t)state
->written
;
3230 state
->cli
->raw_status
= NT_STATUS_OK
;
3231 return NT_STATUS_OK
;
3234 struct cli_smb2_splice_state
{
3235 struct tevent_context
*ev
;
3236 struct cli_state
*cli
;
3237 struct smb2_hnd
*src_ph
;
3238 struct smb2_hnd
*dst_ph
;
3239 int (*splice_cb
)(off_t n
, void *priv
);
3246 struct req_resume_key_rsp resume_rsp
;
3247 struct srv_copychunk_copy cc_copy
;
3250 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
3251 struct tevent_req
*req
);
3253 static void cli_splice_copychunk_done(struct tevent_req
*subreq
)
3255 struct tevent_req
*req
= tevent_req_callback_data(
3256 subreq
, struct tevent_req
);
3257 struct cli_smb2_splice_state
*state
=
3258 tevent_req_data(req
,
3259 struct cli_smb2_splice_state
);
3260 struct smbXcli_conn
*conn
= state
->cli
->conn
;
3261 DATA_BLOB out_input_buffer
= data_blob_null
;
3262 DATA_BLOB out_output_buffer
= data_blob_null
;
3263 struct srv_copychunk_rsp cc_copy_rsp
;
3264 enum ndr_err_code ndr_ret
;
3267 status
= smb2cli_ioctl_recv(subreq
, state
,
3269 &out_output_buffer
);
3270 TALLOC_FREE(subreq
);
3271 if ((!NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
) ||
3272 state
->resized
) && tevent_req_nterror(req
, status
)) {
3276 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
, state
, &cc_copy_rsp
,
3277 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
3278 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
3279 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3280 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3284 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
3285 uint32_t max_chunks
= MIN(cc_copy_rsp
.chunks_written
,
3286 cc_copy_rsp
.total_bytes_written
/ cc_copy_rsp
.chunk_bytes_written
);
3287 if ((cc_copy_rsp
.chunk_bytes_written
> smb2cli_conn_cc_chunk_len(conn
) ||
3288 max_chunks
> smb2cli_conn_cc_max_chunks(conn
)) &&
3289 tevent_req_nterror(req
, status
)) {
3293 state
->resized
= true;
3294 smb2cli_conn_set_cc_chunk_len(conn
, cc_copy_rsp
.chunk_bytes_written
);
3295 smb2cli_conn_set_cc_max_chunks(conn
, max_chunks
);
3297 if ((state
->src_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
3298 (state
->dst_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
3299 (state
->written
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
)) {
3300 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
3303 state
->src_offset
+= cc_copy_rsp
.total_bytes_written
;
3304 state
->dst_offset
+= cc_copy_rsp
.total_bytes_written
;
3305 state
->written
+= cc_copy_rsp
.total_bytes_written
;
3306 if (!state
->splice_cb(state
->written
, state
->priv
)) {
3307 tevent_req_nterror(req
, NT_STATUS_CANCELLED
);
3312 cli_splice_copychunk_send(state
, req
);
3315 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
3316 struct tevent_req
*req
)
3318 struct tevent_req
*subreq
;
3319 enum ndr_err_code ndr_ret
;
3320 struct smbXcli_conn
*conn
= state
->cli
->conn
;
3321 struct srv_copychunk_copy
*cc_copy
= &state
->cc_copy
;
3322 off_t src_offset
= state
->src_offset
;
3323 off_t dst_offset
= state
->dst_offset
;
3324 uint32_t req_len
= MIN(smb2cli_conn_cc_chunk_len(conn
) * smb2cli_conn_cc_max_chunks(conn
),
3325 state
->size
- state
->written
);
3326 DATA_BLOB in_input_buffer
= data_blob_null
;
3327 DATA_BLOB in_output_buffer
= data_blob_null
;
3329 if (state
->size
- state
->written
== 0) {
3330 tevent_req_done(req
);
3334 cc_copy
->chunk_count
= 0;
3336 cc_copy
->chunks
[cc_copy
->chunk_count
].source_off
= src_offset
;
3337 cc_copy
->chunks
[cc_copy
->chunk_count
].target_off
= dst_offset
;
3338 cc_copy
->chunks
[cc_copy
->chunk_count
].length
= MIN(req_len
,
3339 smb2cli_conn_cc_chunk_len(conn
));
3340 if (req_len
< cc_copy
->chunks
[cc_copy
->chunk_count
].length
) {
3341 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
3344 req_len
-= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
3345 if ((src_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
) ||
3346 (dst_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
)) {
3347 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
3350 src_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
3351 dst_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
3352 cc_copy
->chunk_count
++;
3355 ndr_ret
= ndr_push_struct_blob(&in_input_buffer
, state
, cc_copy
,
3356 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
3357 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
3358 DEBUG(0, ("failed to marshall copy chunk req\n"));
3359 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
3363 subreq
= smb2cli_ioctl_send(state
, state
->ev
, state
->cli
->conn
,
3364 state
->cli
->timeout
,
3365 state
->cli
->smb2
.session
,
3366 state
->cli
->smb2
.tcon
,
3367 state
->dst_ph
->fid_persistent
, /* in_fid_persistent */
3368 state
->dst_ph
->fid_volatile
, /* in_fid_volatile */
3369 FSCTL_SRV_COPYCHUNK_WRITE
,
3370 0, /* in_max_input_length */
3372 12, /* in_max_output_length */
3374 SMB2_IOCTL_FLAG_IS_FSCTL
);
3375 if (tevent_req_nomem(subreq
, req
)) {
3378 tevent_req_set_callback(subreq
,
3379 cli_splice_copychunk_done
,
3383 static void cli_splice_key_done(struct tevent_req
*subreq
)
3385 struct tevent_req
*req
= tevent_req_callback_data(
3386 subreq
, struct tevent_req
);
3387 struct cli_smb2_splice_state
*state
=
3388 tevent_req_data(req
,
3389 struct cli_smb2_splice_state
);
3390 enum ndr_err_code ndr_ret
;
3393 DATA_BLOB out_input_buffer
= data_blob_null
;
3394 DATA_BLOB out_output_buffer
= data_blob_null
;
3396 status
= smb2cli_ioctl_recv(subreq
, state
,
3398 &out_output_buffer
);
3399 TALLOC_FREE(subreq
);
3400 if (tevent_req_nterror(req
, status
)) {
3404 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
,
3405 state
, &state
->resume_rsp
,
3406 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
3407 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
3408 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3409 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3413 memcpy(&state
->cc_copy
.source_key
,
3414 &state
->resume_rsp
.resume_key
,
3415 sizeof state
->resume_rsp
.resume_key
);
3417 cli_splice_copychunk_send(state
, req
);
3420 struct tevent_req
*cli_smb2_splice_send(TALLOC_CTX
*mem_ctx
,
3421 struct tevent_context
*ev
,
3422 struct cli_state
*cli
,
3423 uint16_t src_fnum
, uint16_t dst_fnum
,
3424 off_t size
, off_t src_offset
, off_t dst_offset
,
3425 int (*splice_cb
)(off_t n
, void *priv
),
3428 struct tevent_req
*req
;
3429 struct tevent_req
*subreq
;
3430 struct cli_smb2_splice_state
*state
;
3432 DATA_BLOB in_input_buffer
= data_blob_null
;
3433 DATA_BLOB in_output_buffer
= data_blob_null
;
3435 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_splice_state
);
3441 state
->splice_cb
= splice_cb
;
3445 state
->src_offset
= src_offset
;
3446 state
->dst_offset
= dst_offset
;
3447 state
->cc_copy
.chunks
= talloc_array(state
,
3448 struct srv_copychunk
,
3449 smb2cli_conn_cc_max_chunks(cli
->conn
));
3450 if (state
->cc_copy
.chunks
== NULL
) {
3454 status
= map_fnum_to_smb2_handle(cli
, src_fnum
, &state
->src_ph
);
3455 if (tevent_req_nterror(req
, status
))
3456 return tevent_req_post(req
, ev
);
3458 status
= map_fnum_to_smb2_handle(cli
, dst_fnum
, &state
->dst_ph
);
3459 if (tevent_req_nterror(req
, status
))
3460 return tevent_req_post(req
, ev
);
3462 subreq
= smb2cli_ioctl_send(state
, ev
, cli
->conn
,
3466 state
->src_ph
->fid_persistent
, /* in_fid_persistent */
3467 state
->src_ph
->fid_volatile
, /* in_fid_volatile */
3468 FSCTL_SRV_REQUEST_RESUME_KEY
,
3469 0, /* in_max_input_length */
3471 32, /* in_max_output_length */
3473 SMB2_IOCTL_FLAG_IS_FSCTL
);
3474 if (tevent_req_nomem(subreq
, req
)) {
3477 tevent_req_set_callback(subreq
,
3478 cli_splice_key_done
,
3484 NTSTATUS
cli_smb2_splice_recv(struct tevent_req
*req
, off_t
*written
)
3486 struct cli_smb2_splice_state
*state
= tevent_req_data(
3487 req
, struct cli_smb2_splice_state
);
3490 if (tevent_req_is_nterror(req
, &status
)) {
3491 state
->cli
->raw_status
= status
;
3492 tevent_req_received(req
);
3495 if (written
!= NULL
) {
3496 *written
= state
->written
;
3498 state
->cli
->raw_status
= NT_STATUS_OK
;
3499 tevent_req_received(req
);
3500 return NT_STATUS_OK
;
3503 /***************************************************************
3504 SMB2 enum shadow copy data.
3505 ***************************************************************/
3507 struct cli_smb2_shadow_copy_data_fnum_state
{
3508 struct cli_state
*cli
;
3510 struct smb2_hnd
*ph
;
3511 DATA_BLOB out_input_buffer
;
3512 DATA_BLOB out_output_buffer
;
3515 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
);
3517 static struct tevent_req
*cli_smb2_shadow_copy_data_fnum_send(
3518 TALLOC_CTX
*mem_ctx
,
3519 struct tevent_context
*ev
,
3520 struct cli_state
*cli
,
3524 struct tevent_req
*req
, *subreq
;
3525 struct cli_smb2_shadow_copy_data_fnum_state
*state
;
3528 req
= tevent_req_create(mem_ctx
, &state
,
3529 struct cli_smb2_shadow_copy_data_fnum_state
);
3534 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3535 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3536 return tevent_req_post(req
, ev
);
3542 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
3543 if (tevent_req_nterror(req
, status
)) {
3544 return tevent_req_post(req
, ev
);
3548 * TODO. Under SMB2 we should send a zero max_output_length
3549 * ioctl to get the required size, then send another ioctl
3550 * to get the data, but the current SMB1 implementation just
3551 * does one roundtrip with a 64K buffer size. Do the same
3555 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
3556 state
->cli
->timeout
,
3557 state
->cli
->smb2
.session
,
3558 state
->cli
->smb2
.tcon
,
3559 state
->ph
->fid_persistent
, /* in_fid_persistent */
3560 state
->ph
->fid_volatile
, /* in_fid_volatile */
3561 FSCTL_GET_SHADOW_COPY_DATA
,
3562 0, /* in_max_input_length */
3563 NULL
, /* in_input_buffer */
3565 CLI_BUFFER_SIZE
: 16, /* in_max_output_length */
3566 NULL
, /* in_output_buffer */
3567 SMB2_IOCTL_FLAG_IS_FSCTL
);
3569 if (tevent_req_nomem(subreq
, req
)) {
3570 return tevent_req_post(req
, ev
);
3572 tevent_req_set_callback(subreq
,
3573 cli_smb2_shadow_copy_data_fnum_done
,
3579 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
)
3581 struct tevent_req
*req
= tevent_req_callback_data(
3582 subreq
, struct tevent_req
);
3583 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
3584 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
3587 status
= smb2cli_ioctl_recv(subreq
, state
,
3588 &state
->out_input_buffer
,
3589 &state
->out_output_buffer
);
3590 TALLOC_FREE(subreq
);
3591 if (tevent_req_nterror(req
, status
)) {
3594 tevent_req_done(req
);
3597 static NTSTATUS
cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req
*req
,
3598 TALLOC_CTX
*mem_ctx
,
3603 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
3604 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
3605 char **names
= NULL
;
3606 uint32_t num_names
= 0;
3607 uint32_t num_names_returned
= 0;
3608 uint32_t dlength
= 0;
3610 uint8_t *endp
= NULL
;
3613 if (tevent_req_is_nterror(req
, &status
)) {
3617 if (state
->out_output_buffer
.length
< 16) {
3618 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3621 num_names
= IVAL(state
->out_output_buffer
.data
, 0);
3622 num_names_returned
= IVAL(state
->out_output_buffer
.data
, 4);
3623 dlength
= IVAL(state
->out_output_buffer
.data
, 8);
3625 if (num_names
> 0x7FFFFFFF) {
3626 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3629 if (get_names
== false) {
3630 *pnum_names
= (int)num_names
;
3631 return NT_STATUS_OK
;
3633 if (num_names
!= num_names_returned
) {
3634 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3636 if (dlength
+ 12 < 12) {
3637 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3640 * NB. The below is an allowable return if there are
3641 * more snapshots than the buffer size we told the
3642 * server we can receive. We currently don't support
3645 if (dlength
+ 12 > state
->out_output_buffer
.length
) {
3646 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3648 if (state
->out_output_buffer
.length
+
3649 (2 * sizeof(SHADOW_COPY_LABEL
)) <
3650 state
->out_output_buffer
.length
) {
3651 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3654 names
= talloc_array(mem_ctx
, char *, num_names_returned
);
3655 if (names
== NULL
) {
3656 return NT_STATUS_NO_MEMORY
;
3659 endp
= state
->out_output_buffer
.data
+
3660 state
->out_output_buffer
.length
;
3662 for (i
=0; i
<num_names_returned
; i
++) {
3665 size_t converted_size
;
3667 src
= state
->out_output_buffer
.data
+ 12 +
3668 (i
* 2 * sizeof(SHADOW_COPY_LABEL
));
3670 if (src
+ (2 * sizeof(SHADOW_COPY_LABEL
)) > endp
) {
3671 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3673 ret
= convert_string_talloc(
3674 names
, CH_UTF16LE
, CH_UNIX
,
3675 src
, 2 * sizeof(SHADOW_COPY_LABEL
),
3676 &names
[i
], &converted_size
);
3679 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3682 *pnum_names
= num_names
;
3684 return NT_STATUS_OK
;
3687 NTSTATUS
cli_smb2_shadow_copy_data(TALLOC_CTX
*mem_ctx
,
3688 struct cli_state
*cli
,
3694 TALLOC_CTX
*frame
= talloc_stackframe();
3695 struct tevent_context
*ev
;
3696 struct tevent_req
*req
;
3697 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3699 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3701 * Can't use sync call while an async call is in flight
3703 status
= NT_STATUS_INVALID_PARAMETER
;
3706 ev
= samba_tevent_context_init(frame
);
3710 req
= cli_smb2_shadow_copy_data_fnum_send(frame
,
3718 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3721 status
= cli_smb2_shadow_copy_data_fnum_recv(req
,
3727 cli
->raw_status
= status
;
3733 /***************************************************************
3734 Wrapper that allows SMB2 to truncate a file.
3736 ***************************************************************/
3738 NTSTATUS
cli_smb2_ftruncate(struct cli_state
*cli
,
3743 DATA_BLOB inbuf
= data_blob_null
;
3744 struct smb2_hnd
*ph
= NULL
;
3745 TALLOC_CTX
*frame
= talloc_stackframe();
3747 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3749 * Can't use sync call while an async call is in flight
3751 status
= NT_STATUS_INVALID_PARAMETER
;
3755 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3756 status
= NT_STATUS_INVALID_PARAMETER
;
3760 status
= map_fnum_to_smb2_handle(cli
,
3763 if (!NT_STATUS_IS_OK(status
)) {
3767 inbuf
= data_blob_talloc_zero(frame
, 8);
3768 if (inbuf
.data
== NULL
) {
3769 status
= NT_STATUS_NO_MEMORY
;
3773 SBVAL(inbuf
.data
, 0, newsize
);
3775 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3776 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
3778 status
= smb2cli_set_info(cli
->conn
,
3782 1, /* in_info_type */
3783 /* in_file_info_class */
3784 SMB_FILE_END_OF_FILE_INFORMATION
- 1000,
3785 &inbuf
, /* in_input_buffer */
3786 0, /* in_additional_info */
3792 cli
->raw_status
= status
;