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"
50 uint64_t fid_persistent
;
51 uint64_t fid_volatile
;
55 * Handle mapping code.
58 /***************************************************************
59 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
60 Ensures handle is owned by cli struct.
61 ***************************************************************/
63 static NTSTATUS
map_smb2_handle_to_fnum(struct cli_state
*cli
,
64 const struct smb2_hnd
*ph
, /* In */
65 uint16_t *pfnum
) /* Out */
68 struct idr_context
*idp
= cli
->smb2
.open_handles
;
69 struct smb2_hnd
*owned_h
= talloc_memdup(cli
,
71 sizeof(struct smb2_hnd
));
73 if (owned_h
== NULL
) {
74 return NT_STATUS_NO_MEMORY
;
79 cli
->smb2
.open_handles
= idr_init(cli
);
80 if (cli
->smb2
.open_handles
== NULL
) {
82 return NT_STATUS_NO_MEMORY
;
84 idp
= cli
->smb2
.open_handles
;
87 ret
= idr_get_new_above(idp
, owned_h
, 1, 0xFFFE);
90 return NT_STATUS_NO_MEMORY
;
93 *pfnum
= (uint16_t)ret
;
97 /***************************************************************
98 Return the smb2_hnd pointer associated with the given fnum.
99 ***************************************************************/
101 static NTSTATUS
map_fnum_to_smb2_handle(struct cli_state
*cli
,
102 uint16_t fnum
, /* In */
103 struct smb2_hnd
**pph
) /* Out */
105 struct idr_context
*idp
= cli
->smb2
.open_handles
;
108 return NT_STATUS_INVALID_PARAMETER
;
110 *pph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
112 return NT_STATUS_INVALID_HANDLE
;
117 /***************************************************************
118 Delete the fnum to smb2_hnd mapping. Zeros out handle on
120 ***************************************************************/
122 static NTSTATUS
delete_smb2_handle_mapping(struct cli_state
*cli
,
123 struct smb2_hnd
**pph
, /* In */
124 uint16_t fnum
) /* In */
126 struct idr_context
*idp
= cli
->smb2
.open_handles
;
130 return NT_STATUS_INVALID_PARAMETER
;
133 ph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
135 return NT_STATUS_INVALID_PARAMETER
;
137 idr_remove(idp
, fnum
);
142 /***************************************************************
144 ***************************************************************/
146 static uint8_t flags_to_smb2_oplock(struct cli_smb2_create_flags create_flags
)
148 if (create_flags
.batch_oplock
) {
149 return SMB2_OPLOCK_LEVEL_BATCH
;
150 } else if (create_flags
.exclusive_oplock
) {
151 return SMB2_OPLOCK_LEVEL_EXCLUSIVE
;
154 /* create_flags doesn't do a level2 request. */
155 return SMB2_OPLOCK_LEVEL_NONE
;
158 /***************************************************************
159 If we're on a DFS share, ensure we convert to a full DFS path
160 if this hasn't already been done.
161 ***************************************************************/
163 static char *smb2_dfs_share_path(TALLOC_CTX
*ctx
,
164 struct cli_state
*cli
,
167 bool is_dfs
= smbXcli_conn_dfs_supported(cli
->conn
) &&
168 smbXcli_tcon_is_dfs_share(cli
->smb2
.tcon
);
169 bool is_already_dfs_path
= false;
174 is_already_dfs_path
= cli_dfs_is_already_full_path(cli
, path
);
175 if (is_already_dfs_path
) {
178 if (path
[0] == '\0') {
179 return talloc_asprintf(ctx
,
181 smbXcli_conn_remote_name(cli
->conn
),
184 while (*path
== '\\') {
187 return talloc_asprintf(ctx
,
189 smbXcli_conn_remote_name(cli
->conn
),
194 /***************************************************************
195 Small wrapper that allows SMB2 create to return a uint16_t fnum.
196 ***************************************************************/
198 struct cli_smb2_create_fnum_state
{
199 struct cli_state
*cli
;
200 struct smb2_create_blobs in_cblobs
;
201 struct smb2_create_blobs out_cblobs
;
202 struct smb_create_returns cr
;
203 struct symlink_reparse_struct
*symlink
;
205 struct tevent_req
*subreq
;
208 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
);
209 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
);
211 struct tevent_req
*cli_smb2_create_fnum_send(
213 struct tevent_context
*ev
,
214 struct cli_state
*cli
,
215 const char *fname_in
,
216 struct cli_smb2_create_flags create_flags
,
217 uint32_t impersonation_level
,
218 uint32_t desired_access
,
219 uint32_t file_attributes
,
220 uint32_t share_access
,
221 uint32_t create_disposition
,
222 uint32_t create_options
,
223 const struct smb2_create_blobs
*in_cblobs
)
225 struct tevent_req
*req
, *subreq
;
226 struct cli_smb2_create_fnum_state
*state
;
228 size_t fname_len
= 0;
233 req
= tevent_req_create(mem_ctx
, &state
,
234 struct cli_smb2_create_fnum_state
);
240 fname
= talloc_strdup(state
, fname_in
);
241 if (tevent_req_nomem(fname
, req
)) {
242 return tevent_req_post(req
, ev
);
245 if (cli
->backup_intent
) {
246 create_options
|= FILE_OPEN_FOR_BACKUP_INTENT
;
249 if (cli
->smb2
.client_smb311_posix
) {
250 uint8_t modebuf
[4] = {
255 smb2_create_blob_add(state
,
257 SMB2_CREATE_TAG_POSIX
,
260 .length
= sizeof(modebuf
),
262 if (tevent_req_nterror(req
, status
)) {
263 return tevent_req_post(req
, ev
);
267 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
268 have_twrp
= clistr_smb2_extract_snapshot_token(fname
, &ntt
);
270 status
= smb2_create_blob_add(
273 SMB2_CREATE_TAG_TWRP
,
275 .data
= (uint8_t *)&ntt
,
276 .length
= sizeof(ntt
),
278 if (tevent_req_nterror(req
, status
)) {
279 return tevent_req_post(req
, ev
);
283 if (in_cblobs
!= NULL
) {
285 for (i
=0; i
<in_cblobs
->num_blobs
; i
++) {
286 struct smb2_create_blob
*b
= &in_cblobs
->blobs
[i
];
287 status
= smb2_create_blob_add(
288 state
, &state
->in_cblobs
, b
->tag
, b
->data
);
289 if (!NT_STATUS_IS_OK(status
)) {
290 tevent_req_nterror(req
, status
);
291 return tevent_req_post(req
, ev
);
296 fname
= smb2_dfs_share_path(state
, cli
, fname
);
297 if (tevent_req_nomem(fname
, req
)) {
298 return tevent_req_post(req
, ev
);
300 fname_len
= strlen(fname
);
302 /* SMB2 is pickier about pathnames. Ensure it doesn't
304 if (*fname
== '\\') {
309 /* Or end in a '\' */
310 if (fname_len
> 0 && fname
[fname_len
-1] == '\\') {
311 fname
[fname_len
-1] = '\0';
314 subreq
= smb2cli_create_send(state
, ev
,
320 flags_to_smb2_oplock(create_flags
),
328 if (tevent_req_nomem(subreq
, req
)) {
329 return tevent_req_post(req
, ev
);
331 tevent_req_set_callback(subreq
, cli_smb2_create_fnum_done
, req
);
333 state
->subreq
= subreq
;
334 tevent_req_set_cancel_fn(req
, cli_smb2_create_fnum_cancel
);
339 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
)
341 struct tevent_req
*req
= tevent_req_callback_data(
342 subreq
, struct tevent_req
);
343 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
344 req
, struct cli_smb2_create_fnum_state
);
348 status
= smb2cli_create_recv(
351 &h
.fid_volatile
, &state
->cr
,
356 if (tevent_req_nterror(req
, status
)) {
360 status
= map_smb2_handle_to_fnum(state
->cli
, &h
, &state
->fnum
);
361 if (tevent_req_nterror(req
, status
)) {
364 tevent_req_done(req
);
367 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
)
369 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
370 req
, struct cli_smb2_create_fnum_state
);
371 return tevent_req_cancel(state
->subreq
);
374 NTSTATUS
cli_smb2_create_fnum_recv(
375 struct tevent_req
*req
,
377 struct smb_create_returns
*cr
,
379 struct smb2_create_blobs
*out_cblobs
,
380 struct symlink_reparse_struct
**symlink
)
382 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
383 req
, struct cli_smb2_create_fnum_state
);
386 if (tevent_req_is_nterror(req
, &status
)) {
387 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
) &&
389 *symlink
= talloc_move(mem_ctx
, &state
->symlink
);
391 state
->cli
->raw_status
= status
;
395 *pfnum
= state
->fnum
;
400 if (out_cblobs
!= NULL
) {
401 *out_cblobs
= (struct smb2_create_blobs
) {
402 .num_blobs
= state
->out_cblobs
.num_blobs
,
403 .blobs
= talloc_move(
404 mem_ctx
, &state
->out_cblobs
.blobs
),
407 state
->cli
->raw_status
= NT_STATUS_OK
;
411 NTSTATUS
cli_smb2_create_fnum(
412 struct cli_state
*cli
,
414 struct cli_smb2_create_flags create_flags
,
415 uint32_t impersonation_level
,
416 uint32_t desired_access
,
417 uint32_t file_attributes
,
418 uint32_t share_access
,
419 uint32_t create_disposition
,
420 uint32_t create_options
,
421 const struct smb2_create_blobs
*in_cblobs
,
423 struct smb_create_returns
*cr
,
425 struct smb2_create_blobs
*out_cblobs
)
427 TALLOC_CTX
*frame
= talloc_stackframe();
428 struct tevent_context
*ev
;
429 struct tevent_req
*req
;
430 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
432 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
434 * Can't use sync call while an async call is in flight
436 status
= NT_STATUS_INVALID_PARAMETER
;
439 ev
= samba_tevent_context_init(frame
);
443 req
= cli_smb2_create_fnum_send(
459 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
462 status
= cli_smb2_create_fnum_recv(
463 req
, pfid
, cr
, mem_ctx
, out_cblobs
, NULL
);
469 /***************************************************************
470 Small wrapper that allows SMB2 close to use a uint16_t fnum.
471 ***************************************************************/
473 struct cli_smb2_close_fnum_state
{
474 struct cli_state
*cli
;
479 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
);
481 struct tevent_req
*cli_smb2_close_fnum_send(TALLOC_CTX
*mem_ctx
,
482 struct tevent_context
*ev
,
483 struct cli_state
*cli
,
487 struct tevent_req
*req
, *subreq
;
488 struct cli_smb2_close_fnum_state
*state
;
491 req
= tevent_req_create(mem_ctx
, &state
,
492 struct cli_smb2_close_fnum_state
);
499 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
500 if (tevent_req_nterror(req
, status
)) {
501 return tevent_req_post(req
, ev
);
504 subreq
= smb2cli_close_send(state
,
511 state
->ph
->fid_persistent
,
512 state
->ph
->fid_volatile
);
513 if (tevent_req_nomem(subreq
, req
)) {
514 return tevent_req_post(req
, ev
);
516 tevent_req_set_callback(subreq
, cli_smb2_close_fnum_done
, req
);
520 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
)
522 struct tevent_req
*req
= tevent_req_callback_data(
523 subreq
, struct tevent_req
);
524 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
525 req
, struct cli_smb2_close_fnum_state
);
528 status
= smb2cli_close_recv(subreq
);
529 if (tevent_req_nterror(req
, status
)) {
533 /* Delete the fnum -> handle mapping. */
534 status
= delete_smb2_handle_mapping(state
->cli
, &state
->ph
,
536 if (tevent_req_nterror(req
, status
)) {
539 tevent_req_done(req
);
542 NTSTATUS
cli_smb2_close_fnum_recv(struct tevent_req
*req
)
544 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
545 req
, struct cli_smb2_close_fnum_state
);
546 NTSTATUS status
= NT_STATUS_OK
;
548 if (tevent_req_is_nterror(req
, &status
)) {
549 state
->cli
->raw_status
= status
;
551 tevent_req_received(req
);
555 NTSTATUS
cli_smb2_close_fnum(struct cli_state
*cli
, uint16_t fnum
)
557 TALLOC_CTX
*frame
= talloc_stackframe();
558 struct tevent_context
*ev
;
559 struct tevent_req
*req
;
560 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
562 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
564 * Can't use sync call while an async call is in flight
566 status
= NT_STATUS_INVALID_PARAMETER
;
569 ev
= samba_tevent_context_init(frame
);
573 req
= cli_smb2_close_fnum_send(frame
, ev
, cli
, fnum
, 0);
577 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
580 status
= cli_smb2_close_fnum_recv(req
);
586 struct cli_smb2_set_info_fnum_state
{
590 static void cli_smb2_set_info_fnum_done(struct tevent_req
*subreq
);
592 struct tevent_req
*cli_smb2_set_info_fnum_send(
594 struct tevent_context
*ev
,
595 struct cli_state
*cli
,
597 uint8_t in_info_type
,
598 uint8_t in_info_class
,
599 const DATA_BLOB
*in_input_buffer
,
600 uint32_t in_additional_info
)
602 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
603 struct cli_smb2_set_info_fnum_state
*state
= NULL
;
604 struct smb2_hnd
*ph
= NULL
;
607 req
= tevent_req_create(
608 mem_ctx
, &state
, struct cli_smb2_set_info_fnum_state
);
613 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
614 if (tevent_req_nterror(req
, status
)) {
615 return tevent_req_post(req
, ev
);
618 subreq
= smb2cli_set_info_send(
631 if (tevent_req_nomem(subreq
, req
)) {
632 return tevent_req_post(req
, ev
);
634 tevent_req_set_callback(subreq
, cli_smb2_set_info_fnum_done
, req
);
638 static void cli_smb2_set_info_fnum_done(struct tevent_req
*subreq
)
640 NTSTATUS status
= smb2cli_set_info_recv(subreq
);
641 tevent_req_simple_finish_ntstatus(subreq
, status
);
644 NTSTATUS
cli_smb2_set_info_fnum_recv(struct tevent_req
*req
)
646 return tevent_req_simple_recv_ntstatus(req
);
649 NTSTATUS
cli_smb2_set_info_fnum(
650 struct cli_state
*cli
,
652 uint8_t in_info_type
,
653 uint8_t in_info_class
,
654 const DATA_BLOB
*in_input_buffer
,
655 uint32_t in_additional_info
)
657 TALLOC_CTX
*frame
= talloc_stackframe();
658 struct tevent_context
*ev
= NULL
;
659 struct tevent_req
*req
= NULL
;
660 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
663 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
665 * Can't use sync call while an async call is in flight
667 status
= NT_STATUS_INVALID_PARAMETER
;
670 ev
= samba_tevent_context_init(frame
);
674 req
= cli_smb2_set_info_fnum_send(
686 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
690 status
= cli_smb2_set_info_fnum_recv(req
);
696 struct cli_smb2_delete_on_close_state
{
697 struct cli_state
*cli
;
702 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
);
704 struct tevent_req
*cli_smb2_delete_on_close_send(TALLOC_CTX
*mem_ctx
,
705 struct tevent_context
*ev
,
706 struct cli_state
*cli
,
710 struct tevent_req
*req
= NULL
;
711 struct cli_smb2_delete_on_close_state
*state
= NULL
;
712 struct tevent_req
*subreq
= NULL
;
713 uint8_t in_info_type
;
714 uint8_t in_file_info_class
;
716 req
= tevent_req_create(mem_ctx
, &state
,
717 struct cli_smb2_delete_on_close_state
);
724 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
725 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
728 in_file_info_class
= SMB_FILE_DISPOSITION_INFORMATION
- 1000;
729 /* Setup data array. */
730 SCVAL(&state
->data
[0], 0, flag
? 1 : 0);
731 state
->inbuf
.data
= &state
->data
[0];
732 state
->inbuf
.length
= 1;
734 subreq
= cli_smb2_set_info_fnum_send(
743 if (tevent_req_nomem(subreq
, req
)) {
744 return tevent_req_post(req
, ev
);
746 tevent_req_set_callback(subreq
,
747 cli_smb2_delete_on_close_done
,
752 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
)
754 NTSTATUS status
= cli_smb2_set_info_fnum_recv(subreq
);
755 tevent_req_simple_finish_ntstatus(subreq
, status
);
758 NTSTATUS
cli_smb2_delete_on_close_recv(struct tevent_req
*req
)
760 struct cli_smb2_delete_on_close_state
*state
=
762 struct cli_smb2_delete_on_close_state
);
765 if (tevent_req_is_nterror(req
, &status
)) {
766 state
->cli
->raw_status
= status
;
767 tevent_req_received(req
);
771 state
->cli
->raw_status
= NT_STATUS_OK
;
772 tevent_req_received(req
);
776 NTSTATUS
cli_smb2_delete_on_close(struct cli_state
*cli
, uint16_t fnum
, bool flag
)
778 TALLOC_CTX
*frame
= talloc_stackframe();
779 struct tevent_context
*ev
;
780 struct tevent_req
*req
;
781 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
783 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
785 * Can't use sync call while an async call is in flight
787 status
= NT_STATUS_INVALID_PARAMETER
;
790 ev
= samba_tevent_context_init(frame
);
794 req
= cli_smb2_delete_on_close_send(frame
, ev
, cli
, fnum
, flag
);
798 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
801 status
= cli_smb2_delete_on_close_recv(req
);
807 struct cli_smb2_mkdir_state
{
808 struct tevent_context
*ev
;
809 struct cli_state
*cli
;
812 static void cli_smb2_mkdir_opened(struct tevent_req
*subreq
);
813 static void cli_smb2_mkdir_closed(struct tevent_req
*subreq
);
815 struct tevent_req
*cli_smb2_mkdir_send(
817 struct tevent_context
*ev
,
818 struct cli_state
*cli
,
821 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
822 struct cli_smb2_mkdir_state
*state
= NULL
;
824 req
= tevent_req_create(
825 mem_ctx
, &state
, struct cli_smb2_mkdir_state
);
832 /* Ensure this is a directory. */
833 subreq
= cli_smb2_create_fnum_send(
838 (struct cli_smb2_create_flags
){0}, /* create_flags */
839 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation_level */
840 FILE_READ_ATTRIBUTES
, /* desired_access */
841 FILE_ATTRIBUTE_DIRECTORY
, /* file_attributes */
843 FILE_SHARE_WRITE
, /* share_access */
844 FILE_CREATE
, /* create_disposition */
845 FILE_DIRECTORY_FILE
, /* create_options */
846 NULL
); /* in_cblobs */
847 if (tevent_req_nomem(subreq
, req
)) {
848 return tevent_req_post(req
, ev
);
850 tevent_req_set_callback(subreq
, cli_smb2_mkdir_opened
, req
);
854 static void cli_smb2_mkdir_opened(struct tevent_req
*subreq
)
856 struct tevent_req
*req
= tevent_req_callback_data(
857 subreq
, struct tevent_req
);
858 struct cli_smb2_mkdir_state
*state
= tevent_req_data(
859 req
, struct cli_smb2_mkdir_state
);
861 uint16_t fnum
= 0xffff;
863 status
= cli_smb2_create_fnum_recv(
864 subreq
, &fnum
, NULL
, NULL
, NULL
, NULL
);
866 if (tevent_req_nterror(req
, status
)) {
871 cli_smb2_close_fnum_send(state
, state
->ev
, state
->cli
, fnum
, 0);
872 if (tevent_req_nomem(subreq
, req
)) {
875 tevent_req_set_callback(subreq
, cli_smb2_mkdir_closed
, req
);
878 static void cli_smb2_mkdir_closed(struct tevent_req
*subreq
)
880 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
881 tevent_req_simple_finish_ntstatus(subreq
, status
);
884 NTSTATUS
cli_smb2_mkdir_recv(struct tevent_req
*req
)
886 return tevent_req_simple_recv_ntstatus(req
);
889 struct cli_smb2_rmdir_state
{
890 struct tevent_context
*ev
;
891 struct cli_state
*cli
;
893 const struct smb2_create_blobs
*in_cblobs
;
898 static void cli_smb2_rmdir_opened1(struct tevent_req
*subreq
);
899 static void cli_smb2_rmdir_opened2(struct tevent_req
*subreq
);
900 static void cli_smb2_rmdir_disp_set(struct tevent_req
*subreq
);
901 static void cli_smb2_rmdir_closed(struct tevent_req
*subreq
);
903 struct tevent_req
*cli_smb2_rmdir_send(
905 struct tevent_context
*ev
,
906 struct cli_state
*cli
,
908 const struct smb2_create_blobs
*in_cblobs
)
910 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
911 struct cli_smb2_rmdir_state
*state
= NULL
;
913 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_rmdir_state
);
919 state
->dname
= dname
;
920 state
->in_cblobs
= in_cblobs
;
922 subreq
= cli_smb2_create_fnum_send(
927 (struct cli_smb2_create_flags
){0},
928 SMB2_IMPERSONATION_IMPERSONATION
,
929 DELETE_ACCESS
, /* desired_access */
930 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
931 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
932 FILE_OPEN
, /* create_disposition */
933 FILE_DIRECTORY_FILE
, /* create_options */
934 state
->in_cblobs
); /* in_cblobs */
935 if (tevent_req_nomem(subreq
, req
)) {
936 return tevent_req_post(req
, ev
);
938 tevent_req_set_callback(subreq
, cli_smb2_rmdir_opened1
, req
);
942 static void cli_smb2_rmdir_opened1(struct tevent_req
*subreq
)
944 struct tevent_req
*req
= tevent_req_callback_data(
945 subreq
, struct tevent_req
);
946 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
947 req
, struct cli_smb2_rmdir_state
);
950 status
= cli_smb2_create_fnum_recv(
951 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
954 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
956 * Naive option to match our SMB1 code. Assume the
957 * symlink path that tripped us up was the last
958 * component and try again. Eventually we will have to
959 * deal with the returned path unprocessed component. JRA.
961 subreq
= cli_smb2_create_fnum_send(
966 (struct cli_smb2_create_flags
){0},
967 SMB2_IMPERSONATION_IMPERSONATION
,
968 DELETE_ACCESS
, /* desired_access */
969 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
970 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
971 FILE_OPEN
, /* create_disposition */
973 FILE_DELETE_ON_CLOSE
|
974 FILE_OPEN_REPARSE_POINT
, /* create_options */
975 state
->in_cblobs
); /* in_cblobs */
976 if (tevent_req_nomem(subreq
, req
)) {
979 tevent_req_set_callback(subreq
, cli_smb2_rmdir_opened2
, req
);
983 if (tevent_req_nterror(req
, status
)) {
987 subreq
= cli_smb2_delete_on_close_send(
988 state
, state
->ev
, state
->cli
, state
->fnum
, true);
989 if (tevent_req_nomem(subreq
, req
)) {
992 tevent_req_set_callback(subreq
, cli_smb2_rmdir_disp_set
, req
);
995 static void cli_smb2_rmdir_opened2(struct tevent_req
*subreq
)
997 struct tevent_req
*req
= tevent_req_callback_data(
998 subreq
, struct tevent_req
);
999 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
1000 req
, struct cli_smb2_rmdir_state
);
1003 status
= cli_smb2_create_fnum_recv(
1004 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
1005 TALLOC_FREE(subreq
);
1006 if (tevent_req_nterror(req
, status
)) {
1010 subreq
= cli_smb2_delete_on_close_send(
1011 state
, state
->ev
, state
->cli
, state
->fnum
, true);
1012 if (tevent_req_nomem(subreq
, req
)) {
1015 tevent_req_set_callback(subreq
, cli_smb2_rmdir_disp_set
, req
);
1018 static void cli_smb2_rmdir_disp_set(struct tevent_req
*subreq
)
1020 struct tevent_req
*req
= tevent_req_callback_data(
1021 subreq
, struct tevent_req
);
1022 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
1023 req
, struct cli_smb2_rmdir_state
);
1025 state
->status
= cli_smb2_delete_on_close_recv(subreq
);
1026 TALLOC_FREE(subreq
);
1029 * Close the fd even if the set_disp failed
1032 subreq
= cli_smb2_close_fnum_send(state
,
1037 if (tevent_req_nomem(subreq
, req
)) {
1040 tevent_req_set_callback(subreq
, cli_smb2_rmdir_closed
, req
);
1043 static void cli_smb2_rmdir_closed(struct tevent_req
*subreq
)
1045 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
1046 tevent_req_simple_finish_ntstatus(subreq
, status
);
1049 NTSTATUS
cli_smb2_rmdir_recv(struct tevent_req
*req
)
1051 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
1052 req
, struct cli_smb2_rmdir_state
);
1055 if (tevent_req_is_nterror(req
, &status
)) {
1058 return state
->status
;
1061 /***************************************************************
1062 Small wrapper that allows SMB2 to unlink a pathname.
1063 ***************************************************************/
1065 struct cli_smb2_unlink_state
{
1066 struct tevent_context
*ev
;
1067 struct cli_state
*cli
;
1069 const struct smb2_create_blobs
*in_cblobs
;
1072 static void cli_smb2_unlink_opened1(struct tevent_req
*subreq
);
1073 static void cli_smb2_unlink_opened2(struct tevent_req
*subreq
);
1074 static void cli_smb2_unlink_closed(struct tevent_req
*subreq
);
1076 struct tevent_req
*cli_smb2_unlink_send(
1077 TALLOC_CTX
*mem_ctx
,
1078 struct tevent_context
*ev
,
1079 struct cli_state
*cli
,
1081 const struct smb2_create_blobs
*in_cblobs
)
1083 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1084 struct cli_smb2_unlink_state
*state
= NULL
;
1086 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_unlink_state
);
1092 state
->fname
= fname
;
1093 state
->in_cblobs
= in_cblobs
;
1095 subreq
= cli_smb2_create_fnum_send(
1096 state
, /* mem_ctx */
1097 state
->ev
, /* tevent_context */
1098 state
->cli
, /* cli_struct */
1099 state
->fname
, /* filename */
1100 (struct cli_smb2_create_flags
){0},
1101 SMB2_IMPERSONATION_IMPERSONATION
,
1102 DELETE_ACCESS
, /* desired_access */
1103 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
1106 FILE_SHARE_DELETE
, /* share_access */
1107 FILE_OPEN
, /* create_disposition */
1108 FILE_DELETE_ON_CLOSE
, /* create_options */
1109 state
->in_cblobs
); /* in_cblobs */
1110 if (tevent_req_nomem(subreq
, req
)) {
1111 return tevent_req_post(req
, ev
);
1113 tevent_req_set_callback(subreq
, cli_smb2_unlink_opened1
, req
);
1117 static void cli_smb2_unlink_opened1(struct tevent_req
*subreq
)
1119 struct tevent_req
*req
= tevent_req_callback_data(
1120 subreq
, struct tevent_req
);
1121 struct cli_smb2_unlink_state
*state
= tevent_req_data(
1122 req
, struct cli_smb2_unlink_state
);
1123 uint16_t fnum
= 0xffff;
1126 status
= cli_smb2_create_fnum_recv(
1127 subreq
, &fnum
, NULL
, NULL
, NULL
, NULL
);
1128 TALLOC_FREE(subreq
);
1130 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
) ||
1131 NT_STATUS_EQUAL(status
, NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED
)) {
1133 * Naive option to match our SMB1 code. Assume the
1134 * symlink path that tripped us up was the last
1135 * component and try again. Eventually we will have to
1136 * deal with the returned path unprocessed component. JRA.
1138 subreq
= cli_smb2_create_fnum_send(
1139 state
, /* mem_ctx */
1140 state
->ev
, /* tevent_context */
1141 state
->cli
, /* cli_struct */
1142 state
->fname
, /* filename */
1143 (struct cli_smb2_create_flags
){0},
1144 SMB2_IMPERSONATION_IMPERSONATION
,
1145 DELETE_ACCESS
, /* desired_access */
1146 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
1149 FILE_SHARE_DELETE
, /* share_access */
1150 FILE_OPEN
, /* create_disposition */
1151 FILE_DELETE_ON_CLOSE
|
1152 FILE_OPEN_REPARSE_POINT
, /* create_options */
1153 state
->in_cblobs
); /* in_cblobs */
1154 if (tevent_req_nomem(subreq
, req
)) {
1157 tevent_req_set_callback(subreq
, cli_smb2_unlink_opened2
, req
);
1161 if (tevent_req_nterror(req
, status
)) {
1166 cli_smb2_close_fnum_send(state
, state
->ev
, state
->cli
, fnum
, 0);
1167 if (tevent_req_nomem(subreq
, req
)) {
1170 tevent_req_set_callback(subreq
, cli_smb2_unlink_closed
, req
);
1173 static void cli_smb2_unlink_opened2(struct tevent_req
*subreq
)
1175 struct tevent_req
*req
= tevent_req_callback_data(
1176 subreq
, struct tevent_req
);
1177 struct cli_smb2_unlink_state
*state
= tevent_req_data(
1178 req
, struct cli_smb2_unlink_state
);
1179 uint16_t fnum
= 0xffff;
1182 status
= cli_smb2_create_fnum_recv(
1183 subreq
, &fnum
, NULL
, NULL
, NULL
, NULL
);
1184 TALLOC_FREE(subreq
);
1185 if (tevent_req_nterror(req
, status
)) {
1190 cli_smb2_close_fnum_send(state
, state
->ev
, state
->cli
, fnum
, 0);
1191 if (tevent_req_nomem(subreq
, req
)) {
1194 tevent_req_set_callback(subreq
, cli_smb2_unlink_closed
, req
);
1197 static void cli_smb2_unlink_closed(struct tevent_req
*subreq
)
1199 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
1200 tevent_req_simple_finish_ntstatus(subreq
, status
);
1203 NTSTATUS
cli_smb2_unlink_recv(struct tevent_req
*req
)
1205 return tevent_req_simple_recv_ntstatus(req
);
1208 /***************************************************************
1209 Utility function to parse a SMB2_FIND_POSIX_INFORMATION reply.
1210 ***************************************************************/
1212 static NTSTATUS
parse_finfo_posix_info(const uint8_t *dir_data
,
1213 uint32_t dir_data_length
,
1214 struct file_info
*finfo
,
1215 uint32_t *next_offset
)
1217 struct smb3_file_posix_information info
= {};
1219 enum ndr_err_code ndr_err
;
1222 uint32_t _next_offset
= 0;
1224 if (dir_data_length
< 4) {
1225 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1228 _next_offset
= IVAL(dir_data
, 0);
1230 if (_next_offset
> dir_data_length
) {
1231 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1234 if (_next_offset
!= 0) {
1235 /* Ensure we only read what in this record. */
1236 dir_data_length
= _next_offset
;
1240 * Skip NextEntryOffset and FileIndex
1242 if (dir_data_length
< 8) {
1243 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1246 dir_data_length
-= 8;
1248 ndr_err
= ndr_pull_struct_blob_noalloc(
1252 (ndr_pull_flags_fn_t
)ndr_pull_smb3_file_posix_information
,
1254 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1255 return ndr_map_error2ntstatus(ndr_err
);
1257 if (consumed
> dir_data_length
) {
1258 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1260 dir_data
+= consumed
;
1261 dir_data_length
-= consumed
;
1263 finfo
->btime_ts
= interpret_long_date(info
.creation_time
);
1264 finfo
->atime_ts
= interpret_long_date(info
.last_access_time
);
1265 finfo
->mtime_ts
= interpret_long_date(info
.last_write_time
);
1266 finfo
->ctime_ts
= interpret_long_date(info
.change_time
);
1267 finfo
->allocated_size
= info
.allocation_size
;
1268 finfo
->size
= info
.end_of_file
;
1269 finfo
->attr
= info
.file_attributes
;
1270 finfo
->ino
= info
.inode
;
1271 finfo
->st_ex_dev
= info
.device
;
1272 finfo
->st_ex_nlink
= info
.cc
.nlinks
;
1273 finfo
->reparse_tag
= info
.cc
.reparse_tag
;
1274 finfo
->st_ex_mode
= wire_perms_to_unix(info
.cc
.posix_perms
);
1275 sid_copy(&finfo
->owner_sid
, &info
.cc
.owner
);
1276 sid_copy(&finfo
->group_sid
, &info
.cc
.group
);
1278 if (dir_data_length
< 4) {
1279 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1281 namelen
= PULL_LE_U32(dir_data
, 0);
1284 dir_data_length
-= 4;
1286 if (namelen
> dir_data_length
) {
1287 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1290 ret
= pull_string_talloc(finfo
,
1292 FLAGS2_UNICODE_STRINGS
,
1297 if (ret
== (size_t)-1) {
1298 /* Bad conversion. */
1299 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1302 if (finfo
->name
== NULL
) {
1303 /* Bad conversion. */
1304 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1307 *next_offset
= _next_offset
;
1308 return NT_STATUS_OK
;
1311 /***************************************************************
1312 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1313 ***************************************************************/
1315 static NTSTATUS
parse_finfo_id_both_directory_info(const uint8_t *dir_data
,
1316 uint32_t dir_data_length
,
1317 struct file_info
*finfo
,
1318 uint32_t *next_offset
)
1324 if (dir_data_length
< 4) {
1325 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1328 *next_offset
= IVAL(dir_data
, 0);
1330 if (*next_offset
> dir_data_length
) {
1331 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1334 if (*next_offset
!= 0) {
1335 /* Ensure we only read what in this record. */
1336 dir_data_length
= *next_offset
;
1339 if (dir_data_length
< 105) {
1340 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1343 finfo
->btime_ts
= interpret_long_date(BVAL(dir_data
, 8));
1344 finfo
->atime_ts
= interpret_long_date(BVAL(dir_data
, 16));
1345 finfo
->mtime_ts
= interpret_long_date(BVAL(dir_data
, 24));
1346 finfo
->ctime_ts
= interpret_long_date(BVAL(dir_data
, 32));
1347 finfo
->size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 40, 0);
1348 finfo
->allocated_size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 48, 0);
1349 finfo
->attr
= IVAL(dir_data
+ 56, 0);
1350 finfo
->ino
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 96, 0);
1351 namelen
= IVAL(dir_data
+ 60,0);
1352 if (namelen
> (dir_data_length
- 104)) {
1353 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1355 finfo
->reparse_tag
= IVAL(dir_data
+ 64, 0);
1356 slen
= CVAL(dir_data
+ 68, 0);
1358 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1360 ret
= pull_string_talloc(finfo
,
1362 FLAGS2_UNICODE_STRINGS
,
1367 if (ret
== (size_t)-1) {
1368 /* Bad conversion. */
1369 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1372 ret
= pull_string_talloc(finfo
,
1374 FLAGS2_UNICODE_STRINGS
,
1379 if (ret
== (size_t)-1) {
1380 /* Bad conversion. */
1381 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1384 if (finfo
->name
== NULL
) {
1385 /* Bad conversion. */
1386 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1389 return NT_STATUS_OK
;
1392 /*******************************************************************
1393 Given a filename - get its directory name
1394 ********************************************************************/
1396 static bool windows_parent_dirname(TALLOC_CTX
*mem_ctx
,
1404 p
= strrchr_m(dir
, '\\'); /* Find final '\\', if any */
1407 if (!(*parent
= talloc_strdup(mem_ctx
, "\\"))) {
1418 if (!(*parent
= (char *)talloc_memdup(mem_ctx
, dir
, len
+1))) {
1421 (*parent
)[len
] = '\0';
1429 struct cli_smb2_list_dir_data
{
1434 struct cli_smb2_list_state
{
1435 struct tevent_context
*ev
;
1436 struct cli_state
*cli
;
1442 struct cli_smb2_list_dir_data
*response
;
1444 unsigned int info_level
;
1447 static void cli_smb2_list_opened(struct tevent_req
*subreq
);
1448 static void cli_smb2_list_done(struct tevent_req
*subreq
);
1449 static void cli_smb2_list_closed(struct tevent_req
*subreq
);
1451 struct tevent_req
*cli_smb2_list_send(
1452 TALLOC_CTX
*mem_ctx
,
1453 struct tevent_context
*ev
,
1454 struct cli_state
*cli
,
1455 const char *pathname
,
1456 unsigned int info_level
)
1458 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1459 struct cli_smb2_list_state
*state
= NULL
;
1460 char *parent
= NULL
;
1462 struct smb2_create_blobs
*in_cblobs
= NULL
;
1464 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_list_state
);
1470 state
->status
= NT_STATUS_OK
;
1471 state
->info_level
= info_level
;
1473 ok
= windows_parent_dirname(state
, pathname
, &parent
, &state
->mask
);
1475 tevent_req_oom(req
);
1476 return tevent_req_post(req
, ev
);
1479 if (smbXcli_conn_have_posix(cli
->conn
) &&
1480 info_level
== SMB2_FIND_POSIX_INFORMATION
)
1484 /* The mode MUST be 0 when opening an existing file/dir, and
1485 * will be ignored by the server.
1487 uint8_t linear_mode
[4] = { 0 };
1488 DATA_BLOB blob
= { .data
=linear_mode
,
1489 .length
=sizeof(linear_mode
) };
1491 in_cblobs
= talloc_zero(mem_ctx
, struct smb2_create_blobs
);
1492 if (in_cblobs
== NULL
) {
1496 status
= smb2_create_blob_add(in_cblobs
, in_cblobs
,
1497 SMB2_CREATE_TAG_POSIX
, blob
);
1498 if (tevent_req_nterror(req
, status
)) {
1499 tevent_req_nterror(req
, status
);
1500 return tevent_req_post(req
, ev
);
1504 subreq
= cli_smb2_create_fnum_send(
1505 state
, /* mem_ctx */
1509 (struct cli_smb2_create_flags
){0}, /* create_flags */
1510 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation_level */
1511 SEC_DIR_LIST
|SEC_DIR_READ_ATTRIBUTE
, /* desired_access */
1512 FILE_ATTRIBUTE_DIRECTORY
, /* file_attributes */
1513 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
1514 FILE_OPEN
, /* create_disposition */
1515 FILE_DIRECTORY_FILE
, /* create_options */
1516 in_cblobs
); /* in_cblobs */
1517 TALLOC_FREE(in_cblobs
);
1518 if (tevent_req_nomem(subreq
, req
)) {
1519 return tevent_req_post(req
, ev
);
1521 tevent_req_set_callback(subreq
, cli_smb2_list_opened
, req
);
1525 static void cli_smb2_list_opened(struct tevent_req
*subreq
)
1527 struct tevent_req
*req
= tevent_req_callback_data(
1528 subreq
, struct tevent_req
);
1529 struct cli_smb2_list_state
*state
= tevent_req_data(
1530 req
, struct cli_smb2_list_state
);
1533 status
= cli_smb2_create_fnum_recv(
1534 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
1535 TALLOC_FREE(subreq
);
1536 if (tevent_req_nterror(req
, status
)) {
1541 * Make our caller get back to us via cli_smb2_list_recv(),
1542 * triggering the smb2_query_directory_send()
1544 tevent_req_defer_callback(req
, state
->ev
);
1545 tevent_req_notify_callback(req
);
1548 static void cli_smb2_list_done(struct tevent_req
*subreq
)
1550 struct tevent_req
*req
= tevent_req_callback_data(
1551 subreq
, struct tevent_req
);
1552 struct cli_smb2_list_state
*state
= tevent_req_data(
1553 req
, struct cli_smb2_list_state
);
1554 struct cli_smb2_list_dir_data
*response
= NULL
;
1556 response
= talloc(state
, struct cli_smb2_list_dir_data
);
1557 if (tevent_req_nomem(response
, req
)) {
1561 state
->status
= smb2cli_query_directory_recv(
1562 subreq
, response
, &response
->data
, &response
->length
);
1563 TALLOC_FREE(subreq
);
1565 if (NT_STATUS_IS_OK(state
->status
)) {
1566 state
->response
= response
;
1569 tevent_req_defer_callback(req
, state
->ev
);
1570 tevent_req_notify_callback(req
);
1574 TALLOC_FREE(response
);
1576 subreq
= cli_smb2_close_fnum_send(state
,
1581 if (tevent_req_nomem(subreq
, req
)) {
1584 tevent_req_set_callback(subreq
, cli_smb2_list_closed
, req
);
1587 static void cli_smb2_list_closed(struct tevent_req
*subreq
)
1589 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
1590 tevent_req_simple_finish_ntstatus(subreq
, status
);
1594 * Return the next finfo directory.
1596 * This parses the blob returned from QUERY_DIRECTORY step by step. If
1597 * the blob ends, this triggers a fresh QUERY_DIRECTORY and returns
1598 * NT_STATUS_RETRY, which will then trigger the caller again when the
1599 * QUERY_DIRECTORY has returned with another buffer. This way we
1600 * guarantee that no asynchronous request is open after this call
1601 * returns an entry, so that other synchronous requests can be issued
1602 * on the same connection while the directory listing proceeds.
1604 NTSTATUS
cli_smb2_list_recv(
1605 struct tevent_req
*req
,
1606 TALLOC_CTX
*mem_ctx
,
1607 struct file_info
**pfinfo
)
1609 struct cli_smb2_list_state
*state
= tevent_req_data(
1610 req
, struct cli_smb2_list_state
);
1611 struct cli_smb2_list_dir_data
*response
= NULL
;
1612 struct file_info
*finfo
= NULL
;
1614 uint32_t next_offset
= 0;
1617 in_progress
= tevent_req_is_in_progress(req
);
1620 if (!tevent_req_is_nterror(req
, &status
)) {
1621 status
= NT_STATUS_NO_MORE_FILES
;
1626 response
= state
->response
;
1627 if (response
== NULL
) {
1628 struct tevent_req
*subreq
= NULL
;
1629 struct cli_state
*cli
= state
->cli
;
1630 struct smb2_hnd
*ph
= NULL
;
1631 uint32_t max_trans
, max_avail_len
;
1634 if (!NT_STATUS_IS_OK(state
->status
)) {
1635 status
= state
->status
;
1639 status
= map_fnum_to_smb2_handle(cli
, state
->fnum
, &ph
);
1640 if (!NT_STATUS_IS_OK(status
)) {
1644 max_trans
= smb2cli_conn_max_trans_size(cli
->conn
);
1645 ok
= smb2cli_conn_req_possible(cli
->conn
, &max_avail_len
);
1647 max_trans
= MIN(max_trans
, max_avail_len
);
1650 subreq
= smb2cli_query_directory_send(
1651 state
, /* mem_ctx */
1653 cli
->conn
, /* conn */
1654 cli
->timeout
, /* timeout_msec */
1655 cli
->smb2
.session
, /* session */
1656 cli
->smb2
.tcon
, /* tcon */
1657 state
->info_level
, /* level */
1660 ph
->fid_persistent
, /* fid_persistent */
1661 ph
->fid_volatile
, /* fid_volatile */
1662 state
->mask
, /* mask */
1663 max_trans
); /* outbuf_len */
1664 if (subreq
== NULL
) {
1665 status
= NT_STATUS_NO_MEMORY
;
1668 tevent_req_set_callback(subreq
, cli_smb2_list_done
, req
);
1669 return NT_STATUS_RETRY
;
1672 SMB_ASSERT(response
->length
> state
->offset
);
1674 finfo
= talloc_zero(mem_ctx
, struct file_info
);
1675 if (finfo
== NULL
) {
1676 status
= NT_STATUS_NO_MEMORY
;
1680 if (state
->info_level
== SMB2_FIND_POSIX_INFORMATION
) {
1681 status
= parse_finfo_posix_info(
1682 response
->data
+ state
->offset
,
1683 response
->length
- state
->offset
,
1687 status
= parse_finfo_id_both_directory_info(
1688 response
->data
+ state
->offset
,
1689 response
->length
- state
->offset
,
1693 if (!NT_STATUS_IS_OK(status
)) {
1697 status
= is_bad_finfo_name(state
->cli
, finfo
);
1698 if (!NT_STATUS_IS_OK(status
)) {
1703 * parse_finfo_id_both_directory_info() checks for overflow,
1704 * no need to check again here.
1706 state
->offset
+= next_offset
;
1708 if (next_offset
== 0) {
1709 TALLOC_FREE(state
->response
);
1712 tevent_req_defer_callback(req
, state
->ev
);
1713 tevent_req_notify_callback(req
);
1716 return NT_STATUS_OK
;
1720 tevent_req_received(req
);
1724 /***************************************************************
1725 Wrapper that allows SMB2 to query a path info (basic level).
1727 ***************************************************************/
1729 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
1731 SMB_STRUCT_STAT
*sbuf
,
1732 uint32_t *attributes
)
1735 struct smb_create_returns cr
;
1736 uint16_t fnum
= 0xffff;
1737 size_t namelen
= strlen(name
);
1739 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1741 * Can't use sync call while an async call is in flight
1743 return NT_STATUS_INVALID_PARAMETER
;
1746 /* SMB2 is pickier about pathnames. Ensure it doesn't
1748 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1749 char *modname
= talloc_strndup(talloc_tos(), name
, namelen
-1);
1750 if (modname
== NULL
) {
1751 return NT_STATUS_NO_MEMORY
;
1756 /* This is commonly used as a 'cd'. Try qpathinfo on
1757 a directory handle first. */
1759 status
= cli_smb2_create_fnum(cli
,
1761 (struct cli_smb2_create_flags
){0},
1762 SMB2_IMPERSONATION_IMPERSONATION
,
1763 FILE_READ_ATTRIBUTES
, /* desired_access */
1764 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1765 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1766 FILE_OPEN
, /* create_disposition */
1767 FILE_DIRECTORY_FILE
, /* create_options */
1774 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
1775 /* Maybe a file ? */
1776 status
= cli_smb2_create_fnum(cli
,
1778 (struct cli_smb2_create_flags
){0},
1779 SMB2_IMPERSONATION_IMPERSONATION
,
1780 FILE_READ_ATTRIBUTES
, /* desired_access */
1781 0, /* file attributes */
1782 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1783 FILE_OPEN
, /* create_disposition */
1784 0, /* create_options */
1792 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
1793 /* Maybe a reparse point ? */
1794 status
= cli_smb2_create_fnum(cli
,
1796 (struct cli_smb2_create_flags
){0},
1797 SMB2_IMPERSONATION_IMPERSONATION
,
1798 FILE_READ_ATTRIBUTES
, /* desired_access */
1799 0, /* file attributes */
1800 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1801 FILE_OPEN
, /* create_disposition */
1802 FILE_OPEN_REPARSE_POINT
, /* create_options */
1810 if (!NT_STATUS_IS_OK(status
)) {
1814 status
= cli_smb2_close_fnum(cli
, fnum
);
1818 sbuf
->st_ex_atime
= nt_time_to_unix_timespec(cr
.last_access_time
);
1819 sbuf
->st_ex_mtime
= nt_time_to_unix_timespec(cr
.last_write_time
);
1820 sbuf
->st_ex_ctime
= nt_time_to_unix_timespec(cr
.change_time
);
1821 sbuf
->st_ex_size
= cr
.end_of_file
;
1822 *attributes
= cr
.file_attributes
;
1827 struct cli_smb2_query_info_fnum_state
{
1831 static void cli_smb2_query_info_fnum_done(struct tevent_req
*subreq
);
1833 struct tevent_req
*cli_smb2_query_info_fnum_send(
1834 TALLOC_CTX
*mem_ctx
,
1835 struct tevent_context
*ev
,
1836 struct cli_state
*cli
,
1838 uint8_t in_info_type
,
1839 uint8_t in_info_class
,
1840 uint32_t in_max_output_length
,
1841 const DATA_BLOB
*in_input_buffer
,
1842 uint32_t in_additional_info
,
1845 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1846 struct cli_smb2_query_info_fnum_state
*state
= NULL
;
1847 struct smb2_hnd
*ph
= NULL
;
1850 req
= tevent_req_create(
1851 mem_ctx
, &state
, struct cli_smb2_query_info_fnum_state
);
1856 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
1857 if (tevent_req_nterror(req
, status
)) {
1858 return tevent_req_post(req
, ev
);
1861 subreq
= smb2cli_query_info_send(
1870 in_max_output_length
,
1876 if (tevent_req_nomem(subreq
, req
)) {
1877 return tevent_req_post(req
, ev
);
1879 tevent_req_set_callback(subreq
, cli_smb2_query_info_fnum_done
, req
);
1883 static void cli_smb2_query_info_fnum_done(struct tevent_req
*subreq
)
1885 struct tevent_req
*req
= tevent_req_callback_data(
1886 subreq
, struct tevent_req
);
1887 struct cli_smb2_query_info_fnum_state
*state
= tevent_req_data(
1888 req
, struct cli_smb2_query_info_fnum_state
);
1892 status
= smb2cli_query_info_recv(subreq
, state
, &outbuf
);
1893 TALLOC_FREE(subreq
);
1894 if (tevent_req_nterror(req
, status
)) {
1899 * We have to dup the memory here because outbuf.data is not
1900 * returned as a talloc object by smb2cli_query_info_recv.
1901 * It's a pointer into the received buffer.
1903 state
->outbuf
= data_blob_dup_talloc(state
, outbuf
);
1905 if ((outbuf
.length
!= 0) &&
1906 tevent_req_nomem(state
->outbuf
.data
, req
)) {
1909 tevent_req_done(req
);
1912 NTSTATUS
cli_smb2_query_info_fnum_recv(
1913 struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
, DATA_BLOB
*outbuf
)
1915 struct cli_smb2_query_info_fnum_state
*state
= tevent_req_data(
1916 req
, struct cli_smb2_query_info_fnum_state
);
1919 if (tevent_req_is_nterror(req
, &status
)) {
1922 *outbuf
= (DATA_BLOB
) {
1923 .data
= talloc_move(mem_ctx
, &state
->outbuf
.data
),
1924 .length
= state
->outbuf
.length
,
1926 return NT_STATUS_OK
;
1929 NTSTATUS
cli_smb2_query_info_fnum(
1930 struct cli_state
*cli
,
1932 uint8_t in_info_type
,
1933 uint8_t in_info_class
,
1934 uint32_t in_max_output_length
,
1935 const DATA_BLOB
*in_input_buffer
,
1936 uint32_t in_additional_info
,
1938 TALLOC_CTX
*mem_ctx
,
1941 TALLOC_CTX
*frame
= talloc_stackframe();
1942 struct tevent_context
*ev
= NULL
;
1943 struct tevent_req
*req
= NULL
;
1944 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1947 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1949 * Can't use sync call while an async call is in flight
1951 status
= NT_STATUS_INVALID_PARAMETER
;
1954 ev
= samba_tevent_context_init(frame
);
1958 req
= cli_smb2_query_info_fnum_send(
1965 in_max_output_length
,
1972 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
1976 status
= cli_smb2_query_info_fnum_recv(req
, mem_ctx
, outbuf
);
1982 /***************************************************************
1983 Helper function for pathname operations.
1984 ***************************************************************/
1986 struct get_fnum_from_path_state
{
1987 struct tevent_context
*ev
;
1988 struct cli_state
*cli
;
1990 uint32_t desired_access
;
1994 static void get_fnum_from_path_opened_file(struct tevent_req
*subreq
);
1995 static void get_fnum_from_path_opened_reparse(struct tevent_req
*subreq
);
1996 static void get_fnum_from_path_opened_dir(struct tevent_req
*subreq
);
1998 static struct tevent_req
*get_fnum_from_path_send(
1999 TALLOC_CTX
*mem_ctx
,
2000 struct tevent_context
*ev
,
2001 struct cli_state
*cli
,
2003 uint32_t desired_access
)
2005 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
2006 struct get_fnum_from_path_state
*state
= NULL
;
2007 size_t namelen
= strlen(name
);
2009 req
= tevent_req_create(
2010 mem_ctx
, &state
, struct get_fnum_from_path_state
);
2017 state
->desired_access
= desired_access
;
2020 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
2023 if (namelen
> 0 && name
[namelen
-1] == '\\') {
2024 state
->name
= talloc_strndup(state
, name
, namelen
-1);
2025 if (tevent_req_nomem(state
->name
, req
)) {
2026 return tevent_req_post(req
, ev
);
2030 subreq
= cli_smb2_create_fnum_send(
2031 state
, /* mem_ctx, */
2034 state
->name
, /* fname */
2035 (struct cli_smb2_create_flags
){0}, /* create_flags */
2036 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation_level */
2037 desired_access
, /* desired_access */
2038 0, /* file_attributes */
2041 FILE_SHARE_DELETE
, /* share_access */
2042 FILE_OPEN
, /* create_disposition */
2043 0, /* create_options */
2044 NULL
); /* in_cblobs */
2045 if (tevent_req_nomem(subreq
, req
)) {
2046 return tevent_req_post(req
, ev
);
2048 tevent_req_set_callback(subreq
, get_fnum_from_path_opened_file
, req
);
2052 static void get_fnum_from_path_opened_file(struct tevent_req
*subreq
)
2054 struct tevent_req
*req
= tevent_req_callback_data(
2055 subreq
, struct tevent_req
);
2056 struct get_fnum_from_path_state
*state
= tevent_req_data(
2057 req
, struct get_fnum_from_path_state
);
2060 status
= cli_smb2_create_fnum_recv(
2061 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
2062 TALLOC_FREE(subreq
);
2064 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
) ||
2065 NT_STATUS_EQUAL(status
, NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED
)) {
2067 * Naive option to match our SMB1 code. Assume the
2068 * symlink path that tripped us up was the last
2069 * component and try again. Eventually we will have to
2070 * deal with the returned path unprocessed component. JRA.
2072 subreq
= cli_smb2_create_fnum_send(
2073 state
, /* mem_ctx, */
2075 state
->cli
, /* cli */
2076 state
->name
, /* fname */
2077 (struct cli_smb2_create_flags
){0}, /* create_flags */
2078 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation */
2079 state
->desired_access
, /* desired_access */
2080 0, /* file_attributes */
2083 FILE_SHARE_DELETE
, /* share_access */
2084 FILE_OPEN
, /* create_disposition */
2085 FILE_OPEN_REPARSE_POINT
, /* create_options */
2086 NULL
); /* in_cblobs */
2087 if (tevent_req_nomem(subreq
, req
)) {
2090 tevent_req_set_callback(
2091 subreq
, get_fnum_from_path_opened_reparse
, req
);
2095 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
2096 subreq
= cli_smb2_create_fnum_send(
2097 state
, /* mem_ctx, */
2099 state
->cli
, /* cli */
2100 state
->name
, /* fname */
2101 (struct cli_smb2_create_flags
){0}, /* create_flags */
2102 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation */
2103 state
->desired_access
, /* desired_access */
2104 0, /* file_attributes */
2107 FILE_SHARE_DELETE
, /* share_access */
2108 FILE_OPEN
, /* create_disposition */
2109 FILE_DIRECTORY_FILE
, /* create_options */
2110 NULL
); /* in_cblobs */
2111 if (tevent_req_nomem(subreq
, req
)) {
2114 tevent_req_set_callback(
2115 subreq
, get_fnum_from_path_opened_dir
, req
);
2119 if (tevent_req_nterror(req
, status
)) {
2122 tevent_req_done(req
);
2125 static void get_fnum_from_path_opened_reparse(struct tevent_req
*subreq
)
2127 struct tevent_req
*req
= tevent_req_callback_data(
2128 subreq
, struct tevent_req
);
2129 struct get_fnum_from_path_state
*state
= tevent_req_data(
2130 req
, struct get_fnum_from_path_state
);
2131 NTSTATUS status
= cli_smb2_create_fnum_recv(
2132 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
2133 tevent_req_simple_finish_ntstatus(subreq
, status
);
2136 static void get_fnum_from_path_opened_dir(struct tevent_req
*subreq
)
2138 /* Abstraction violation, but these two are just the same... */
2139 get_fnum_from_path_opened_reparse(subreq
);
2142 static NTSTATUS
get_fnum_from_path_recv(
2143 struct tevent_req
*req
, uint16_t *pfnum
)
2145 struct get_fnum_from_path_state
*state
= tevent_req_data(
2146 req
, struct get_fnum_from_path_state
);
2147 NTSTATUS status
= NT_STATUS_OK
;
2149 if (!tevent_req_is_nterror(req
, &status
)) {
2150 *pfnum
= state
->fnum
;
2152 tevent_req_received(req
);
2156 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
2158 uint32_t desired_access
,
2161 TALLOC_CTX
*frame
= talloc_stackframe();
2162 struct tevent_context
*ev
= NULL
;
2163 struct tevent_req
*req
= NULL
;
2164 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
2166 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2167 status
= NT_STATUS_INVALID_PARAMETER
;
2170 ev
= samba_tevent_context_init(frame
);
2174 req
= get_fnum_from_path_send(frame
, ev
, cli
, name
, desired_access
);
2178 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2181 status
= get_fnum_from_path_recv(req
, pfnum
);
2187 struct cli_smb2_qpathinfo_state
{
2188 struct tevent_context
*ev
;
2189 struct cli_state
*cli
;
2200 static void cli_smb2_qpathinfo_opened(struct tevent_req
*subreq
);
2201 static void cli_smb2_qpathinfo_done(struct tevent_req
*subreq
);
2202 static void cli_smb2_qpathinfo_closed(struct tevent_req
*subreq
);
2204 struct tevent_req
*cli_smb2_qpathinfo_send(TALLOC_CTX
*mem_ctx
,
2205 struct tevent_context
*ev
,
2206 struct cli_state
*cli
,
2212 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
2213 struct cli_smb2_qpathinfo_state
*state
= NULL
;
2215 req
= tevent_req_create(mem_ctx
,
2217 struct cli_smb2_qpathinfo_state
);
2223 state
->level
= level
;
2224 state
->min_rdata
= min_rdata
;
2225 state
->max_rdata
= max_rdata
;
2227 subreq
= get_fnum_from_path_send(state
,
2231 FILE_READ_ATTRIBUTES
);
2232 if (tevent_req_nomem(subreq
, req
)) {
2233 return tevent_req_post(req
, ev
);
2235 tevent_req_set_callback(subreq
, cli_smb2_qpathinfo_opened
, req
);
2239 static void cli_smb2_qpathinfo_opened(struct tevent_req
*subreq
)
2241 struct tevent_req
*req
=
2242 tevent_req_callback_data(subreq
, struct tevent_req
);
2243 struct cli_smb2_qpathinfo_state
*state
=
2244 tevent_req_data(req
, struct cli_smb2_qpathinfo_state
);
2247 status
= get_fnum_from_path_recv(subreq
, &state
->fnum
);
2248 TALLOC_FREE(subreq
);
2249 if (tevent_req_nterror(req
, status
)) {
2253 subreq
= cli_smb2_query_info_fnum_send(state
,
2257 1, /* in_info_type */
2260 NULL
, /* in_input_buffer */
2261 0, /* in_additional_info */
2263 if (tevent_req_nomem(subreq
, req
)) {
2266 tevent_req_set_callback(subreq
, cli_smb2_qpathinfo_done
, req
);
2269 static void cli_smb2_qpathinfo_done(struct tevent_req
*subreq
)
2271 struct tevent_req
*req
=
2272 tevent_req_callback_data(subreq
, struct tevent_req
);
2273 struct cli_smb2_qpathinfo_state
*state
=
2274 tevent_req_data(req
, struct cli_smb2_qpathinfo_state
);
2277 cli_smb2_query_info_fnum_recv(subreq
, state
, &state
->out
);
2278 TALLOC_FREE(subreq
);
2280 if (NT_STATUS_IS_OK(state
->status
) &&
2281 (state
->out
.length
< state
->min_rdata
)) {
2282 state
->status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2285 subreq
= cli_smb2_close_fnum_send(state
,
2290 if (tevent_req_nomem(subreq
, req
)) {
2293 tevent_req_set_callback(subreq
, cli_smb2_qpathinfo_closed
, req
);
2296 static void cli_smb2_qpathinfo_closed(struct tevent_req
*subreq
)
2298 struct tevent_req
*req
=
2299 tevent_req_callback_data(subreq
, struct tevent_req
);
2300 struct cli_smb2_qpathinfo_state
*state
=
2301 tevent_req_data(req
, struct cli_smb2_qpathinfo_state
);
2304 status
= cli_smb2_close_fnum_recv(subreq
);
2305 TALLOC_FREE(subreq
);
2306 if (tevent_req_nterror(req
, status
)) {
2309 if (tevent_req_nterror(req
, state
->status
)) {
2312 tevent_req_done(req
);
2315 NTSTATUS
cli_smb2_qpathinfo_recv(struct tevent_req
*req
,
2316 TALLOC_CTX
*mem_ctx
,
2318 uint32_t *num_rdata
)
2320 struct cli_smb2_qpathinfo_state
*state
=
2321 tevent_req_data(req
, struct cli_smb2_qpathinfo_state
);
2324 if (tevent_req_is_nterror(req
, &status
)) {
2328 *rdata
= talloc_move(mem_ctx
, &state
->out
.data
);
2329 *num_rdata
= state
->out
.length
;
2330 tevent_req_received(req
);
2331 return NT_STATUS_OK
;
2334 /***************************************************************
2335 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2338 ***************************************************************/
2340 NTSTATUS
cli_smb2_setpathinfo(struct cli_state
*cli
,
2342 uint8_t in_info_type
,
2343 uint8_t in_file_info_class
,
2344 const DATA_BLOB
*p_in_data
)
2347 uint16_t fnum
= 0xffff;
2348 TALLOC_CTX
*frame
= talloc_stackframe();
2350 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2352 * Can't use sync call while an async call is in flight
2354 status
= NT_STATUS_INVALID_PARAMETER
;
2358 status
= get_fnum_from_path(cli
,
2360 FILE_WRITE_ATTRIBUTES
,
2363 if (!NT_STATUS_IS_OK(status
)) {
2367 status
= cli_smb2_set_info_fnum(
2372 p_in_data
, /* in_input_buffer */
2373 0); /* in_additional_info */
2376 if (fnum
!= 0xffff) {
2377 cli_smb2_close_fnum(cli
, fnum
);
2380 cli
->raw_status
= status
;
2387 /***************************************************************
2388 Wrapper that allows SMB2 to set pathname attributes.
2390 ***************************************************************/
2392 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
2397 uint8_t inbuf_store
[40];
2398 DATA_BLOB inbuf
= data_blob_null
;
2400 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2401 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2403 inbuf
.data
= inbuf_store
;
2404 inbuf
.length
= sizeof(inbuf_store
);
2405 data_blob_clear(&inbuf
);
2408 * SMB1 uses attr == 0 to clear all attributes
2409 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2410 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2411 * request attribute change.
2413 * SMB2 uses exactly the reverse. Unfortunately as the
2414 * cli_setatr() ABI is exposed inside libsmbclient,
2415 * we must make the SMB2 cli_smb2_setatr() call
2416 * export the same ABI as the SMB1 cli_setatr()
2417 * which calls it. This means reversing the sense
2418 * of the requested attr argument if it's zero
2419 * or FILE_ATTRIBUTE_NORMAL.
2421 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2425 attr
= FILE_ATTRIBUTE_NORMAL
;
2426 } else if (attr
== FILE_ATTRIBUTE_NORMAL
) {
2430 SIVAL(inbuf
.data
, 32, attr
);
2432 put_long_date((char *)inbuf
.data
+ 16,mtime
);
2434 /* Set all the other times to -1. */
2435 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
2436 SBVAL(inbuf
.data
, 8, 0xFFFFFFFFFFFFFFFFLL
);
2437 SBVAL(inbuf
.data
, 24, 0xFFFFFFFFFFFFFFFFLL
);
2439 return cli_smb2_setpathinfo(cli
,
2441 1, /* in_info_type */
2442 /* in_file_info_class */
2443 SMB_FILE_BASIC_INFORMATION
- 1000,
2448 /***************************************************************
2449 Wrapper that allows SMB2 to set file handle times.
2451 ***************************************************************/
2453 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
2459 uint8_t inbuf_store
[40];
2460 DATA_BLOB inbuf
= data_blob_null
;
2463 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2465 * Can't use sync call while an async call is in flight
2467 return NT_STATUS_INVALID_PARAMETER
;
2470 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2471 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2473 inbuf
.data
= inbuf_store
;
2474 inbuf
.length
= sizeof(inbuf_store
);
2475 data_blob_clear(&inbuf
);
2477 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
2478 if (change_time
!= 0) {
2479 put_long_date((char *)inbuf
.data
+ 24, change_time
);
2481 if (access_time
!= 0) {
2482 put_long_date((char *)inbuf
.data
+ 8, access_time
);
2484 if (write_time
!= 0) {
2485 put_long_date((char *)inbuf
.data
+ 16, write_time
);
2488 status
= cli_smb2_set_info_fnum(cli
,
2490 1, /* in_info_type */
2491 SMB_FILE_BASIC_INFORMATION
-
2492 1000, /* in_file_info_class */
2493 &inbuf
, /* in_input_buffer */
2494 0); /* in_additional_info */
2495 cli
->raw_status
= status
;
2499 /***************************************************************
2500 Wrapper that allows SMB2 to query disk attributes (size).
2502 ***************************************************************/
2504 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, const char *path
,
2505 uint64_t *bsize
, uint64_t *total
, uint64_t *avail
)
2508 uint16_t fnum
= 0xffff;
2509 DATA_BLOB outbuf
= data_blob_null
;
2510 uint32_t sectors_per_unit
= 0;
2511 uint32_t bytes_per_sector
= 0;
2512 uint64_t total_size
= 0;
2513 uint64_t size_free
= 0;
2514 TALLOC_CTX
*frame
= talloc_stackframe();
2516 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2518 * Can't use sync call while an async call is in flight
2520 status
= NT_STATUS_INVALID_PARAMETER
;
2524 /* First open the top level directory. */
2525 status
= cli_smb2_create_fnum(cli
,
2527 (struct cli_smb2_create_flags
){0},
2528 SMB2_IMPERSONATION_IMPERSONATION
,
2529 FILE_READ_ATTRIBUTES
, /* desired_access */
2530 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2531 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
2532 FILE_OPEN
, /* create_disposition */
2533 FILE_DIRECTORY_FILE
, /* create_options */
2540 if (!NT_STATUS_IS_OK(status
)) {
2544 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2545 level 3 (SMB_FS_SIZE_INFORMATION). */
2547 status
= cli_smb2_query_info_fnum(
2550 2, /* in_info_type */
2551 3, /* in_file_info_class */
2552 0xFFFF, /* in_max_output_length */
2553 NULL
, /* in_input_buffer */
2554 0, /* in_additional_info */
2558 if (!NT_STATUS_IS_OK(status
)) {
2562 /* Parse the reply. */
2563 if (outbuf
.length
!= 24) {
2564 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2568 total_size
= BVAL(outbuf
.data
, 0);
2569 size_free
= BVAL(outbuf
.data
, 8);
2570 sectors_per_unit
= IVAL(outbuf
.data
, 16);
2571 bytes_per_sector
= IVAL(outbuf
.data
, 20);
2574 *bsize
= (uint64_t)sectors_per_unit
* (uint64_t)bytes_per_sector
;
2577 *total
= total_size
;
2583 status
= NT_STATUS_OK
;
2587 if (fnum
!= 0xffff) {
2588 cli_smb2_close_fnum(cli
, fnum
);
2591 cli
->raw_status
= status
;
2597 /***************************************************************
2598 Wrapper that allows SMB2 to query file system sizes.
2600 ***************************************************************/
2602 NTSTATUS
cli_smb2_get_fs_full_size_info(struct cli_state
*cli
,
2603 uint64_t *total_allocation_units
,
2604 uint64_t *caller_allocation_units
,
2605 uint64_t *actual_allocation_units
,
2606 uint64_t *sectors_per_allocation_unit
,
2607 uint64_t *bytes_per_sector
)
2610 uint16_t fnum
= 0xffff;
2611 DATA_BLOB outbuf
= data_blob_null
;
2612 TALLOC_CTX
*frame
= talloc_stackframe();
2614 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2616 * Can't use sync call while an async call is in flight
2618 status
= NT_STATUS_INVALID_PARAMETER
;
2622 /* First open the top level directory. */
2624 cli_smb2_create_fnum(cli
, "",
2625 (struct cli_smb2_create_flags
){0},
2626 SMB2_IMPERSONATION_IMPERSONATION
,
2627 FILE_READ_ATTRIBUTES
, /* desired_access */
2628 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2629 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2630 FILE_SHARE_DELETE
, /* share_access */
2631 FILE_OPEN
, /* create_disposition */
2632 FILE_DIRECTORY_FILE
, /* create_options */
2639 if (!NT_STATUS_IS_OK(status
)) {
2643 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2644 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2646 status
= cli_smb2_query_info_fnum(
2649 SMB2_0_INFO_FILESYSTEM
, /* in_info_type */
2650 SMB_FS_FULL_SIZE_INFORMATION
- 1000, /* in_file_info_class */
2651 0xFFFF, /* in_max_output_length */
2652 NULL
, /* in_input_buffer */
2653 0, /* in_additional_info */
2657 if (!NT_STATUS_IS_OK(status
)) {
2661 if (outbuf
.length
< 32) {
2662 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2666 *total_allocation_units
= BIG_UINT(outbuf
.data
, 0);
2667 *caller_allocation_units
= BIG_UINT(outbuf
.data
, 8);
2668 *actual_allocation_units
= BIG_UINT(outbuf
.data
, 16);
2669 *sectors_per_allocation_unit
= (uint64_t)IVAL(outbuf
.data
, 24);
2670 *bytes_per_sector
= (uint64_t)IVAL(outbuf
.data
, 28);
2674 if (fnum
!= 0xffff) {
2675 cli_smb2_close_fnum(cli
, fnum
);
2678 cli
->raw_status
= status
;
2684 /***************************************************************
2685 Wrapper that allows SMB2 to query file system attributes.
2687 ***************************************************************/
2689 NTSTATUS
cli_smb2_get_fs_attr_info(struct cli_state
*cli
, uint32_t *fs_attr
)
2692 uint16_t fnum
= 0xffff;
2693 DATA_BLOB outbuf
= data_blob_null
;
2694 TALLOC_CTX
*frame
= talloc_stackframe();
2696 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2698 * Can't use sync call while an async call is in flight
2700 status
= NT_STATUS_INVALID_PARAMETER
;
2704 /* First open the top level directory. */
2706 cli_smb2_create_fnum(cli
, "",
2707 (struct cli_smb2_create_flags
){0},
2708 SMB2_IMPERSONATION_IMPERSONATION
,
2709 FILE_READ_ATTRIBUTES
, /* desired_access */
2710 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2711 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2712 FILE_SHARE_DELETE
, /* share_access */
2713 FILE_OPEN
, /* create_disposition */
2714 FILE_DIRECTORY_FILE
, /* create_options */
2721 if (!NT_STATUS_IS_OK(status
)) {
2725 status
= cli_smb2_query_info_fnum(
2728 2, /* in_info_type */
2729 5, /* in_file_info_class */
2730 0xFFFF, /* in_max_output_length */
2731 NULL
, /* in_input_buffer */
2732 0, /* in_additional_info */
2736 if (!NT_STATUS_IS_OK(status
)) {
2740 if (outbuf
.length
< 12) {
2741 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2745 *fs_attr
= IVAL(outbuf
.data
, 0);
2749 if (fnum
!= 0xffff) {
2750 cli_smb2_close_fnum(cli
, fnum
);
2753 cli
->raw_status
= status
;
2759 /***************************************************************
2760 Wrapper that allows SMB2 to query file system volume info.
2762 ***************************************************************/
2764 NTSTATUS
cli_smb2_get_fs_volume_info(struct cli_state
*cli
,
2765 TALLOC_CTX
*mem_ctx
,
2766 char **_volume_name
,
2767 uint32_t *pserial_number
,
2771 uint16_t fnum
= 0xffff;
2772 DATA_BLOB outbuf
= data_blob_null
;
2774 char *volume_name
= NULL
;
2775 TALLOC_CTX
*frame
= talloc_stackframe();
2777 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2779 * Can't use sync call while an async call is in flight
2781 status
= NT_STATUS_INVALID_PARAMETER
;
2785 /* First open the top level directory. */
2787 cli_smb2_create_fnum(cli
, "",
2788 (struct cli_smb2_create_flags
){0},
2789 SMB2_IMPERSONATION_IMPERSONATION
,
2790 FILE_READ_ATTRIBUTES
, /* desired_access */
2791 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2792 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2793 FILE_SHARE_DELETE
, /* share_access */
2794 FILE_OPEN
, /* create_disposition */
2795 FILE_DIRECTORY_FILE
, /* create_options */
2802 if (!NT_STATUS_IS_OK(status
)) {
2806 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2807 level 1 (SMB_FS_VOLUME_INFORMATION). */
2809 status
= cli_smb2_query_info_fnum(
2812 SMB2_0_INFO_FILESYSTEM
, /* in_info_type */
2813 /* in_file_info_class */
2814 SMB_FS_VOLUME_INFORMATION
- 1000,
2815 0xFFFF, /* in_max_output_length */
2816 NULL
, /* in_input_buffer */
2817 0, /* in_additional_info */
2821 if (!NT_STATUS_IS_OK(status
)) {
2825 if (outbuf
.length
< 24) {
2826 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2832 ts
= interpret_long_date(BVAL(outbuf
.data
, 0));
2835 if (pserial_number
) {
2836 *pserial_number
= IVAL(outbuf
.data
,8);
2838 nlen
= IVAL(outbuf
.data
,12);
2839 if (nlen
+ 18 < 18) {
2841 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2845 * The next check is safe as we know outbuf.length >= 24
2848 if (nlen
> (outbuf
.length
- 18)) {
2849 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2853 pull_string_talloc(mem_ctx
,
2854 (const char *)outbuf
.data
,
2860 if (volume_name
== NULL
) {
2861 status
= map_nt_error_from_unix(errno
);
2865 *_volume_name
= volume_name
;
2869 if (fnum
!= 0xffff) {
2870 cli_smb2_close_fnum(cli
, fnum
);
2873 cli
->raw_status
= status
;
2879 struct cli_smb2_mxac_state
{
2880 struct tevent_context
*ev
;
2881 struct cli_state
*cli
;
2883 struct smb2_create_blobs in_cblobs
;
2889 static void cli_smb2_mxac_opened(struct tevent_req
*subreq
);
2890 static void cli_smb2_mxac_closed(struct tevent_req
*subreq
);
2892 struct tevent_req
*cli_smb2_query_mxac_send(TALLOC_CTX
*mem_ctx
,
2893 struct tevent_context
*ev
,
2894 struct cli_state
*cli
,
2897 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
2898 struct cli_smb2_mxac_state
*state
= NULL
;
2901 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_mxac_state
);
2905 *state
= (struct cli_smb2_mxac_state
) {
2911 status
= smb2_create_blob_add(state
,
2913 SMB2_CREATE_TAG_MXAC
,
2914 data_blob(NULL
, 0));
2915 if (tevent_req_nterror(req
, status
)) {
2916 return tevent_req_post(req
, ev
);
2919 subreq
= cli_smb2_create_fnum_send(
2924 (struct cli_smb2_create_flags
){0},
2925 SMB2_IMPERSONATION_IMPERSONATION
,
2926 FILE_READ_ATTRIBUTES
,
2927 0, /* file attributes */
2928 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
2930 0, /* create_options */
2932 if (tevent_req_nomem(subreq
, req
)) {
2933 return tevent_req_post(req
, ev
);
2935 tevent_req_set_callback(subreq
, cli_smb2_mxac_opened
, req
);
2939 static void cli_smb2_mxac_opened(struct tevent_req
*subreq
)
2941 struct tevent_req
*req
= tevent_req_callback_data(
2942 subreq
, struct tevent_req
);
2943 struct cli_smb2_mxac_state
*state
= tevent_req_data(
2944 req
, struct cli_smb2_mxac_state
);
2945 struct smb2_create_blobs out_cblobs
= {0};
2946 struct smb2_create_blob
*mxac_blob
= NULL
;
2949 status
= cli_smb2_create_fnum_recv(
2950 subreq
, &state
->fnum
, NULL
, state
, &out_cblobs
, NULL
);
2951 TALLOC_FREE(subreq
);
2953 if (tevent_req_nterror(req
, status
)) {
2957 mxac_blob
= smb2_create_blob_find(&out_cblobs
, SMB2_CREATE_TAG_MXAC
);
2958 if (mxac_blob
== NULL
) {
2959 state
->status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2962 if (mxac_blob
->data
.length
!= 8) {
2963 state
->status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2967 state
->status
= NT_STATUS(IVAL(mxac_blob
->data
.data
, 0));
2968 state
->mxac
= IVAL(mxac_blob
->data
.data
, 4);
2971 subreq
= cli_smb2_close_fnum_send(state
,
2976 if (tevent_req_nomem(subreq
, req
)) {
2979 tevent_req_set_callback(subreq
, cli_smb2_mxac_closed
, req
);
2984 static void cli_smb2_mxac_closed(struct tevent_req
*subreq
)
2986 struct tevent_req
*req
= tevent_req_callback_data(
2987 subreq
, struct tevent_req
);
2990 status
= cli_smb2_close_fnum_recv(subreq
);
2991 if (tevent_req_nterror(req
, status
)) {
2995 tevent_req_done(req
);
2998 NTSTATUS
cli_smb2_query_mxac_recv(struct tevent_req
*req
, uint32_t *mxac
)
3000 struct cli_smb2_mxac_state
*state
= tevent_req_data(
3001 req
, struct cli_smb2_mxac_state
);
3004 if (tevent_req_is_nterror(req
, &status
)) {
3008 if (!NT_STATUS_IS_OK(state
->status
)) {
3009 return state
->status
;
3012 *mxac
= state
->mxac
;
3013 return NT_STATUS_OK
;
3016 NTSTATUS
cli_smb2_query_mxac(struct cli_state
*cli
,
3020 TALLOC_CTX
*frame
= talloc_stackframe();
3021 struct tevent_context
*ev
= NULL
;
3022 struct tevent_req
*req
= NULL
;
3023 NTSTATUS status
= NT_STATUS_INTERNAL_ERROR
;
3026 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3028 * Can't use sync call while an async call is in flight
3030 status
= NT_STATUS_INVALID_PARAMETER
;
3034 ev
= samba_tevent_context_init(frame
);
3038 req
= cli_smb2_query_mxac_send(frame
, ev
, cli
, fname
);
3042 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
3046 status
= cli_smb2_query_mxac_recv(req
, _mxac
);
3049 cli
->raw_status
= status
;
3054 struct cli_smb2_rename_fnum_state
{
3058 static void cli_smb2_rename_fnum_done(struct tevent_req
*subreq
);
3060 static struct tevent_req
*cli_smb2_rename_fnum_send(
3061 TALLOC_CTX
*mem_ctx
,
3062 struct tevent_context
*ev
,
3063 struct cli_state
*cli
,
3065 const char *fname_dst
,
3068 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
3069 struct cli_smb2_rename_fnum_state
*state
= NULL
;
3070 size_t namelen
= strlen(fname_dst
);
3071 smb_ucs2_t
*converted_str
= NULL
;
3072 size_t converted_size_bytes
= 0;
3076 req
= tevent_req_create(
3077 mem_ctx
, &state
, struct cli_smb2_rename_fnum_state
);
3083 * SMB2 is pickier about pathnames. Ensure it doesn't start in
3086 if (*fname_dst
== '\\') {
3091 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
3094 if (namelen
> 0 && fname_dst
[namelen
-1] == '\\') {
3095 fname_dst
= talloc_strndup(state
, fname_dst
, namelen
-1);
3096 if (tevent_req_nomem(fname_dst
, req
)) {
3097 return tevent_req_post(req
, ev
);
3101 ok
= push_ucs2_talloc(
3102 state
, &converted_str
, fname_dst
, &converted_size_bytes
);
3104 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3105 return tevent_req_post(req
, ev
);
3109 * W2K8 insists the dest name is not null terminated. Remove
3110 * the last 2 zero bytes and reduce the name length.
3112 if (converted_size_bytes
< 2) {
3113 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3114 return tevent_req_post(req
, ev
);
3116 converted_size_bytes
-= 2;
3118 inbuf_size
= 20 + converted_size_bytes
;
3119 if (inbuf_size
< 20) {
3120 /* Integer wrap check. */
3121 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3122 return tevent_req_post(req
, ev
);
3126 * The Windows 10 SMB2 server has a minimum length
3127 * for a SMB2_FILE_RENAME_INFORMATION buffer of
3128 * 24 bytes. It returns NT_STATUS_INFO_LENGTH_MISMATCH
3129 * if the length is less. This isn't an alignment
3130 * issue as Windows client accepts happily 2-byte align
3131 * for larger target name sizes. Also the Windows 10
3132 * SMB1 server doesn't have this restriction.
3134 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14403
3136 inbuf_size
= MAX(inbuf_size
, 24);
3138 state
->inbuf
= data_blob_talloc_zero(state
, inbuf_size
);
3139 if (tevent_req_nomem(state
->inbuf
.data
, req
)) {
3140 return tevent_req_post(req
, ev
);
3144 SCVAL(state
->inbuf
.data
, 0, 1);
3147 SIVAL(state
->inbuf
.data
, 16, converted_size_bytes
);
3148 memcpy(state
->inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
3150 TALLOC_FREE(converted_str
);
3152 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3153 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3155 subreq
= cli_smb2_set_info_fnum_send(
3156 state
, /* mem_ctx */
3160 1, /* in_info_type */
3161 SMB_FILE_RENAME_INFORMATION
- 1000, /* in_file_info_class */
3162 &state
->inbuf
, /* in_input_buffer */
3163 0); /* in_additional_info */
3164 if (tevent_req_nomem(subreq
, req
)) {
3165 return tevent_req_post(req
, ev
);
3167 tevent_req_set_callback(subreq
, cli_smb2_rename_fnum_done
, req
);
3171 static void cli_smb2_rename_fnum_done(struct tevent_req
*subreq
)
3173 NTSTATUS status
= cli_smb2_set_info_fnum_recv(subreq
);
3174 tevent_req_simple_finish_ntstatus(subreq
, status
);
3177 static NTSTATUS
cli_smb2_rename_fnum_recv(struct tevent_req
*req
)
3179 return tevent_req_simple_recv_ntstatus(req
);
3182 /***************************************************************
3183 Wrapper that allows SMB2 to rename a file.
3184 ***************************************************************/
3186 struct cli_smb2_rename_state
{
3187 struct tevent_context
*ev
;
3188 struct cli_state
*cli
;
3189 const char *fname_dst
;
3193 NTSTATUS rename_status
;
3196 static void cli_smb2_rename_opened(struct tevent_req
*subreq
);
3197 static void cli_smb2_rename_renamed(struct tevent_req
*subreq
);
3198 static void cli_smb2_rename_closed(struct tevent_req
*subreq
);
3200 struct tevent_req
*cli_smb2_rename_send(
3201 TALLOC_CTX
*mem_ctx
,
3202 struct tevent_context
*ev
,
3203 struct cli_state
*cli
,
3204 const char *fname_src
,
3205 const char *fname_dst
,
3208 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
3209 struct cli_smb2_rename_state
*state
= NULL
;
3212 req
= tevent_req_create(
3213 mem_ctx
, &state
, struct cli_smb2_rename_state
);
3219 * Strip a MSDFS path from fname_dst if we were given one.
3221 status
= cli_dfs_target_check(state
,
3225 if (tevent_req_nterror(req
, status
)) {
3226 return tevent_req_post(req
, ev
);
3231 state
->fname_dst
= fname_dst
;
3232 state
->replace
= replace
;
3234 subreq
= get_fnum_from_path_send(
3235 state
, ev
, cli
, fname_src
, DELETE_ACCESS
);
3236 if (tevent_req_nomem(subreq
, req
)) {
3237 return tevent_req_post(req
, ev
);
3239 tevent_req_set_callback(subreq
, cli_smb2_rename_opened
, req
);
3243 static void cli_smb2_rename_opened(struct tevent_req
*subreq
)
3245 struct tevent_req
*req
= tevent_req_callback_data(
3246 subreq
, struct tevent_req
);
3247 struct cli_smb2_rename_state
*state
= tevent_req_data(
3248 req
, struct cli_smb2_rename_state
);
3251 status
= get_fnum_from_path_recv(subreq
, &state
->fnum
);
3252 TALLOC_FREE(subreq
);
3253 if (tevent_req_nterror(req
, status
)) {
3257 subreq
= cli_smb2_rename_fnum_send(
3264 if (tevent_req_nomem(subreq
, req
)) {
3267 tevent_req_set_callback(subreq
, cli_smb2_rename_renamed
, req
);
3270 static void cli_smb2_rename_renamed(struct tevent_req
*subreq
)
3272 struct tevent_req
*req
= tevent_req_callback_data(
3273 subreq
, struct tevent_req
);
3274 struct cli_smb2_rename_state
*state
= tevent_req_data(
3275 req
, struct cli_smb2_rename_state
);
3277 state
->rename_status
= cli_smb2_rename_fnum_recv(subreq
);
3278 TALLOC_FREE(subreq
);
3280 subreq
= cli_smb2_close_fnum_send(state
,
3285 if (tevent_req_nomem(subreq
, req
)) {
3288 tevent_req_set_callback(subreq
, cli_smb2_rename_closed
, req
);
3291 static void cli_smb2_rename_closed(struct tevent_req
*subreq
)
3293 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
3294 tevent_req_simple_finish_ntstatus(subreq
, status
);
3297 NTSTATUS
cli_smb2_rename_recv(struct tevent_req
*req
)
3299 struct cli_smb2_rename_state
*state
= tevent_req_data(
3300 req
, struct cli_smb2_rename_state
);
3301 NTSTATUS status
= NT_STATUS_OK
;
3303 if (!tevent_req_is_nterror(req
, &status
)) {
3304 status
= state
->rename_status
;
3306 tevent_req_received(req
);
3310 /***************************************************************
3311 Wrapper that allows SMB2 to set an EA on a fnum.
3313 ***************************************************************/
3315 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
3317 const char *ea_name
,
3322 DATA_BLOB inbuf
= data_blob_null
;
3324 char *ea_name_ascii
= NULL
;
3326 TALLOC_CTX
*frame
= talloc_stackframe();
3328 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3330 * Can't use sync call while an async call is in flight
3332 status
= NT_STATUS_INVALID_PARAMETER
;
3336 /* Marshall the SMB2 EA data. */
3337 if (ea_len
> 0xFFFF) {
3338 status
= NT_STATUS_INVALID_PARAMETER
;
3342 if (!push_ascii_talloc(frame
,
3346 status
= NT_STATUS_INVALID_PARAMETER
;
3350 if (namelen
< 2 || namelen
> 0xFF) {
3351 status
= NT_STATUS_INVALID_PARAMETER
;
3355 bloblen
= 8 + ea_len
+ namelen
;
3356 /* Round up to a 4 byte boundary. */
3357 bloblen
= ((bloblen
+ 3)&~3);
3359 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
3360 if (inbuf
.data
== NULL
) {
3361 status
= NT_STATUS_NO_MEMORY
;
3364 /* namelen doesn't include the NULL byte. */
3365 SCVAL(inbuf
.data
, 5, namelen
- 1);
3366 SSVAL(inbuf
.data
, 6, ea_len
);
3367 memcpy(inbuf
.data
+ 8, ea_name_ascii
, namelen
);
3368 memcpy(inbuf
.data
+ 8 + namelen
, ea_val
, ea_len
);
3370 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3371 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3373 status
= cli_smb2_set_info_fnum(
3376 1, /* in_info_type */
3377 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
3378 &inbuf
, /* in_input_buffer */
3379 0); /* in_additional_info */
3383 cli
->raw_status
= status
;
3389 /***************************************************************
3390 Wrapper that allows SMB2 to set an EA on a pathname.
3392 ***************************************************************/
3394 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
3396 const char *ea_name
,
3401 uint16_t fnum
= 0xffff;
3403 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3405 * Can't use sync call while an async call is in flight
3407 status
= NT_STATUS_INVALID_PARAMETER
;
3411 status
= get_fnum_from_path(cli
,
3416 if (!NT_STATUS_IS_OK(status
)) {
3420 status
= cli_set_ea_fnum(cli
,
3425 if (!NT_STATUS_IS_OK(status
)) {
3431 if (fnum
!= 0xffff) {
3432 cli_smb2_close_fnum(cli
, fnum
);
3435 cli
->raw_status
= status
;
3440 /***************************************************************
3441 Wrapper that allows SMB2 to get an EA list on a pathname.
3443 ***************************************************************/
3445 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
3449 struct ea_struct
**pea_array
)
3452 uint16_t fnum
= 0xffff;
3453 DATA_BLOB outbuf
= data_blob_null
;
3454 struct ea_list
*ea_list
= NULL
;
3455 struct ea_list
*eal
= NULL
;
3456 size_t ea_count
= 0;
3457 TALLOC_CTX
*frame
= talloc_stackframe();
3462 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3464 * Can't use sync call while an async call is in flight
3466 status
= NT_STATUS_INVALID_PARAMETER
;
3470 status
= get_fnum_from_path(cli
,
3475 if (!NT_STATUS_IS_OK(status
)) {
3479 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3480 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3482 status
= cli_smb2_query_info_fnum(
3485 1, /* in_info_type */
3486 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
3487 0xFFFF, /* in_max_output_length */
3488 NULL
, /* in_input_buffer */
3489 0, /* in_additional_info */
3494 if (!NT_STATUS_IS_OK(status
)) {
3498 /* Parse the reply. */
3499 ea_list
= read_nttrans_ea_list(ctx
,
3500 (const char *)outbuf
.data
,
3502 if (ea_list
== NULL
) {
3503 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3507 /* Convert to an array. */
3508 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
3513 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
3514 if (*pea_array
== NULL
) {
3515 status
= NT_STATUS_NO_MEMORY
;
3519 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
3520 (*pea_array
)[ea_count
++] = eal
->ea
;
3522 *pnum_eas
= ea_count
;
3527 if (fnum
!= 0xffff) {
3528 cli_smb2_close_fnum(cli
, fnum
);
3531 cli
->raw_status
= status
;
3537 /***************************************************************
3538 Wrapper that allows SMB2 to get user quota.
3540 ***************************************************************/
3542 NTSTATUS
cli_smb2_get_user_quota(struct cli_state
*cli
,
3544 SMB_NTQUOTA_STRUCT
*pqt
)
3547 DATA_BLOB inbuf
= data_blob_null
;
3548 DATA_BLOB info_blob
= data_blob_null
;
3549 DATA_BLOB outbuf
= data_blob_null
;
3550 TALLOC_CTX
*frame
= talloc_stackframe();
3552 unsigned int offset
;
3553 struct smb2_query_quota_info query
= {0};
3554 struct file_get_quota_info info
= {0};
3555 enum ndr_err_code err
;
3556 struct ndr_push
*ndr_push
= NULL
;
3558 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3560 * Can't use sync call while an async call is in flight
3562 status
= NT_STATUS_INVALID_PARAMETER
;
3566 sid_len
= ndr_size_dom_sid(&pqt
->sid
, 0);
3568 query
.return_single
= 1;
3570 info
.next_entry_offset
= 0;
3571 info
.sid_length
= sid_len
;
3572 info
.sid
= pqt
->sid
;
3574 err
= ndr_push_struct_blob(
3578 (ndr_push_flags_fn_t
)ndr_push_file_get_quota_info
);
3580 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3581 status
= NT_STATUS_INTERNAL_ERROR
;
3585 query
.sid_list_length
= info_blob
.length
;
3586 ndr_push
= ndr_push_init_ctx(frame
);
3588 status
= NT_STATUS_NO_MEMORY
;
3592 err
= ndr_push_smb2_query_quota_info(ndr_push
,
3593 NDR_SCALARS
| NDR_BUFFERS
,
3596 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3597 status
= NT_STATUS_INTERNAL_ERROR
;
3601 err
= ndr_push_array_uint8(ndr_push
, NDR_SCALARS
, info_blob
.data
,
3604 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3605 status
= NT_STATUS_INTERNAL_ERROR
;
3608 inbuf
.data
= ndr_push
->data
;
3609 inbuf
.length
= ndr_push
->offset
;
3611 status
= cli_smb2_query_info_fnum(
3614 4, /* in_info_type */
3615 0, /* in_file_info_class */
3616 0xFFFF, /* in_max_output_length */
3617 &inbuf
, /* in_input_buffer */
3618 0, /* in_additional_info */
3623 if (!NT_STATUS_IS_OK(status
)) {
3627 if (!parse_user_quota_record(outbuf
.data
, outbuf
.length
, &offset
,
3629 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3630 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3634 cli
->raw_status
= status
;
3640 /***************************************************************
3641 Wrapper that allows SMB2 to list user quota.
3643 ***************************************************************/
3645 NTSTATUS
cli_smb2_list_user_quota_step(struct cli_state
*cli
,
3646 TALLOC_CTX
*mem_ctx
,
3648 SMB_NTQUOTA_LIST
**pqt_list
,
3652 DATA_BLOB inbuf
= data_blob_null
;
3653 DATA_BLOB outbuf
= data_blob_null
;
3654 TALLOC_CTX
*frame
= talloc_stackframe();
3655 struct smb2_query_quota_info info
= {0};
3656 enum ndr_err_code err
;
3658 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3660 * Can't use sync call while an async call is in flight
3662 status
= NT_STATUS_INVALID_PARAMETER
;
3666 info
.restart_scan
= first
? 1 : 0;
3668 err
= ndr_push_struct_blob(
3672 (ndr_push_flags_fn_t
)ndr_push_smb2_query_quota_info
);
3674 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3675 status
= NT_STATUS_INTERNAL_ERROR
;
3679 status
= cli_smb2_query_info_fnum(
3682 4, /* in_info_type */
3683 0, /* in_file_info_class */
3684 0xFFFF, /* in_max_output_length */
3685 &inbuf
, /* in_input_buffer */
3686 0, /* in_additional_info */
3692 * safeguard against panic from calling parse_user_quota_list with
3695 if (NT_STATUS_IS_OK(status
) && outbuf
.length
== 0) {
3696 status
= NT_STATUS_NO_MORE_ENTRIES
;
3699 if (!NT_STATUS_IS_OK(status
)) {
3703 status
= parse_user_quota_list(outbuf
.data
, outbuf
.length
, mem_ctx
,
3707 cli
->raw_status
= status
;
3713 /***************************************************************
3714 Wrapper that allows SMB2 to get file system quota.
3716 ***************************************************************/
3718 NTSTATUS
cli_smb2_get_fs_quota_info(struct cli_state
*cli
,
3720 SMB_NTQUOTA_STRUCT
*pqt
)
3723 DATA_BLOB outbuf
= data_blob_null
;
3724 TALLOC_CTX
*frame
= talloc_stackframe();
3726 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3728 * Can't use sync call while an async call is in flight
3730 status
= NT_STATUS_INVALID_PARAMETER
;
3734 status
= cli_smb2_query_info_fnum(
3737 2, /* in_info_type */
3738 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
3739 0xFFFF, /* in_max_output_length */
3740 NULL
, /* in_input_buffer */
3741 0, /* in_additional_info */
3746 if (!NT_STATUS_IS_OK(status
)) {
3750 status
= parse_fs_quota_buffer(outbuf
.data
, outbuf
.length
, pqt
);
3753 cli
->raw_status
= status
;
3759 /***************************************************************
3760 Wrapper that allows SMB2 to set user quota.
3762 ***************************************************************/
3764 NTSTATUS
cli_smb2_set_user_quota(struct cli_state
*cli
,
3766 SMB_NTQUOTA_LIST
*qtl
)
3769 DATA_BLOB inbuf
= data_blob_null
;
3770 TALLOC_CTX
*frame
= talloc_stackframe();
3772 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3774 * Can't use sync call while an async call is in flight
3776 status
= NT_STATUS_INVALID_PARAMETER
;
3780 status
= build_user_quota_buffer(qtl
, 0, talloc_tos(), &inbuf
, NULL
);
3781 if (!NT_STATUS_IS_OK(status
)) {
3785 status
= cli_smb2_set_info_fnum(
3788 4, /* in_info_type */
3789 0, /* in_file_info_class */
3790 &inbuf
, /* in_input_buffer */
3791 0); /* in_additional_info */
3794 cli
->raw_status
= status
;
3801 NTSTATUS
cli_smb2_set_fs_quota_info(struct cli_state
*cli
,
3803 SMB_NTQUOTA_STRUCT
*pqt
)
3806 DATA_BLOB inbuf
= data_blob_null
;
3807 TALLOC_CTX
*frame
= talloc_stackframe();
3809 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3811 * Can't use sync call while an async call is in flight
3813 status
= NT_STATUS_INVALID_PARAMETER
;
3817 status
= build_fs_quota_buffer(talloc_tos(), pqt
, &inbuf
, 0);
3818 if (!NT_STATUS_IS_OK(status
)) {
3822 status
= cli_smb2_set_info_fnum(
3825 2, /* in_info_type */
3826 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
3827 &inbuf
, /* in_input_buffer */
3828 0); /* in_additional_info */
3830 cli
->raw_status
= status
;
3836 struct cli_smb2_read_state
{
3837 struct tevent_context
*ev
;
3838 struct cli_state
*cli
;
3839 struct smb2_hnd
*ph
;
3840 uint64_t start_offset
;
3846 static void cli_smb2_read_done(struct tevent_req
*subreq
);
3848 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
3849 struct tevent_context
*ev
,
3850 struct cli_state
*cli
,
3856 struct tevent_req
*req
, *subreq
;
3857 struct cli_smb2_read_state
*state
;
3859 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
3865 state
->start_offset
= (uint64_t)offset
;
3866 state
->size
= (uint32_t)size
;
3867 state
->received
= 0;
3870 status
= map_fnum_to_smb2_handle(cli
,
3873 if (tevent_req_nterror(req
, status
)) {
3874 return tevent_req_post(req
, ev
);
3877 subreq
= smb2cli_read_send(state
,
3880 state
->cli
->timeout
,
3881 state
->cli
->smb2
.session
,
3882 state
->cli
->smb2
.tcon
,
3884 state
->start_offset
,
3885 state
->ph
->fid_persistent
,
3886 state
->ph
->fid_volatile
,
3887 0, /* minimum_count */
3888 0); /* remaining_bytes */
3890 if (tevent_req_nomem(subreq
, req
)) {
3891 return tevent_req_post(req
, ev
);
3893 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
3897 static void cli_smb2_read_done(struct tevent_req
*subreq
)
3899 struct tevent_req
*req
= tevent_req_callback_data(
3900 subreq
, struct tevent_req
);
3901 struct cli_smb2_read_state
*state
= tevent_req_data(
3902 req
, struct cli_smb2_read_state
);
3905 status
= smb2cli_read_recv(subreq
, state
,
3906 &state
->buf
, &state
->received
);
3907 if (tevent_req_nterror(req
, status
)) {
3911 if (state
->received
> state
->size
) {
3912 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3916 tevent_req_done(req
);
3919 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
3924 struct cli_smb2_read_state
*state
= tevent_req_data(
3925 req
, struct cli_smb2_read_state
);
3927 if (tevent_req_is_nterror(req
, &status
)) {
3928 state
->cli
->raw_status
= status
;
3932 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3933 * better make sure that you copy it away before you talloc_free(req).
3934 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3936 *received
= (ssize_t
)state
->received
;
3937 *rcvbuf
= state
->buf
;
3938 state
->cli
->raw_status
= NT_STATUS_OK
;
3939 return NT_STATUS_OK
;
3942 struct cli_smb2_write_state
{
3943 struct tevent_context
*ev
;
3944 struct cli_state
*cli
;
3945 struct smb2_hnd
*ph
;
3953 static void cli_smb2_write_written(struct tevent_req
*req
);
3955 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
3956 struct tevent_context
*ev
,
3957 struct cli_state
*cli
,
3965 struct tevent_req
*req
, *subreq
= NULL
;
3966 struct cli_smb2_write_state
*state
= NULL
;
3968 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
3974 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3975 state
->flags
= (uint32_t)mode
;
3977 state
->offset
= (uint64_t)offset
;
3978 state
->size
= (uint32_t)size
;
3981 status
= map_fnum_to_smb2_handle(cli
,
3984 if (tevent_req_nterror(req
, status
)) {
3985 return tevent_req_post(req
, ev
);
3988 subreq
= smb2cli_write_send(state
,
3991 state
->cli
->timeout
,
3992 state
->cli
->smb2
.session
,
3993 state
->cli
->smb2
.tcon
,
3996 state
->ph
->fid_persistent
,
3997 state
->ph
->fid_volatile
,
3998 0, /* remaining_bytes */
3999 state
->flags
, /* flags */
4002 if (tevent_req_nomem(subreq
, req
)) {
4003 return tevent_req_post(req
, ev
);
4005 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
4009 static void cli_smb2_write_written(struct tevent_req
*subreq
)
4011 struct tevent_req
*req
= tevent_req_callback_data(
4012 subreq
, struct tevent_req
);
4013 struct cli_smb2_write_state
*state
= tevent_req_data(
4014 req
, struct cli_smb2_write_state
);
4018 status
= smb2cli_write_recv(subreq
, &written
);
4019 TALLOC_FREE(subreq
);
4020 if (tevent_req_nterror(req
, status
)) {
4024 state
->written
= written
;
4026 tevent_req_done(req
);
4029 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
4032 struct cli_smb2_write_state
*state
= tevent_req_data(
4033 req
, struct cli_smb2_write_state
);
4036 if (tevent_req_is_nterror(req
, &status
)) {
4037 state
->cli
->raw_status
= status
;
4038 tevent_req_received(req
);
4042 if (pwritten
!= NULL
) {
4043 *pwritten
= (size_t)state
->written
;
4045 state
->cli
->raw_status
= NT_STATUS_OK
;
4046 tevent_req_received(req
);
4047 return NT_STATUS_OK
;
4050 /***************************************************************
4051 Wrapper that allows SMB2 async write using an fnum.
4052 This is mostly cut-and-paste from Volker's code inside
4053 source3/libsmb/clireadwrite.c, adapted for SMB2.
4055 Done this way so I can reuse all the logic inside cli_push()
4057 ***************************************************************/
4059 struct cli_smb2_writeall_state
{
4060 struct tevent_context
*ev
;
4061 struct cli_state
*cli
;
4062 struct smb2_hnd
*ph
;
4070 static void cli_smb2_writeall_written(struct tevent_req
*req
);
4072 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
4073 struct tevent_context
*ev
,
4074 struct cli_state
*cli
,
4082 struct tevent_req
*req
, *subreq
= NULL
;
4083 struct cli_smb2_writeall_state
*state
= NULL
;
4088 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
4094 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4095 state
->flags
= (uint32_t)mode
;
4097 state
->offset
= (uint64_t)offset
;
4098 state
->size
= (uint32_t)size
;
4101 status
= map_fnum_to_smb2_handle(cli
,
4104 if (tevent_req_nterror(req
, status
)) {
4105 return tevent_req_post(req
, ev
);
4108 to_write
= state
->size
;
4109 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
4110 to_write
= MIN(max_size
, to_write
);
4111 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
4113 to_write
= MIN(max_size
, to_write
);
4116 subreq
= smb2cli_write_send(state
,
4119 state
->cli
->timeout
,
4120 state
->cli
->smb2
.session
,
4121 state
->cli
->smb2
.tcon
,
4124 state
->ph
->fid_persistent
,
4125 state
->ph
->fid_volatile
,
4126 0, /* remaining_bytes */
4127 state
->flags
, /* flags */
4128 state
->buf
+ state
->written
);
4130 if (tevent_req_nomem(subreq
, req
)) {
4131 return tevent_req_post(req
, ev
);
4133 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
4137 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
4139 struct tevent_req
*req
= tevent_req_callback_data(
4140 subreq
, struct tevent_req
);
4141 struct cli_smb2_writeall_state
*state
= tevent_req_data(
4142 req
, struct cli_smb2_writeall_state
);
4144 uint32_t written
, to_write
;
4148 status
= smb2cli_write_recv(subreq
, &written
);
4149 TALLOC_FREE(subreq
);
4150 if (tevent_req_nterror(req
, status
)) {
4154 state
->written
+= written
;
4156 if (state
->written
> state
->size
) {
4157 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4161 to_write
= state
->size
- state
->written
;
4163 if (to_write
== 0) {
4164 tevent_req_done(req
);
4168 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
4169 to_write
= MIN(max_size
, to_write
);
4170 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
4172 to_write
= MIN(max_size
, to_write
);
4175 subreq
= smb2cli_write_send(state
,
4178 state
->cli
->timeout
,
4179 state
->cli
->smb2
.session
,
4180 state
->cli
->smb2
.tcon
,
4182 state
->offset
+ state
->written
,
4183 state
->ph
->fid_persistent
,
4184 state
->ph
->fid_volatile
,
4185 0, /* remaining_bytes */
4186 state
->flags
, /* flags */
4187 state
->buf
+ state
->written
);
4189 if (tevent_req_nomem(subreq
, req
)) {
4192 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
4195 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
4198 struct cli_smb2_writeall_state
*state
= tevent_req_data(
4199 req
, struct cli_smb2_writeall_state
);
4202 if (tevent_req_is_nterror(req
, &status
)) {
4203 state
->cli
->raw_status
= status
;
4206 if (pwritten
!= NULL
) {
4207 *pwritten
= (size_t)state
->written
;
4209 state
->cli
->raw_status
= NT_STATUS_OK
;
4210 return NT_STATUS_OK
;
4213 struct cli_smb2_splice_state
{
4214 struct tevent_context
*ev
;
4215 struct cli_state
*cli
;
4216 struct smb2_hnd
*src_ph
;
4217 struct smb2_hnd
*dst_ph
;
4218 int (*splice_cb
)(off_t n
, void *priv
);
4225 struct req_resume_key_rsp resume_rsp
;
4226 struct srv_copychunk_copy cc_copy
;
4229 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
4230 struct tevent_req
*req
);
4232 static void cli_splice_copychunk_done(struct tevent_req
*subreq
)
4234 struct tevent_req
*req
= tevent_req_callback_data(
4235 subreq
, struct tevent_req
);
4236 struct cli_smb2_splice_state
*state
=
4237 tevent_req_data(req
,
4238 struct cli_smb2_splice_state
);
4239 struct smbXcli_conn
*conn
= state
->cli
->conn
;
4240 DATA_BLOB out_input_buffer
= data_blob_null
;
4241 DATA_BLOB out_output_buffer
= data_blob_null
;
4242 struct srv_copychunk_rsp cc_copy_rsp
;
4243 enum ndr_err_code ndr_ret
;
4246 status
= smb2cli_ioctl_recv(subreq
, state
,
4248 &out_output_buffer
);
4249 TALLOC_FREE(subreq
);
4250 if ((!NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
) ||
4251 state
->resized
) && tevent_req_nterror(req
, status
)) {
4255 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
, state
, &cc_copy_rsp
,
4256 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
4257 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4258 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4259 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4263 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
4264 uint32_t max_chunks
= MIN(cc_copy_rsp
.chunks_written
,
4265 cc_copy_rsp
.total_bytes_written
/ cc_copy_rsp
.chunk_bytes_written
);
4266 if ((cc_copy_rsp
.chunk_bytes_written
> smb2cli_conn_cc_chunk_len(conn
) ||
4267 max_chunks
> smb2cli_conn_cc_max_chunks(conn
)) &&
4268 tevent_req_nterror(req
, status
)) {
4272 state
->resized
= true;
4273 smb2cli_conn_set_cc_chunk_len(conn
, cc_copy_rsp
.chunk_bytes_written
);
4274 smb2cli_conn_set_cc_max_chunks(conn
, max_chunks
);
4276 if ((state
->src_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
4277 (state
->dst_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
4278 (state
->written
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
)) {
4279 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
4282 state
->src_offset
+= cc_copy_rsp
.total_bytes_written
;
4283 state
->dst_offset
+= cc_copy_rsp
.total_bytes_written
;
4284 state
->written
+= cc_copy_rsp
.total_bytes_written
;
4285 if (!state
->splice_cb(state
->written
, state
->priv
)) {
4286 tevent_req_nterror(req
, NT_STATUS_CANCELLED
);
4291 cli_splice_copychunk_send(state
, req
);
4294 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
4295 struct tevent_req
*req
)
4297 struct tevent_req
*subreq
;
4298 enum ndr_err_code ndr_ret
;
4299 struct smbXcli_conn
*conn
= state
->cli
->conn
;
4300 struct srv_copychunk_copy
*cc_copy
= &state
->cc_copy
;
4301 off_t src_offset
= state
->src_offset
;
4302 off_t dst_offset
= state
->dst_offset
;
4303 uint32_t req_len
= MIN(smb2cli_conn_cc_chunk_len(conn
) * smb2cli_conn_cc_max_chunks(conn
),
4304 state
->size
- state
->written
);
4305 DATA_BLOB in_input_buffer
= data_blob_null
;
4306 DATA_BLOB in_output_buffer
= data_blob_null
;
4308 if (state
->size
- state
->written
== 0) {
4309 tevent_req_done(req
);
4313 cc_copy
->chunk_count
= 0;
4315 cc_copy
->chunks
[cc_copy
->chunk_count
].source_off
= src_offset
;
4316 cc_copy
->chunks
[cc_copy
->chunk_count
].target_off
= dst_offset
;
4317 cc_copy
->chunks
[cc_copy
->chunk_count
].length
= MIN(req_len
,
4318 smb2cli_conn_cc_chunk_len(conn
));
4319 if (req_len
< cc_copy
->chunks
[cc_copy
->chunk_count
].length
) {
4320 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
4323 req_len
-= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4324 if ((src_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
) ||
4325 (dst_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
)) {
4326 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
4329 src_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4330 dst_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4331 cc_copy
->chunk_count
++;
4334 ndr_ret
= ndr_push_struct_blob(&in_input_buffer
, state
, cc_copy
,
4335 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
4336 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4337 DEBUG(0, ("failed to marshall copy chunk req\n"));
4338 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
4342 subreq
= smb2cli_ioctl_send(state
, state
->ev
, state
->cli
->conn
,
4343 state
->cli
->timeout
,
4344 state
->cli
->smb2
.session
,
4345 state
->cli
->smb2
.tcon
,
4346 state
->dst_ph
->fid_persistent
, /* in_fid_persistent */
4347 state
->dst_ph
->fid_volatile
, /* in_fid_volatile */
4348 FSCTL_SRV_COPYCHUNK_WRITE
,
4349 0, /* in_max_input_length */
4351 12, /* in_max_output_length */
4353 SMB2_IOCTL_FLAG_IS_FSCTL
);
4354 if (tevent_req_nomem(subreq
, req
)) {
4357 tevent_req_set_callback(subreq
,
4358 cli_splice_copychunk_done
,
4362 static void cli_splice_key_done(struct tevent_req
*subreq
)
4364 struct tevent_req
*req
= tevent_req_callback_data(
4365 subreq
, struct tevent_req
);
4366 struct cli_smb2_splice_state
*state
=
4367 tevent_req_data(req
,
4368 struct cli_smb2_splice_state
);
4369 enum ndr_err_code ndr_ret
;
4372 DATA_BLOB out_input_buffer
= data_blob_null
;
4373 DATA_BLOB out_output_buffer
= data_blob_null
;
4375 status
= smb2cli_ioctl_recv(subreq
, state
,
4377 &out_output_buffer
);
4378 TALLOC_FREE(subreq
);
4379 if (tevent_req_nterror(req
, status
)) {
4383 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
,
4384 state
, &state
->resume_rsp
,
4385 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
4386 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4387 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4388 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4392 memcpy(&state
->cc_copy
.source_key
,
4393 &state
->resume_rsp
.resume_key
,
4394 sizeof state
->resume_rsp
.resume_key
);
4396 cli_splice_copychunk_send(state
, req
);
4399 struct tevent_req
*cli_smb2_splice_send(TALLOC_CTX
*mem_ctx
,
4400 struct tevent_context
*ev
,
4401 struct cli_state
*cli
,
4402 uint16_t src_fnum
, uint16_t dst_fnum
,
4403 off_t size
, off_t src_offset
, off_t dst_offset
,
4404 int (*splice_cb
)(off_t n
, void *priv
),
4407 struct tevent_req
*req
;
4408 struct tevent_req
*subreq
;
4409 struct cli_smb2_splice_state
*state
;
4411 DATA_BLOB in_input_buffer
= data_blob_null
;
4412 DATA_BLOB in_output_buffer
= data_blob_null
;
4414 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_splice_state
);
4420 state
->splice_cb
= splice_cb
;
4424 state
->src_offset
= src_offset
;
4425 state
->dst_offset
= dst_offset
;
4426 state
->cc_copy
.chunks
= talloc_array(state
,
4427 struct srv_copychunk
,
4428 smb2cli_conn_cc_max_chunks(cli
->conn
));
4429 if (state
->cc_copy
.chunks
== NULL
) {
4433 status
= map_fnum_to_smb2_handle(cli
, src_fnum
, &state
->src_ph
);
4434 if (tevent_req_nterror(req
, status
))
4435 return tevent_req_post(req
, ev
);
4437 status
= map_fnum_to_smb2_handle(cli
, dst_fnum
, &state
->dst_ph
);
4438 if (tevent_req_nterror(req
, status
))
4439 return tevent_req_post(req
, ev
);
4441 subreq
= smb2cli_ioctl_send(state
, ev
, cli
->conn
,
4445 state
->src_ph
->fid_persistent
, /* in_fid_persistent */
4446 state
->src_ph
->fid_volatile
, /* in_fid_volatile */
4447 FSCTL_SRV_REQUEST_RESUME_KEY
,
4448 0, /* in_max_input_length */
4450 32, /* in_max_output_length */
4452 SMB2_IOCTL_FLAG_IS_FSCTL
);
4453 if (tevent_req_nomem(subreq
, req
)) {
4456 tevent_req_set_callback(subreq
,
4457 cli_splice_key_done
,
4463 NTSTATUS
cli_smb2_splice_recv(struct tevent_req
*req
, off_t
*written
)
4465 struct cli_smb2_splice_state
*state
= tevent_req_data(
4466 req
, struct cli_smb2_splice_state
);
4469 if (tevent_req_is_nterror(req
, &status
)) {
4470 state
->cli
->raw_status
= status
;
4471 tevent_req_received(req
);
4474 if (written
!= NULL
) {
4475 *written
= state
->written
;
4477 state
->cli
->raw_status
= NT_STATUS_OK
;
4478 tevent_req_received(req
);
4479 return NT_STATUS_OK
;
4482 /***************************************************************
4483 SMB2 enum shadow copy data.
4484 ***************************************************************/
4486 struct cli_smb2_shadow_copy_data_fnum_state
{
4487 struct cli_state
*cli
;
4489 struct smb2_hnd
*ph
;
4490 DATA_BLOB out_input_buffer
;
4491 DATA_BLOB out_output_buffer
;
4494 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
);
4496 static struct tevent_req
*cli_smb2_shadow_copy_data_fnum_send(
4497 TALLOC_CTX
*mem_ctx
,
4498 struct tevent_context
*ev
,
4499 struct cli_state
*cli
,
4503 struct tevent_req
*req
, *subreq
;
4504 struct cli_smb2_shadow_copy_data_fnum_state
*state
;
4507 req
= tevent_req_create(mem_ctx
, &state
,
4508 struct cli_smb2_shadow_copy_data_fnum_state
);
4516 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
4517 if (tevent_req_nterror(req
, status
)) {
4518 return tevent_req_post(req
, ev
);
4522 * TODO. Under SMB2 we should send a zero max_output_length
4523 * ioctl to get the required size, then send another ioctl
4524 * to get the data, but the current SMB1 implementation just
4525 * does one roundtrip with a 64K buffer size. Do the same
4529 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
4530 state
->cli
->timeout
,
4531 state
->cli
->smb2
.session
,
4532 state
->cli
->smb2
.tcon
,
4533 state
->ph
->fid_persistent
, /* in_fid_persistent */
4534 state
->ph
->fid_volatile
, /* in_fid_volatile */
4535 FSCTL_GET_SHADOW_COPY_DATA
,
4536 0, /* in_max_input_length */
4537 NULL
, /* in_input_buffer */
4539 CLI_BUFFER_SIZE
: 16, /* in_max_output_length */
4540 NULL
, /* in_output_buffer */
4541 SMB2_IOCTL_FLAG_IS_FSCTL
);
4543 if (tevent_req_nomem(subreq
, req
)) {
4544 return tevent_req_post(req
, ev
);
4546 tevent_req_set_callback(subreq
,
4547 cli_smb2_shadow_copy_data_fnum_done
,
4553 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
)
4555 struct tevent_req
*req
= tevent_req_callback_data(
4556 subreq
, struct tevent_req
);
4557 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
4558 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
4561 status
= smb2cli_ioctl_recv(subreq
, state
,
4562 &state
->out_input_buffer
,
4563 &state
->out_output_buffer
);
4564 tevent_req_simple_finish_ntstatus(subreq
, status
);
4567 static NTSTATUS
cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req
*req
,
4568 TALLOC_CTX
*mem_ctx
,
4573 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
4574 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
4575 char **names
= NULL
;
4576 uint32_t num_names
= 0;
4577 uint32_t num_names_returned
= 0;
4578 uint32_t dlength
= 0;
4580 uint8_t *endp
= NULL
;
4583 if (tevent_req_is_nterror(req
, &status
)) {
4587 if (state
->out_output_buffer
.length
< 16) {
4588 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4591 num_names
= IVAL(state
->out_output_buffer
.data
, 0);
4592 num_names_returned
= IVAL(state
->out_output_buffer
.data
, 4);
4593 dlength
= IVAL(state
->out_output_buffer
.data
, 8);
4595 if (num_names
> 0x7FFFFFFF) {
4596 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4599 if (get_names
== false) {
4600 *pnum_names
= (int)num_names
;
4601 return NT_STATUS_OK
;
4603 if (num_names
!= num_names_returned
) {
4604 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4606 if (dlength
+ 12 < 12) {
4607 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4610 * NB. The below is an allowable return if there are
4611 * more snapshots than the buffer size we told the
4612 * server we can receive. We currently don't support
4615 if (dlength
+ 12 > state
->out_output_buffer
.length
) {
4616 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4618 if (state
->out_output_buffer
.length
+
4619 (2 * sizeof(SHADOW_COPY_LABEL
)) <
4620 state
->out_output_buffer
.length
) {
4621 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4624 names
= talloc_array(mem_ctx
, char *, num_names_returned
);
4625 if (names
== NULL
) {
4626 return NT_STATUS_NO_MEMORY
;
4629 endp
= state
->out_output_buffer
.data
+
4630 state
->out_output_buffer
.length
;
4632 for (i
=0; i
<num_names_returned
; i
++) {
4635 size_t converted_size
;
4637 src
= state
->out_output_buffer
.data
+ 12 +
4638 (i
* 2 * sizeof(SHADOW_COPY_LABEL
));
4640 if (src
+ (2 * sizeof(SHADOW_COPY_LABEL
)) > endp
) {
4641 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4643 ret
= convert_string_talloc(
4644 names
, CH_UTF16LE
, CH_UNIX
,
4645 src
, 2 * sizeof(SHADOW_COPY_LABEL
),
4646 &names
[i
], &converted_size
);
4649 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4652 *pnum_names
= num_names
;
4654 return NT_STATUS_OK
;
4657 NTSTATUS
cli_smb2_shadow_copy_data(TALLOC_CTX
*mem_ctx
,
4658 struct cli_state
*cli
,
4664 TALLOC_CTX
*frame
= talloc_stackframe();
4665 struct tevent_context
*ev
;
4666 struct tevent_req
*req
;
4667 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
4669 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4671 * Can't use sync call while an async call is in flight
4673 status
= NT_STATUS_INVALID_PARAMETER
;
4676 ev
= samba_tevent_context_init(frame
);
4680 req
= cli_smb2_shadow_copy_data_fnum_send(frame
,
4688 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4691 status
= cli_smb2_shadow_copy_data_fnum_recv(req
,
4697 cli
->raw_status
= status
;
4703 /***************************************************************
4704 Wrapper that allows SMB2 to truncate a file.
4706 ***************************************************************/
4708 NTSTATUS
cli_smb2_ftruncate(struct cli_state
*cli
,
4713 uint8_t buf
[8] = {0};
4714 DATA_BLOB inbuf
= { .data
= buf
, .length
= sizeof(buf
) };
4715 TALLOC_CTX
*frame
= talloc_stackframe();
4717 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4719 * Can't use sync call while an async call is in flight
4721 status
= NT_STATUS_INVALID_PARAMETER
;
4725 SBVAL(buf
, 0, newsize
);
4727 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4728 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4730 status
= cli_smb2_set_info_fnum(
4733 1, /* in_info_type */
4734 SMB_FILE_END_OF_FILE_INFORMATION
-1000, /* in_file_info_class */
4735 &inbuf
, /* in_input_buffer */
4740 cli
->raw_status
= status
;
4746 struct cli_smb2_notify_state
{
4747 struct tevent_req
*subreq
;
4748 struct notify_change
*changes
;
4752 static void cli_smb2_notify_done(struct tevent_req
*subreq
);
4753 static bool cli_smb2_notify_cancel(struct tevent_req
*req
);
4755 struct tevent_req
*cli_smb2_notify_send(
4756 TALLOC_CTX
*mem_ctx
,
4757 struct tevent_context
*ev
,
4758 struct cli_state
*cli
,
4760 uint32_t buffer_size
,
4761 uint32_t completion_filter
,
4764 struct tevent_req
*req
= NULL
;
4765 struct cli_smb2_notify_state
*state
= NULL
;
4766 struct smb2_hnd
*ph
= NULL
;
4769 req
= tevent_req_create(mem_ctx
, &state
,
4770 struct cli_smb2_notify_state
);
4775 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
4776 if (tevent_req_nterror(req
, status
)) {
4777 return tevent_req_post(req
, ev
);
4780 state
->subreq
= smb2cli_notify_send(
4792 if (tevent_req_nomem(state
->subreq
, req
)) {
4793 return tevent_req_post(req
, ev
);
4795 tevent_req_set_callback(state
->subreq
, cli_smb2_notify_done
, req
);
4796 tevent_req_set_cancel_fn(req
, cli_smb2_notify_cancel
);
4800 static bool cli_smb2_notify_cancel(struct tevent_req
*req
)
4802 struct cli_smb2_notify_state
*state
= tevent_req_data(
4803 req
, struct cli_smb2_notify_state
);
4806 ok
= tevent_req_cancel(state
->subreq
);
4810 static void cli_smb2_notify_done(struct tevent_req
*subreq
)
4812 struct tevent_req
*req
= tevent_req_callback_data(
4813 subreq
, struct tevent_req
);
4814 struct cli_smb2_notify_state
*state
= tevent_req_data(
4815 req
, struct cli_smb2_notify_state
);
4821 status
= smb2cli_notify_recv(subreq
, state
, &base
, &len
);
4822 TALLOC_FREE(subreq
);
4824 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
4825 tevent_req_done(req
);
4828 if (tevent_req_nterror(req
, status
)) {
4834 while (len
- ofs
>= 12) {
4835 struct notify_change
*tmp
;
4836 struct notify_change
*c
;
4837 uint32_t next_ofs
= IVAL(base
, ofs
);
4838 uint32_t file_name_length
= IVAL(base
, ofs
+8);
4842 tmp
= talloc_realloc(
4845 struct notify_change
,
4846 state
->num_changes
+ 1);
4847 if (tevent_req_nomem(tmp
, req
)) {
4850 state
->changes
= tmp
;
4851 c
= &state
->changes
[state
->num_changes
];
4852 state
->num_changes
+= 1;
4854 if (smb_buffer_oob(len
, ofs
, next_ofs
) ||
4855 smb_buffer_oob(len
, ofs
+12, file_name_length
)) {
4857 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4861 c
->action
= IVAL(base
, ofs
+4);
4863 ok
= convert_string_talloc(
4873 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4877 if (next_ofs
== 0) {
4883 tevent_req_done(req
);
4886 NTSTATUS
cli_smb2_notify_recv(struct tevent_req
*req
,
4887 TALLOC_CTX
*mem_ctx
,
4888 struct notify_change
**pchanges
,
4889 uint32_t *pnum_changes
)
4891 struct cli_smb2_notify_state
*state
= tevent_req_data(
4892 req
, struct cli_smb2_notify_state
);
4895 if (tevent_req_is_nterror(req
, &status
)) {
4898 *pchanges
= talloc_move(mem_ctx
, &state
->changes
);
4899 *pnum_changes
= state
->num_changes
;
4900 return NT_STATUS_OK
;
4903 NTSTATUS
cli_smb2_notify(struct cli_state
*cli
, uint16_t fnum
,
4904 uint32_t buffer_size
, uint32_t completion_filter
,
4905 bool recursive
, TALLOC_CTX
*mem_ctx
,
4906 struct notify_change
**pchanges
,
4907 uint32_t *pnum_changes
)
4909 TALLOC_CTX
*frame
= talloc_stackframe();
4910 struct tevent_context
*ev
;
4911 struct tevent_req
*req
;
4912 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
4914 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4916 * Can't use sync call while an async call is in flight
4918 status
= NT_STATUS_INVALID_PARAMETER
;
4921 ev
= samba_tevent_context_init(frame
);
4925 req
= cli_smb2_notify_send(
4936 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4939 status
= cli_smb2_notify_recv(req
, mem_ctx
, pchanges
, pnum_changes
);
4945 struct cli_smb2_fsctl_state
{
4949 static void cli_smb2_fsctl_done(struct tevent_req
*subreq
);
4951 struct tevent_req
*cli_smb2_fsctl_send(
4952 TALLOC_CTX
*mem_ctx
,
4953 struct tevent_context
*ev
,
4954 struct cli_state
*cli
,
4957 const DATA_BLOB
*in
,
4960 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
4961 struct cli_smb2_fsctl_state
*state
= NULL
;
4962 struct smb2_hnd
*ph
= NULL
;
4965 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_fsctl_state
);
4970 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
4971 if (tevent_req_nterror(req
, status
)) {
4972 return tevent_req_post(req
, ev
);
4975 subreq
= smb2cli_ioctl_send(
4985 0, /* in_max_input_length */
4989 SMB2_IOCTL_FLAG_IS_FSCTL
);
4991 if (tevent_req_nomem(subreq
, req
)) {
4992 return tevent_req_post(req
, ev
);
4994 tevent_req_set_callback(subreq
, cli_smb2_fsctl_done
, req
);
4998 static void cli_smb2_fsctl_done(struct tevent_req
*subreq
)
5000 struct tevent_req
*req
= tevent_req_callback_data(
5001 subreq
, struct tevent_req
);
5002 struct cli_smb2_fsctl_state
*state
= tevent_req_data(
5003 req
, struct cli_smb2_fsctl_state
);
5006 status
= smb2cli_ioctl_recv(subreq
, state
, NULL
, &state
->out
);
5007 tevent_req_simple_finish_ntstatus(subreq
, status
);
5010 NTSTATUS
cli_smb2_fsctl_recv(
5011 struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
, DATA_BLOB
*out
)
5013 struct cli_smb2_fsctl_state
*state
= tevent_req_data(
5014 req
, struct cli_smb2_fsctl_state
);
5015 NTSTATUS status
= NT_STATUS_OK
;
5017 if (tevent_req_is_nterror(req
, &status
)) {
5018 tevent_req_received(req
);
5022 if (state
->out
.length
== 0) {
5023 *out
= (DATA_BLOB
) { .data
= NULL
, };
5026 * Can't use talloc_move() here, the outblobs from
5027 * smb2cli_ioctl_recv() are not standalone talloc
5028 * objects but just peek into the larger buffers
5029 * received, hanging off "state".
5031 *out
= data_blob_talloc(
5032 mem_ctx
, state
->out
.data
, state
->out
.length
);
5033 if (out
->data
== NULL
) {
5034 status
= NT_STATUS_NO_MEMORY
;
5038 tevent_req_received(req
);
5039 return NT_STATUS_OK
;