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"
44 #include "librpc/gen_ndr/ndr_quota.h"
45 #include "librpc/gen_ndr/ndr_smb3posix.h"
46 #include "lib/util/string_wrappers.h"
47 #include "lib/util/idtree.h"
48 #include "libcli/smb/smb2_posix.h"
51 uint64_t fid_persistent
;
52 uint64_t fid_volatile
;
53 bool posix
; /* Opened with posix context */
57 * Handle mapping code.
60 /***************************************************************
61 Allocate a new fnum between 1 and 0xFFFE from an smb2 file id.
62 Ensures handle is owned by cli struct.
63 ***************************************************************/
65 static NTSTATUS
map_smb2_handle_to_fnum(struct cli_state
*cli
,
66 uint64_t fid_persistent
,
67 uint64_t fid_volatile
,
72 struct idr_context
*idp
= cli
->smb2
.open_handles
;
73 struct smb2_hnd
*owned_h
= NULL
;
75 owned_h
= talloc(cli
, struct smb2_hnd
);
76 if (owned_h
== NULL
) {
77 return NT_STATUS_NO_MEMORY
;
79 *owned_h
= (struct smb2_hnd
){
80 .fid_persistent
= fid_persistent
,
81 .fid_volatile
= fid_volatile
,
87 cli
->smb2
.open_handles
= idr_init(cli
);
88 if (cli
->smb2
.open_handles
== NULL
) {
90 return NT_STATUS_NO_MEMORY
;
92 idp
= cli
->smb2
.open_handles
;
95 ret
= idr_get_new_above(idp
, owned_h
, 1, 0xFFFE);
98 return NT_STATUS_NO_MEMORY
;
101 *pfnum
= (uint16_t)ret
;
105 /***************************************************************
106 Return the smb2_hnd pointer associated with the given fnum.
107 ***************************************************************/
109 static NTSTATUS
map_fnum_to_smb2_handle(struct cli_state
*cli
,
110 uint16_t fnum
, /* In */
111 struct smb2_hnd
**pph
) /* Out */
113 struct idr_context
*idp
= cli
->smb2
.open_handles
;
116 return NT_STATUS_INVALID_PARAMETER
;
118 *pph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
120 return NT_STATUS_INVALID_HANDLE
;
125 /***************************************************************
126 Delete the fnum to smb2_hnd mapping. Zeros out handle on
128 ***************************************************************/
130 static NTSTATUS
delete_smb2_handle_mapping(struct cli_state
*cli
,
131 struct smb2_hnd
**pph
, /* In */
132 uint16_t fnum
) /* In */
134 struct idr_context
*idp
= cli
->smb2
.open_handles
;
138 return NT_STATUS_INVALID_PARAMETER
;
141 ph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
143 return NT_STATUS_INVALID_PARAMETER
;
145 idr_remove(idp
, fnum
);
150 /***************************************************************
152 ***************************************************************/
154 static uint8_t flags_to_smb2_oplock(struct cli_smb2_create_flags create_flags
)
156 if (create_flags
.batch_oplock
) {
157 return SMB2_OPLOCK_LEVEL_BATCH
;
158 } else if (create_flags
.exclusive_oplock
) {
159 return SMB2_OPLOCK_LEVEL_EXCLUSIVE
;
162 /* create_flags doesn't do a level2 request. */
163 return SMB2_OPLOCK_LEVEL_NONE
;
166 /***************************************************************
167 If we're on a DFS share, ensure we convert to a full DFS path
168 if this hasn't already been done.
169 ***************************************************************/
171 static char *smb2_dfs_share_path(TALLOC_CTX
*ctx
,
172 struct cli_state
*cli
,
175 bool is_dfs
= smbXcli_conn_dfs_supported(cli
->conn
) &&
176 smbXcli_tcon_is_dfs_share(cli
->smb2
.tcon
);
177 bool is_already_dfs_path
= false;
182 is_already_dfs_path
= cli_dfs_is_already_full_path(cli
, path
);
183 if (is_already_dfs_path
) {
186 if (path
[0] == '\0') {
187 return talloc_asprintf(ctx
,
189 smbXcli_conn_remote_name(cli
->conn
),
192 while (*path
== '\\') {
195 return talloc_asprintf(ctx
,
197 smbXcli_conn_remote_name(cli
->conn
),
202 /***************************************************************
203 Small wrapper that allows SMB2 create to return a uint16_t fnum.
204 ***************************************************************/
206 struct cli_smb2_create_fnum_state
{
207 struct cli_state
*cli
;
208 struct smb2_create_blobs in_cblobs
;
209 struct smb2_create_blobs out_cblobs
;
210 struct smb_create_returns cr
;
211 struct symlink_reparse_struct
*symlink
;
213 struct tevent_req
*subreq
;
216 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
);
217 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
);
219 struct tevent_req
*cli_smb2_create_fnum_send(
221 struct tevent_context
*ev
,
222 struct cli_state
*cli
,
223 const char *fname_in
,
224 struct cli_smb2_create_flags create_flags
,
225 uint32_t impersonation_level
,
226 uint32_t desired_access
,
227 uint32_t file_attributes
,
228 uint32_t share_access
,
229 uint32_t create_disposition
,
230 uint32_t create_options
,
231 const struct smb2_create_blobs
*in_cblobs
)
233 struct tevent_req
*req
, *subreq
;
234 struct cli_smb2_create_fnum_state
*state
;
236 size_t fname_len
= 0;
241 req
= tevent_req_create(mem_ctx
, &state
,
242 struct cli_smb2_create_fnum_state
);
248 fname
= talloc_strdup(state
, fname_in
);
249 if (tevent_req_nomem(fname
, req
)) {
250 return tevent_req_post(req
, ev
);
253 if (cli
->backup_intent
) {
254 create_options
|= FILE_OPEN_FOR_BACKUP_INTENT
;
257 if (cli
->smb2
.client_smb311_posix
) {
258 uint8_t modebuf
[4] = {
263 smb2_create_blob_add(state
,
265 SMB2_CREATE_TAG_POSIX
,
268 .length
= sizeof(modebuf
),
270 if (tevent_req_nterror(req
, status
)) {
271 return tevent_req_post(req
, ev
);
275 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
276 have_twrp
= clistr_smb2_extract_snapshot_token(fname
, &ntt
);
278 status
= smb2_create_blob_add(
281 SMB2_CREATE_TAG_TWRP
,
283 .data
= (uint8_t *)&ntt
,
284 .length
= sizeof(ntt
),
286 if (tevent_req_nterror(req
, status
)) {
287 return tevent_req_post(req
, ev
);
291 if (in_cblobs
!= NULL
) {
293 for (i
=0; i
<in_cblobs
->num_blobs
; i
++) {
294 struct smb2_create_blob
*b
= &in_cblobs
->blobs
[i
];
295 status
= smb2_create_blob_add(
296 state
, &state
->in_cblobs
, b
->tag
, b
->data
);
297 if (!NT_STATUS_IS_OK(status
)) {
298 tevent_req_nterror(req
, status
);
299 return tevent_req_post(req
, ev
);
304 fname
= smb2_dfs_share_path(state
, cli
, fname
);
305 if (tevent_req_nomem(fname
, req
)) {
306 return tevent_req_post(req
, ev
);
308 fname_len
= strlen(fname
);
310 /* SMB2 is pickier about pathnames. Ensure it doesn't
312 if (*fname
== '\\') {
317 /* Or end in a '\' */
318 if (fname_len
> 0 && fname
[fname_len
-1] == '\\') {
319 fname
[fname_len
-1] = '\0';
322 subreq
= smb2cli_create_send(state
, ev
,
328 flags_to_smb2_oplock(create_flags
),
336 if (tevent_req_nomem(subreq
, req
)) {
337 return tevent_req_post(req
, ev
);
339 tevent_req_set_callback(subreq
, cli_smb2_create_fnum_done
, req
);
341 state
->subreq
= subreq
;
342 tevent_req_set_cancel_fn(req
, cli_smb2_create_fnum_cancel
);
347 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
)
349 struct tevent_req
*req
= tevent_req_callback_data(
350 subreq
, struct tevent_req
);
351 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
352 req
, struct cli_smb2_create_fnum_state
);
353 uint64_t fid_persistent
, fid_volatile
;
354 struct smb2_create_blob
*posix
= NULL
;
357 status
= smb2cli_create_recv(subreq
,
365 if (tevent_req_nterror(req
, status
)) {
369 posix
= smb2_create_blob_find(&state
->in_cblobs
,
370 SMB2_CREATE_TAG_POSIX
);
372 status
= map_smb2_handle_to_fnum(state
->cli
,
377 if (tevent_req_nterror(req
, status
)) {
380 tevent_req_done(req
);
383 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
)
385 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
386 req
, struct cli_smb2_create_fnum_state
);
387 return tevent_req_cancel(state
->subreq
);
390 NTSTATUS
cli_smb2_create_fnum_recv(
391 struct tevent_req
*req
,
393 struct smb_create_returns
*cr
,
395 struct smb2_create_blobs
*out_cblobs
,
396 struct symlink_reparse_struct
**symlink
)
398 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
399 req
, struct cli_smb2_create_fnum_state
);
402 if (tevent_req_is_nterror(req
, &status
)) {
403 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
) &&
405 *symlink
= talloc_move(mem_ctx
, &state
->symlink
);
410 *pfnum
= state
->fnum
;
415 if (out_cblobs
!= NULL
) {
416 *out_cblobs
= (struct smb2_create_blobs
) {
417 .num_blobs
= state
->out_cblobs
.num_blobs
,
418 .blobs
= talloc_move(
419 mem_ctx
, &state
->out_cblobs
.blobs
),
425 bool cli_smb2_fnum_is_posix(struct cli_state
*cli
, uint16_t fnum
)
427 struct smb2_hnd
*ph
= NULL
;
430 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
431 if (!NT_STATUS_IS_OK(status
)) {
437 NTSTATUS
cli_smb2_create_fnum(
438 struct cli_state
*cli
,
440 struct cli_smb2_create_flags create_flags
,
441 uint32_t impersonation_level
,
442 uint32_t desired_access
,
443 uint32_t file_attributes
,
444 uint32_t share_access
,
445 uint32_t create_disposition
,
446 uint32_t create_options
,
447 const struct smb2_create_blobs
*in_cblobs
,
449 struct smb_create_returns
*cr
,
451 struct smb2_create_blobs
*out_cblobs
)
453 TALLOC_CTX
*frame
= talloc_stackframe();
454 struct tevent_context
*ev
;
455 struct tevent_req
*req
;
456 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
458 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
460 * Can't use sync call while an async call is in flight
462 status
= NT_STATUS_INVALID_PARAMETER
;
465 ev
= samba_tevent_context_init(frame
);
469 req
= cli_smb2_create_fnum_send(
485 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
488 status
= cli_smb2_create_fnum_recv(
489 req
, pfid
, cr
, mem_ctx
, out_cblobs
, NULL
);
495 /***************************************************************
496 Small wrapper that allows SMB2 close to use a uint16_t fnum.
497 ***************************************************************/
499 struct cli_smb2_close_fnum_state
{
500 struct cli_state
*cli
;
505 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
);
507 struct tevent_req
*cli_smb2_close_fnum_send(TALLOC_CTX
*mem_ctx
,
508 struct tevent_context
*ev
,
509 struct cli_state
*cli
,
513 struct tevent_req
*req
, *subreq
;
514 struct cli_smb2_close_fnum_state
*state
;
517 req
= tevent_req_create(mem_ctx
, &state
,
518 struct cli_smb2_close_fnum_state
);
525 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
526 if (tevent_req_nterror(req
, status
)) {
527 return tevent_req_post(req
, ev
);
530 subreq
= smb2cli_close_send(state
,
537 state
->ph
->fid_persistent
,
538 state
->ph
->fid_volatile
);
539 if (tevent_req_nomem(subreq
, req
)) {
540 return tevent_req_post(req
, ev
);
542 tevent_req_set_callback(subreq
, cli_smb2_close_fnum_done
, req
);
546 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
)
548 struct tevent_req
*req
= tevent_req_callback_data(
549 subreq
, struct tevent_req
);
550 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
551 req
, struct cli_smb2_close_fnum_state
);
554 status
= smb2cli_close_recv(subreq
);
555 if (tevent_req_nterror(req
, status
)) {
559 /* Delete the fnum -> handle mapping. */
560 status
= delete_smb2_handle_mapping(state
->cli
, &state
->ph
,
562 if (tevent_req_nterror(req
, status
)) {
565 tevent_req_done(req
);
568 NTSTATUS
cli_smb2_close_fnum_recv(struct tevent_req
*req
)
570 return tevent_req_simple_recv_ntstatus(req
);
573 NTSTATUS
cli_smb2_close_fnum(struct cli_state
*cli
, uint16_t fnum
)
575 TALLOC_CTX
*frame
= talloc_stackframe();
576 struct tevent_context
*ev
;
577 struct tevent_req
*req
;
578 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
580 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
582 * Can't use sync call while an async call is in flight
584 status
= NT_STATUS_INVALID_PARAMETER
;
587 ev
= samba_tevent_context_init(frame
);
591 req
= cli_smb2_close_fnum_send(frame
, ev
, cli
, fnum
, 0);
595 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
598 status
= cli_smb2_close_fnum_recv(req
);
604 struct cli_smb2_set_info_fnum_state
{
608 static void cli_smb2_set_info_fnum_done(struct tevent_req
*subreq
);
610 struct tevent_req
*cli_smb2_set_info_fnum_send(
612 struct tevent_context
*ev
,
613 struct cli_state
*cli
,
615 uint8_t in_info_type
,
616 uint8_t in_info_class
,
617 const DATA_BLOB
*in_input_buffer
,
618 uint32_t in_additional_info
)
620 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
621 struct cli_smb2_set_info_fnum_state
*state
= NULL
;
622 struct smb2_hnd
*ph
= NULL
;
625 req
= tevent_req_create(
626 mem_ctx
, &state
, struct cli_smb2_set_info_fnum_state
);
631 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
632 if (tevent_req_nterror(req
, status
)) {
633 return tevent_req_post(req
, ev
);
636 subreq
= smb2cli_set_info_send(
649 if (tevent_req_nomem(subreq
, req
)) {
650 return tevent_req_post(req
, ev
);
652 tevent_req_set_callback(subreq
, cli_smb2_set_info_fnum_done
, req
);
656 static void cli_smb2_set_info_fnum_done(struct tevent_req
*subreq
)
658 NTSTATUS status
= smb2cli_set_info_recv(subreq
);
659 tevent_req_simple_finish_ntstatus(subreq
, status
);
662 NTSTATUS
cli_smb2_set_info_fnum_recv(struct tevent_req
*req
)
664 return tevent_req_simple_recv_ntstatus(req
);
667 NTSTATUS
cli_smb2_set_info_fnum(
668 struct cli_state
*cli
,
670 uint8_t in_info_type
,
671 uint8_t in_info_class
,
672 const DATA_BLOB
*in_input_buffer
,
673 uint32_t in_additional_info
)
675 TALLOC_CTX
*frame
= talloc_stackframe();
676 struct tevent_context
*ev
= NULL
;
677 struct tevent_req
*req
= NULL
;
678 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
681 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
683 * Can't use sync call while an async call is in flight
685 status
= NT_STATUS_INVALID_PARAMETER
;
688 ev
= samba_tevent_context_init(frame
);
692 req
= cli_smb2_set_info_fnum_send(
704 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
708 status
= cli_smb2_set_info_fnum_recv(req
);
714 struct cli_smb2_delete_on_close_state
{
715 struct cli_state
*cli
;
720 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
);
722 struct tevent_req
*cli_smb2_delete_on_close_send(TALLOC_CTX
*mem_ctx
,
723 struct tevent_context
*ev
,
724 struct cli_state
*cli
,
728 struct tevent_req
*req
= NULL
;
729 struct cli_smb2_delete_on_close_state
*state
= NULL
;
730 struct tevent_req
*subreq
= NULL
;
732 req
= tevent_req_create(mem_ctx
, &state
,
733 struct cli_smb2_delete_on_close_state
);
739 /* Setup data array. */
740 SCVAL(&state
->data
[0], 0, flag
? 1 : 0);
741 state
->inbuf
.data
= &state
->data
[0];
742 state
->inbuf
.length
= 1;
744 subreq
= cli_smb2_set_info_fnum_send(state
,
749 FSCC_FILE_DISPOSITION_INFORMATION
,
752 if (tevent_req_nomem(subreq
, req
)) {
753 return tevent_req_post(req
, ev
);
755 tevent_req_set_callback(subreq
,
756 cli_smb2_delete_on_close_done
,
761 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
)
763 NTSTATUS status
= cli_smb2_set_info_fnum_recv(subreq
);
764 tevent_req_simple_finish_ntstatus(subreq
, status
);
767 NTSTATUS
cli_smb2_delete_on_close_recv(struct tevent_req
*req
)
769 return tevent_req_simple_recv_ntstatus(req
);
772 NTSTATUS
cli_smb2_delete_on_close(struct cli_state
*cli
, uint16_t fnum
, bool flag
)
774 TALLOC_CTX
*frame
= talloc_stackframe();
775 struct tevent_context
*ev
;
776 struct tevent_req
*req
;
777 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
779 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
781 * Can't use sync call while an async call is in flight
783 status
= NT_STATUS_INVALID_PARAMETER
;
786 ev
= samba_tevent_context_init(frame
);
790 req
= cli_smb2_delete_on_close_send(frame
, ev
, cli
, fnum
, flag
);
794 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
797 status
= cli_smb2_delete_on_close_recv(req
);
803 struct cli_smb2_mkdir_state
{
804 struct tevent_context
*ev
;
805 struct cli_state
*cli
;
808 static void cli_smb2_mkdir_opened(struct tevent_req
*subreq
);
809 static void cli_smb2_mkdir_closed(struct tevent_req
*subreq
);
811 struct tevent_req
*cli_smb2_mkdir_send(
813 struct tevent_context
*ev
,
814 struct cli_state
*cli
,
817 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
818 struct cli_smb2_mkdir_state
*state
= NULL
;
820 req
= tevent_req_create(
821 mem_ctx
, &state
, struct cli_smb2_mkdir_state
);
828 /* Ensure this is a directory. */
829 subreq
= cli_smb2_create_fnum_send(
834 (struct cli_smb2_create_flags
){0}, /* create_flags */
835 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation_level */
836 FILE_READ_ATTRIBUTES
, /* desired_access */
837 FILE_ATTRIBUTE_DIRECTORY
, /* file_attributes */
839 FILE_SHARE_WRITE
, /* share_access */
840 FILE_CREATE
, /* create_disposition */
841 FILE_DIRECTORY_FILE
, /* create_options */
842 NULL
); /* in_cblobs */
843 if (tevent_req_nomem(subreq
, req
)) {
844 return tevent_req_post(req
, ev
);
846 tevent_req_set_callback(subreq
, cli_smb2_mkdir_opened
, req
);
850 static void cli_smb2_mkdir_opened(struct tevent_req
*subreq
)
852 struct tevent_req
*req
= tevent_req_callback_data(
853 subreq
, struct tevent_req
);
854 struct cli_smb2_mkdir_state
*state
= tevent_req_data(
855 req
, struct cli_smb2_mkdir_state
);
857 uint16_t fnum
= 0xffff;
859 status
= cli_smb2_create_fnum_recv(
860 subreq
, &fnum
, NULL
, NULL
, NULL
, NULL
);
862 if (tevent_req_nterror(req
, status
)) {
867 cli_smb2_close_fnum_send(state
, state
->ev
, state
->cli
, fnum
, 0);
868 if (tevent_req_nomem(subreq
, req
)) {
871 tevent_req_set_callback(subreq
, cli_smb2_mkdir_closed
, req
);
874 static void cli_smb2_mkdir_closed(struct tevent_req
*subreq
)
876 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
877 tevent_req_simple_finish_ntstatus(subreq
, status
);
880 NTSTATUS
cli_smb2_mkdir_recv(struct tevent_req
*req
)
882 return tevent_req_simple_recv_ntstatus(req
);
885 struct cli_smb2_rmdir_state
{
886 struct tevent_context
*ev
;
887 struct cli_state
*cli
;
889 const struct smb2_create_blobs
*in_cblobs
;
894 static void cli_smb2_rmdir_opened1(struct tevent_req
*subreq
);
895 static void cli_smb2_rmdir_opened2(struct tevent_req
*subreq
);
896 static void cli_smb2_rmdir_disp_set(struct tevent_req
*subreq
);
897 static void cli_smb2_rmdir_closed(struct tevent_req
*subreq
);
899 struct tevent_req
*cli_smb2_rmdir_send(
901 struct tevent_context
*ev
,
902 struct cli_state
*cli
,
904 const struct smb2_create_blobs
*in_cblobs
)
906 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
907 struct cli_smb2_rmdir_state
*state
= NULL
;
909 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_rmdir_state
);
915 state
->dname
= dname
;
916 state
->in_cblobs
= in_cblobs
;
918 subreq
= cli_smb2_create_fnum_send(
923 (struct cli_smb2_create_flags
){0},
924 SMB2_IMPERSONATION_IMPERSONATION
,
925 DELETE_ACCESS
, /* desired_access */
926 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
927 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
928 FILE_OPEN
, /* create_disposition */
929 FILE_DIRECTORY_FILE
, /* create_options */
930 state
->in_cblobs
); /* in_cblobs */
931 if (tevent_req_nomem(subreq
, req
)) {
932 return tevent_req_post(req
, ev
);
934 tevent_req_set_callback(subreq
, cli_smb2_rmdir_opened1
, req
);
938 static void cli_smb2_rmdir_opened1(struct tevent_req
*subreq
)
940 struct tevent_req
*req
= tevent_req_callback_data(
941 subreq
, struct tevent_req
);
942 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
943 req
, struct cli_smb2_rmdir_state
);
946 status
= cli_smb2_create_fnum_recv(
947 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
950 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
952 * Naive option to match our SMB1 code. Assume the
953 * symlink path that tripped us up was the last
954 * component and try again. Eventually we will have to
955 * deal with the returned path unprocessed component. JRA.
957 subreq
= cli_smb2_create_fnum_send(
962 (struct cli_smb2_create_flags
){0},
963 SMB2_IMPERSONATION_IMPERSONATION
,
964 DELETE_ACCESS
, /* desired_access */
965 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
966 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
967 FILE_OPEN
, /* create_disposition */
969 FILE_DELETE_ON_CLOSE
|
970 FILE_OPEN_REPARSE_POINT
, /* create_options */
971 state
->in_cblobs
); /* in_cblobs */
972 if (tevent_req_nomem(subreq
, req
)) {
975 tevent_req_set_callback(subreq
, cli_smb2_rmdir_opened2
, req
);
979 if (tevent_req_nterror(req
, status
)) {
983 subreq
= cli_smb2_delete_on_close_send(
984 state
, state
->ev
, state
->cli
, state
->fnum
, true);
985 if (tevent_req_nomem(subreq
, req
)) {
988 tevent_req_set_callback(subreq
, cli_smb2_rmdir_disp_set
, req
);
991 static void cli_smb2_rmdir_opened2(struct tevent_req
*subreq
)
993 struct tevent_req
*req
= tevent_req_callback_data(
994 subreq
, struct tevent_req
);
995 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
996 req
, struct cli_smb2_rmdir_state
);
999 status
= cli_smb2_create_fnum_recv(
1000 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
1001 TALLOC_FREE(subreq
);
1002 if (tevent_req_nterror(req
, status
)) {
1006 subreq
= cli_smb2_delete_on_close_send(
1007 state
, state
->ev
, state
->cli
, state
->fnum
, true);
1008 if (tevent_req_nomem(subreq
, req
)) {
1011 tevent_req_set_callback(subreq
, cli_smb2_rmdir_disp_set
, req
);
1014 static void cli_smb2_rmdir_disp_set(struct tevent_req
*subreq
)
1016 struct tevent_req
*req
= tevent_req_callback_data(
1017 subreq
, struct tevent_req
);
1018 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
1019 req
, struct cli_smb2_rmdir_state
);
1021 state
->status
= cli_smb2_delete_on_close_recv(subreq
);
1022 TALLOC_FREE(subreq
);
1025 * Close the fd even if the set_disp failed
1028 subreq
= cli_smb2_close_fnum_send(state
,
1033 if (tevent_req_nomem(subreq
, req
)) {
1036 tevent_req_set_callback(subreq
, cli_smb2_rmdir_closed
, req
);
1039 static void cli_smb2_rmdir_closed(struct tevent_req
*subreq
)
1041 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
1042 tevent_req_simple_finish_ntstatus(subreq
, status
);
1045 NTSTATUS
cli_smb2_rmdir_recv(struct tevent_req
*req
)
1047 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
1048 req
, struct cli_smb2_rmdir_state
);
1051 if (tevent_req_is_nterror(req
, &status
)) {
1054 return state
->status
;
1057 /***************************************************************
1058 Small wrapper that allows SMB2 to unlink a pathname.
1059 ***************************************************************/
1061 struct cli_smb2_unlink_state
{
1062 struct tevent_context
*ev
;
1063 struct cli_state
*cli
;
1065 const struct smb2_create_blobs
*in_cblobs
;
1068 static void cli_smb2_unlink_opened1(struct tevent_req
*subreq
);
1069 static void cli_smb2_unlink_opened2(struct tevent_req
*subreq
);
1070 static void cli_smb2_unlink_closed(struct tevent_req
*subreq
);
1072 struct tevent_req
*cli_smb2_unlink_send(
1073 TALLOC_CTX
*mem_ctx
,
1074 struct tevent_context
*ev
,
1075 struct cli_state
*cli
,
1077 const struct smb2_create_blobs
*in_cblobs
)
1079 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1080 struct cli_smb2_unlink_state
*state
= NULL
;
1082 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_unlink_state
);
1088 state
->fname
= fname
;
1089 state
->in_cblobs
= in_cblobs
;
1091 subreq
= cli_smb2_create_fnum_send(
1092 state
, /* mem_ctx */
1093 state
->ev
, /* tevent_context */
1094 state
->cli
, /* cli_struct */
1095 state
->fname
, /* filename */
1096 (struct cli_smb2_create_flags
){0},
1097 SMB2_IMPERSONATION_IMPERSONATION
,
1098 DELETE_ACCESS
, /* desired_access */
1099 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
1102 FILE_SHARE_DELETE
, /* share_access */
1103 FILE_OPEN
, /* create_disposition */
1104 FILE_DELETE_ON_CLOSE
, /* create_options */
1105 state
->in_cblobs
); /* in_cblobs */
1106 if (tevent_req_nomem(subreq
, req
)) {
1107 return tevent_req_post(req
, ev
);
1109 tevent_req_set_callback(subreq
, cli_smb2_unlink_opened1
, req
);
1113 static void cli_smb2_unlink_opened1(struct tevent_req
*subreq
)
1115 struct tevent_req
*req
= tevent_req_callback_data(
1116 subreq
, struct tevent_req
);
1117 struct cli_smb2_unlink_state
*state
= tevent_req_data(
1118 req
, struct cli_smb2_unlink_state
);
1119 uint16_t fnum
= 0xffff;
1122 status
= cli_smb2_create_fnum_recv(
1123 subreq
, &fnum
, NULL
, NULL
, NULL
, NULL
);
1124 TALLOC_FREE(subreq
);
1126 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
) ||
1127 NT_STATUS_EQUAL(status
, NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED
)) {
1129 * Naive option to match our SMB1 code. Assume the
1130 * symlink path that tripped us up was the last
1131 * component and try again. Eventually we will have to
1132 * deal with the returned path unprocessed component. JRA.
1134 subreq
= cli_smb2_create_fnum_send(
1135 state
, /* mem_ctx */
1136 state
->ev
, /* tevent_context */
1137 state
->cli
, /* cli_struct */
1138 state
->fname
, /* filename */
1139 (struct cli_smb2_create_flags
){0},
1140 SMB2_IMPERSONATION_IMPERSONATION
,
1141 DELETE_ACCESS
, /* desired_access */
1142 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
1145 FILE_SHARE_DELETE
, /* share_access */
1146 FILE_OPEN
, /* create_disposition */
1147 FILE_DELETE_ON_CLOSE
|
1148 FILE_OPEN_REPARSE_POINT
, /* create_options */
1149 state
->in_cblobs
); /* in_cblobs */
1150 if (tevent_req_nomem(subreq
, req
)) {
1153 tevent_req_set_callback(subreq
, cli_smb2_unlink_opened2
, req
);
1157 if (tevent_req_nterror(req
, status
)) {
1162 cli_smb2_close_fnum_send(state
, state
->ev
, state
->cli
, fnum
, 0);
1163 if (tevent_req_nomem(subreq
, req
)) {
1166 tevent_req_set_callback(subreq
, cli_smb2_unlink_closed
, req
);
1169 static void cli_smb2_unlink_opened2(struct tevent_req
*subreq
)
1171 struct tevent_req
*req
= tevent_req_callback_data(
1172 subreq
, struct tevent_req
);
1173 struct cli_smb2_unlink_state
*state
= tevent_req_data(
1174 req
, struct cli_smb2_unlink_state
);
1175 uint16_t fnum
= 0xffff;
1178 status
= cli_smb2_create_fnum_recv(
1179 subreq
, &fnum
, NULL
, NULL
, NULL
, NULL
);
1180 TALLOC_FREE(subreq
);
1181 if (tevent_req_nterror(req
, status
)) {
1186 cli_smb2_close_fnum_send(state
, state
->ev
, state
->cli
, fnum
, 0);
1187 if (tevent_req_nomem(subreq
, req
)) {
1190 tevent_req_set_callback(subreq
, cli_smb2_unlink_closed
, req
);
1193 static void cli_smb2_unlink_closed(struct tevent_req
*subreq
)
1195 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
1196 tevent_req_simple_finish_ntstatus(subreq
, status
);
1199 NTSTATUS
cli_smb2_unlink_recv(struct tevent_req
*req
)
1201 return tevent_req_simple_recv_ntstatus(req
);
1204 /***************************************************************
1205 Utility function to parse a SMB2_FIND_POSIX_INFORMATION reply.
1206 ***************************************************************/
1208 static NTSTATUS
parse_finfo_posix_info(const uint8_t *dir_data
,
1209 uint32_t dir_data_length
,
1210 struct file_info
*finfo
,
1211 uint32_t *next_offset
)
1213 struct smb3_file_posix_information info
= {};
1215 enum ndr_err_code ndr_err
;
1218 uint32_t _next_offset
= 0;
1220 if (dir_data_length
< 4) {
1221 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1224 _next_offset
= IVAL(dir_data
, 0);
1226 if (_next_offset
> dir_data_length
) {
1227 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1230 if (_next_offset
!= 0) {
1231 /* Ensure we only read what in this record. */
1232 dir_data_length
= _next_offset
;
1236 * Skip NextEntryOffset and FileIndex
1238 if (dir_data_length
< 8) {
1239 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1242 dir_data_length
-= 8;
1244 ndr_err
= ndr_pull_struct_blob_noalloc(
1248 (ndr_pull_flags_fn_t
)ndr_pull_smb3_file_posix_information
,
1250 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1251 return ndr_map_error2ntstatus(ndr_err
);
1253 if (consumed
> dir_data_length
) {
1254 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1256 dir_data
+= consumed
;
1257 dir_data_length
-= consumed
;
1259 finfo
->btime_ts
= interpret_long_date(info
.creation_time
);
1260 finfo
->atime_ts
= interpret_long_date(info
.last_access_time
);
1261 finfo
->mtime_ts
= interpret_long_date(info
.last_write_time
);
1262 finfo
->ctime_ts
= interpret_long_date(info
.change_time
);
1263 finfo
->allocated_size
= info
.allocation_size
;
1264 finfo
->size
= info
.end_of_file
;
1265 finfo
->attr
= info
.file_attributes
;
1266 finfo
->ino
= info
.inode
;
1267 finfo
->st_ex_dev
= info
.device
;
1268 finfo
->st_ex_nlink
= info
.cc
.nlinks
;
1269 finfo
->reparse_tag
= info
.cc
.reparse_tag
;
1270 finfo
->st_ex_mode
= wire_mode_to_unix(info
.cc
.posix_mode
);
1271 sid_copy(&finfo
->owner_sid
, &info
.cc
.owner
);
1272 sid_copy(&finfo
->group_sid
, &info
.cc
.group
);
1274 if (dir_data_length
< 4) {
1275 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1277 namelen
= PULL_LE_U32(dir_data
, 0);
1280 dir_data_length
-= 4;
1282 if (namelen
> dir_data_length
) {
1283 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1286 ret
= pull_string_talloc(finfo
,
1288 FLAGS2_UNICODE_STRINGS
,
1293 if (ret
== (size_t)-1) {
1294 /* Bad conversion. */
1295 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1298 if (finfo
->name
== NULL
) {
1299 /* Bad conversion. */
1300 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1303 *next_offset
= _next_offset
;
1304 return NT_STATUS_OK
;
1307 /***************************************************************
1308 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1309 ***************************************************************/
1311 static NTSTATUS
parse_finfo_id_both_directory_info(const uint8_t *dir_data
,
1312 uint32_t dir_data_length
,
1313 struct file_info
*finfo
,
1314 uint32_t *next_offset
)
1320 if (dir_data_length
< 4) {
1321 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1324 *next_offset
= IVAL(dir_data
, 0);
1326 if (*next_offset
> dir_data_length
) {
1327 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1330 if (*next_offset
!= 0) {
1331 /* Ensure we only read what in this record. */
1332 dir_data_length
= *next_offset
;
1335 if (dir_data_length
< 105) {
1336 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1339 finfo
->btime_ts
= interpret_long_date(BVAL(dir_data
, 8));
1340 finfo
->atime_ts
= interpret_long_date(BVAL(dir_data
, 16));
1341 finfo
->mtime_ts
= interpret_long_date(BVAL(dir_data
, 24));
1342 finfo
->ctime_ts
= interpret_long_date(BVAL(dir_data
, 32));
1343 finfo
->size
= BVAL(dir_data
+ 40, 0);
1344 finfo
->allocated_size
= BVAL(dir_data
+ 48, 0);
1345 finfo
->attr
= IVAL(dir_data
+ 56, 0);
1346 finfo
->ino
= BVAL(dir_data
+ 96, 0);
1347 namelen
= IVAL(dir_data
+ 60,0);
1348 if (namelen
> (dir_data_length
- 104)) {
1349 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1351 finfo
->reparse_tag
= IVAL(dir_data
+ 64, 0);
1352 slen
= CVAL(dir_data
+ 68, 0);
1354 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1356 ret
= pull_string_talloc(finfo
,
1358 FLAGS2_UNICODE_STRINGS
,
1363 if (ret
== (size_t)-1) {
1364 /* Bad conversion. */
1365 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1368 ret
= pull_string_talloc(finfo
,
1370 FLAGS2_UNICODE_STRINGS
,
1375 if (ret
== (size_t)-1) {
1376 /* Bad conversion. */
1377 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1380 if (finfo
->name
== NULL
) {
1381 /* Bad conversion. */
1382 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1385 return NT_STATUS_OK
;
1388 /*******************************************************************
1389 Given a filename - get its directory name
1390 ********************************************************************/
1392 static bool windows_parent_dirname(TALLOC_CTX
*mem_ctx
,
1400 p
= strrchr_m(dir
, '\\'); /* Find final '\\', if any */
1403 if (!(*parent
= talloc_strdup(mem_ctx
, "\\"))) {
1414 if (!(*parent
= (char *)talloc_memdup(mem_ctx
, dir
, len
+1))) {
1417 (*parent
)[len
] = '\0';
1425 struct cli_smb2_list_dir_data
{
1430 struct cli_smb2_list_state
{
1431 struct tevent_context
*ev
;
1432 struct cli_state
*cli
;
1438 struct cli_smb2_list_dir_data
*response
;
1440 unsigned int info_level
;
1443 static void cli_smb2_list_opened(struct tevent_req
*subreq
);
1444 static void cli_smb2_list_done(struct tevent_req
*subreq
);
1445 static void cli_smb2_list_closed(struct tevent_req
*subreq
);
1447 struct tevent_req
*cli_smb2_list_send(
1448 TALLOC_CTX
*mem_ctx
,
1449 struct tevent_context
*ev
,
1450 struct cli_state
*cli
,
1451 const char *pathname
,
1452 unsigned int info_level
)
1454 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1455 struct cli_smb2_list_state
*state
= NULL
;
1456 char *parent
= NULL
;
1458 struct smb2_create_blobs
*in_cblobs
= NULL
;
1460 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_list_state
);
1466 state
->status
= NT_STATUS_OK
;
1467 state
->info_level
= info_level
;
1469 ok
= windows_parent_dirname(state
, pathname
, &parent
, &state
->mask
);
1471 tevent_req_oom(req
);
1472 return tevent_req_post(req
, ev
);
1475 if (smbXcli_conn_have_posix(cli
->conn
) &&
1476 info_level
== SMB2_FIND_POSIX_INFORMATION
)
1480 /* The mode MUST be 0 when opening an existing file/dir, and
1481 * will be ignored by the server.
1483 uint8_t linear_mode
[4] = { 0 };
1484 DATA_BLOB blob
= { .data
=linear_mode
,
1485 .length
=sizeof(linear_mode
) };
1487 in_cblobs
= talloc_zero(mem_ctx
, struct smb2_create_blobs
);
1488 if (in_cblobs
== NULL
) {
1492 status
= smb2_create_blob_add(in_cblobs
, in_cblobs
,
1493 SMB2_CREATE_TAG_POSIX
, blob
);
1494 if (tevent_req_nterror(req
, status
)) {
1495 tevent_req_nterror(req
, status
);
1496 return tevent_req_post(req
, ev
);
1500 subreq
= cli_smb2_create_fnum_send(
1501 state
, /* mem_ctx */
1505 (struct cli_smb2_create_flags
){0}, /* create_flags */
1506 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation_level */
1507 SEC_DIR_LIST
|SEC_DIR_READ_ATTRIBUTE
, /* desired_access */
1508 FILE_ATTRIBUTE_DIRECTORY
, /* file_attributes */
1509 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
1510 FILE_OPEN
, /* create_disposition */
1511 FILE_DIRECTORY_FILE
, /* create_options */
1512 in_cblobs
); /* in_cblobs */
1513 TALLOC_FREE(in_cblobs
);
1514 if (tevent_req_nomem(subreq
, req
)) {
1515 return tevent_req_post(req
, ev
);
1517 tevent_req_set_callback(subreq
, cli_smb2_list_opened
, req
);
1521 static void cli_smb2_list_opened(struct tevent_req
*subreq
)
1523 struct tevent_req
*req
= tevent_req_callback_data(
1524 subreq
, struct tevent_req
);
1525 struct cli_smb2_list_state
*state
= tevent_req_data(
1526 req
, struct cli_smb2_list_state
);
1529 status
= cli_smb2_create_fnum_recv(
1530 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
1531 TALLOC_FREE(subreq
);
1532 if (tevent_req_nterror(req
, status
)) {
1537 * Make our caller get back to us via cli_smb2_list_recv(),
1538 * triggering the smb2_query_directory_send()
1540 tevent_req_defer_callback(req
, state
->ev
);
1541 tevent_req_notify_callback(req
);
1544 static void cli_smb2_list_done(struct tevent_req
*subreq
)
1546 struct tevent_req
*req
= tevent_req_callback_data(
1547 subreq
, struct tevent_req
);
1548 struct cli_smb2_list_state
*state
= tevent_req_data(
1549 req
, struct cli_smb2_list_state
);
1550 struct cli_smb2_list_dir_data
*response
= NULL
;
1552 response
= talloc(state
, struct cli_smb2_list_dir_data
);
1553 if (tevent_req_nomem(response
, req
)) {
1557 state
->status
= smb2cli_query_directory_recv(
1558 subreq
, response
, &response
->data
, &response
->length
);
1559 TALLOC_FREE(subreq
);
1561 if (NT_STATUS_IS_OK(state
->status
)) {
1562 state
->response
= response
;
1565 tevent_req_defer_callback(req
, state
->ev
);
1566 tevent_req_notify_callback(req
);
1570 TALLOC_FREE(response
);
1572 subreq
= cli_smb2_close_fnum_send(state
,
1577 if (tevent_req_nomem(subreq
, req
)) {
1580 tevent_req_set_callback(subreq
, cli_smb2_list_closed
, req
);
1583 static void cli_smb2_list_closed(struct tevent_req
*subreq
)
1585 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
1586 tevent_req_simple_finish_ntstatus(subreq
, status
);
1590 * Return the next finfo directory.
1592 * This parses the blob returned from QUERY_DIRECTORY step by step. If
1593 * the blob ends, this triggers a fresh QUERY_DIRECTORY and returns
1594 * NT_STATUS_RETRY, which will then trigger the caller again when the
1595 * QUERY_DIRECTORY has returned with another buffer. This way we
1596 * guarantee that no asynchronous request is open after this call
1597 * returns an entry, so that other synchronous requests can be issued
1598 * on the same connection while the directory listing proceeds.
1600 NTSTATUS
cli_smb2_list_recv(
1601 struct tevent_req
*req
,
1602 TALLOC_CTX
*mem_ctx
,
1603 struct file_info
**pfinfo
)
1605 struct cli_smb2_list_state
*state
= tevent_req_data(
1606 req
, struct cli_smb2_list_state
);
1607 struct cli_smb2_list_dir_data
*response
= NULL
;
1608 struct file_info
*finfo
= NULL
;
1610 uint32_t next_offset
= 0;
1613 in_progress
= tevent_req_is_in_progress(req
);
1616 if (!tevent_req_is_nterror(req
, &status
)) {
1617 status
= NT_STATUS_NO_MORE_FILES
;
1622 response
= state
->response
;
1623 if (response
== NULL
) {
1624 struct tevent_req
*subreq
= NULL
;
1625 struct cli_state
*cli
= state
->cli
;
1626 struct smb2_hnd
*ph
= NULL
;
1627 uint32_t max_trans
, max_avail_len
;
1630 if (!NT_STATUS_IS_OK(state
->status
)) {
1631 status
= state
->status
;
1635 status
= map_fnum_to_smb2_handle(cli
, state
->fnum
, &ph
);
1636 if (!NT_STATUS_IS_OK(status
)) {
1640 max_trans
= smb2cli_conn_max_trans_size(cli
->conn
);
1641 ok
= smb2cli_conn_req_possible(cli
->conn
, &max_avail_len
);
1643 max_trans
= MIN(max_trans
, max_avail_len
);
1646 subreq
= smb2cli_query_directory_send(
1647 state
, /* mem_ctx */
1649 cli
->conn
, /* conn */
1650 cli
->timeout
, /* timeout_msec */
1651 cli
->smb2
.session
, /* session */
1652 cli
->smb2
.tcon
, /* tcon */
1653 state
->info_level
, /* level */
1656 ph
->fid_persistent
, /* fid_persistent */
1657 ph
->fid_volatile
, /* fid_volatile */
1658 state
->mask
, /* mask */
1659 max_trans
); /* outbuf_len */
1660 if (subreq
== NULL
) {
1661 status
= NT_STATUS_NO_MEMORY
;
1664 tevent_req_set_callback(subreq
, cli_smb2_list_done
, req
);
1665 return NT_STATUS_RETRY
;
1668 SMB_ASSERT(response
->length
> state
->offset
);
1670 finfo
= talloc_zero(mem_ctx
, struct file_info
);
1671 if (finfo
== NULL
) {
1672 status
= NT_STATUS_NO_MEMORY
;
1676 if (state
->info_level
== SMB2_FIND_POSIX_INFORMATION
) {
1677 status
= parse_finfo_posix_info(
1678 response
->data
+ state
->offset
,
1679 response
->length
- state
->offset
,
1683 status
= parse_finfo_id_both_directory_info(
1684 response
->data
+ state
->offset
,
1685 response
->length
- state
->offset
,
1689 if (!NT_STATUS_IS_OK(status
)) {
1693 status
= is_bad_finfo_name(state
->cli
, finfo
);
1694 if (!NT_STATUS_IS_OK(status
)) {
1699 * parse_finfo_id_both_directory_info() checks for overflow,
1700 * no need to check again here.
1702 state
->offset
+= next_offset
;
1704 if (next_offset
== 0) {
1705 TALLOC_FREE(state
->response
);
1708 tevent_req_defer_callback(req
, state
->ev
);
1709 tevent_req_notify_callback(req
);
1712 return NT_STATUS_OK
;
1716 tevent_req_received(req
);
1720 /***************************************************************
1721 Wrapper that allows SMB2 to query a path info (basic level).
1723 ***************************************************************/
1725 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
1727 SMB_STRUCT_STAT
*sbuf
,
1728 uint32_t *attributes
)
1731 struct smb_create_returns cr
;
1732 uint16_t fnum
= 0xffff;
1733 size_t namelen
= strlen(name
);
1735 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1737 * Can't use sync call while an async call is in flight
1739 return NT_STATUS_INVALID_PARAMETER
;
1742 /* SMB2 is pickier about pathnames. Ensure it doesn't
1744 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1745 char *modname
= talloc_strndup(talloc_tos(), name
, namelen
-1);
1746 if (modname
== NULL
) {
1747 return NT_STATUS_NO_MEMORY
;
1752 /* This is commonly used as a 'cd'. Try qpathinfo on
1753 a directory handle first. */
1755 status
= cli_smb2_create_fnum(cli
,
1757 (struct cli_smb2_create_flags
){0},
1758 SMB2_IMPERSONATION_IMPERSONATION
,
1759 FILE_READ_ATTRIBUTES
, /* desired_access */
1760 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1761 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1762 FILE_OPEN
, /* create_disposition */
1763 FILE_DIRECTORY_FILE
, /* create_options */
1770 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
1771 /* Maybe a file ? */
1772 status
= cli_smb2_create_fnum(cli
,
1774 (struct cli_smb2_create_flags
){0},
1775 SMB2_IMPERSONATION_IMPERSONATION
,
1776 FILE_READ_ATTRIBUTES
, /* desired_access */
1777 0, /* file attributes */
1778 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1779 FILE_OPEN
, /* create_disposition */
1780 0, /* create_options */
1788 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
1789 /* Maybe a reparse point ? */
1790 status
= cli_smb2_create_fnum(cli
,
1792 (struct cli_smb2_create_flags
){0},
1793 SMB2_IMPERSONATION_IMPERSONATION
,
1794 FILE_READ_ATTRIBUTES
, /* desired_access */
1795 0, /* file attributes */
1796 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1797 FILE_OPEN
, /* create_disposition */
1798 FILE_OPEN_REPARSE_POINT
, /* create_options */
1806 if (!NT_STATUS_IS_OK(status
)) {
1810 status
= cli_smb2_close_fnum(cli
, fnum
);
1814 sbuf
->st_ex_atime
= nt_time_to_unix_timespec(cr
.last_access_time
);
1815 sbuf
->st_ex_mtime
= nt_time_to_unix_timespec(cr
.last_write_time
);
1816 sbuf
->st_ex_ctime
= nt_time_to_unix_timespec(cr
.change_time
);
1817 sbuf
->st_ex_size
= cr
.end_of_file
;
1818 *attributes
= cr
.file_attributes
;
1823 struct cli_smb2_query_info_fnum_state
{
1827 static void cli_smb2_query_info_fnum_done(struct tevent_req
*subreq
);
1829 struct tevent_req
*cli_smb2_query_info_fnum_send(
1830 TALLOC_CTX
*mem_ctx
,
1831 struct tevent_context
*ev
,
1832 struct cli_state
*cli
,
1834 uint8_t in_info_type
,
1835 uint8_t in_info_class
,
1836 uint32_t in_max_output_length
,
1837 const DATA_BLOB
*in_input_buffer
,
1838 uint32_t in_additional_info
,
1841 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1842 struct cli_smb2_query_info_fnum_state
*state
= NULL
;
1843 struct smb2_hnd
*ph
= NULL
;
1846 req
= tevent_req_create(
1847 mem_ctx
, &state
, struct cli_smb2_query_info_fnum_state
);
1852 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
1853 if (tevent_req_nterror(req
, status
)) {
1854 return tevent_req_post(req
, ev
);
1857 subreq
= smb2cli_query_info_send(
1866 in_max_output_length
,
1872 if (tevent_req_nomem(subreq
, req
)) {
1873 return tevent_req_post(req
, ev
);
1875 tevent_req_set_callback(subreq
, cli_smb2_query_info_fnum_done
, req
);
1879 static void cli_smb2_query_info_fnum_done(struct tevent_req
*subreq
)
1881 struct tevent_req
*req
= tevent_req_callback_data(
1882 subreq
, struct tevent_req
);
1883 struct cli_smb2_query_info_fnum_state
*state
= tevent_req_data(
1884 req
, struct cli_smb2_query_info_fnum_state
);
1888 status
= smb2cli_query_info_recv(subreq
, state
, &outbuf
);
1889 TALLOC_FREE(subreq
);
1890 if (tevent_req_nterror(req
, status
)) {
1895 * We have to dup the memory here because outbuf.data is not
1896 * returned as a talloc object by smb2cli_query_info_recv.
1897 * It's a pointer into the received buffer.
1899 state
->outbuf
= data_blob_dup_talloc(state
, outbuf
);
1901 if ((outbuf
.length
!= 0) &&
1902 tevent_req_nomem(state
->outbuf
.data
, req
)) {
1905 tevent_req_done(req
);
1908 NTSTATUS
cli_smb2_query_info_fnum_recv(
1909 struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
, DATA_BLOB
*outbuf
)
1911 struct cli_smb2_query_info_fnum_state
*state
= tevent_req_data(
1912 req
, struct cli_smb2_query_info_fnum_state
);
1915 if (tevent_req_is_nterror(req
, &status
)) {
1918 *outbuf
= (DATA_BLOB
) {
1919 .data
= talloc_move(mem_ctx
, &state
->outbuf
.data
),
1920 .length
= state
->outbuf
.length
,
1922 tevent_req_received(req
);
1923 return NT_STATUS_OK
;
1926 NTSTATUS
cli_smb2_query_info_fnum(
1927 struct cli_state
*cli
,
1929 uint8_t in_info_type
,
1930 uint8_t in_info_class
,
1931 uint32_t in_max_output_length
,
1932 const DATA_BLOB
*in_input_buffer
,
1933 uint32_t in_additional_info
,
1935 TALLOC_CTX
*mem_ctx
,
1938 TALLOC_CTX
*frame
= talloc_stackframe();
1939 struct tevent_context
*ev
= NULL
;
1940 struct tevent_req
*req
= NULL
;
1941 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
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
;
1951 ev
= samba_tevent_context_init(frame
);
1955 req
= cli_smb2_query_info_fnum_send(
1962 in_max_output_length
,
1969 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
1973 status
= cli_smb2_query_info_fnum_recv(req
, mem_ctx
, outbuf
);
1979 /***************************************************************
1980 Helper function for pathname operations.
1981 ***************************************************************/
1983 struct get_fnum_from_path_state
{
1984 struct tevent_context
*ev
;
1985 struct cli_state
*cli
;
1987 uint32_t desired_access
;
1991 static void get_fnum_from_path_opened_file(struct tevent_req
*subreq
);
1992 static void get_fnum_from_path_opened_reparse(struct tevent_req
*subreq
);
1993 static void get_fnum_from_path_opened_dir(struct tevent_req
*subreq
);
1995 static struct tevent_req
*get_fnum_from_path_send(
1996 TALLOC_CTX
*mem_ctx
,
1997 struct tevent_context
*ev
,
1998 struct cli_state
*cli
,
2000 uint32_t desired_access
)
2002 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
2003 struct get_fnum_from_path_state
*state
= NULL
;
2004 size_t namelen
= strlen(name
);
2006 req
= tevent_req_create(
2007 mem_ctx
, &state
, struct get_fnum_from_path_state
);
2014 state
->desired_access
= desired_access
;
2017 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
2020 if (namelen
> 0 && name
[namelen
-1] == '\\') {
2021 state
->name
= talloc_strndup(state
, name
, namelen
-1);
2022 if (tevent_req_nomem(state
->name
, req
)) {
2023 return tevent_req_post(req
, ev
);
2027 subreq
= cli_smb2_create_fnum_send(
2028 state
, /* mem_ctx, */
2031 state
->name
, /* fname */
2032 (struct cli_smb2_create_flags
){0}, /* create_flags */
2033 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation_level */
2034 desired_access
, /* desired_access */
2035 0, /* file_attributes */
2038 FILE_SHARE_DELETE
, /* share_access */
2039 FILE_OPEN
, /* create_disposition */
2040 0, /* create_options */
2041 NULL
); /* in_cblobs */
2042 if (tevent_req_nomem(subreq
, req
)) {
2043 return tevent_req_post(req
, ev
);
2045 tevent_req_set_callback(subreq
, get_fnum_from_path_opened_file
, req
);
2049 static void get_fnum_from_path_opened_file(struct tevent_req
*subreq
)
2051 struct tevent_req
*req
= tevent_req_callback_data(
2052 subreq
, struct tevent_req
);
2053 struct get_fnum_from_path_state
*state
= tevent_req_data(
2054 req
, struct get_fnum_from_path_state
);
2057 status
= cli_smb2_create_fnum_recv(
2058 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
2059 TALLOC_FREE(subreq
);
2061 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
) ||
2062 NT_STATUS_EQUAL(status
, NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED
)) {
2064 * Naive option to match our SMB1 code. Assume the
2065 * symlink path that tripped us up was the last
2066 * component and try again. Eventually we will have to
2067 * deal with the returned path unprocessed component. JRA.
2069 subreq
= cli_smb2_create_fnum_send(
2070 state
, /* mem_ctx, */
2072 state
->cli
, /* cli */
2073 state
->name
, /* fname */
2074 (struct cli_smb2_create_flags
){0}, /* create_flags */
2075 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation */
2076 state
->desired_access
, /* desired_access */
2077 0, /* file_attributes */
2080 FILE_SHARE_DELETE
, /* share_access */
2081 FILE_OPEN
, /* create_disposition */
2082 FILE_OPEN_REPARSE_POINT
, /* create_options */
2083 NULL
); /* in_cblobs */
2084 if (tevent_req_nomem(subreq
, req
)) {
2087 tevent_req_set_callback(
2088 subreq
, get_fnum_from_path_opened_reparse
, req
);
2092 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
2093 subreq
= cli_smb2_create_fnum_send(
2094 state
, /* mem_ctx, */
2096 state
->cli
, /* cli */
2097 state
->name
, /* fname */
2098 (struct cli_smb2_create_flags
){0}, /* create_flags */
2099 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation */
2100 state
->desired_access
, /* desired_access */
2101 0, /* file_attributes */
2104 FILE_SHARE_DELETE
, /* share_access */
2105 FILE_OPEN
, /* create_disposition */
2106 FILE_DIRECTORY_FILE
, /* create_options */
2107 NULL
); /* in_cblobs */
2108 if (tevent_req_nomem(subreq
, req
)) {
2111 tevent_req_set_callback(
2112 subreq
, get_fnum_from_path_opened_dir
, req
);
2116 if (tevent_req_nterror(req
, status
)) {
2119 tevent_req_done(req
);
2122 static void get_fnum_from_path_opened_reparse(struct tevent_req
*subreq
)
2124 struct tevent_req
*req
= tevent_req_callback_data(
2125 subreq
, struct tevent_req
);
2126 struct get_fnum_from_path_state
*state
= tevent_req_data(
2127 req
, struct get_fnum_from_path_state
);
2128 NTSTATUS status
= cli_smb2_create_fnum_recv(
2129 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
2130 tevent_req_simple_finish_ntstatus(subreq
, status
);
2133 static void get_fnum_from_path_opened_dir(struct tevent_req
*subreq
)
2135 /* Abstraction violation, but these two are just the same... */
2136 get_fnum_from_path_opened_reparse(subreq
);
2139 static NTSTATUS
get_fnum_from_path_recv(
2140 struct tevent_req
*req
, uint16_t *pfnum
)
2142 struct get_fnum_from_path_state
*state
= tevent_req_data(
2143 req
, struct get_fnum_from_path_state
);
2144 NTSTATUS status
= NT_STATUS_OK
;
2146 if (!tevent_req_is_nterror(req
, &status
)) {
2147 *pfnum
= state
->fnum
;
2149 tevent_req_received(req
);
2153 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
2155 uint32_t desired_access
,
2158 TALLOC_CTX
*frame
= talloc_stackframe();
2159 struct tevent_context
*ev
= NULL
;
2160 struct tevent_req
*req
= NULL
;
2161 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
2163 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2164 status
= NT_STATUS_INVALID_PARAMETER
;
2167 ev
= samba_tevent_context_init(frame
);
2171 req
= get_fnum_from_path_send(frame
, ev
, cli
, name
, desired_access
);
2175 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2178 status
= get_fnum_from_path_recv(req
, pfnum
);
2184 struct cli_smb2_qpathinfo_state
{
2185 struct tevent_context
*ev
;
2186 struct cli_state
*cli
;
2197 static void cli_smb2_qpathinfo_opened(struct tevent_req
*subreq
);
2198 static void cli_smb2_qpathinfo_done(struct tevent_req
*subreq
);
2199 static void cli_smb2_qpathinfo_closed(struct tevent_req
*subreq
);
2201 struct tevent_req
*cli_smb2_qpathinfo_send(TALLOC_CTX
*mem_ctx
,
2202 struct tevent_context
*ev
,
2203 struct cli_state
*cli
,
2209 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
2210 struct cli_smb2_qpathinfo_state
*state
= NULL
;
2212 req
= tevent_req_create(mem_ctx
,
2214 struct cli_smb2_qpathinfo_state
);
2220 state
->level
= level
;
2221 state
->min_rdata
= min_rdata
;
2222 state
->max_rdata
= max_rdata
;
2224 subreq
= get_fnum_from_path_send(state
,
2228 FILE_READ_ATTRIBUTES
);
2229 if (tevent_req_nomem(subreq
, req
)) {
2230 return tevent_req_post(req
, ev
);
2232 tevent_req_set_callback(subreq
, cli_smb2_qpathinfo_opened
, req
);
2236 static void cli_smb2_qpathinfo_opened(struct tevent_req
*subreq
)
2238 struct tevent_req
*req
=
2239 tevent_req_callback_data(subreq
, struct tevent_req
);
2240 struct cli_smb2_qpathinfo_state
*state
=
2241 tevent_req_data(req
, struct cli_smb2_qpathinfo_state
);
2244 status
= get_fnum_from_path_recv(subreq
, &state
->fnum
);
2245 TALLOC_FREE(subreq
);
2246 if (tevent_req_nterror(req
, status
)) {
2250 subreq
= cli_smb2_query_info_fnum_send(state
,
2254 1, /* in_info_type */
2257 NULL
, /* in_input_buffer */
2258 0, /* in_additional_info */
2260 if (tevent_req_nomem(subreq
, req
)) {
2263 tevent_req_set_callback(subreq
, cli_smb2_qpathinfo_done
, req
);
2266 static void cli_smb2_qpathinfo_done(struct tevent_req
*subreq
)
2268 struct tevent_req
*req
=
2269 tevent_req_callback_data(subreq
, struct tevent_req
);
2270 struct cli_smb2_qpathinfo_state
*state
=
2271 tevent_req_data(req
, struct cli_smb2_qpathinfo_state
);
2274 cli_smb2_query_info_fnum_recv(subreq
, state
, &state
->out
);
2275 TALLOC_FREE(subreq
);
2277 if (NT_STATUS_IS_OK(state
->status
) &&
2278 (state
->out
.length
< state
->min_rdata
)) {
2279 state
->status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2282 subreq
= cli_smb2_close_fnum_send(state
,
2287 if (tevent_req_nomem(subreq
, req
)) {
2290 tevent_req_set_callback(subreq
, cli_smb2_qpathinfo_closed
, req
);
2293 static void cli_smb2_qpathinfo_closed(struct tevent_req
*subreq
)
2295 struct tevent_req
*req
=
2296 tevent_req_callback_data(subreq
, struct tevent_req
);
2297 struct cli_smb2_qpathinfo_state
*state
=
2298 tevent_req_data(req
, struct cli_smb2_qpathinfo_state
);
2301 status
= cli_smb2_close_fnum_recv(subreq
);
2302 TALLOC_FREE(subreq
);
2303 if (tevent_req_nterror(req
, status
)) {
2306 if (tevent_req_nterror(req
, state
->status
)) {
2309 tevent_req_done(req
);
2312 NTSTATUS
cli_smb2_qpathinfo_recv(struct tevent_req
*req
,
2313 TALLOC_CTX
*mem_ctx
,
2315 uint32_t *num_rdata
)
2317 struct cli_smb2_qpathinfo_state
*state
=
2318 tevent_req_data(req
, struct cli_smb2_qpathinfo_state
);
2321 if (tevent_req_is_nterror(req
, &status
)) {
2325 *rdata
= talloc_move(mem_ctx
, &state
->out
.data
);
2326 *num_rdata
= state
->out
.length
;
2327 tevent_req_received(req
);
2328 return NT_STATUS_OK
;
2331 /***************************************************************
2332 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2335 ***************************************************************/
2337 NTSTATUS
cli_smb2_setpathinfo(struct cli_state
*cli
,
2339 uint8_t in_info_type
,
2340 uint8_t in_file_info_class
,
2341 const DATA_BLOB
*p_in_data
)
2344 uint16_t fnum
= 0xffff;
2345 TALLOC_CTX
*frame
= talloc_stackframe();
2347 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2349 * Can't use sync call while an async call is in flight
2351 status
= NT_STATUS_INVALID_PARAMETER
;
2355 status
= get_fnum_from_path(cli
,
2357 FILE_WRITE_ATTRIBUTES
,
2360 if (!NT_STATUS_IS_OK(status
)) {
2364 status
= cli_smb2_set_info_fnum(
2369 p_in_data
, /* in_input_buffer */
2370 0); /* in_additional_info */
2373 if (fnum
!= 0xffff) {
2374 cli_smb2_close_fnum(cli
, fnum
);
2382 /***************************************************************
2383 Wrapper that allows SMB2 to set pathname attributes.
2385 ***************************************************************/
2387 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
2392 uint8_t inbuf_store
[40];
2393 DATA_BLOB inbuf
= data_blob_null
;
2395 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2396 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2398 inbuf
.data
= inbuf_store
;
2399 inbuf
.length
= sizeof(inbuf_store
);
2400 data_blob_clear(&inbuf
);
2403 * SMB1 uses attr == 0 to clear all attributes
2404 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2405 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2406 * request attribute change.
2408 * SMB2 uses exactly the reverse. Unfortunately as the
2409 * cli_setatr() ABI is exposed inside libsmbclient,
2410 * we must make the SMB2 cli_smb2_setatr() call
2411 * export the same ABI as the SMB1 cli_setatr()
2412 * which calls it. This means reversing the sense
2413 * of the requested attr argument if it's zero
2414 * or FILE_ATTRIBUTE_NORMAL.
2416 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2420 attr
= FILE_ATTRIBUTE_NORMAL
;
2421 } else if (attr
== FILE_ATTRIBUTE_NORMAL
) {
2425 SIVAL(inbuf
.data
, 32, attr
);
2427 put_long_date((char *)inbuf
.data
+ 16,mtime
);
2429 /* Set all the other times to -1. */
2430 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
2431 SBVAL(inbuf
.data
, 8, 0xFFFFFFFFFFFFFFFFLL
);
2432 SBVAL(inbuf
.data
, 24, 0xFFFFFFFFFFFFFFFFLL
);
2434 return cli_smb2_setpathinfo(
2437 SMB2_0_INFO_FILE
, /* in_info_type */
2438 FSCC_FILE_BASIC_INFORMATION
, /* in_file_info_class */
2443 /***************************************************************
2444 Wrapper that allows SMB2 to set file handle times.
2446 ***************************************************************/
2448 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
2454 uint8_t inbuf_store
[40];
2455 DATA_BLOB inbuf
= data_blob_null
;
2458 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2460 * Can't use sync call while an async call is in flight
2462 return NT_STATUS_INVALID_PARAMETER
;
2465 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2466 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2468 inbuf
.data
= inbuf_store
;
2469 inbuf
.length
= sizeof(inbuf_store
);
2470 data_blob_clear(&inbuf
);
2472 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
2473 if (change_time
!= 0) {
2474 put_long_date((char *)inbuf
.data
+ 24, change_time
);
2476 if (access_time
!= 0) {
2477 put_long_date((char *)inbuf
.data
+ 8, access_time
);
2479 if (write_time
!= 0) {
2480 put_long_date((char *)inbuf
.data
+ 16, write_time
);
2483 status
= cli_smb2_set_info_fnum(
2486 SMB2_0_INFO_FILE
, /* in_info_type */
2487 FSCC_FILE_BASIC_INFORMATION
, /* in_file_info_class */
2488 &inbuf
, /* in_input_buffer */
2489 0); /* in_additional_info */
2493 /***************************************************************
2494 Wrapper that allows SMB2 to query disk attributes (size).
2496 ***************************************************************/
2498 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, const char *path
,
2499 uint64_t *bsize
, uint64_t *total
, uint64_t *avail
)
2502 uint16_t fnum
= 0xffff;
2503 DATA_BLOB outbuf
= data_blob_null
;
2504 uint32_t sectors_per_unit
= 0;
2505 uint32_t bytes_per_sector
= 0;
2506 uint64_t total_size
= 0;
2507 uint64_t size_free
= 0;
2508 TALLOC_CTX
*frame
= talloc_stackframe();
2510 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2512 * Can't use sync call while an async call is in flight
2514 status
= NT_STATUS_INVALID_PARAMETER
;
2518 /* First open the top level directory. */
2519 status
= cli_smb2_create_fnum(cli
,
2521 (struct cli_smb2_create_flags
){0},
2522 SMB2_IMPERSONATION_IMPERSONATION
,
2523 FILE_READ_ATTRIBUTES
, /* desired_access */
2524 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2525 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
2526 FILE_OPEN
, /* create_disposition */
2527 FILE_DIRECTORY_FILE
, /* create_options */
2534 if (!NT_STATUS_IS_OK(status
)) {
2538 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2539 level 3 (SMB_FS_SIZE_INFORMATION). */
2541 status
= cli_smb2_query_info_fnum(
2544 2, /* in_info_type */
2545 3, /* in_file_info_class */
2546 0xFFFF, /* in_max_output_length */
2547 NULL
, /* in_input_buffer */
2548 0, /* in_additional_info */
2552 if (!NT_STATUS_IS_OK(status
)) {
2556 /* Parse the reply. */
2557 if (outbuf
.length
!= 24) {
2558 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2562 total_size
= BVAL(outbuf
.data
, 0);
2563 size_free
= BVAL(outbuf
.data
, 8);
2564 sectors_per_unit
= IVAL(outbuf
.data
, 16);
2565 bytes_per_sector
= IVAL(outbuf
.data
, 20);
2568 *bsize
= (uint64_t)sectors_per_unit
* (uint64_t)bytes_per_sector
;
2571 *total
= total_size
;
2577 status
= NT_STATUS_OK
;
2581 if (fnum
!= 0xffff) {
2582 cli_smb2_close_fnum(cli
, fnum
);
2589 /***************************************************************
2590 Wrapper that allows SMB2 to query file system sizes.
2592 ***************************************************************/
2594 NTSTATUS
cli_smb2_get_fs_full_size_info(struct cli_state
*cli
,
2595 uint64_t *total_allocation_units
,
2596 uint64_t *caller_allocation_units
,
2597 uint64_t *actual_allocation_units
,
2598 uint64_t *sectors_per_allocation_unit
,
2599 uint64_t *bytes_per_sector
)
2602 uint16_t fnum
= 0xffff;
2603 DATA_BLOB outbuf
= data_blob_null
;
2604 TALLOC_CTX
*frame
= talloc_stackframe();
2606 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2608 * Can't use sync call while an async call is in flight
2610 status
= NT_STATUS_INVALID_PARAMETER
;
2614 /* First open the top level directory. */
2616 cli_smb2_create_fnum(cli
, "",
2617 (struct cli_smb2_create_flags
){0},
2618 SMB2_IMPERSONATION_IMPERSONATION
,
2619 FILE_READ_ATTRIBUTES
, /* desired_access */
2620 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2621 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2622 FILE_SHARE_DELETE
, /* share_access */
2623 FILE_OPEN
, /* create_disposition */
2624 FILE_DIRECTORY_FILE
, /* create_options */
2631 if (!NT_STATUS_IS_OK(status
)) {
2635 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2636 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2638 status
= cli_smb2_query_info_fnum(
2641 SMB2_0_INFO_FILESYSTEM
, /* in_info_type */
2642 FSCC_FS_FULL_SIZE_INFORMATION
, /* in_file_info_class */
2643 0xFFFF, /* in_max_output_length */
2644 NULL
, /* in_input_buffer */
2645 0, /* in_additional_info */
2649 if (!NT_STATUS_IS_OK(status
)) {
2653 if (outbuf
.length
< 32) {
2654 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2658 *total_allocation_units
= BIG_UINT(outbuf
.data
, 0);
2659 *caller_allocation_units
= BIG_UINT(outbuf
.data
, 8);
2660 *actual_allocation_units
= BIG_UINT(outbuf
.data
, 16);
2661 *sectors_per_allocation_unit
= (uint64_t)IVAL(outbuf
.data
, 24);
2662 *bytes_per_sector
= (uint64_t)IVAL(outbuf
.data
, 28);
2666 if (fnum
!= 0xffff) {
2667 cli_smb2_close_fnum(cli
, fnum
);
2674 /***************************************************************
2675 Wrapper that allows SMB2 to query file system attributes.
2677 ***************************************************************/
2679 NTSTATUS
cli_smb2_get_fs_attr_info(struct cli_state
*cli
, uint32_t *fs_attr
)
2682 uint16_t fnum
= 0xffff;
2683 DATA_BLOB outbuf
= data_blob_null
;
2684 TALLOC_CTX
*frame
= talloc_stackframe();
2686 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2688 * Can't use sync call while an async call is in flight
2690 status
= NT_STATUS_INVALID_PARAMETER
;
2694 /* First open the top level directory. */
2696 cli_smb2_create_fnum(cli
, "",
2697 (struct cli_smb2_create_flags
){0},
2698 SMB2_IMPERSONATION_IMPERSONATION
,
2699 FILE_READ_ATTRIBUTES
, /* desired_access */
2700 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2701 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2702 FILE_SHARE_DELETE
, /* share_access */
2703 FILE_OPEN
, /* create_disposition */
2704 FILE_DIRECTORY_FILE
, /* create_options */
2711 if (!NT_STATUS_IS_OK(status
)) {
2715 status
= cli_smb2_query_info_fnum(
2718 2, /* in_info_type */
2719 5, /* in_file_info_class */
2720 0xFFFF, /* in_max_output_length */
2721 NULL
, /* in_input_buffer */
2722 0, /* in_additional_info */
2726 if (!NT_STATUS_IS_OK(status
)) {
2730 if (outbuf
.length
< 12) {
2731 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2735 *fs_attr
= IVAL(outbuf
.data
, 0);
2739 if (fnum
!= 0xffff) {
2740 cli_smb2_close_fnum(cli
, fnum
);
2747 /***************************************************************
2748 Wrapper that allows SMB2 to query file system volume info.
2750 ***************************************************************/
2752 NTSTATUS
cli_smb2_get_fs_volume_info(struct cli_state
*cli
,
2753 TALLOC_CTX
*mem_ctx
,
2754 char **_volume_name
,
2755 uint32_t *pserial_number
,
2759 uint16_t fnum
= 0xffff;
2760 DATA_BLOB outbuf
= data_blob_null
;
2762 char *volume_name
= NULL
;
2763 TALLOC_CTX
*frame
= talloc_stackframe();
2765 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2767 * Can't use sync call while an async call is in flight
2769 status
= NT_STATUS_INVALID_PARAMETER
;
2773 /* First open the top level directory. */
2775 cli_smb2_create_fnum(cli
, "",
2776 (struct cli_smb2_create_flags
){0},
2777 SMB2_IMPERSONATION_IMPERSONATION
,
2778 FILE_READ_ATTRIBUTES
, /* desired_access */
2779 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2780 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2781 FILE_SHARE_DELETE
, /* share_access */
2782 FILE_OPEN
, /* create_disposition */
2783 FILE_DIRECTORY_FILE
, /* create_options */
2790 if (!NT_STATUS_IS_OK(status
)) {
2794 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2795 level 1 (SMB_FS_VOLUME_INFORMATION). */
2797 status
= cli_smb2_query_info_fnum(
2800 SMB2_0_INFO_FILESYSTEM
, /* in_info_type */
2801 /* in_file_info_class */
2802 FSCC_FS_VOLUME_INFORMATION
,
2803 0xFFFF, /* in_max_output_length */
2804 NULL
, /* in_input_buffer */
2805 0, /* in_additional_info */
2809 if (!NT_STATUS_IS_OK(status
)) {
2813 if (outbuf
.length
< 24) {
2814 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2820 ts
= interpret_long_date(BVAL(outbuf
.data
, 0));
2823 if (pserial_number
) {
2824 *pserial_number
= IVAL(outbuf
.data
,8);
2826 nlen
= IVAL(outbuf
.data
,12);
2827 if (nlen
+ 18 < 18) {
2829 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2833 * The next check is safe as we know outbuf.length >= 24
2836 if (nlen
> (outbuf
.length
- 18)) {
2837 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2841 pull_string_talloc(mem_ctx
,
2842 (const char *)outbuf
.data
,
2848 if (volume_name
== NULL
) {
2849 status
= map_nt_error_from_unix(errno
);
2853 *_volume_name
= volume_name
;
2857 if (fnum
!= 0xffff) {
2858 cli_smb2_close_fnum(cli
, fnum
);
2865 struct cli_smb2_mxac_state
{
2866 struct tevent_context
*ev
;
2867 struct cli_state
*cli
;
2869 struct smb2_create_blobs in_cblobs
;
2875 static void cli_smb2_mxac_opened(struct tevent_req
*subreq
);
2876 static void cli_smb2_mxac_closed(struct tevent_req
*subreq
);
2878 struct tevent_req
*cli_smb2_query_mxac_send(TALLOC_CTX
*mem_ctx
,
2879 struct tevent_context
*ev
,
2880 struct cli_state
*cli
,
2883 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
2884 struct cli_smb2_mxac_state
*state
= NULL
;
2887 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_mxac_state
);
2891 *state
= (struct cli_smb2_mxac_state
) {
2897 status
= smb2_create_blob_add(state
,
2899 SMB2_CREATE_TAG_MXAC
,
2900 data_blob(NULL
, 0));
2901 if (tevent_req_nterror(req
, status
)) {
2902 return tevent_req_post(req
, ev
);
2905 subreq
= cli_smb2_create_fnum_send(
2910 (struct cli_smb2_create_flags
){0},
2911 SMB2_IMPERSONATION_IMPERSONATION
,
2912 FILE_READ_ATTRIBUTES
,
2913 0, /* file attributes */
2914 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
2916 0, /* create_options */
2918 if (tevent_req_nomem(subreq
, req
)) {
2919 return tevent_req_post(req
, ev
);
2921 tevent_req_set_callback(subreq
, cli_smb2_mxac_opened
, req
);
2925 static void cli_smb2_mxac_opened(struct tevent_req
*subreq
)
2927 struct tevent_req
*req
= tevent_req_callback_data(
2928 subreq
, struct tevent_req
);
2929 struct cli_smb2_mxac_state
*state
= tevent_req_data(
2930 req
, struct cli_smb2_mxac_state
);
2931 struct smb2_create_blobs out_cblobs
= {0};
2932 struct smb2_create_blob
*mxac_blob
= NULL
;
2935 status
= cli_smb2_create_fnum_recv(
2936 subreq
, &state
->fnum
, NULL
, state
, &out_cblobs
, NULL
);
2937 TALLOC_FREE(subreq
);
2939 if (tevent_req_nterror(req
, status
)) {
2943 mxac_blob
= smb2_create_blob_find(&out_cblobs
, SMB2_CREATE_TAG_MXAC
);
2944 if (mxac_blob
== NULL
) {
2945 state
->status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2948 if (mxac_blob
->data
.length
!= 8) {
2949 state
->status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2953 state
->status
= NT_STATUS(IVAL(mxac_blob
->data
.data
, 0));
2954 state
->mxac
= IVAL(mxac_blob
->data
.data
, 4);
2957 subreq
= cli_smb2_close_fnum_send(state
,
2962 if (tevent_req_nomem(subreq
, req
)) {
2965 tevent_req_set_callback(subreq
, cli_smb2_mxac_closed
, req
);
2970 static void cli_smb2_mxac_closed(struct tevent_req
*subreq
)
2972 struct tevent_req
*req
= tevent_req_callback_data(
2973 subreq
, struct tevent_req
);
2976 status
= cli_smb2_close_fnum_recv(subreq
);
2977 if (tevent_req_nterror(req
, status
)) {
2981 tevent_req_done(req
);
2984 NTSTATUS
cli_smb2_query_mxac_recv(struct tevent_req
*req
, uint32_t *mxac
)
2986 struct cli_smb2_mxac_state
*state
= tevent_req_data(
2987 req
, struct cli_smb2_mxac_state
);
2990 if (tevent_req_is_nterror(req
, &status
)) {
2994 if (!NT_STATUS_IS_OK(state
->status
)) {
2995 return state
->status
;
2998 *mxac
= state
->mxac
;
2999 return NT_STATUS_OK
;
3002 NTSTATUS
cli_smb2_query_mxac(struct cli_state
*cli
,
3006 TALLOC_CTX
*frame
= talloc_stackframe();
3007 struct tevent_context
*ev
= NULL
;
3008 struct tevent_req
*req
= NULL
;
3009 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3012 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3014 * Can't use sync call while an async call is in flight
3016 status
= NT_STATUS_INVALID_PARAMETER
;
3020 ev
= samba_tevent_context_init(frame
);
3024 req
= cli_smb2_query_mxac_send(frame
, ev
, cli
, fname
);
3028 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
3032 status
= cli_smb2_query_mxac_recv(req
, _mxac
);
3039 struct cli_smb2_rename_fnum_state
{
3043 static void cli_smb2_rename_fnum_done(struct tevent_req
*subreq
);
3045 static struct tevent_req
*cli_smb2_rename_fnum_send(
3046 TALLOC_CTX
*mem_ctx
,
3047 struct tevent_context
*ev
,
3048 struct cli_state
*cli
,
3050 const char *fname_dst
,
3053 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
3054 struct cli_smb2_rename_fnum_state
*state
= NULL
;
3055 size_t namelen
= strlen(fname_dst
);
3056 smb_ucs2_t
*converted_str
= NULL
;
3057 size_t converted_size_bytes
= 0;
3061 req
= tevent_req_create(
3062 mem_ctx
, &state
, struct cli_smb2_rename_fnum_state
);
3068 * SMB2 is pickier about pathnames. Ensure it doesn't start in
3071 if (*fname_dst
== '\\') {
3076 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
3079 if (namelen
> 0 && fname_dst
[namelen
-1] == '\\') {
3080 fname_dst
= talloc_strndup(state
, fname_dst
, namelen
-1);
3081 if (tevent_req_nomem(fname_dst
, req
)) {
3082 return tevent_req_post(req
, ev
);
3086 ok
= push_ucs2_talloc(
3087 state
, &converted_str
, fname_dst
, &converted_size_bytes
);
3089 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3090 return tevent_req_post(req
, ev
);
3094 * W2K8 insists the dest name is not null terminated. Remove
3095 * the last 2 zero bytes and reduce the name length.
3097 if (converted_size_bytes
< 2) {
3098 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3099 return tevent_req_post(req
, ev
);
3101 converted_size_bytes
-= 2;
3103 inbuf_size
= 20 + converted_size_bytes
;
3104 if (inbuf_size
< 20) {
3105 /* Integer wrap check. */
3106 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3107 return tevent_req_post(req
, ev
);
3111 * The Windows 10 SMB2 server has a minimum length
3112 * for a SMB2_FILE_RENAME_INFORMATION buffer of
3113 * 24 bytes. It returns NT_STATUS_INFO_LENGTH_MISMATCH
3114 * if the length is less. This isn't an alignment
3115 * issue as Windows client accepts happily 2-byte align
3116 * for larger target name sizes. Also the Windows 10
3117 * SMB1 server doesn't have this restriction.
3119 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14403
3121 inbuf_size
= MAX(inbuf_size
, 24);
3123 state
->inbuf
= data_blob_talloc_zero(state
, inbuf_size
);
3124 if (tevent_req_nomem(state
->inbuf
.data
, req
)) {
3125 return tevent_req_post(req
, ev
);
3129 SCVAL(state
->inbuf
.data
, 0, 1);
3132 SIVAL(state
->inbuf
.data
, 16, converted_size_bytes
);
3133 memcpy(state
->inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
3135 TALLOC_FREE(converted_str
);
3137 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3138 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3140 subreq
= cli_smb2_set_info_fnum_send(
3141 state
, /* mem_ctx */
3145 SMB2_0_INFO_FILE
, /* in_info_type */
3146 FSCC_FILE_RENAME_INFORMATION
, /* in_file_info_class */
3147 &state
->inbuf
, /* in_input_buffer */
3148 0); /* in_additional_info */
3149 if (tevent_req_nomem(subreq
, req
)) {
3150 return tevent_req_post(req
, ev
);
3152 tevent_req_set_callback(subreq
, cli_smb2_rename_fnum_done
, req
);
3156 static void cli_smb2_rename_fnum_done(struct tevent_req
*subreq
)
3158 NTSTATUS status
= cli_smb2_set_info_fnum_recv(subreq
);
3159 tevent_req_simple_finish_ntstatus(subreq
, status
);
3162 static NTSTATUS
cli_smb2_rename_fnum_recv(struct tevent_req
*req
)
3164 return tevent_req_simple_recv_ntstatus(req
);
3167 /***************************************************************
3168 Wrapper that allows SMB2 to rename a file.
3169 ***************************************************************/
3171 struct cli_smb2_rename_state
{
3172 struct tevent_context
*ev
;
3173 struct cli_state
*cli
;
3174 const char *fname_dst
;
3178 NTSTATUS rename_status
;
3181 static void cli_smb2_rename_opened(struct tevent_req
*subreq
);
3182 static void cli_smb2_rename_renamed(struct tevent_req
*subreq
);
3183 static void cli_smb2_rename_closed(struct tevent_req
*subreq
);
3185 struct tevent_req
*cli_smb2_rename_send(
3186 TALLOC_CTX
*mem_ctx
,
3187 struct tevent_context
*ev
,
3188 struct cli_state
*cli
,
3189 const char *fname_src
,
3190 const char *fname_dst
,
3193 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
3194 struct cli_smb2_rename_state
*state
= NULL
;
3197 req
= tevent_req_create(
3198 mem_ctx
, &state
, struct cli_smb2_rename_state
);
3204 * Strip a MSDFS path from fname_dst if we were given one.
3206 status
= cli_dfs_target_check(state
,
3210 if (tevent_req_nterror(req
, status
)) {
3211 return tevent_req_post(req
, ev
);
3216 state
->fname_dst
= fname_dst
;
3217 state
->replace
= replace
;
3219 subreq
= get_fnum_from_path_send(
3220 state
, ev
, cli
, fname_src
, DELETE_ACCESS
);
3221 if (tevent_req_nomem(subreq
, req
)) {
3222 return tevent_req_post(req
, ev
);
3224 tevent_req_set_callback(subreq
, cli_smb2_rename_opened
, req
);
3228 static void cli_smb2_rename_opened(struct tevent_req
*subreq
)
3230 struct tevent_req
*req
= tevent_req_callback_data(
3231 subreq
, struct tevent_req
);
3232 struct cli_smb2_rename_state
*state
= tevent_req_data(
3233 req
, struct cli_smb2_rename_state
);
3236 status
= get_fnum_from_path_recv(subreq
, &state
->fnum
);
3237 TALLOC_FREE(subreq
);
3238 if (tevent_req_nterror(req
, status
)) {
3242 subreq
= cli_smb2_rename_fnum_send(
3249 if (tevent_req_nomem(subreq
, req
)) {
3252 tevent_req_set_callback(subreq
, cli_smb2_rename_renamed
, req
);
3255 static void cli_smb2_rename_renamed(struct tevent_req
*subreq
)
3257 struct tevent_req
*req
= tevent_req_callback_data(
3258 subreq
, struct tevent_req
);
3259 struct cli_smb2_rename_state
*state
= tevent_req_data(
3260 req
, struct cli_smb2_rename_state
);
3262 state
->rename_status
= cli_smb2_rename_fnum_recv(subreq
);
3263 TALLOC_FREE(subreq
);
3265 subreq
= cli_smb2_close_fnum_send(state
,
3270 if (tevent_req_nomem(subreq
, req
)) {
3273 tevent_req_set_callback(subreq
, cli_smb2_rename_closed
, req
);
3276 static void cli_smb2_rename_closed(struct tevent_req
*subreq
)
3278 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
3279 tevent_req_simple_finish_ntstatus(subreq
, status
);
3282 NTSTATUS
cli_smb2_rename_recv(struct tevent_req
*req
)
3284 struct cli_smb2_rename_state
*state
= tevent_req_data(
3285 req
, struct cli_smb2_rename_state
);
3286 NTSTATUS status
= NT_STATUS_OK
;
3288 if (!tevent_req_is_nterror(req
, &status
)) {
3289 status
= state
->rename_status
;
3291 tevent_req_received(req
);
3295 /***************************************************************
3296 Wrapper that allows SMB2 to set an EA on a fnum.
3298 ***************************************************************/
3300 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
3302 const char *ea_name
,
3307 DATA_BLOB inbuf
= data_blob_null
;
3309 char *ea_name_ascii
= NULL
;
3311 TALLOC_CTX
*frame
= talloc_stackframe();
3313 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3315 * Can't use sync call while an async call is in flight
3317 status
= NT_STATUS_INVALID_PARAMETER
;
3321 /* Marshall the SMB2 EA data. */
3322 if (ea_len
> 0xFFFF) {
3323 status
= NT_STATUS_INVALID_PARAMETER
;
3327 if (!push_ascii_talloc(frame
,
3331 status
= NT_STATUS_INVALID_PARAMETER
;
3335 if (namelen
< 2 || namelen
> 0xFF) {
3336 status
= NT_STATUS_INVALID_PARAMETER
;
3340 bloblen
= 8 + ea_len
+ namelen
;
3341 /* Round up to a 4 byte boundary. */
3342 bloblen
= ((bloblen
+ 3)&~3);
3344 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
3345 if (inbuf
.data
== NULL
) {
3346 status
= NT_STATUS_NO_MEMORY
;
3349 /* namelen doesn't include the NULL byte. */
3350 SCVAL(inbuf
.data
, 5, namelen
- 1);
3351 SSVAL(inbuf
.data
, 6, ea_len
);
3352 memcpy(inbuf
.data
+ 8, ea_name_ascii
, namelen
);
3353 memcpy(inbuf
.data
+ 8 + namelen
, ea_val
, ea_len
);
3355 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3356 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3358 status
= cli_smb2_set_info_fnum(
3361 SMB2_0_INFO_FILE
, /* in_info_type */
3362 FSCC_FILE_FULL_EA_INFORMATION
, /* in_file_info_class */
3363 &inbuf
, /* in_input_buffer */
3364 0); /* in_additional_info */
3371 /***************************************************************
3372 Wrapper that allows SMB2 to set an EA on a pathname.
3374 ***************************************************************/
3376 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
3378 const char *ea_name
,
3383 uint16_t fnum
= 0xffff;
3385 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3387 * Can't use sync call while an async call is in flight
3389 status
= NT_STATUS_INVALID_PARAMETER
;
3393 status
= get_fnum_from_path(cli
,
3398 if (!NT_STATUS_IS_OK(status
)) {
3402 status
= cli_set_ea_fnum(cli
,
3407 if (!NT_STATUS_IS_OK(status
)) {
3413 if (fnum
!= 0xffff) {
3414 cli_smb2_close_fnum(cli
, fnum
);
3419 /***************************************************************
3420 Wrapper that allows SMB2 to get an EA list on a pathname.
3422 ***************************************************************/
3424 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
3428 struct ea_struct
**pea_array
)
3431 uint16_t fnum
= 0xffff;
3432 DATA_BLOB outbuf
= data_blob_null
;
3433 struct ea_list
*ea_list
= NULL
;
3434 struct ea_list
*eal
= NULL
;
3435 size_t ea_count
= 0;
3436 TALLOC_CTX
*frame
= talloc_stackframe();
3441 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3443 * Can't use sync call while an async call is in flight
3445 status
= NT_STATUS_INVALID_PARAMETER
;
3449 status
= get_fnum_from_path(cli
,
3454 if (!NT_STATUS_IS_OK(status
)) {
3458 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3459 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3461 status
= cli_smb2_query_info_fnum(
3464 SMB2_0_INFO_FILE
, /* in_info_type */
3465 FSCC_FILE_FULL_EA_INFORMATION
, /* in_file_info_class */
3466 0xFFFF, /* in_max_output_length */
3467 NULL
, /* in_input_buffer */
3468 0, /* in_additional_info */
3473 if (!NT_STATUS_IS_OK(status
)) {
3477 /* Parse the reply. */
3478 ea_list
= read_nttrans_ea_list(ctx
,
3479 (const char *)outbuf
.data
,
3481 if (ea_list
== NULL
) {
3482 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3486 /* Convert to an array. */
3487 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
3492 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
3493 if (*pea_array
== NULL
) {
3494 status
= NT_STATUS_NO_MEMORY
;
3498 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
3499 (*pea_array
)[ea_count
++] = eal
->ea
;
3501 *pnum_eas
= ea_count
;
3506 if (fnum
!= 0xffff) {
3507 cli_smb2_close_fnum(cli
, fnum
);
3514 /***************************************************************
3515 Wrapper that allows SMB2 to get user quota.
3517 ***************************************************************/
3519 NTSTATUS
cli_smb2_get_user_quota(struct cli_state
*cli
,
3521 SMB_NTQUOTA_STRUCT
*pqt
)
3524 DATA_BLOB inbuf
= data_blob_null
;
3525 DATA_BLOB info_blob
= data_blob_null
;
3526 DATA_BLOB outbuf
= data_blob_null
;
3527 TALLOC_CTX
*frame
= talloc_stackframe();
3529 unsigned int offset
;
3530 struct smb2_query_quota_info query
= {0};
3531 struct file_get_quota_info info
= {0};
3532 enum ndr_err_code err
;
3533 struct ndr_push
*ndr_push
= NULL
;
3535 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3537 * Can't use sync call while an async call is in flight
3539 status
= NT_STATUS_INVALID_PARAMETER
;
3543 sid_len
= ndr_size_dom_sid(&pqt
->sid
, 0);
3545 query
.return_single
= 1;
3547 info
.next_entry_offset
= 0;
3548 info
.sid_length
= sid_len
;
3549 info
.sid
= pqt
->sid
;
3551 err
= ndr_push_struct_blob(
3555 (ndr_push_flags_fn_t
)ndr_push_file_get_quota_info
);
3557 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3558 status
= NT_STATUS_INTERNAL_ERROR
;
3562 query
.sid_list_length
= info_blob
.length
;
3563 ndr_push
= ndr_push_init_ctx(frame
);
3565 status
= NT_STATUS_NO_MEMORY
;
3569 err
= ndr_push_smb2_query_quota_info(ndr_push
,
3570 NDR_SCALARS
| NDR_BUFFERS
,
3573 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3574 status
= NT_STATUS_INTERNAL_ERROR
;
3578 err
= ndr_push_array_uint8(ndr_push
, NDR_SCALARS
, info_blob
.data
,
3581 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3582 status
= NT_STATUS_INTERNAL_ERROR
;
3585 inbuf
.data
= ndr_push
->data
;
3586 inbuf
.length
= ndr_push
->offset
;
3588 status
= cli_smb2_query_info_fnum(
3591 4, /* in_info_type */
3592 0, /* in_file_info_class */
3593 0xFFFF, /* in_max_output_length */
3594 &inbuf
, /* in_input_buffer */
3595 0, /* in_additional_info */
3600 if (!NT_STATUS_IS_OK(status
)) {
3604 if (!parse_user_quota_record(outbuf
.data
, outbuf
.length
, &offset
,
3606 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3607 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3615 /***************************************************************
3616 Wrapper that allows SMB2 to list user quota.
3618 ***************************************************************/
3620 NTSTATUS
cli_smb2_list_user_quota_step(struct cli_state
*cli
,
3621 TALLOC_CTX
*mem_ctx
,
3623 SMB_NTQUOTA_LIST
**pqt_list
,
3627 DATA_BLOB inbuf
= data_blob_null
;
3628 DATA_BLOB outbuf
= data_blob_null
;
3629 TALLOC_CTX
*frame
= talloc_stackframe();
3630 struct smb2_query_quota_info info
= {0};
3631 enum ndr_err_code err
;
3633 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3635 * Can't use sync call while an async call is in flight
3637 status
= NT_STATUS_INVALID_PARAMETER
;
3641 info
.restart_scan
= first
? 1 : 0;
3643 err
= ndr_push_struct_blob(
3647 (ndr_push_flags_fn_t
)ndr_push_smb2_query_quota_info
);
3649 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3650 status
= NT_STATUS_INTERNAL_ERROR
;
3654 status
= cli_smb2_query_info_fnum(
3657 4, /* in_info_type */
3658 0, /* in_file_info_class */
3659 0xFFFF, /* in_max_output_length */
3660 &inbuf
, /* in_input_buffer */
3661 0, /* in_additional_info */
3667 * safeguard against panic from calling parse_user_quota_list with
3670 if (NT_STATUS_IS_OK(status
) && outbuf
.length
== 0) {
3671 status
= NT_STATUS_NO_MORE_ENTRIES
;
3674 if (!NT_STATUS_IS_OK(status
)) {
3678 status
= parse_user_quota_list(outbuf
.data
, outbuf
.length
, mem_ctx
,
3686 /***************************************************************
3687 Wrapper that allows SMB2 to get file system quota.
3689 ***************************************************************/
3691 NTSTATUS
cli_smb2_get_fs_quota_info(struct cli_state
*cli
,
3693 SMB_NTQUOTA_STRUCT
*pqt
)
3696 DATA_BLOB outbuf
= data_blob_null
;
3697 TALLOC_CTX
*frame
= talloc_stackframe();
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
;
3707 status
= cli_smb2_query_info_fnum(
3710 SMB2_0_INFO_FILESYSTEM
, /* in_info_type */
3711 FSCC_FS_QUOTA_INFORMATION
, /* in_file_info_class */
3712 0xFFFF, /* in_max_output_length */
3713 NULL
, /* in_input_buffer */
3714 0, /* in_additional_info */
3719 if (!NT_STATUS_IS_OK(status
)) {
3723 status
= parse_fs_quota_buffer(outbuf
.data
, outbuf
.length
, pqt
);
3730 /***************************************************************
3731 Wrapper that allows SMB2 to set user quota.
3733 ***************************************************************/
3735 NTSTATUS
cli_smb2_set_user_quota(struct cli_state
*cli
,
3737 SMB_NTQUOTA_LIST
*qtl
)
3740 DATA_BLOB inbuf
= data_blob_null
;
3741 TALLOC_CTX
*frame
= talloc_stackframe();
3743 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3745 * Can't use sync call while an async call is in flight
3747 status
= NT_STATUS_INVALID_PARAMETER
;
3751 status
= build_user_quota_buffer(qtl
, 0, talloc_tos(), &inbuf
, NULL
);
3752 if (!NT_STATUS_IS_OK(status
)) {
3756 status
= cli_smb2_set_info_fnum(
3759 4, /* in_info_type */
3760 0, /* in_file_info_class */
3761 &inbuf
, /* in_input_buffer */
3762 0); /* in_additional_info */
3769 NTSTATUS
cli_smb2_set_fs_quota_info(struct cli_state
*cli
,
3771 SMB_NTQUOTA_STRUCT
*pqt
)
3774 DATA_BLOB inbuf
= data_blob_null
;
3775 TALLOC_CTX
*frame
= talloc_stackframe();
3777 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3779 * Can't use sync call while an async call is in flight
3781 status
= NT_STATUS_INVALID_PARAMETER
;
3785 status
= build_fs_quota_buffer(talloc_tos(), pqt
, &inbuf
, 0);
3786 if (!NT_STATUS_IS_OK(status
)) {
3790 status
= cli_smb2_set_info_fnum(
3793 SMB2_0_INFO_FILESYSTEM
, /* in_info_type */
3794 FSCC_FS_QUOTA_INFORMATION
, /* in_file_info_class */
3795 &inbuf
, /* in_input_buffer */
3796 0); /* in_additional_info */
3802 struct cli_smb2_read_state
{
3803 struct tevent_context
*ev
;
3804 struct cli_state
*cli
;
3805 struct smb2_hnd
*ph
;
3806 uint64_t start_offset
;
3812 static void cli_smb2_read_done(struct tevent_req
*subreq
);
3814 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
3815 struct tevent_context
*ev
,
3816 struct cli_state
*cli
,
3822 struct tevent_req
*req
, *subreq
;
3823 struct cli_smb2_read_state
*state
;
3825 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
3831 state
->start_offset
= (uint64_t)offset
;
3832 state
->size
= (uint32_t)size
;
3833 state
->received
= 0;
3836 status
= map_fnum_to_smb2_handle(cli
,
3839 if (tevent_req_nterror(req
, status
)) {
3840 return tevent_req_post(req
, ev
);
3843 subreq
= smb2cli_read_send(state
,
3846 state
->cli
->timeout
,
3847 state
->cli
->smb2
.session
,
3848 state
->cli
->smb2
.tcon
,
3850 state
->start_offset
,
3851 state
->ph
->fid_persistent
,
3852 state
->ph
->fid_volatile
,
3853 0, /* minimum_count */
3854 0); /* remaining_bytes */
3856 if (tevent_req_nomem(subreq
, req
)) {
3857 return tevent_req_post(req
, ev
);
3859 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
3863 static void cli_smb2_read_done(struct tevent_req
*subreq
)
3865 struct tevent_req
*req
= tevent_req_callback_data(
3866 subreq
, struct tevent_req
);
3867 struct cli_smb2_read_state
*state
= tevent_req_data(
3868 req
, struct cli_smb2_read_state
);
3871 status
= smb2cli_read_recv(subreq
, state
,
3872 &state
->buf
, &state
->received
);
3873 if (tevent_req_nterror(req
, status
)) {
3877 if (state
->received
> state
->size
) {
3878 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3882 tevent_req_done(req
);
3885 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
3890 struct cli_smb2_read_state
*state
= tevent_req_data(
3891 req
, struct cli_smb2_read_state
);
3893 if (tevent_req_is_nterror(req
, &status
)) {
3897 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3898 * better make sure that you copy it away before you talloc_free(req).
3899 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3901 *received
= (ssize_t
)state
->received
;
3902 *rcvbuf
= state
->buf
;
3903 return NT_STATUS_OK
;
3906 struct cli_smb2_write_state
{
3907 struct tevent_context
*ev
;
3908 struct cli_state
*cli
;
3909 struct smb2_hnd
*ph
;
3917 static void cli_smb2_write_written(struct tevent_req
*req
);
3919 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
3920 struct tevent_context
*ev
,
3921 struct cli_state
*cli
,
3929 struct tevent_req
*req
, *subreq
= NULL
;
3930 struct cli_smb2_write_state
*state
= NULL
;
3932 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
3938 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3939 state
->flags
= (uint32_t)mode
;
3941 state
->offset
= (uint64_t)offset
;
3942 state
->size
= (uint32_t)size
;
3945 status
= map_fnum_to_smb2_handle(cli
,
3948 if (tevent_req_nterror(req
, status
)) {
3949 return tevent_req_post(req
, ev
);
3952 subreq
= smb2cli_write_send(state
,
3955 state
->cli
->timeout
,
3956 state
->cli
->smb2
.session
,
3957 state
->cli
->smb2
.tcon
,
3960 state
->ph
->fid_persistent
,
3961 state
->ph
->fid_volatile
,
3962 0, /* remaining_bytes */
3963 state
->flags
, /* flags */
3966 if (tevent_req_nomem(subreq
, req
)) {
3967 return tevent_req_post(req
, ev
);
3969 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
3973 static void cli_smb2_write_written(struct tevent_req
*subreq
)
3975 struct tevent_req
*req
= tevent_req_callback_data(
3976 subreq
, struct tevent_req
);
3977 struct cli_smb2_write_state
*state
= tevent_req_data(
3978 req
, struct cli_smb2_write_state
);
3982 status
= smb2cli_write_recv(subreq
, &written
);
3983 TALLOC_FREE(subreq
);
3984 if (tevent_req_nterror(req
, status
)) {
3988 state
->written
= written
;
3990 tevent_req_done(req
);
3993 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
3996 struct cli_smb2_write_state
*state
= tevent_req_data(
3997 req
, struct cli_smb2_write_state
);
4000 if (tevent_req_is_nterror(req
, &status
)) {
4001 tevent_req_received(req
);
4005 if (pwritten
!= NULL
) {
4006 *pwritten
= (size_t)state
->written
;
4008 tevent_req_received(req
);
4009 return NT_STATUS_OK
;
4012 /***************************************************************
4013 Wrapper that allows SMB2 async write using an fnum.
4014 This is mostly cut-and-paste from Volker's code inside
4015 source3/libsmb/clireadwrite.c, adapted for SMB2.
4017 Done this way so I can reuse all the logic inside cli_push()
4019 ***************************************************************/
4021 struct cli_smb2_writeall_state
{
4022 struct tevent_context
*ev
;
4023 struct cli_state
*cli
;
4024 struct smb2_hnd
*ph
;
4032 static void cli_smb2_writeall_written(struct tevent_req
*req
);
4034 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
4035 struct tevent_context
*ev
,
4036 struct cli_state
*cli
,
4044 struct tevent_req
*req
, *subreq
= NULL
;
4045 struct cli_smb2_writeall_state
*state
= NULL
;
4050 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
4056 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4057 state
->flags
= (uint32_t)mode
;
4059 state
->offset
= (uint64_t)offset
;
4060 state
->size
= (uint32_t)size
;
4063 status
= map_fnum_to_smb2_handle(cli
,
4066 if (tevent_req_nterror(req
, status
)) {
4067 return tevent_req_post(req
, ev
);
4070 to_write
= state
->size
;
4071 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
4072 to_write
= MIN(max_size
, to_write
);
4073 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
4075 to_write
= MIN(max_size
, to_write
);
4078 subreq
= smb2cli_write_send(state
,
4081 state
->cli
->timeout
,
4082 state
->cli
->smb2
.session
,
4083 state
->cli
->smb2
.tcon
,
4086 state
->ph
->fid_persistent
,
4087 state
->ph
->fid_volatile
,
4088 0, /* remaining_bytes */
4089 state
->flags
, /* flags */
4090 state
->buf
+ state
->written
);
4092 if (tevent_req_nomem(subreq
, req
)) {
4093 return tevent_req_post(req
, ev
);
4095 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
4099 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
4101 struct tevent_req
*req
= tevent_req_callback_data(
4102 subreq
, struct tevent_req
);
4103 struct cli_smb2_writeall_state
*state
= tevent_req_data(
4104 req
, struct cli_smb2_writeall_state
);
4106 uint32_t written
, to_write
;
4110 status
= smb2cli_write_recv(subreq
, &written
);
4111 TALLOC_FREE(subreq
);
4112 if (tevent_req_nterror(req
, status
)) {
4116 state
->written
+= written
;
4118 if (state
->written
> state
->size
) {
4119 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4123 to_write
= state
->size
- state
->written
;
4125 if (to_write
== 0) {
4126 tevent_req_done(req
);
4130 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
4131 to_write
= MIN(max_size
, to_write
);
4132 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
4134 to_write
= MIN(max_size
, to_write
);
4137 subreq
= smb2cli_write_send(state
,
4140 state
->cli
->timeout
,
4141 state
->cli
->smb2
.session
,
4142 state
->cli
->smb2
.tcon
,
4144 state
->offset
+ state
->written
,
4145 state
->ph
->fid_persistent
,
4146 state
->ph
->fid_volatile
,
4147 0, /* remaining_bytes */
4148 state
->flags
, /* flags */
4149 state
->buf
+ state
->written
);
4151 if (tevent_req_nomem(subreq
, req
)) {
4154 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
4157 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
4160 struct cli_smb2_writeall_state
*state
= tevent_req_data(
4161 req
, struct cli_smb2_writeall_state
);
4164 if (tevent_req_is_nterror(req
, &status
)) {
4167 if (pwritten
!= NULL
) {
4168 *pwritten
= (size_t)state
->written
;
4170 return NT_STATUS_OK
;
4173 struct cli_smb2_splice_state
{
4174 struct tevent_context
*ev
;
4175 struct cli_state
*cli
;
4176 struct smb2_hnd
*src_ph
;
4177 struct smb2_hnd
*dst_ph
;
4178 int (*splice_cb
)(off_t n
, void *priv
);
4185 struct req_resume_key_rsp resume_rsp
;
4186 struct srv_copychunk_copy cc_copy
;
4189 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
4190 struct tevent_req
*req
);
4192 static void cli_splice_copychunk_done(struct tevent_req
*subreq
)
4194 struct tevent_req
*req
= tevent_req_callback_data(
4195 subreq
, struct tevent_req
);
4196 struct cli_smb2_splice_state
*state
=
4197 tevent_req_data(req
,
4198 struct cli_smb2_splice_state
);
4199 struct smbXcli_conn
*conn
= state
->cli
->conn
;
4200 DATA_BLOB out_input_buffer
= data_blob_null
;
4201 DATA_BLOB out_output_buffer
= data_blob_null
;
4202 struct srv_copychunk_rsp cc_copy_rsp
;
4203 enum ndr_err_code ndr_ret
;
4206 status
= smb2cli_ioctl_recv(subreq
, state
,
4208 &out_output_buffer
);
4209 TALLOC_FREE(subreq
);
4210 if ((!NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
) ||
4211 state
->resized
) && tevent_req_nterror(req
, status
)) {
4215 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
, state
, &cc_copy_rsp
,
4216 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
4217 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4218 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4219 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4223 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
4224 uint32_t max_chunks
= MIN(cc_copy_rsp
.chunks_written
,
4225 cc_copy_rsp
.total_bytes_written
/ cc_copy_rsp
.chunk_bytes_written
);
4226 if ((cc_copy_rsp
.chunk_bytes_written
> smb2cli_conn_cc_chunk_len(conn
) ||
4227 max_chunks
> smb2cli_conn_cc_max_chunks(conn
)) &&
4228 tevent_req_nterror(req
, status
)) {
4232 state
->resized
= true;
4233 smb2cli_conn_set_cc_chunk_len(conn
, cc_copy_rsp
.chunk_bytes_written
);
4234 smb2cli_conn_set_cc_max_chunks(conn
, max_chunks
);
4236 if ((state
->src_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
4237 (state
->dst_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
4238 (state
->written
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
)) {
4239 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
4242 state
->src_offset
+= cc_copy_rsp
.total_bytes_written
;
4243 state
->dst_offset
+= cc_copy_rsp
.total_bytes_written
;
4244 state
->written
+= cc_copy_rsp
.total_bytes_written
;
4245 if (!state
->splice_cb(state
->written
, state
->priv
)) {
4246 tevent_req_nterror(req
, NT_STATUS_CANCELLED
);
4251 cli_splice_copychunk_send(state
, req
);
4254 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
4255 struct tevent_req
*req
)
4257 struct tevent_req
*subreq
;
4258 enum ndr_err_code ndr_ret
;
4259 struct smbXcli_conn
*conn
= state
->cli
->conn
;
4260 struct srv_copychunk_copy
*cc_copy
= &state
->cc_copy
;
4261 off_t src_offset
= state
->src_offset
;
4262 off_t dst_offset
= state
->dst_offset
;
4263 uint32_t req_len
= MIN(smb2cli_conn_cc_chunk_len(conn
) * smb2cli_conn_cc_max_chunks(conn
),
4264 state
->size
- state
->written
);
4265 DATA_BLOB in_input_buffer
= data_blob_null
;
4266 DATA_BLOB in_output_buffer
= data_blob_null
;
4268 if (state
->size
- state
->written
== 0) {
4269 tevent_req_done(req
);
4273 cc_copy
->chunk_count
= 0;
4275 cc_copy
->chunks
[cc_copy
->chunk_count
].source_off
= src_offset
;
4276 cc_copy
->chunks
[cc_copy
->chunk_count
].target_off
= dst_offset
;
4277 cc_copy
->chunks
[cc_copy
->chunk_count
].length
= MIN(req_len
,
4278 smb2cli_conn_cc_chunk_len(conn
));
4279 if (req_len
< cc_copy
->chunks
[cc_copy
->chunk_count
].length
) {
4280 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
4283 req_len
-= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4284 if ((src_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
) ||
4285 (dst_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
)) {
4286 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
4289 src_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4290 dst_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4291 cc_copy
->chunk_count
++;
4294 ndr_ret
= ndr_push_struct_blob(&in_input_buffer
, state
, cc_copy
,
4295 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
4296 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4297 DEBUG(0, ("failed to marshall copy chunk req\n"));
4298 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
4302 subreq
= smb2cli_ioctl_send(state
, state
->ev
, state
->cli
->conn
,
4303 state
->cli
->timeout
,
4304 state
->cli
->smb2
.session
,
4305 state
->cli
->smb2
.tcon
,
4306 state
->dst_ph
->fid_persistent
, /* in_fid_persistent */
4307 state
->dst_ph
->fid_volatile
, /* in_fid_volatile */
4308 FSCTL_SRV_COPYCHUNK_WRITE
,
4309 0, /* in_max_input_length */
4311 12, /* in_max_output_length */
4313 SMB2_IOCTL_FLAG_IS_FSCTL
);
4314 if (tevent_req_nomem(subreq
, req
)) {
4317 tevent_req_set_callback(subreq
,
4318 cli_splice_copychunk_done
,
4322 static void cli_splice_key_done(struct tevent_req
*subreq
)
4324 struct tevent_req
*req
= tevent_req_callback_data(
4325 subreq
, struct tevent_req
);
4326 struct cli_smb2_splice_state
*state
=
4327 tevent_req_data(req
,
4328 struct cli_smb2_splice_state
);
4329 enum ndr_err_code ndr_ret
;
4332 DATA_BLOB out_input_buffer
= data_blob_null
;
4333 DATA_BLOB out_output_buffer
= data_blob_null
;
4335 status
= smb2cli_ioctl_recv(subreq
, state
,
4337 &out_output_buffer
);
4338 TALLOC_FREE(subreq
);
4339 if (tevent_req_nterror(req
, status
)) {
4343 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
,
4344 state
, &state
->resume_rsp
,
4345 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
4346 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4347 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4348 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4352 memcpy(&state
->cc_copy
.source_key
,
4353 &state
->resume_rsp
.resume_key
,
4354 sizeof state
->resume_rsp
.resume_key
);
4356 cli_splice_copychunk_send(state
, req
);
4359 struct tevent_req
*cli_smb2_splice_send(TALLOC_CTX
*mem_ctx
,
4360 struct tevent_context
*ev
,
4361 struct cli_state
*cli
,
4362 uint16_t src_fnum
, uint16_t dst_fnum
,
4363 off_t size
, off_t src_offset
, off_t dst_offset
,
4364 int (*splice_cb
)(off_t n
, void *priv
),
4367 struct tevent_req
*req
;
4368 struct tevent_req
*subreq
;
4369 struct cli_smb2_splice_state
*state
;
4371 DATA_BLOB in_input_buffer
= data_blob_null
;
4372 DATA_BLOB in_output_buffer
= data_blob_null
;
4374 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_splice_state
);
4380 state
->splice_cb
= splice_cb
;
4384 state
->src_offset
= src_offset
;
4385 state
->dst_offset
= dst_offset
;
4386 state
->cc_copy
.chunks
= talloc_array(state
,
4387 struct srv_copychunk
,
4388 smb2cli_conn_cc_max_chunks(cli
->conn
));
4389 if (state
->cc_copy
.chunks
== NULL
) {
4393 status
= map_fnum_to_smb2_handle(cli
, src_fnum
, &state
->src_ph
);
4394 if (tevent_req_nterror(req
, status
))
4395 return tevent_req_post(req
, ev
);
4397 status
= map_fnum_to_smb2_handle(cli
, dst_fnum
, &state
->dst_ph
);
4398 if (tevent_req_nterror(req
, status
))
4399 return tevent_req_post(req
, ev
);
4401 subreq
= smb2cli_ioctl_send(state
, ev
, cli
->conn
,
4405 state
->src_ph
->fid_persistent
, /* in_fid_persistent */
4406 state
->src_ph
->fid_volatile
, /* in_fid_volatile */
4407 FSCTL_SRV_REQUEST_RESUME_KEY
,
4408 0, /* in_max_input_length */
4410 32, /* in_max_output_length */
4412 SMB2_IOCTL_FLAG_IS_FSCTL
);
4413 if (tevent_req_nomem(subreq
, req
)) {
4416 tevent_req_set_callback(subreq
,
4417 cli_splice_key_done
,
4423 NTSTATUS
cli_smb2_splice_recv(struct tevent_req
*req
, off_t
*written
)
4425 struct cli_smb2_splice_state
*state
= tevent_req_data(
4426 req
, struct cli_smb2_splice_state
);
4429 if (tevent_req_is_nterror(req
, &status
)) {
4430 tevent_req_received(req
);
4433 if (written
!= NULL
) {
4434 *written
= state
->written
;
4436 tevent_req_received(req
);
4437 return NT_STATUS_OK
;
4440 /***************************************************************
4441 SMB2 enum shadow copy data.
4442 ***************************************************************/
4444 struct cli_smb2_shadow_copy_data_fnum_state
{
4445 struct cli_state
*cli
;
4447 struct smb2_hnd
*ph
;
4448 DATA_BLOB out_input_buffer
;
4449 DATA_BLOB out_output_buffer
;
4452 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
);
4454 static struct tevent_req
*cli_smb2_shadow_copy_data_fnum_send(
4455 TALLOC_CTX
*mem_ctx
,
4456 struct tevent_context
*ev
,
4457 struct cli_state
*cli
,
4461 struct tevent_req
*req
, *subreq
;
4462 struct cli_smb2_shadow_copy_data_fnum_state
*state
;
4465 req
= tevent_req_create(mem_ctx
, &state
,
4466 struct cli_smb2_shadow_copy_data_fnum_state
);
4474 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
4475 if (tevent_req_nterror(req
, status
)) {
4476 return tevent_req_post(req
, ev
);
4480 * TODO. Under SMB2 we should send a zero max_output_length
4481 * ioctl to get the required size, then send another ioctl
4482 * to get the data, but the current SMB1 implementation just
4483 * does one roundtrip with a 64K buffer size. Do the same
4487 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
4488 state
->cli
->timeout
,
4489 state
->cli
->smb2
.session
,
4490 state
->cli
->smb2
.tcon
,
4491 state
->ph
->fid_persistent
, /* in_fid_persistent */
4492 state
->ph
->fid_volatile
, /* in_fid_volatile */
4493 FSCTL_GET_SHADOW_COPY_DATA
,
4494 0, /* in_max_input_length */
4495 NULL
, /* in_input_buffer */
4497 CLI_BUFFER_SIZE
: 16, /* in_max_output_length */
4498 NULL
, /* in_output_buffer */
4499 SMB2_IOCTL_FLAG_IS_FSCTL
);
4501 if (tevent_req_nomem(subreq
, req
)) {
4502 return tevent_req_post(req
, ev
);
4504 tevent_req_set_callback(subreq
,
4505 cli_smb2_shadow_copy_data_fnum_done
,
4511 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
)
4513 struct tevent_req
*req
= tevent_req_callback_data(
4514 subreq
, struct tevent_req
);
4515 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
4516 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
4519 status
= smb2cli_ioctl_recv(subreq
, state
,
4520 &state
->out_input_buffer
,
4521 &state
->out_output_buffer
);
4522 tevent_req_simple_finish_ntstatus(subreq
, status
);
4525 static NTSTATUS
cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req
*req
,
4526 TALLOC_CTX
*mem_ctx
,
4531 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
4532 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
4533 char **names
= NULL
;
4534 uint32_t num_names
= 0;
4535 uint32_t num_names_returned
= 0;
4536 uint32_t dlength
= 0;
4538 uint8_t *endp
= NULL
;
4541 if (tevent_req_is_nterror(req
, &status
)) {
4545 if (state
->out_output_buffer
.length
< 16) {
4546 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4549 num_names
= IVAL(state
->out_output_buffer
.data
, 0);
4550 num_names_returned
= IVAL(state
->out_output_buffer
.data
, 4);
4551 dlength
= IVAL(state
->out_output_buffer
.data
, 8);
4553 if (num_names
> 0x7FFFFFFF) {
4554 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4557 if (get_names
== false) {
4558 *pnum_names
= (int)num_names
;
4559 return NT_STATUS_OK
;
4561 if (num_names
!= num_names_returned
) {
4562 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4564 if (dlength
+ 12 < 12) {
4565 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4568 * NB. The below is an allowable return if there are
4569 * more snapshots than the buffer size we told the
4570 * server we can receive. We currently don't support
4573 if (dlength
+ 12 > state
->out_output_buffer
.length
) {
4574 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4576 if (state
->out_output_buffer
.length
+
4577 (2 * sizeof(SHADOW_COPY_LABEL
)) <
4578 state
->out_output_buffer
.length
) {
4579 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4582 names
= talloc_array(mem_ctx
, char *, num_names_returned
);
4583 if (names
== NULL
) {
4584 return NT_STATUS_NO_MEMORY
;
4587 endp
= state
->out_output_buffer
.data
+
4588 state
->out_output_buffer
.length
;
4590 for (i
=0; i
<num_names_returned
; i
++) {
4593 size_t converted_size
;
4595 src
= state
->out_output_buffer
.data
+ 12 +
4596 (i
* 2 * sizeof(SHADOW_COPY_LABEL
));
4598 if (src
+ (2 * sizeof(SHADOW_COPY_LABEL
)) > endp
) {
4599 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4601 ret
= convert_string_talloc(
4602 names
, CH_UTF16LE
, CH_UNIX
,
4603 src
, 2 * sizeof(SHADOW_COPY_LABEL
),
4604 &names
[i
], &converted_size
);
4607 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4610 *pnum_names
= num_names
;
4612 return NT_STATUS_OK
;
4615 NTSTATUS
cli_smb2_shadow_copy_data(TALLOC_CTX
*mem_ctx
,
4616 struct cli_state
*cli
,
4622 TALLOC_CTX
*frame
= talloc_stackframe();
4623 struct tevent_context
*ev
;
4624 struct tevent_req
*req
;
4625 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
4627 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4629 * Can't use sync call while an async call is in flight
4631 status
= NT_STATUS_INVALID_PARAMETER
;
4634 ev
= samba_tevent_context_init(frame
);
4638 req
= cli_smb2_shadow_copy_data_fnum_send(frame
,
4646 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4649 status
= cli_smb2_shadow_copy_data_fnum_recv(req
,
4659 /***************************************************************
4660 Wrapper that allows SMB2 to truncate a file.
4662 ***************************************************************/
4664 NTSTATUS
cli_smb2_ftruncate(struct cli_state
*cli
,
4669 uint8_t buf
[8] = {0};
4670 DATA_BLOB inbuf
= { .data
= buf
, .length
= sizeof(buf
) };
4671 TALLOC_CTX
*frame
= talloc_stackframe();
4673 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4675 * Can't use sync call while an async call is in flight
4677 status
= NT_STATUS_INVALID_PARAMETER
;
4681 SBVAL(buf
, 0, newsize
);
4683 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4684 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4686 status
= cli_smb2_set_info_fnum(
4689 SMB2_0_INFO_FILE
, /* in_info_type */
4690 FSCC_FILE_END_OF_FILE_INFORMATION
, /* in_file_info_class */
4691 &inbuf
, /* in_input_buffer */
4699 struct cli_smb2_notify_state
{
4700 struct tevent_req
*subreq
;
4701 struct notify_change
*changes
;
4705 static void cli_smb2_notify_done(struct tevent_req
*subreq
);
4706 static bool cli_smb2_notify_cancel(struct tevent_req
*req
);
4708 struct tevent_req
*cli_smb2_notify_send(
4709 TALLOC_CTX
*mem_ctx
,
4710 struct tevent_context
*ev
,
4711 struct cli_state
*cli
,
4713 uint32_t buffer_size
,
4714 uint32_t completion_filter
,
4717 struct tevent_req
*req
= NULL
;
4718 struct cli_smb2_notify_state
*state
= NULL
;
4719 struct smb2_hnd
*ph
= NULL
;
4722 req
= tevent_req_create(mem_ctx
, &state
,
4723 struct cli_smb2_notify_state
);
4728 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
4729 if (tevent_req_nterror(req
, status
)) {
4730 return tevent_req_post(req
, ev
);
4733 state
->subreq
= smb2cli_notify_send(
4745 if (tevent_req_nomem(state
->subreq
, req
)) {
4746 return tevent_req_post(req
, ev
);
4748 tevent_req_set_callback(state
->subreq
, cli_smb2_notify_done
, req
);
4749 tevent_req_set_cancel_fn(req
, cli_smb2_notify_cancel
);
4753 static bool cli_smb2_notify_cancel(struct tevent_req
*req
)
4755 struct cli_smb2_notify_state
*state
= tevent_req_data(
4756 req
, struct cli_smb2_notify_state
);
4759 ok
= tevent_req_cancel(state
->subreq
);
4763 static void cli_smb2_notify_done(struct tevent_req
*subreq
)
4765 struct tevent_req
*req
= tevent_req_callback_data(
4766 subreq
, struct tevent_req
);
4767 struct cli_smb2_notify_state
*state
= tevent_req_data(
4768 req
, struct cli_smb2_notify_state
);
4774 status
= smb2cli_notify_recv(subreq
, state
, &base
, &len
);
4775 TALLOC_FREE(subreq
);
4777 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
4778 tevent_req_done(req
);
4781 if (tevent_req_nterror(req
, status
)) {
4787 while (len
- ofs
>= 12) {
4788 struct notify_change
*tmp
;
4789 struct notify_change
*c
;
4790 uint32_t next_ofs
= IVAL(base
, ofs
);
4791 uint32_t file_name_length
= IVAL(base
, ofs
+8);
4795 tmp
= talloc_realloc(
4798 struct notify_change
,
4799 state
->num_changes
+ 1);
4800 if (tevent_req_nomem(tmp
, req
)) {
4803 state
->changes
= tmp
;
4804 c
= &state
->changes
[state
->num_changes
];
4805 state
->num_changes
+= 1;
4807 if (smb_buffer_oob(len
, ofs
, next_ofs
) ||
4808 smb_buffer_oob(len
, ofs
+12, file_name_length
)) {
4810 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4814 c
->action
= IVAL(base
, ofs
+4);
4816 ok
= convert_string_talloc(
4826 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4830 if (next_ofs
== 0) {
4836 tevent_req_done(req
);
4839 NTSTATUS
cli_smb2_notify_recv(struct tevent_req
*req
,
4840 TALLOC_CTX
*mem_ctx
,
4841 struct notify_change
**pchanges
,
4842 uint32_t *pnum_changes
)
4844 struct cli_smb2_notify_state
*state
= tevent_req_data(
4845 req
, struct cli_smb2_notify_state
);
4848 if (tevent_req_is_nterror(req
, &status
)) {
4851 *pchanges
= talloc_move(mem_ctx
, &state
->changes
);
4852 *pnum_changes
= state
->num_changes
;
4853 return NT_STATUS_OK
;
4856 NTSTATUS
cli_smb2_notify(struct cli_state
*cli
, uint16_t fnum
,
4857 uint32_t buffer_size
, uint32_t completion_filter
,
4858 bool recursive
, TALLOC_CTX
*mem_ctx
,
4859 struct notify_change
**pchanges
,
4860 uint32_t *pnum_changes
)
4862 TALLOC_CTX
*frame
= talloc_stackframe();
4863 struct tevent_context
*ev
;
4864 struct tevent_req
*req
;
4865 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
4867 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4869 * Can't use sync call while an async call is in flight
4871 status
= NT_STATUS_INVALID_PARAMETER
;
4874 ev
= samba_tevent_context_init(frame
);
4878 req
= cli_smb2_notify_send(
4889 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4892 status
= cli_smb2_notify_recv(req
, mem_ctx
, pchanges
, pnum_changes
);
4898 struct cli_smb2_fsctl_state
{
4902 static void cli_smb2_fsctl_done(struct tevent_req
*subreq
);
4904 struct tevent_req
*cli_smb2_fsctl_send(
4905 TALLOC_CTX
*mem_ctx
,
4906 struct tevent_context
*ev
,
4907 struct cli_state
*cli
,
4910 const DATA_BLOB
*in
,
4913 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
4914 struct cli_smb2_fsctl_state
*state
= NULL
;
4915 struct smb2_hnd
*ph
= NULL
;
4918 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_fsctl_state
);
4923 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
4924 if (tevent_req_nterror(req
, status
)) {
4925 return tevent_req_post(req
, ev
);
4928 subreq
= smb2cli_ioctl_send(
4938 0, /* in_max_input_length */
4942 SMB2_IOCTL_FLAG_IS_FSCTL
);
4944 if (tevent_req_nomem(subreq
, req
)) {
4945 return tevent_req_post(req
, ev
);
4947 tevent_req_set_callback(subreq
, cli_smb2_fsctl_done
, req
);
4951 static void cli_smb2_fsctl_done(struct tevent_req
*subreq
)
4953 struct tevent_req
*req
= tevent_req_callback_data(
4954 subreq
, struct tevent_req
);
4955 struct cli_smb2_fsctl_state
*state
= tevent_req_data(
4956 req
, struct cli_smb2_fsctl_state
);
4959 status
= smb2cli_ioctl_recv(subreq
, state
, NULL
, &state
->out
);
4960 tevent_req_simple_finish_ntstatus(subreq
, status
);
4963 NTSTATUS
cli_smb2_fsctl_recv(
4964 struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
, DATA_BLOB
*out
)
4966 struct cli_smb2_fsctl_state
*state
= tevent_req_data(
4967 req
, struct cli_smb2_fsctl_state
);
4968 NTSTATUS status
= NT_STATUS_OK
;
4970 if (tevent_req_is_nterror(req
, &status
)) {
4971 tevent_req_received(req
);
4975 if (state
->out
.length
== 0) {
4976 *out
= (DATA_BLOB
) { .data
= NULL
, };
4979 * Can't use talloc_move() here, the outblobs from
4980 * smb2cli_ioctl_recv() are not standalone talloc
4981 * objects but just peek into the larger buffers
4982 * received, hanging off "state".
4984 *out
= data_blob_talloc(
4985 mem_ctx
, state
->out
.data
, state
->out
.length
);
4986 if (out
->data
== NULL
) {
4987 status
= NT_STATUS_NO_MEMORY
;
4991 tevent_req_received(req
);
4992 return NT_STATUS_OK
;
4995 struct cli_smb2_get_posix_fs_info_state
{
4996 struct tevent_context
*ev
;
4997 struct cli_state
*cli
;
4999 uint32_t optimal_transfer_size
;
5000 uint32_t block_size
;
5001 uint64_t total_blocks
;
5002 uint64_t blocks_available
;
5003 uint64_t user_blocks_available
;
5004 uint64_t total_file_nodes
;
5005 uint64_t free_file_nodes
;
5006 uint64_t fs_identifier
;
5009 static void cli_smb2_get_posix_fs_info_opened(struct tevent_req
*subreq
);
5010 static void cli_smb2_get_posix_fs_info_queried(struct tevent_req
*subreq
);
5011 static void cli_smb2_get_posix_fs_info_done(struct tevent_req
*subreq
);
5013 struct tevent_req
*cli_smb2_get_posix_fs_info_send(TALLOC_CTX
*mem_ctx
,
5014 struct tevent_context
*ev
,
5015 struct cli_state
*cli
)
5017 struct smb2_create_blobs
*cblob
= NULL
;
5018 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
5019 struct cli_smb2_get_posix_fs_info_state
*state
= NULL
;
5022 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_get_posix_fs_info_state
);
5026 *state
= (struct cli_smb2_get_posix_fs_info_state
) {
5030 status
= make_smb2_posix_create_ctx(state
, &cblob
, 0);
5031 if (!NT_STATUS_IS_OK(status
)) {
5035 /* First open the top level directory. */
5036 subreq
= cli_smb2_create_fnum_send(state
,
5040 (struct cli_smb2_create_flags
){0},
5041 SMB2_IMPERSONATION_IMPERSONATION
,
5042 FILE_READ_ATTRIBUTES
,
5043 FILE_ATTRIBUTE_DIRECTORY
,
5044 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
5047 FILE_DIRECTORY_FILE
,
5049 if (tevent_req_nomem(subreq
, req
)) {
5050 return tevent_req_post(req
, ev
);
5053 tevent_req_set_callback(subreq
, cli_smb2_get_posix_fs_info_opened
, req
);
5057 static void cli_smb2_get_posix_fs_info_opened(struct tevent_req
*subreq
)
5059 struct tevent_req
*req
= tevent_req_callback_data(
5060 subreq
, struct tevent_req
);
5061 struct cli_smb2_get_posix_fs_info_state
*state
= tevent_req_data(
5062 req
, struct cli_smb2_get_posix_fs_info_state
);
5063 struct smb2_create_blobs
*cblob
= {0};
5066 status
= cli_smb2_create_fnum_recv(subreq
,
5072 TALLOC_FREE(subreq
);
5074 if (tevent_req_nterror(req
, status
)) {
5078 subreq
= cli_smb2_query_info_fnum_send(
5083 SMB2_0_INFO_FILESYSTEM
, /* in_info_type */
5084 SMB2_FS_POSIX_INFORMATION
, /* in_file_info_class */
5085 0xFFFF, /* in_max_output_length */
5086 NULL
, /* in_input_buffer */
5087 0, /* in_additional_info */
5089 if (tevent_req_nomem(subreq
, req
)) {
5093 tevent_req_set_callback(subreq
, cli_smb2_get_posix_fs_info_queried
, req
);
5096 static void cli_smb2_get_posix_fs_info_queried(struct tevent_req
*subreq
)
5098 struct tevent_req
*req
= tevent_req_callback_data(
5099 subreq
, struct tevent_req
);
5100 struct cli_smb2_get_posix_fs_info_state
*state
= tevent_req_data(
5101 req
, struct cli_smb2_get_posix_fs_info_state
);
5102 DATA_BLOB outbuf
= data_blob_null
;
5105 status
= cli_smb2_query_info_fnum_recv(subreq
, state
, &outbuf
);
5106 TALLOC_FREE(subreq
);
5108 if (tevent_req_nterror(req
, status
)) {
5112 if (outbuf
.length
!= 56) {
5116 state
->optimal_transfer_size
= PULL_LE_U32(outbuf
.data
, 0);
5117 state
->block_size
= PULL_LE_U32(outbuf
.data
, 4);
5118 state
->total_blocks
= PULL_LE_U64(outbuf
.data
, 8);
5119 state
->blocks_available
= PULL_LE_U64(outbuf
.data
, 16);
5120 state
->user_blocks_available
= PULL_LE_U64(outbuf
.data
, 24);
5121 state
->total_file_nodes
= PULL_LE_U64(outbuf
.data
, 32);
5122 state
->free_file_nodes
= PULL_LE_U64(outbuf
.data
, 40);
5123 state
->fs_identifier
= PULL_LE_U64(outbuf
.data
, 48);
5126 subreq
= cli_smb2_close_fnum_send(state
,
5131 if (tevent_req_nomem(subreq
, req
)) {
5135 tevent_req_set_callback(subreq
, cli_smb2_get_posix_fs_info_done
, req
);
5138 static void cli_smb2_get_posix_fs_info_done(struct tevent_req
*subreq
)
5140 struct tevent_req
*req
= tevent_req_callback_data(
5141 subreq
, struct tevent_req
);
5144 status
= cli_smb2_close_fnum_recv(subreq
);
5145 TALLOC_FREE(subreq
);
5146 if (tevent_req_nterror(req
, status
)) {
5150 tevent_req_done(req
);
5153 NTSTATUS
cli_smb2_get_posix_fs_info_recv(struct tevent_req
*req
,
5154 uint32_t *optimal_transfer_size
,
5155 uint32_t *block_size
,
5156 uint64_t *total_blocks
,
5157 uint64_t *blocks_available
,
5158 uint64_t *user_blocks_available
,
5159 uint64_t *total_file_nodes
,
5160 uint64_t *free_file_nodes
,
5161 uint64_t *fs_identifier
)
5163 struct cli_smb2_get_posix_fs_info_state
*state
= tevent_req_data(
5164 req
, struct cli_smb2_get_posix_fs_info_state
);
5167 if (tevent_req_is_nterror(req
, &status
)) {
5168 tevent_req_received(req
);
5171 *optimal_transfer_size
= state
->optimal_transfer_size
;
5172 *block_size
= state
->block_size
;
5173 *total_blocks
= state
->total_blocks
;
5174 *blocks_available
= state
->blocks_available
;
5175 *user_blocks_available
= state
->user_blocks_available
;
5176 *total_file_nodes
= state
->total_file_nodes
;
5177 *free_file_nodes
= state
->free_file_nodes
;
5178 *fs_identifier
= state
->fs_identifier
;
5179 tevent_req_received(req
);
5180 return NT_STATUS_OK
;