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 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
250 have_twrp
= clistr_smb2_extract_snapshot_token(fname
, &ntt
);
252 status
= smb2_create_blob_add(
255 SMB2_CREATE_TAG_TWRP
,
257 .data
= (uint8_t *)&ntt
,
258 .length
= sizeof(ntt
),
260 if (tevent_req_nterror(req
, status
)) {
261 return tevent_req_post(req
, ev
);
265 if (in_cblobs
!= NULL
) {
267 for (i
=0; i
<in_cblobs
->num_blobs
; i
++) {
268 struct smb2_create_blob
*b
= &in_cblobs
->blobs
[i
];
269 status
= smb2_create_blob_add(
270 state
, &state
->in_cblobs
, b
->tag
, b
->data
);
271 if (!NT_STATUS_IS_OK(status
)) {
272 tevent_req_nterror(req
, status
);
273 return tevent_req_post(req
, ev
);
278 fname
= smb2_dfs_share_path(state
, cli
, fname
);
279 if (tevent_req_nomem(fname
, req
)) {
280 return tevent_req_post(req
, ev
);
282 fname_len
= strlen(fname
);
284 /* SMB2 is pickier about pathnames. Ensure it doesn't
286 if (*fname
== '\\') {
291 /* Or end in a '\' */
292 if (fname_len
> 0 && fname
[fname_len
-1] == '\\') {
293 fname
[fname_len
-1] = '\0';
296 subreq
= smb2cli_create_send(state
, ev
,
302 flags_to_smb2_oplock(create_flags
),
310 if (tevent_req_nomem(subreq
, req
)) {
311 return tevent_req_post(req
, ev
);
313 tevent_req_set_callback(subreq
, cli_smb2_create_fnum_done
, req
);
315 state
->subreq
= subreq
;
316 tevent_req_set_cancel_fn(req
, cli_smb2_create_fnum_cancel
);
321 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
)
323 struct tevent_req
*req
= tevent_req_callback_data(
324 subreq
, struct tevent_req
);
325 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
326 req
, struct cli_smb2_create_fnum_state
);
330 status
= smb2cli_create_recv(
333 &h
.fid_volatile
, &state
->cr
,
338 if (tevent_req_nterror(req
, status
)) {
342 status
= map_smb2_handle_to_fnum(state
->cli
, &h
, &state
->fnum
);
343 if (tevent_req_nterror(req
, status
)) {
346 tevent_req_done(req
);
349 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
)
351 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
352 req
, struct cli_smb2_create_fnum_state
);
353 return tevent_req_cancel(state
->subreq
);
356 NTSTATUS
cli_smb2_create_fnum_recv(
357 struct tevent_req
*req
,
359 struct smb_create_returns
*cr
,
361 struct smb2_create_blobs
*out_cblobs
,
362 struct symlink_reparse_struct
**symlink
)
364 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
365 req
, struct cli_smb2_create_fnum_state
);
368 if (tevent_req_is_nterror(req
, &status
)) {
369 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
) &&
371 *symlink
= talloc_move(mem_ctx
, &state
->symlink
);
373 state
->cli
->raw_status
= status
;
377 *pfnum
= state
->fnum
;
382 if (out_cblobs
!= NULL
) {
383 *out_cblobs
= (struct smb2_create_blobs
) {
384 .num_blobs
= state
->out_cblobs
.num_blobs
,
385 .blobs
= talloc_move(
386 mem_ctx
, &state
->out_cblobs
.blobs
),
389 state
->cli
->raw_status
= NT_STATUS_OK
;
393 NTSTATUS
cli_smb2_create_fnum(
394 struct cli_state
*cli
,
396 struct cli_smb2_create_flags create_flags
,
397 uint32_t impersonation_level
,
398 uint32_t desired_access
,
399 uint32_t file_attributes
,
400 uint32_t share_access
,
401 uint32_t create_disposition
,
402 uint32_t create_options
,
403 const struct smb2_create_blobs
*in_cblobs
,
405 struct smb_create_returns
*cr
,
407 struct smb2_create_blobs
*out_cblobs
)
409 TALLOC_CTX
*frame
= talloc_stackframe();
410 struct tevent_context
*ev
;
411 struct tevent_req
*req
;
412 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
414 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
416 * Can't use sync call while an async call is in flight
418 status
= NT_STATUS_INVALID_PARAMETER
;
421 ev
= samba_tevent_context_init(frame
);
425 req
= cli_smb2_create_fnum_send(
441 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
444 status
= cli_smb2_create_fnum_recv(
445 req
, pfid
, cr
, mem_ctx
, out_cblobs
, NULL
);
451 /***************************************************************
452 Small wrapper that allows SMB2 close to use a uint16_t fnum.
453 ***************************************************************/
455 struct cli_smb2_close_fnum_state
{
456 struct cli_state
*cli
;
461 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
);
463 struct tevent_req
*cli_smb2_close_fnum_send(TALLOC_CTX
*mem_ctx
,
464 struct tevent_context
*ev
,
465 struct cli_state
*cli
,
468 struct tevent_req
*req
, *subreq
;
469 struct cli_smb2_close_fnum_state
*state
;
472 req
= tevent_req_create(mem_ctx
, &state
,
473 struct cli_smb2_close_fnum_state
);
480 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
481 if (tevent_req_nterror(req
, status
)) {
482 return tevent_req_post(req
, ev
);
485 subreq
= smb2cli_close_send(state
, ev
, cli
->conn
, cli
->timeout
,
486 cli
->smb2
.session
, cli
->smb2
.tcon
,
487 0, state
->ph
->fid_persistent
,
488 state
->ph
->fid_volatile
);
489 if (tevent_req_nomem(subreq
, req
)) {
490 return tevent_req_post(req
, ev
);
492 tevent_req_set_callback(subreq
, cli_smb2_close_fnum_done
, req
);
496 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
)
498 struct tevent_req
*req
= tevent_req_callback_data(
499 subreq
, struct tevent_req
);
500 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
501 req
, struct cli_smb2_close_fnum_state
);
504 status
= smb2cli_close_recv(subreq
);
505 if (tevent_req_nterror(req
, status
)) {
509 /* Delete the fnum -> handle mapping. */
510 status
= delete_smb2_handle_mapping(state
->cli
, &state
->ph
,
512 if (tevent_req_nterror(req
, status
)) {
515 tevent_req_done(req
);
518 NTSTATUS
cli_smb2_close_fnum_recv(struct tevent_req
*req
)
520 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
521 req
, struct cli_smb2_close_fnum_state
);
522 NTSTATUS status
= NT_STATUS_OK
;
524 if (tevent_req_is_nterror(req
, &status
)) {
525 state
->cli
->raw_status
= status
;
527 tevent_req_received(req
);
531 NTSTATUS
cli_smb2_close_fnum(struct cli_state
*cli
, uint16_t fnum
)
533 TALLOC_CTX
*frame
= talloc_stackframe();
534 struct tevent_context
*ev
;
535 struct tevent_req
*req
;
536 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
538 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
540 * Can't use sync call while an async call is in flight
542 status
= NT_STATUS_INVALID_PARAMETER
;
545 ev
= samba_tevent_context_init(frame
);
549 req
= cli_smb2_close_fnum_send(frame
, ev
, cli
, fnum
);
553 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
556 status
= cli_smb2_close_fnum_recv(req
);
562 struct cli_smb2_set_info_fnum_state
{
566 static void cli_smb2_set_info_fnum_done(struct tevent_req
*subreq
);
568 struct tevent_req
*cli_smb2_set_info_fnum_send(
570 struct tevent_context
*ev
,
571 struct cli_state
*cli
,
573 uint8_t in_info_type
,
574 uint8_t in_info_class
,
575 const DATA_BLOB
*in_input_buffer
,
576 uint32_t in_additional_info
)
578 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
579 struct cli_smb2_set_info_fnum_state
*state
= NULL
;
580 struct smb2_hnd
*ph
= NULL
;
583 req
= tevent_req_create(
584 mem_ctx
, &state
, struct cli_smb2_set_info_fnum_state
);
589 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
590 if (tevent_req_nterror(req
, status
)) {
591 return tevent_req_post(req
, ev
);
594 subreq
= smb2cli_set_info_send(
607 if (tevent_req_nomem(subreq
, req
)) {
608 return tevent_req_post(req
, ev
);
610 tevent_req_set_callback(subreq
, cli_smb2_set_info_fnum_done
, req
);
614 static void cli_smb2_set_info_fnum_done(struct tevent_req
*subreq
)
616 NTSTATUS status
= smb2cli_set_info_recv(subreq
);
617 tevent_req_simple_finish_ntstatus(subreq
, status
);
620 NTSTATUS
cli_smb2_set_info_fnum_recv(struct tevent_req
*req
)
622 return tevent_req_simple_recv_ntstatus(req
);
625 NTSTATUS
cli_smb2_set_info_fnum(
626 struct cli_state
*cli
,
628 uint8_t in_info_type
,
629 uint8_t in_info_class
,
630 const DATA_BLOB
*in_input_buffer
,
631 uint32_t in_additional_info
)
633 TALLOC_CTX
*frame
= talloc_stackframe();
634 struct tevent_context
*ev
= NULL
;
635 struct tevent_req
*req
= NULL
;
636 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
639 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
641 * Can't use sync call while an async call is in flight
643 status
= NT_STATUS_INVALID_PARAMETER
;
646 ev
= samba_tevent_context_init(frame
);
650 req
= cli_smb2_set_info_fnum_send(
662 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
666 status
= cli_smb2_set_info_fnum_recv(req
);
672 struct cli_smb2_delete_on_close_state
{
673 struct cli_state
*cli
;
678 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
);
680 struct tevent_req
*cli_smb2_delete_on_close_send(TALLOC_CTX
*mem_ctx
,
681 struct tevent_context
*ev
,
682 struct cli_state
*cli
,
686 struct tevent_req
*req
= NULL
;
687 struct cli_smb2_delete_on_close_state
*state
= NULL
;
688 struct tevent_req
*subreq
= NULL
;
689 uint8_t in_info_type
;
690 uint8_t in_file_info_class
;
692 req
= tevent_req_create(mem_ctx
, &state
,
693 struct cli_smb2_delete_on_close_state
);
700 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
701 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
704 in_file_info_class
= SMB_FILE_DISPOSITION_INFORMATION
- 1000;
705 /* Setup data array. */
706 SCVAL(&state
->data
[0], 0, flag
? 1 : 0);
707 state
->inbuf
.data
= &state
->data
[0];
708 state
->inbuf
.length
= 1;
710 subreq
= cli_smb2_set_info_fnum_send(
719 if (tevent_req_nomem(subreq
, req
)) {
720 return tevent_req_post(req
, ev
);
722 tevent_req_set_callback(subreq
,
723 cli_smb2_delete_on_close_done
,
728 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
)
730 NTSTATUS status
= cli_smb2_set_info_fnum_recv(subreq
);
731 tevent_req_simple_finish_ntstatus(subreq
, status
);
734 NTSTATUS
cli_smb2_delete_on_close_recv(struct tevent_req
*req
)
736 struct cli_smb2_delete_on_close_state
*state
=
738 struct cli_smb2_delete_on_close_state
);
741 if (tevent_req_is_nterror(req
, &status
)) {
742 state
->cli
->raw_status
= status
;
743 tevent_req_received(req
);
747 state
->cli
->raw_status
= NT_STATUS_OK
;
748 tevent_req_received(req
);
752 NTSTATUS
cli_smb2_delete_on_close(struct cli_state
*cli
, uint16_t fnum
, bool flag
)
754 TALLOC_CTX
*frame
= talloc_stackframe();
755 struct tevent_context
*ev
;
756 struct tevent_req
*req
;
757 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
759 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
761 * Can't use sync call while an async call is in flight
763 status
= NT_STATUS_INVALID_PARAMETER
;
766 ev
= samba_tevent_context_init(frame
);
770 req
= cli_smb2_delete_on_close_send(frame
, ev
, cli
, fnum
, flag
);
774 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
777 status
= cli_smb2_delete_on_close_recv(req
);
783 struct cli_smb2_mkdir_state
{
784 struct tevent_context
*ev
;
785 struct cli_state
*cli
;
788 static void cli_smb2_mkdir_opened(struct tevent_req
*subreq
);
789 static void cli_smb2_mkdir_closed(struct tevent_req
*subreq
);
791 struct tevent_req
*cli_smb2_mkdir_send(
793 struct tevent_context
*ev
,
794 struct cli_state
*cli
,
797 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
798 struct cli_smb2_mkdir_state
*state
= NULL
;
800 req
= tevent_req_create(
801 mem_ctx
, &state
, struct cli_smb2_mkdir_state
);
808 /* Ensure this is a directory. */
809 subreq
= cli_smb2_create_fnum_send(
814 (struct cli_smb2_create_flags
){0}, /* create_flags */
815 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation_level */
816 FILE_READ_ATTRIBUTES
, /* desired_access */
817 FILE_ATTRIBUTE_DIRECTORY
, /* file_attributes */
819 FILE_SHARE_WRITE
, /* share_access */
820 FILE_CREATE
, /* create_disposition */
821 FILE_DIRECTORY_FILE
, /* create_options */
822 NULL
); /* in_cblobs */
823 if (tevent_req_nomem(subreq
, req
)) {
824 return tevent_req_post(req
, ev
);
826 tevent_req_set_callback(subreq
, cli_smb2_mkdir_opened
, req
);
830 static void cli_smb2_mkdir_opened(struct tevent_req
*subreq
)
832 struct tevent_req
*req
= tevent_req_callback_data(
833 subreq
, struct tevent_req
);
834 struct cli_smb2_mkdir_state
*state
= tevent_req_data(
835 req
, struct cli_smb2_mkdir_state
);
837 uint16_t fnum
= 0xffff;
839 status
= cli_smb2_create_fnum_recv(
840 subreq
, &fnum
, NULL
, NULL
, NULL
, NULL
);
842 if (tevent_req_nterror(req
, status
)) {
846 subreq
= cli_smb2_close_fnum_send(state
, state
->ev
, state
->cli
, fnum
);
847 if (tevent_req_nomem(subreq
, req
)) {
850 tevent_req_set_callback(subreq
, cli_smb2_mkdir_closed
, req
);
853 static void cli_smb2_mkdir_closed(struct tevent_req
*subreq
)
855 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
856 tevent_req_simple_finish_ntstatus(subreq
, status
);
859 NTSTATUS
cli_smb2_mkdir_recv(struct tevent_req
*req
)
861 return tevent_req_simple_recv_ntstatus(req
);
864 struct cli_smb2_rmdir_state
{
865 struct tevent_context
*ev
;
866 struct cli_state
*cli
;
868 const struct smb2_create_blobs
*in_cblobs
;
873 static void cli_smb2_rmdir_opened1(struct tevent_req
*subreq
);
874 static void cli_smb2_rmdir_opened2(struct tevent_req
*subreq
);
875 static void cli_smb2_rmdir_disp_set(struct tevent_req
*subreq
);
876 static void cli_smb2_rmdir_closed(struct tevent_req
*subreq
);
878 struct tevent_req
*cli_smb2_rmdir_send(
880 struct tevent_context
*ev
,
881 struct cli_state
*cli
,
883 const struct smb2_create_blobs
*in_cblobs
)
885 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
886 struct cli_smb2_rmdir_state
*state
= NULL
;
888 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_rmdir_state
);
894 state
->dname
= dname
;
895 state
->in_cblobs
= in_cblobs
;
897 subreq
= cli_smb2_create_fnum_send(
902 (struct cli_smb2_create_flags
){0},
903 SMB2_IMPERSONATION_IMPERSONATION
,
904 DELETE_ACCESS
, /* desired_access */
905 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
906 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
907 FILE_OPEN
, /* create_disposition */
908 FILE_DIRECTORY_FILE
, /* create_options */
909 state
->in_cblobs
); /* in_cblobs */
910 if (tevent_req_nomem(subreq
, req
)) {
911 return tevent_req_post(req
, ev
);
913 tevent_req_set_callback(subreq
, cli_smb2_rmdir_opened1
, req
);
917 static void cli_smb2_rmdir_opened1(struct tevent_req
*subreq
)
919 struct tevent_req
*req
= tevent_req_callback_data(
920 subreq
, struct tevent_req
);
921 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
922 req
, struct cli_smb2_rmdir_state
);
925 status
= cli_smb2_create_fnum_recv(
926 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
929 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
931 * Naive option to match our SMB1 code. Assume the
932 * symlink path that tripped us up was the last
933 * component and try again. Eventually we will have to
934 * deal with the returned path unprocessed component. JRA.
936 subreq
= cli_smb2_create_fnum_send(
941 (struct cli_smb2_create_flags
){0},
942 SMB2_IMPERSONATION_IMPERSONATION
,
943 DELETE_ACCESS
, /* desired_access */
944 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
945 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
946 FILE_OPEN
, /* create_disposition */
948 FILE_DELETE_ON_CLOSE
|
949 FILE_OPEN_REPARSE_POINT
, /* create_options */
950 state
->in_cblobs
); /* in_cblobs */
951 if (tevent_req_nomem(subreq
, req
)) {
954 tevent_req_set_callback(subreq
, cli_smb2_rmdir_opened2
, req
);
958 if (tevent_req_nterror(req
, status
)) {
962 subreq
= cli_smb2_delete_on_close_send(
963 state
, state
->ev
, state
->cli
, state
->fnum
, true);
964 if (tevent_req_nomem(subreq
, req
)) {
967 tevent_req_set_callback(subreq
, cli_smb2_rmdir_disp_set
, req
);
970 static void cli_smb2_rmdir_opened2(struct tevent_req
*subreq
)
972 struct tevent_req
*req
= tevent_req_callback_data(
973 subreq
, struct tevent_req
);
974 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
975 req
, struct cli_smb2_rmdir_state
);
978 status
= cli_smb2_create_fnum_recv(
979 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
981 if (tevent_req_nterror(req
, status
)) {
985 subreq
= cli_smb2_delete_on_close_send(
986 state
, state
->ev
, state
->cli
, state
->fnum
, true);
987 if (tevent_req_nomem(subreq
, req
)) {
990 tevent_req_set_callback(subreq
, cli_smb2_rmdir_disp_set
, req
);
993 static void cli_smb2_rmdir_disp_set(struct tevent_req
*subreq
)
995 struct tevent_req
*req
= tevent_req_callback_data(
996 subreq
, struct tevent_req
);
997 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
998 req
, struct cli_smb2_rmdir_state
);
1000 state
->status
= cli_smb2_delete_on_close_recv(subreq
);
1001 TALLOC_FREE(subreq
);
1004 * Close the fd even if the set_disp failed
1007 subreq
= cli_smb2_close_fnum_send(
1008 state
, state
->ev
, state
->cli
, state
->fnum
);
1009 if (tevent_req_nomem(subreq
, req
)) {
1012 tevent_req_set_callback(subreq
, cli_smb2_rmdir_closed
, req
);
1015 static void cli_smb2_rmdir_closed(struct tevent_req
*subreq
)
1017 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
1018 tevent_req_simple_finish_ntstatus(subreq
, status
);
1021 NTSTATUS
cli_smb2_rmdir_recv(struct tevent_req
*req
)
1023 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
1024 req
, struct cli_smb2_rmdir_state
);
1027 if (tevent_req_is_nterror(req
, &status
)) {
1030 return state
->status
;
1033 /***************************************************************
1034 Small wrapper that allows SMB2 to unlink a pathname.
1035 ***************************************************************/
1037 struct cli_smb2_unlink_state
{
1038 struct tevent_context
*ev
;
1039 struct cli_state
*cli
;
1041 const struct smb2_create_blobs
*in_cblobs
;
1044 static void cli_smb2_unlink_opened1(struct tevent_req
*subreq
);
1045 static void cli_smb2_unlink_opened2(struct tevent_req
*subreq
);
1046 static void cli_smb2_unlink_closed(struct tevent_req
*subreq
);
1048 struct tevent_req
*cli_smb2_unlink_send(
1049 TALLOC_CTX
*mem_ctx
,
1050 struct tevent_context
*ev
,
1051 struct cli_state
*cli
,
1053 const struct smb2_create_blobs
*in_cblobs
)
1055 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1056 struct cli_smb2_unlink_state
*state
= NULL
;
1058 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_unlink_state
);
1064 state
->fname
= fname
;
1065 state
->in_cblobs
= in_cblobs
;
1067 subreq
= cli_smb2_create_fnum_send(
1068 state
, /* mem_ctx */
1069 state
->ev
, /* tevent_context */
1070 state
->cli
, /* cli_struct */
1071 state
->fname
, /* filename */
1072 (struct cli_smb2_create_flags
){0},
1073 SMB2_IMPERSONATION_IMPERSONATION
,
1074 DELETE_ACCESS
, /* desired_access */
1075 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
1078 FILE_SHARE_DELETE
, /* share_access */
1079 FILE_OPEN
, /* create_disposition */
1080 FILE_DELETE_ON_CLOSE
, /* create_options */
1081 state
->in_cblobs
); /* in_cblobs */
1082 if (tevent_req_nomem(subreq
, req
)) {
1083 return tevent_req_post(req
, ev
);
1085 tevent_req_set_callback(subreq
, cli_smb2_unlink_opened1
, req
);
1089 static void cli_smb2_unlink_opened1(struct tevent_req
*subreq
)
1091 struct tevent_req
*req
= tevent_req_callback_data(
1092 subreq
, struct tevent_req
);
1093 struct cli_smb2_unlink_state
*state
= tevent_req_data(
1094 req
, struct cli_smb2_unlink_state
);
1095 uint16_t fnum
= 0xffff;
1098 status
= cli_smb2_create_fnum_recv(
1099 subreq
, &fnum
, NULL
, NULL
, NULL
, NULL
);
1100 TALLOC_FREE(subreq
);
1102 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
) ||
1103 NT_STATUS_EQUAL(status
, NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED
)) {
1105 * Naive option to match our SMB1 code. Assume the
1106 * symlink path that tripped us up was the last
1107 * component and try again. Eventually we will have to
1108 * deal with the returned path unprocessed component. JRA.
1110 subreq
= cli_smb2_create_fnum_send(
1111 state
, /* mem_ctx */
1112 state
->ev
, /* tevent_context */
1113 state
->cli
, /* cli_struct */
1114 state
->fname
, /* filename */
1115 (struct cli_smb2_create_flags
){0},
1116 SMB2_IMPERSONATION_IMPERSONATION
,
1117 DELETE_ACCESS
, /* desired_access */
1118 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
1121 FILE_SHARE_DELETE
, /* share_access */
1122 FILE_OPEN
, /* create_disposition */
1123 FILE_DELETE_ON_CLOSE
|
1124 FILE_OPEN_REPARSE_POINT
, /* create_options */
1125 state
->in_cblobs
); /* in_cblobs */
1126 if (tevent_req_nomem(subreq
, req
)) {
1129 tevent_req_set_callback(subreq
, cli_smb2_unlink_opened2
, req
);
1133 if (tevent_req_nterror(req
, status
)) {
1137 subreq
= cli_smb2_close_fnum_send(state
, state
->ev
, state
->cli
, fnum
);
1138 if (tevent_req_nomem(subreq
, req
)) {
1141 tevent_req_set_callback(subreq
, cli_smb2_unlink_closed
, req
);
1144 static void cli_smb2_unlink_opened2(struct tevent_req
*subreq
)
1146 struct tevent_req
*req
= tevent_req_callback_data(
1147 subreq
, struct tevent_req
);
1148 struct cli_smb2_unlink_state
*state
= tevent_req_data(
1149 req
, struct cli_smb2_unlink_state
);
1150 uint16_t fnum
= 0xffff;
1153 status
= cli_smb2_create_fnum_recv(
1154 subreq
, &fnum
, NULL
, NULL
, NULL
, NULL
);
1155 TALLOC_FREE(subreq
);
1156 if (tevent_req_nterror(req
, status
)) {
1160 subreq
= cli_smb2_close_fnum_send(state
, state
->ev
, state
->cli
, fnum
);
1161 if (tevent_req_nomem(subreq
, req
)) {
1164 tevent_req_set_callback(subreq
, cli_smb2_unlink_closed
, req
);
1167 static void cli_smb2_unlink_closed(struct tevent_req
*subreq
)
1169 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
1170 tevent_req_simple_finish_ntstatus(subreq
, status
);
1173 NTSTATUS
cli_smb2_unlink_recv(struct tevent_req
*req
)
1175 return tevent_req_simple_recv_ntstatus(req
);
1178 /***************************************************************
1179 Utility function to parse a SMB2_FIND_POSIX_INFORMATION reply.
1180 ***************************************************************/
1182 static NTSTATUS
parse_finfo_posix_info(const uint8_t *dir_data
,
1183 uint32_t dir_data_length
,
1184 struct file_info
*finfo
,
1185 uint32_t *next_offset
)
1187 struct smb3_file_posix_information info
= {};
1189 enum ndr_err_code ndr_err
;
1192 uint32_t _next_offset
= 0;
1194 if (dir_data_length
< 4) {
1195 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1198 _next_offset
= IVAL(dir_data
, 0);
1200 if (_next_offset
> dir_data_length
) {
1201 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1204 if (_next_offset
!= 0) {
1205 /* Ensure we only read what in this record. */
1206 dir_data_length
= _next_offset
;
1210 * Skip NextEntryOffset and FileIndex
1212 if (dir_data_length
< 8) {
1213 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1216 dir_data_length
-= 8;
1218 ndr_err
= ndr_pull_struct_blob_noalloc(
1222 (ndr_pull_flags_fn_t
)ndr_pull_smb3_file_posix_information
,
1224 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1225 return ndr_map_error2ntstatus(ndr_err
);
1227 if (consumed
> dir_data_length
) {
1228 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1230 dir_data
+= consumed
;
1231 dir_data_length
-= consumed
;
1233 finfo
->btime_ts
= interpret_long_date(info
.creation_time
);
1234 finfo
->atime_ts
= interpret_long_date(info
.last_access_time
);
1235 finfo
->mtime_ts
= interpret_long_date(info
.last_write_time
);
1236 finfo
->ctime_ts
= interpret_long_date(info
.change_time
);
1237 finfo
->allocated_size
= info
.allocation_size
;
1238 finfo
->size
= info
.end_of_file
;
1239 finfo
->mode
= info
.file_attributes
;
1240 finfo
->ino
= info
.inode
;
1241 finfo
->st_ex_dev
= info
.device
;
1242 finfo
->st_ex_nlink
= info
.cc
.nlinks
;
1243 finfo
->reparse_tag
= info
.cc
.reparse_tag
;
1244 finfo
->st_ex_mode
= wire_perms_to_unix(info
.cc
.posix_perms
);
1245 sid_copy(&finfo
->owner_sid
, &info
.cc
.owner
);
1246 sid_copy(&finfo
->group_sid
, &info
.cc
.group
);
1248 if (dir_data_length
< 4) {
1249 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1251 namelen
= PULL_LE_U32(dir_data
, 0);
1254 dir_data_length
-= 4;
1256 if (namelen
> dir_data_length
) {
1257 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1260 ret
= pull_string_talloc(finfo
,
1262 FLAGS2_UNICODE_STRINGS
,
1267 if (ret
== (size_t)-1) {
1268 /* Bad conversion. */
1269 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1272 if (finfo
->name
== NULL
) {
1273 /* Bad conversion. */
1274 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1277 *next_offset
= _next_offset
;
1278 return NT_STATUS_OK
;
1281 /***************************************************************
1282 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1283 ***************************************************************/
1285 static NTSTATUS
parse_finfo_id_both_directory_info(const uint8_t *dir_data
,
1286 uint32_t dir_data_length
,
1287 struct file_info
*finfo
,
1288 uint32_t *next_offset
)
1294 if (dir_data_length
< 4) {
1295 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1298 *next_offset
= IVAL(dir_data
, 0);
1300 if (*next_offset
> dir_data_length
) {
1301 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1304 if (*next_offset
!= 0) {
1305 /* Ensure we only read what in this record. */
1306 dir_data_length
= *next_offset
;
1309 if (dir_data_length
< 105) {
1310 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1313 finfo
->btime_ts
= interpret_long_date(BVAL(dir_data
, 8));
1314 finfo
->atime_ts
= interpret_long_date(BVAL(dir_data
, 16));
1315 finfo
->mtime_ts
= interpret_long_date(BVAL(dir_data
, 24));
1316 finfo
->ctime_ts
= interpret_long_date(BVAL(dir_data
, 32));
1317 finfo
->size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 40, 0);
1318 finfo
->allocated_size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 48, 0);
1319 finfo
->attr
= IVAL(dir_data
+ 56, 0);
1320 finfo
->ino
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 96, 0);
1321 namelen
= IVAL(dir_data
+ 60,0);
1322 if (namelen
> (dir_data_length
- 104)) {
1323 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1325 slen
= CVAL(dir_data
+ 68, 0);
1327 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1329 ret
= pull_string_talloc(finfo
,
1331 FLAGS2_UNICODE_STRINGS
,
1336 if (ret
== (size_t)-1) {
1337 /* Bad conversion. */
1338 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1341 ret
= pull_string_talloc(finfo
,
1343 FLAGS2_UNICODE_STRINGS
,
1348 if (ret
== (size_t)-1) {
1349 /* Bad conversion. */
1350 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1353 if (finfo
->name
== NULL
) {
1354 /* Bad conversion. */
1355 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1358 return NT_STATUS_OK
;
1361 /*******************************************************************
1362 Given a filename - get its directory name
1363 ********************************************************************/
1365 static bool windows_parent_dirname(TALLOC_CTX
*mem_ctx
,
1373 p
= strrchr_m(dir
, '\\'); /* Find final '\\', if any */
1376 if (!(*parent
= talloc_strdup(mem_ctx
, "\\"))) {
1387 if (!(*parent
= (char *)talloc_memdup(mem_ctx
, dir
, len
+1))) {
1390 (*parent
)[len
] = '\0';
1398 struct cli_smb2_list_dir_data
{
1403 struct cli_smb2_list_state
{
1404 struct tevent_context
*ev
;
1405 struct cli_state
*cli
;
1411 struct cli_smb2_list_dir_data
*response
;
1413 unsigned int info_level
;
1416 static void cli_smb2_list_opened(struct tevent_req
*subreq
);
1417 static void cli_smb2_list_done(struct tevent_req
*subreq
);
1418 static void cli_smb2_list_closed(struct tevent_req
*subreq
);
1420 struct tevent_req
*cli_smb2_list_send(
1421 TALLOC_CTX
*mem_ctx
,
1422 struct tevent_context
*ev
,
1423 struct cli_state
*cli
,
1424 const char *pathname
,
1425 unsigned int info_level
,
1428 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1429 struct cli_smb2_list_state
*state
= NULL
;
1430 char *parent
= NULL
;
1432 struct smb2_create_blobs
*in_cblobs
= NULL
;
1434 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_list_state
);
1440 state
->status
= NT_STATUS_OK
;
1441 state
->info_level
= info_level
;
1443 ok
= windows_parent_dirname(state
, pathname
, &parent
, &state
->mask
);
1445 tevent_req_oom(req
);
1446 return tevent_req_post(req
, ev
);
1449 if (smbXcli_conn_have_posix(cli
->conn
) && posix
) {
1452 /* The mode MUST be 0 when opening an existing file/dir, and
1453 * will be ignored by the server.
1455 uint8_t linear_mode
[4] = { 0 };
1456 DATA_BLOB blob
= { .data
=linear_mode
,
1457 .length
=sizeof(linear_mode
) };
1459 in_cblobs
= talloc_zero(mem_ctx
, struct smb2_create_blobs
);
1460 if (in_cblobs
== NULL
) {
1464 status
= smb2_create_blob_add(in_cblobs
, in_cblobs
,
1465 SMB2_CREATE_TAG_POSIX
, blob
);
1466 if (tevent_req_nterror(req
, status
)) {
1467 tevent_req_nterror(req
, status
);
1468 return tevent_req_post(req
, ev
);
1472 subreq
= cli_smb2_create_fnum_send(
1473 state
, /* mem_ctx */
1477 (struct cli_smb2_create_flags
){0}, /* create_flags */
1478 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation_level */
1479 SEC_DIR_LIST
|SEC_DIR_READ_ATTRIBUTE
, /* desired_access */
1480 FILE_ATTRIBUTE_DIRECTORY
, /* file_attributes */
1481 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
1482 FILE_OPEN
, /* create_disposition */
1483 FILE_DIRECTORY_FILE
, /* create_options */
1484 in_cblobs
); /* in_cblobs */
1485 TALLOC_FREE(in_cblobs
);
1486 if (tevent_req_nomem(subreq
, req
)) {
1487 return tevent_req_post(req
, ev
);
1489 tevent_req_set_callback(subreq
, cli_smb2_list_opened
, req
);
1493 static void cli_smb2_list_opened(struct tevent_req
*subreq
)
1495 struct tevent_req
*req
= tevent_req_callback_data(
1496 subreq
, struct tevent_req
);
1497 struct cli_smb2_list_state
*state
= tevent_req_data(
1498 req
, struct cli_smb2_list_state
);
1501 status
= cli_smb2_create_fnum_recv(
1502 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
1503 TALLOC_FREE(subreq
);
1504 if (tevent_req_nterror(req
, status
)) {
1509 * Make our caller get back to us via cli_smb2_list_recv(),
1510 * triggering the smb2_query_directory_send()
1512 tevent_req_defer_callback(req
, state
->ev
);
1513 tevent_req_notify_callback(req
);
1516 static void cli_smb2_list_done(struct tevent_req
*subreq
)
1518 struct tevent_req
*req
= tevent_req_callback_data(
1519 subreq
, struct tevent_req
);
1520 struct cli_smb2_list_state
*state
= tevent_req_data(
1521 req
, struct cli_smb2_list_state
);
1522 struct cli_smb2_list_dir_data
*response
= NULL
;
1524 response
= talloc(state
, struct cli_smb2_list_dir_data
);
1525 if (tevent_req_nomem(response
, req
)) {
1529 state
->status
= smb2cli_query_directory_recv(
1530 subreq
, response
, &response
->data
, &response
->length
);
1531 TALLOC_FREE(subreq
);
1533 if (NT_STATUS_IS_OK(state
->status
)) {
1534 state
->response
= response
;
1537 tevent_req_defer_callback(req
, state
->ev
);
1538 tevent_req_notify_callback(req
);
1542 TALLOC_FREE(response
);
1544 subreq
= cli_smb2_close_fnum_send(
1545 state
, state
->ev
, state
->cli
, state
->fnum
);
1546 if (tevent_req_nomem(subreq
, req
)) {
1549 tevent_req_set_callback(subreq
, cli_smb2_list_closed
, req
);
1552 static void cli_smb2_list_closed(struct tevent_req
*subreq
)
1554 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
1555 tevent_req_simple_finish_ntstatus(subreq
, status
);
1559 * Return the next finfo directory.
1561 * This parses the blob returned from QUERY_DIRECTORY step by step. If
1562 * the blob ends, this triggers a fresh QUERY_DIRECTORY and returns
1563 * NT_STATUS_RETRY, which will then trigger the caller again when the
1564 * QUERY_DIRECTORY has returned with another buffer. This way we
1565 * guarantee that no asynchronous request is open after this call
1566 * returns an entry, so that other synchronous requests can be issued
1567 * on the same connection while the directory listing proceeds.
1569 NTSTATUS
cli_smb2_list_recv(
1570 struct tevent_req
*req
,
1571 TALLOC_CTX
*mem_ctx
,
1572 struct file_info
**pfinfo
)
1574 struct cli_smb2_list_state
*state
= tevent_req_data(
1575 req
, struct cli_smb2_list_state
);
1576 struct cli_smb2_list_dir_data
*response
= NULL
;
1577 struct file_info
*finfo
= NULL
;
1579 uint32_t next_offset
= 0;
1582 in_progress
= tevent_req_is_in_progress(req
);
1585 if (!tevent_req_is_nterror(req
, &status
)) {
1586 status
= NT_STATUS_NO_MORE_FILES
;
1591 response
= state
->response
;
1592 if (response
== NULL
) {
1593 struct tevent_req
*subreq
= NULL
;
1594 struct cli_state
*cli
= state
->cli
;
1595 struct smb2_hnd
*ph
= NULL
;
1596 uint32_t max_trans
, max_avail_len
;
1599 if (!NT_STATUS_IS_OK(state
->status
)) {
1600 status
= state
->status
;
1604 status
= map_fnum_to_smb2_handle(cli
, state
->fnum
, &ph
);
1605 if (!NT_STATUS_IS_OK(status
)) {
1609 max_trans
= smb2cli_conn_max_trans_size(cli
->conn
);
1610 ok
= smb2cli_conn_req_possible(cli
->conn
, &max_avail_len
);
1612 max_trans
= MIN(max_trans
, max_avail_len
);
1615 subreq
= smb2cli_query_directory_send(
1616 state
, /* mem_ctx */
1618 cli
->conn
, /* conn */
1619 cli
->timeout
, /* timeout_msec */
1620 cli
->smb2
.session
, /* session */
1621 cli
->smb2
.tcon
, /* tcon */
1622 state
->info_level
, /* level */
1625 ph
->fid_persistent
, /* fid_persistent */
1626 ph
->fid_volatile
, /* fid_volatile */
1627 state
->mask
, /* mask */
1628 max_trans
); /* outbuf_len */
1629 if (subreq
== NULL
) {
1630 status
= NT_STATUS_NO_MEMORY
;
1633 tevent_req_set_callback(subreq
, cli_smb2_list_done
, req
);
1634 return NT_STATUS_RETRY
;
1637 SMB_ASSERT(response
->length
> state
->offset
);
1639 finfo
= talloc_zero(mem_ctx
, struct file_info
);
1640 if (finfo
== NULL
) {
1641 status
= NT_STATUS_NO_MEMORY
;
1645 if (state
->info_level
== SMB2_FIND_POSIX_INFORMATION
) {
1646 status
= parse_finfo_posix_info(
1647 response
->data
+ state
->offset
,
1648 response
->length
- state
->offset
,
1652 status
= parse_finfo_id_both_directory_info(
1653 response
->data
+ state
->offset
,
1654 response
->length
- state
->offset
,
1658 if (!NT_STATUS_IS_OK(status
)) {
1662 status
= is_bad_finfo_name(state
->cli
, finfo
);
1663 if (!NT_STATUS_IS_OK(status
)) {
1668 * parse_finfo_id_both_directory_info() checks for overflow,
1669 * no need to check again here.
1671 state
->offset
+= next_offset
;
1673 if (next_offset
== 0) {
1674 TALLOC_FREE(state
->response
);
1677 tevent_req_defer_callback(req
, state
->ev
);
1678 tevent_req_notify_callback(req
);
1681 return NT_STATUS_OK
;
1685 tevent_req_received(req
);
1689 /***************************************************************
1690 Wrapper that allows SMB2 to query a path info (basic level).
1692 ***************************************************************/
1694 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
1696 SMB_STRUCT_STAT
*sbuf
,
1697 uint32_t *attributes
)
1700 struct smb_create_returns cr
;
1701 uint16_t fnum
= 0xffff;
1702 size_t namelen
= strlen(name
);
1704 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1706 * Can't use sync call while an async call is in flight
1708 return NT_STATUS_INVALID_PARAMETER
;
1711 /* SMB2 is pickier about pathnames. Ensure it doesn't
1713 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1714 char *modname
= talloc_strndup(talloc_tos(), name
, namelen
-1);
1715 if (modname
== NULL
) {
1716 return NT_STATUS_NO_MEMORY
;
1721 /* This is commonly used as a 'cd'. Try qpathinfo on
1722 a directory handle first. */
1724 status
= cli_smb2_create_fnum(cli
,
1726 (struct cli_smb2_create_flags
){0},
1727 SMB2_IMPERSONATION_IMPERSONATION
,
1728 FILE_READ_ATTRIBUTES
, /* desired_access */
1729 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1730 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1731 FILE_OPEN
, /* create_disposition */
1732 FILE_DIRECTORY_FILE
, /* create_options */
1739 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
1740 /* Maybe a file ? */
1741 status
= cli_smb2_create_fnum(cli
,
1743 (struct cli_smb2_create_flags
){0},
1744 SMB2_IMPERSONATION_IMPERSONATION
,
1745 FILE_READ_ATTRIBUTES
, /* desired_access */
1746 0, /* file attributes */
1747 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1748 FILE_OPEN
, /* create_disposition */
1749 0, /* create_options */
1757 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
1758 /* Maybe a reparse point ? */
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 0, /* file attributes */
1765 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1766 FILE_OPEN
, /* create_disposition */
1767 FILE_OPEN_REPARSE_POINT
, /* create_options */
1775 if (!NT_STATUS_IS_OK(status
)) {
1779 status
= cli_smb2_close_fnum(cli
, fnum
);
1783 sbuf
->st_ex_atime
= nt_time_to_unix_timespec(cr
.last_access_time
);
1784 sbuf
->st_ex_mtime
= nt_time_to_unix_timespec(cr
.last_write_time
);
1785 sbuf
->st_ex_ctime
= nt_time_to_unix_timespec(cr
.change_time
);
1786 sbuf
->st_ex_size
= cr
.end_of_file
;
1787 *attributes
= cr
.file_attributes
;
1792 struct cli_smb2_query_info_fnum_state
{
1796 static void cli_smb2_query_info_fnum_done(struct tevent_req
*subreq
);
1798 struct tevent_req
*cli_smb2_query_info_fnum_send(
1799 TALLOC_CTX
*mem_ctx
,
1800 struct tevent_context
*ev
,
1801 struct cli_state
*cli
,
1803 uint8_t in_info_type
,
1804 uint8_t in_info_class
,
1805 uint32_t in_max_output_length
,
1806 const DATA_BLOB
*in_input_buffer
,
1807 uint32_t in_additional_info
,
1810 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1811 struct cli_smb2_query_info_fnum_state
*state
= NULL
;
1812 struct smb2_hnd
*ph
= NULL
;
1815 req
= tevent_req_create(
1816 mem_ctx
, &state
, struct cli_smb2_query_info_fnum_state
);
1821 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
1822 if (tevent_req_nterror(req
, status
)) {
1823 return tevent_req_post(req
, ev
);
1826 subreq
= smb2cli_query_info_send(
1835 in_max_output_length
,
1841 if (tevent_req_nomem(subreq
, req
)) {
1842 return tevent_req_post(req
, ev
);
1844 tevent_req_set_callback(subreq
, cli_smb2_query_info_fnum_done
, req
);
1848 static void cli_smb2_query_info_fnum_done(struct tevent_req
*subreq
)
1850 struct tevent_req
*req
= tevent_req_callback_data(
1851 subreq
, struct tevent_req
);
1852 struct cli_smb2_query_info_fnum_state
*state
= tevent_req_data(
1853 req
, struct cli_smb2_query_info_fnum_state
);
1857 status
= smb2cli_query_info_recv(subreq
, state
, &outbuf
);
1858 TALLOC_FREE(subreq
);
1859 if (tevent_req_nterror(req
, status
)) {
1864 * We have to dup the memory here because outbuf.data is not
1865 * returned as a talloc object by smb2cli_query_info_recv.
1866 * It's a pointer into the received buffer.
1868 state
->outbuf
= data_blob_dup_talloc(state
, outbuf
);
1870 if ((outbuf
.length
!= 0) &&
1871 tevent_req_nomem(state
->outbuf
.data
, req
)) {
1874 tevent_req_done(req
);
1877 NTSTATUS
cli_smb2_query_info_fnum_recv(
1878 struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
, DATA_BLOB
*outbuf
)
1880 struct cli_smb2_query_info_fnum_state
*state
= tevent_req_data(
1881 req
, struct cli_smb2_query_info_fnum_state
);
1884 if (tevent_req_is_nterror(req
, &status
)) {
1887 *outbuf
= (DATA_BLOB
) {
1888 .data
= talloc_move(mem_ctx
, &state
->outbuf
.data
),
1889 .length
= state
->outbuf
.length
,
1891 return NT_STATUS_OK
;
1894 NTSTATUS
cli_smb2_query_info_fnum(
1895 struct cli_state
*cli
,
1897 uint8_t in_info_type
,
1898 uint8_t in_info_class
,
1899 uint32_t in_max_output_length
,
1900 const DATA_BLOB
*in_input_buffer
,
1901 uint32_t in_additional_info
,
1903 TALLOC_CTX
*mem_ctx
,
1906 TALLOC_CTX
*frame
= talloc_stackframe();
1907 struct tevent_context
*ev
= NULL
;
1908 struct tevent_req
*req
= NULL
;
1909 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1912 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1914 * Can't use sync call while an async call is in flight
1916 status
= NT_STATUS_INVALID_PARAMETER
;
1919 ev
= samba_tevent_context_init(frame
);
1923 req
= cli_smb2_query_info_fnum_send(
1930 in_max_output_length
,
1937 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
1941 status
= cli_smb2_query_info_fnum_recv(req
, mem_ctx
, outbuf
);
1947 /***************************************************************
1948 Helper function for pathname operations.
1949 ***************************************************************/
1951 struct get_fnum_from_path_state
{
1952 struct tevent_context
*ev
;
1953 struct cli_state
*cli
;
1955 uint32_t desired_access
;
1959 static void get_fnum_from_path_opened_file(struct tevent_req
*subreq
);
1960 static void get_fnum_from_path_opened_reparse(struct tevent_req
*subreq
);
1961 static void get_fnum_from_path_opened_dir(struct tevent_req
*subreq
);
1963 static struct tevent_req
*get_fnum_from_path_send(
1964 TALLOC_CTX
*mem_ctx
,
1965 struct tevent_context
*ev
,
1966 struct cli_state
*cli
,
1968 uint32_t desired_access
)
1970 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1971 struct get_fnum_from_path_state
*state
= NULL
;
1972 size_t namelen
= strlen(name
);
1974 req
= tevent_req_create(
1975 mem_ctx
, &state
, struct get_fnum_from_path_state
);
1982 state
->desired_access
= desired_access
;
1985 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
1988 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1989 state
->name
= talloc_strndup(state
, name
, namelen
-1);
1990 if (tevent_req_nomem(state
->name
, req
)) {
1991 return tevent_req_post(req
, ev
);
1995 subreq
= cli_smb2_create_fnum_send(
1996 state
, /* mem_ctx, */
1999 state
->name
, /* fname */
2000 (struct cli_smb2_create_flags
){0}, /* create_flags */
2001 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation_level */
2002 desired_access
, /* desired_access */
2003 0, /* file_attributes */
2006 FILE_SHARE_DELETE
, /* share_access */
2007 FILE_OPEN
, /* create_disposition */
2008 0, /* create_options */
2009 NULL
); /* in_cblobs */
2010 if (tevent_req_nomem(subreq
, req
)) {
2011 return tevent_req_post(req
, ev
);
2013 tevent_req_set_callback(subreq
, get_fnum_from_path_opened_file
, req
);
2017 static void get_fnum_from_path_opened_file(struct tevent_req
*subreq
)
2019 struct tevent_req
*req
= tevent_req_callback_data(
2020 subreq
, struct tevent_req
);
2021 struct get_fnum_from_path_state
*state
= tevent_req_data(
2022 req
, struct get_fnum_from_path_state
);
2025 status
= cli_smb2_create_fnum_recv(
2026 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
2027 TALLOC_FREE(subreq
);
2029 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
) ||
2030 NT_STATUS_EQUAL(status
, NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED
)) {
2032 * Naive option to match our SMB1 code. Assume the
2033 * symlink path that tripped us up was the last
2034 * component and try again. Eventually we will have to
2035 * deal with the returned path unprocessed component. JRA.
2037 subreq
= cli_smb2_create_fnum_send(
2038 state
, /* mem_ctx, */
2040 state
->cli
, /* cli */
2041 state
->name
, /* fname */
2042 (struct cli_smb2_create_flags
){0}, /* create_flags */
2043 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation */
2044 state
->desired_access
, /* desired_access */
2045 0, /* file_attributes */
2048 FILE_SHARE_DELETE
, /* share_access */
2049 FILE_OPEN
, /* create_disposition */
2050 FILE_OPEN_REPARSE_POINT
, /* create_options */
2051 NULL
); /* in_cblobs */
2052 if (tevent_req_nomem(subreq
, req
)) {
2055 tevent_req_set_callback(
2056 subreq
, get_fnum_from_path_opened_reparse
, req
);
2060 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
2061 subreq
= cli_smb2_create_fnum_send(
2062 state
, /* mem_ctx, */
2064 state
->cli
, /* cli */
2065 state
->name
, /* fname */
2066 (struct cli_smb2_create_flags
){0}, /* create_flags */
2067 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation */
2068 state
->desired_access
, /* desired_access */
2069 0, /* file_attributes */
2072 FILE_SHARE_DELETE
, /* share_access */
2073 FILE_OPEN
, /* create_disposition */
2074 FILE_DIRECTORY_FILE
, /* create_options */
2075 NULL
); /* in_cblobs */
2076 if (tevent_req_nomem(subreq
, req
)) {
2079 tevent_req_set_callback(
2080 subreq
, get_fnum_from_path_opened_dir
, req
);
2084 if (tevent_req_nterror(req
, status
)) {
2087 tevent_req_done(req
);
2090 static void get_fnum_from_path_opened_reparse(struct tevent_req
*subreq
)
2092 struct tevent_req
*req
= tevent_req_callback_data(
2093 subreq
, struct tevent_req
);
2094 struct get_fnum_from_path_state
*state
= tevent_req_data(
2095 req
, struct get_fnum_from_path_state
);
2096 NTSTATUS status
= cli_smb2_create_fnum_recv(
2097 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
2098 tevent_req_simple_finish_ntstatus(subreq
, status
);
2101 static void get_fnum_from_path_opened_dir(struct tevent_req
*subreq
)
2103 /* Abstraction violation, but these two are just the same... */
2104 get_fnum_from_path_opened_reparse(subreq
);
2107 static NTSTATUS
get_fnum_from_path_recv(
2108 struct tevent_req
*req
, uint16_t *pfnum
)
2110 struct get_fnum_from_path_state
*state
= tevent_req_data(
2111 req
, struct get_fnum_from_path_state
);
2112 NTSTATUS status
= NT_STATUS_OK
;
2114 if (!tevent_req_is_nterror(req
, &status
)) {
2115 *pfnum
= state
->fnum
;
2117 tevent_req_received(req
);
2121 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
2123 uint32_t desired_access
,
2126 TALLOC_CTX
*frame
= talloc_stackframe();
2127 struct tevent_context
*ev
= NULL
;
2128 struct tevent_req
*req
= NULL
;
2129 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
2131 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2132 status
= NT_STATUS_INVALID_PARAMETER
;
2135 ev
= samba_tevent_context_init(frame
);
2139 req
= get_fnum_from_path_send(frame
, ev
, cli
, name
, desired_access
);
2143 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2146 status
= get_fnum_from_path_recv(req
, pfnum
);
2152 /***************************************************************
2153 Wrapper that allows SMB2 to query a path info (ALTNAME level).
2155 ***************************************************************/
2157 NTSTATUS
cli_smb2_qpathinfo_alt_name(struct cli_state
*cli
,
2162 DATA_BLOB outbuf
= data_blob_null
;
2163 uint16_t fnum
= 0xffff;
2164 uint32_t altnamelen
= 0;
2165 TALLOC_CTX
*frame
= talloc_stackframe();
2167 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2169 * Can't use sync call while an async call is in flight
2171 status
= NT_STATUS_INVALID_PARAMETER
;
2175 status
= get_fnum_from_path(cli
,
2177 FILE_READ_ATTRIBUTES
,
2180 if (!NT_STATUS_IS_OK(status
)) {
2184 status
= cli_smb2_query_info_fnum(
2187 1, /* in_info_type */
2188 (SMB_FILE_ALTERNATE_NAME_INFORMATION
- 1000), /* in_file_info_class */
2189 0xFFFF, /* in_max_output_length */
2190 NULL
, /* in_input_buffer */
2191 0, /* in_additional_info */
2196 if (!NT_STATUS_IS_OK(status
)) {
2200 /* Parse the reply. */
2201 if (outbuf
.length
< 4) {
2202 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2206 altnamelen
= IVAL(outbuf
.data
, 0);
2207 if (altnamelen
> outbuf
.length
- 4) {
2208 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2212 if (altnamelen
> 0) {
2214 char *short_name
= NULL
;
2215 ret
= pull_string_talloc(frame
,
2217 FLAGS2_UNICODE_STRINGS
,
2222 if (ret
== (size_t)-1) {
2223 /* Bad conversion. */
2224 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2228 fstrcpy(alt_name
, short_name
);
2233 status
= NT_STATUS_OK
;
2237 if (fnum
!= 0xffff) {
2238 cli_smb2_close_fnum(cli
, fnum
);
2241 cli
->raw_status
= status
;
2247 struct cli_smb2_qpathinfo_state
{
2248 struct tevent_context
*ev
;
2249 struct cli_state
*cli
;
2260 static void cli_smb2_qpathinfo_opened(struct tevent_req
*subreq
);
2261 static void cli_smb2_qpathinfo_done(struct tevent_req
*subreq
);
2262 static void cli_smb2_qpathinfo_closed(struct tevent_req
*subreq
);
2264 struct tevent_req
*cli_smb2_qpathinfo_send(TALLOC_CTX
*mem_ctx
,
2265 struct tevent_context
*ev
,
2266 struct cli_state
*cli
,
2272 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
2273 struct cli_smb2_qpathinfo_state
*state
= NULL
;
2275 req
= tevent_req_create(mem_ctx
,
2277 struct cli_smb2_qpathinfo_state
);
2283 state
->level
= level
;
2284 state
->min_rdata
= min_rdata
;
2285 state
->max_rdata
= max_rdata
;
2287 subreq
= get_fnum_from_path_send(state
,
2291 FILE_READ_ATTRIBUTES
);
2292 if (tevent_req_nomem(subreq
, req
)) {
2293 return tevent_req_post(req
, ev
);
2295 tevent_req_set_callback(subreq
, cli_smb2_qpathinfo_opened
, req
);
2299 static void cli_smb2_qpathinfo_opened(struct tevent_req
*subreq
)
2301 struct tevent_req
*req
=
2302 tevent_req_callback_data(subreq
, struct tevent_req
);
2303 struct cli_smb2_qpathinfo_state
*state
=
2304 tevent_req_data(req
, struct cli_smb2_qpathinfo_state
);
2307 status
= get_fnum_from_path_recv(subreq
, &state
->fnum
);
2308 TALLOC_FREE(subreq
);
2309 if (tevent_req_nterror(req
, status
)) {
2313 subreq
= cli_smb2_query_info_fnum_send(state
,
2317 1, /* in_info_type */
2320 NULL
, /* in_input_buffer */
2321 0, /* in_additional_info */
2323 if (tevent_req_nomem(subreq
, req
)) {
2326 tevent_req_set_callback(subreq
, cli_smb2_qpathinfo_done
, req
);
2329 static void cli_smb2_qpathinfo_done(struct tevent_req
*subreq
)
2331 struct tevent_req
*req
=
2332 tevent_req_callback_data(subreq
, struct tevent_req
);
2333 struct cli_smb2_qpathinfo_state
*state
=
2334 tevent_req_data(req
, struct cli_smb2_qpathinfo_state
);
2337 cli_smb2_query_info_fnum_recv(subreq
, state
, &state
->out
);
2338 TALLOC_FREE(subreq
);
2340 if (NT_STATUS_IS_OK(state
->status
) &&
2341 (state
->out
.length
< state
->min_rdata
)) {
2342 state
->status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2345 subreq
= cli_smb2_close_fnum_send(state
,
2349 if (tevent_req_nomem(subreq
, req
)) {
2352 tevent_req_set_callback(subreq
, cli_smb2_qpathinfo_closed
, req
);
2355 static void cli_smb2_qpathinfo_closed(struct tevent_req
*subreq
)
2357 struct tevent_req
*req
=
2358 tevent_req_callback_data(subreq
, struct tevent_req
);
2359 struct cli_smb2_qpathinfo_state
*state
=
2360 tevent_req_data(req
, struct cli_smb2_qpathinfo_state
);
2363 status
= cli_smb2_close_fnum_recv(subreq
);
2364 TALLOC_FREE(subreq
);
2365 if (tevent_req_nterror(req
, status
)) {
2368 if (tevent_req_nterror(req
, state
->status
)) {
2371 tevent_req_done(req
);
2374 NTSTATUS
cli_smb2_qpathinfo_recv(struct tevent_req
*req
,
2375 TALLOC_CTX
*mem_ctx
,
2377 uint32_t *num_rdata
)
2379 struct cli_smb2_qpathinfo_state
*state
=
2380 tevent_req_data(req
, struct cli_smb2_qpathinfo_state
);
2383 if (tevent_req_is_nterror(req
, &status
)) {
2387 *rdata
= talloc_move(mem_ctx
, &state
->out
.data
);
2388 *num_rdata
= state
->out
.length
;
2389 tevent_req_received(req
);
2390 return NT_STATUS_OK
;
2393 /***************************************************************
2394 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2397 ***************************************************************/
2399 NTSTATUS
cli_smb2_setpathinfo(struct cli_state
*cli
,
2401 uint8_t in_info_type
,
2402 uint8_t in_file_info_class
,
2403 const DATA_BLOB
*p_in_data
)
2406 uint16_t fnum
= 0xffff;
2407 TALLOC_CTX
*frame
= talloc_stackframe();
2409 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2411 * Can't use sync call while an async call is in flight
2413 status
= NT_STATUS_INVALID_PARAMETER
;
2417 status
= get_fnum_from_path(cli
,
2419 FILE_WRITE_ATTRIBUTES
,
2422 if (!NT_STATUS_IS_OK(status
)) {
2426 status
= cli_smb2_set_info_fnum(
2431 p_in_data
, /* in_input_buffer */
2432 0); /* in_additional_info */
2435 if (fnum
!= 0xffff) {
2436 cli_smb2_close_fnum(cli
, fnum
);
2439 cli
->raw_status
= status
;
2446 /***************************************************************
2447 Wrapper that allows SMB2 to set pathname attributes.
2449 ***************************************************************/
2451 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
2456 uint8_t inbuf_store
[40];
2457 DATA_BLOB inbuf
= data_blob_null
;
2459 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2460 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2462 inbuf
.data
= inbuf_store
;
2463 inbuf
.length
= sizeof(inbuf_store
);
2464 data_blob_clear(&inbuf
);
2467 * SMB1 uses attr == 0 to clear all attributes
2468 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2469 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2470 * request attribute change.
2472 * SMB2 uses exactly the reverse. Unfortunately as the
2473 * cli_setatr() ABI is exposed inside libsmbclient,
2474 * we must make the SMB2 cli_smb2_setatr() call
2475 * export the same ABI as the SMB1 cli_setatr()
2476 * which calls it. This means reversing the sense
2477 * of the requested attr argument if it's zero
2478 * or FILE_ATTRIBUTE_NORMAL.
2480 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2484 attr
= FILE_ATTRIBUTE_NORMAL
;
2485 } else if (attr
== FILE_ATTRIBUTE_NORMAL
) {
2489 SIVAL(inbuf
.data
, 32, attr
);
2491 put_long_date((char *)inbuf
.data
+ 16,mtime
);
2493 /* Set all the other times to -1. */
2494 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
2495 SBVAL(inbuf
.data
, 8, 0xFFFFFFFFFFFFFFFFLL
);
2496 SBVAL(inbuf
.data
, 24, 0xFFFFFFFFFFFFFFFFLL
);
2498 return cli_smb2_setpathinfo(cli
,
2500 1, /* in_info_type */
2501 /* in_file_info_class */
2502 SMB_FILE_BASIC_INFORMATION
- 1000,
2507 /***************************************************************
2508 Wrapper that allows SMB2 to set file handle times.
2510 ***************************************************************/
2512 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
2518 uint8_t inbuf_store
[40];
2519 DATA_BLOB inbuf
= data_blob_null
;
2522 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2524 * Can't use sync call while an async call is in flight
2526 return NT_STATUS_INVALID_PARAMETER
;
2529 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2530 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2532 inbuf
.data
= inbuf_store
;
2533 inbuf
.length
= sizeof(inbuf_store
);
2534 data_blob_clear(&inbuf
);
2536 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
2537 if (change_time
!= 0) {
2538 put_long_date((char *)inbuf
.data
+ 24, change_time
);
2540 if (access_time
!= 0) {
2541 put_long_date((char *)inbuf
.data
+ 8, access_time
);
2543 if (write_time
!= 0) {
2544 put_long_date((char *)inbuf
.data
+ 16, write_time
);
2547 status
= cli_smb2_set_info_fnum(cli
,
2549 1, /* in_info_type */
2550 SMB_FILE_BASIC_INFORMATION
-
2551 1000, /* in_file_info_class */
2552 &inbuf
, /* in_input_buffer */
2553 0); /* in_additional_info */
2554 cli
->raw_status
= status
;
2558 /***************************************************************
2559 Wrapper that allows SMB2 to query disk attributes (size).
2561 ***************************************************************/
2563 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, const char *path
,
2564 uint64_t *bsize
, uint64_t *total
, uint64_t *avail
)
2567 uint16_t fnum
= 0xffff;
2568 DATA_BLOB outbuf
= data_blob_null
;
2569 uint32_t sectors_per_unit
= 0;
2570 uint32_t bytes_per_sector
= 0;
2571 uint64_t total_size
= 0;
2572 uint64_t size_free
= 0;
2573 TALLOC_CTX
*frame
= talloc_stackframe();
2575 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2577 * Can't use sync call while an async call is in flight
2579 status
= NT_STATUS_INVALID_PARAMETER
;
2583 /* First open the top level directory. */
2584 status
= cli_smb2_create_fnum(cli
,
2586 (struct cli_smb2_create_flags
){0},
2587 SMB2_IMPERSONATION_IMPERSONATION
,
2588 FILE_READ_ATTRIBUTES
, /* desired_access */
2589 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2590 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
2591 FILE_OPEN
, /* create_disposition */
2592 FILE_DIRECTORY_FILE
, /* create_options */
2599 if (!NT_STATUS_IS_OK(status
)) {
2603 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2604 level 3 (SMB_FS_SIZE_INFORMATION). */
2606 status
= cli_smb2_query_info_fnum(
2609 2, /* in_info_type */
2610 3, /* in_file_info_class */
2611 0xFFFF, /* in_max_output_length */
2612 NULL
, /* in_input_buffer */
2613 0, /* in_additional_info */
2617 if (!NT_STATUS_IS_OK(status
)) {
2621 /* Parse the reply. */
2622 if (outbuf
.length
!= 24) {
2623 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2627 total_size
= BVAL(outbuf
.data
, 0);
2628 size_free
= BVAL(outbuf
.data
, 8);
2629 sectors_per_unit
= IVAL(outbuf
.data
, 16);
2630 bytes_per_sector
= IVAL(outbuf
.data
, 20);
2633 *bsize
= (uint64_t)sectors_per_unit
* (uint64_t)bytes_per_sector
;
2636 *total
= total_size
;
2642 status
= NT_STATUS_OK
;
2646 if (fnum
!= 0xffff) {
2647 cli_smb2_close_fnum(cli
, fnum
);
2650 cli
->raw_status
= status
;
2656 /***************************************************************
2657 Wrapper that allows SMB2 to query file system sizes.
2659 ***************************************************************/
2661 NTSTATUS
cli_smb2_get_fs_full_size_info(struct cli_state
*cli
,
2662 uint64_t *total_allocation_units
,
2663 uint64_t *caller_allocation_units
,
2664 uint64_t *actual_allocation_units
,
2665 uint64_t *sectors_per_allocation_unit
,
2666 uint64_t *bytes_per_sector
)
2669 uint16_t fnum
= 0xffff;
2670 DATA_BLOB outbuf
= data_blob_null
;
2671 TALLOC_CTX
*frame
= talloc_stackframe();
2673 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2675 * Can't use sync call while an async call is in flight
2677 status
= NT_STATUS_INVALID_PARAMETER
;
2681 /* First open the top level directory. */
2683 cli_smb2_create_fnum(cli
, "",
2684 (struct cli_smb2_create_flags
){0},
2685 SMB2_IMPERSONATION_IMPERSONATION
,
2686 FILE_READ_ATTRIBUTES
, /* desired_access */
2687 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2688 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2689 FILE_SHARE_DELETE
, /* share_access */
2690 FILE_OPEN
, /* create_disposition */
2691 FILE_DIRECTORY_FILE
, /* create_options */
2698 if (!NT_STATUS_IS_OK(status
)) {
2702 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2703 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2705 status
= cli_smb2_query_info_fnum(
2708 SMB2_0_INFO_FILESYSTEM
, /* in_info_type */
2709 SMB_FS_FULL_SIZE_INFORMATION
- 1000, /* in_file_info_class */
2710 0xFFFF, /* in_max_output_length */
2711 NULL
, /* in_input_buffer */
2712 0, /* in_additional_info */
2716 if (!NT_STATUS_IS_OK(status
)) {
2720 if (outbuf
.length
< 32) {
2721 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2725 *total_allocation_units
= BIG_UINT(outbuf
.data
, 0);
2726 *caller_allocation_units
= BIG_UINT(outbuf
.data
, 8);
2727 *actual_allocation_units
= BIG_UINT(outbuf
.data
, 16);
2728 *sectors_per_allocation_unit
= (uint64_t)IVAL(outbuf
.data
, 24);
2729 *bytes_per_sector
= (uint64_t)IVAL(outbuf
.data
, 28);
2733 if (fnum
!= 0xffff) {
2734 cli_smb2_close_fnum(cli
, fnum
);
2737 cli
->raw_status
= status
;
2743 /***************************************************************
2744 Wrapper that allows SMB2 to query file system attributes.
2746 ***************************************************************/
2748 NTSTATUS
cli_smb2_get_fs_attr_info(struct cli_state
*cli
, uint32_t *fs_attr
)
2751 uint16_t fnum
= 0xffff;
2752 DATA_BLOB outbuf
= data_blob_null
;
2753 TALLOC_CTX
*frame
= talloc_stackframe();
2755 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2757 * Can't use sync call while an async call is in flight
2759 status
= NT_STATUS_INVALID_PARAMETER
;
2763 /* First open the top level directory. */
2765 cli_smb2_create_fnum(cli
, "",
2766 (struct cli_smb2_create_flags
){0},
2767 SMB2_IMPERSONATION_IMPERSONATION
,
2768 FILE_READ_ATTRIBUTES
, /* desired_access */
2769 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2770 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2771 FILE_SHARE_DELETE
, /* share_access */
2772 FILE_OPEN
, /* create_disposition */
2773 FILE_DIRECTORY_FILE
, /* create_options */
2780 if (!NT_STATUS_IS_OK(status
)) {
2784 status
= cli_smb2_query_info_fnum(
2787 2, /* in_info_type */
2788 5, /* in_file_info_class */
2789 0xFFFF, /* in_max_output_length */
2790 NULL
, /* in_input_buffer */
2791 0, /* in_additional_info */
2795 if (!NT_STATUS_IS_OK(status
)) {
2799 if (outbuf
.length
< 12) {
2800 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2804 *fs_attr
= IVAL(outbuf
.data
, 0);
2808 if (fnum
!= 0xffff) {
2809 cli_smb2_close_fnum(cli
, fnum
);
2812 cli
->raw_status
= status
;
2818 /***************************************************************
2819 Wrapper that allows SMB2 to query file system volume info.
2821 ***************************************************************/
2823 NTSTATUS
cli_smb2_get_fs_volume_info(struct cli_state
*cli
,
2824 TALLOC_CTX
*mem_ctx
,
2825 char **_volume_name
,
2826 uint32_t *pserial_number
,
2830 uint16_t fnum
= 0xffff;
2831 DATA_BLOB outbuf
= data_blob_null
;
2833 char *volume_name
= NULL
;
2834 TALLOC_CTX
*frame
= talloc_stackframe();
2836 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2838 * Can't use sync call while an async call is in flight
2840 status
= NT_STATUS_INVALID_PARAMETER
;
2844 /* First open the top level directory. */
2846 cli_smb2_create_fnum(cli
, "",
2847 (struct cli_smb2_create_flags
){0},
2848 SMB2_IMPERSONATION_IMPERSONATION
,
2849 FILE_READ_ATTRIBUTES
, /* desired_access */
2850 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2851 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2852 FILE_SHARE_DELETE
, /* share_access */
2853 FILE_OPEN
, /* create_disposition */
2854 FILE_DIRECTORY_FILE
, /* create_options */
2861 if (!NT_STATUS_IS_OK(status
)) {
2865 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2866 level 1 (SMB_FS_VOLUME_INFORMATION). */
2868 status
= cli_smb2_query_info_fnum(
2871 SMB2_0_INFO_FILESYSTEM
, /* in_info_type */
2872 /* in_file_info_class */
2873 SMB_FS_VOLUME_INFORMATION
- 1000,
2874 0xFFFF, /* in_max_output_length */
2875 NULL
, /* in_input_buffer */
2876 0, /* in_additional_info */
2880 if (!NT_STATUS_IS_OK(status
)) {
2884 if (outbuf
.length
< 24) {
2885 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2891 ts
= interpret_long_date(BVAL(outbuf
.data
, 0));
2894 if (pserial_number
) {
2895 *pserial_number
= IVAL(outbuf
.data
,8);
2897 nlen
= IVAL(outbuf
.data
,12);
2898 if (nlen
+ 18 < 18) {
2900 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2904 * The next check is safe as we know outbuf.length >= 24
2907 if (nlen
> (outbuf
.length
- 18)) {
2908 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2912 pull_string_talloc(mem_ctx
,
2913 (const char *)outbuf
.data
,
2919 if (volume_name
== NULL
) {
2920 status
= map_nt_error_from_unix(errno
);
2924 *_volume_name
= volume_name
;
2928 if (fnum
!= 0xffff) {
2929 cli_smb2_close_fnum(cli
, fnum
);
2932 cli
->raw_status
= status
;
2938 struct cli_smb2_mxac_state
{
2939 struct tevent_context
*ev
;
2940 struct cli_state
*cli
;
2942 struct smb2_create_blobs in_cblobs
;
2948 static void cli_smb2_mxac_opened(struct tevent_req
*subreq
);
2949 static void cli_smb2_mxac_closed(struct tevent_req
*subreq
);
2951 struct tevent_req
*cli_smb2_query_mxac_send(TALLOC_CTX
*mem_ctx
,
2952 struct tevent_context
*ev
,
2953 struct cli_state
*cli
,
2956 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
2957 struct cli_smb2_mxac_state
*state
= NULL
;
2960 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_mxac_state
);
2964 *state
= (struct cli_smb2_mxac_state
) {
2970 status
= smb2_create_blob_add(state
,
2972 SMB2_CREATE_TAG_MXAC
,
2973 data_blob(NULL
, 0));
2974 if (tevent_req_nterror(req
, status
)) {
2975 return tevent_req_post(req
, ev
);
2978 subreq
= cli_smb2_create_fnum_send(
2983 (struct cli_smb2_create_flags
){0},
2984 SMB2_IMPERSONATION_IMPERSONATION
,
2985 FILE_READ_ATTRIBUTES
,
2986 0, /* file attributes */
2987 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
2989 0, /* create_options */
2991 if (tevent_req_nomem(subreq
, req
)) {
2992 return tevent_req_post(req
, ev
);
2994 tevent_req_set_callback(subreq
, cli_smb2_mxac_opened
, req
);
2998 static void cli_smb2_mxac_opened(struct tevent_req
*subreq
)
3000 struct tevent_req
*req
= tevent_req_callback_data(
3001 subreq
, struct tevent_req
);
3002 struct cli_smb2_mxac_state
*state
= tevent_req_data(
3003 req
, struct cli_smb2_mxac_state
);
3004 struct smb2_create_blobs out_cblobs
= {0};
3005 struct smb2_create_blob
*mxac_blob
= NULL
;
3008 status
= cli_smb2_create_fnum_recv(
3009 subreq
, &state
->fnum
, NULL
, state
, &out_cblobs
, NULL
);
3010 TALLOC_FREE(subreq
);
3012 if (tevent_req_nterror(req
, status
)) {
3016 mxac_blob
= smb2_create_blob_find(&out_cblobs
, SMB2_CREATE_TAG_MXAC
);
3017 if (mxac_blob
== NULL
) {
3018 state
->status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3021 if (mxac_blob
->data
.length
!= 8) {
3022 state
->status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3026 state
->status
= NT_STATUS(IVAL(mxac_blob
->data
.data
, 0));
3027 state
->mxac
= IVAL(mxac_blob
->data
.data
, 4);
3030 subreq
= cli_smb2_close_fnum_send(
3031 state
, state
->ev
, state
->cli
, state
->fnum
);
3032 if (tevent_req_nomem(subreq
, req
)) {
3035 tevent_req_set_callback(subreq
, cli_smb2_mxac_closed
, req
);
3040 static void cli_smb2_mxac_closed(struct tevent_req
*subreq
)
3042 struct tevent_req
*req
= tevent_req_callback_data(
3043 subreq
, struct tevent_req
);
3046 status
= cli_smb2_close_fnum_recv(subreq
);
3047 if (tevent_req_nterror(req
, status
)) {
3051 tevent_req_done(req
);
3054 NTSTATUS
cli_smb2_query_mxac_recv(struct tevent_req
*req
, uint32_t *mxac
)
3056 struct cli_smb2_mxac_state
*state
= tevent_req_data(
3057 req
, struct cli_smb2_mxac_state
);
3060 if (tevent_req_is_nterror(req
, &status
)) {
3064 if (!NT_STATUS_IS_OK(state
->status
)) {
3065 return state
->status
;
3068 *mxac
= state
->mxac
;
3069 return NT_STATUS_OK
;
3072 NTSTATUS
cli_smb2_query_mxac(struct cli_state
*cli
,
3076 TALLOC_CTX
*frame
= talloc_stackframe();
3077 struct tevent_context
*ev
= NULL
;
3078 struct tevent_req
*req
= NULL
;
3079 NTSTATUS status
= NT_STATUS_INTERNAL_ERROR
;
3082 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3084 * Can't use sync call while an async call is in flight
3086 status
= NT_STATUS_INVALID_PARAMETER
;
3090 ev
= samba_tevent_context_init(frame
);
3094 req
= cli_smb2_query_mxac_send(frame
, ev
, cli
, fname
);
3098 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
3102 status
= cli_smb2_query_mxac_recv(req
, _mxac
);
3105 cli
->raw_status
= status
;
3110 struct cli_smb2_rename_fnum_state
{
3114 static void cli_smb2_rename_fnum_done(struct tevent_req
*subreq
);
3116 static struct tevent_req
*cli_smb2_rename_fnum_send(
3117 TALLOC_CTX
*mem_ctx
,
3118 struct tevent_context
*ev
,
3119 struct cli_state
*cli
,
3121 const char *fname_dst
,
3124 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
3125 struct cli_smb2_rename_fnum_state
*state
= NULL
;
3126 size_t namelen
= strlen(fname_dst
);
3127 smb_ucs2_t
*converted_str
= NULL
;
3128 size_t converted_size_bytes
= 0;
3132 req
= tevent_req_create(
3133 mem_ctx
, &state
, struct cli_smb2_rename_fnum_state
);
3139 * SMB2 is pickier about pathnames. Ensure it doesn't start in
3142 if (*fname_dst
== '\\') {
3147 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
3150 if (namelen
> 0 && fname_dst
[namelen
-1] == '\\') {
3151 fname_dst
= talloc_strndup(state
, fname_dst
, namelen
-1);
3152 if (tevent_req_nomem(fname_dst
, req
)) {
3153 return tevent_req_post(req
, ev
);
3157 ok
= push_ucs2_talloc(
3158 state
, &converted_str
, fname_dst
, &converted_size_bytes
);
3160 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3161 return tevent_req_post(req
, ev
);
3165 * W2K8 insists the dest name is not null terminated. Remove
3166 * the last 2 zero bytes and reduce the name length.
3168 if (converted_size_bytes
< 2) {
3169 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3170 return tevent_req_post(req
, ev
);
3172 converted_size_bytes
-= 2;
3174 inbuf_size
= 20 + converted_size_bytes
;
3175 if (inbuf_size
< 20) {
3176 /* Integer wrap check. */
3177 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3178 return tevent_req_post(req
, ev
);
3182 * The Windows 10 SMB2 server has a minimum length
3183 * for a SMB2_FILE_RENAME_INFORMATION buffer of
3184 * 24 bytes. It returns NT_STATUS_INFO_LENGTH_MISMATCH
3185 * if the length is less. This isn't an alignment
3186 * issue as Windows client accepts happily 2-byte align
3187 * for larger target name sizes. Also the Windows 10
3188 * SMB1 server doesn't have this restriction.
3190 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14403
3192 inbuf_size
= MAX(inbuf_size
, 24);
3194 state
->inbuf
= data_blob_talloc_zero(state
, inbuf_size
);
3195 if (tevent_req_nomem(state
->inbuf
.data
, req
)) {
3196 return tevent_req_post(req
, ev
);
3200 SCVAL(state
->inbuf
.data
, 0, 1);
3203 SIVAL(state
->inbuf
.data
, 16, converted_size_bytes
);
3204 memcpy(state
->inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
3206 TALLOC_FREE(converted_str
);
3208 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3209 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3211 subreq
= cli_smb2_set_info_fnum_send(
3212 state
, /* mem_ctx */
3216 1, /* in_info_type */
3217 SMB_FILE_RENAME_INFORMATION
- 1000, /* in_file_info_class */
3218 &state
->inbuf
, /* in_input_buffer */
3219 0); /* in_additional_info */
3220 if (tevent_req_nomem(subreq
, req
)) {
3221 return tevent_req_post(req
, ev
);
3223 tevent_req_set_callback(subreq
, cli_smb2_rename_fnum_done
, req
);
3227 static void cli_smb2_rename_fnum_done(struct tevent_req
*subreq
)
3229 NTSTATUS status
= cli_smb2_set_info_fnum_recv(subreq
);
3230 tevent_req_simple_finish_ntstatus(subreq
, status
);
3233 static NTSTATUS
cli_smb2_rename_fnum_recv(struct tevent_req
*req
)
3235 return tevent_req_simple_recv_ntstatus(req
);
3238 /***************************************************************
3239 Wrapper that allows SMB2 to rename a file.
3240 ***************************************************************/
3242 struct cli_smb2_rename_state
{
3243 struct tevent_context
*ev
;
3244 struct cli_state
*cli
;
3245 const char *fname_dst
;
3249 NTSTATUS rename_status
;
3252 static void cli_smb2_rename_opened(struct tevent_req
*subreq
);
3253 static void cli_smb2_rename_renamed(struct tevent_req
*subreq
);
3254 static void cli_smb2_rename_closed(struct tevent_req
*subreq
);
3256 struct tevent_req
*cli_smb2_rename_send(
3257 TALLOC_CTX
*mem_ctx
,
3258 struct tevent_context
*ev
,
3259 struct cli_state
*cli
,
3260 const char *fname_src
,
3261 const char *fname_dst
,
3264 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
3265 struct cli_smb2_rename_state
*state
= NULL
;
3268 req
= tevent_req_create(
3269 mem_ctx
, &state
, struct cli_smb2_rename_state
);
3275 * Strip a MSDFS path from fname_dst if we were given one.
3277 status
= cli_dfs_target_check(state
,
3281 if (tevent_req_nterror(req
, status
)) {
3282 return tevent_req_post(req
, ev
);
3287 state
->fname_dst
= fname_dst
;
3288 state
->replace
= replace
;
3290 subreq
= get_fnum_from_path_send(
3291 state
, ev
, cli
, fname_src
, DELETE_ACCESS
);
3292 if (tevent_req_nomem(subreq
, req
)) {
3293 return tevent_req_post(req
, ev
);
3295 tevent_req_set_callback(subreq
, cli_smb2_rename_opened
, req
);
3299 static void cli_smb2_rename_opened(struct tevent_req
*subreq
)
3301 struct tevent_req
*req
= tevent_req_callback_data(
3302 subreq
, struct tevent_req
);
3303 struct cli_smb2_rename_state
*state
= tevent_req_data(
3304 req
, struct cli_smb2_rename_state
);
3307 status
= get_fnum_from_path_recv(subreq
, &state
->fnum
);
3308 TALLOC_FREE(subreq
);
3309 if (tevent_req_nterror(req
, status
)) {
3313 subreq
= cli_smb2_rename_fnum_send(
3320 if (tevent_req_nomem(subreq
, req
)) {
3323 tevent_req_set_callback(subreq
, cli_smb2_rename_renamed
, req
);
3326 static void cli_smb2_rename_renamed(struct tevent_req
*subreq
)
3328 struct tevent_req
*req
= tevent_req_callback_data(
3329 subreq
, struct tevent_req
);
3330 struct cli_smb2_rename_state
*state
= tevent_req_data(
3331 req
, struct cli_smb2_rename_state
);
3333 state
->rename_status
= cli_smb2_rename_fnum_recv(subreq
);
3334 TALLOC_FREE(subreq
);
3336 subreq
= cli_smb2_close_fnum_send(
3337 state
, state
->ev
, state
->cli
, state
->fnum
);
3338 if (tevent_req_nomem(subreq
, req
)) {
3341 tevent_req_set_callback(subreq
, cli_smb2_rename_closed
, req
);
3344 static void cli_smb2_rename_closed(struct tevent_req
*subreq
)
3346 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
3347 tevent_req_simple_finish_ntstatus(subreq
, status
);
3350 NTSTATUS
cli_smb2_rename_recv(struct tevent_req
*req
)
3352 struct cli_smb2_rename_state
*state
= tevent_req_data(
3353 req
, struct cli_smb2_rename_state
);
3354 NTSTATUS status
= NT_STATUS_OK
;
3356 if (!tevent_req_is_nterror(req
, &status
)) {
3357 status
= state
->rename_status
;
3359 tevent_req_received(req
);
3363 /***************************************************************
3364 Wrapper that allows SMB2 to set an EA on a fnum.
3366 ***************************************************************/
3368 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
3370 const char *ea_name
,
3375 DATA_BLOB inbuf
= data_blob_null
;
3377 char *ea_name_ascii
= NULL
;
3379 TALLOC_CTX
*frame
= talloc_stackframe();
3381 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3383 * Can't use sync call while an async call is in flight
3385 status
= NT_STATUS_INVALID_PARAMETER
;
3389 /* Marshall the SMB2 EA data. */
3390 if (ea_len
> 0xFFFF) {
3391 status
= NT_STATUS_INVALID_PARAMETER
;
3395 if (!push_ascii_talloc(frame
,
3399 status
= NT_STATUS_INVALID_PARAMETER
;
3403 if (namelen
< 2 || namelen
> 0xFF) {
3404 status
= NT_STATUS_INVALID_PARAMETER
;
3408 bloblen
= 8 + ea_len
+ namelen
;
3409 /* Round up to a 4 byte boundary. */
3410 bloblen
= ((bloblen
+ 3)&~3);
3412 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
3413 if (inbuf
.data
== NULL
) {
3414 status
= NT_STATUS_NO_MEMORY
;
3417 /* namelen doesn't include the NULL byte. */
3418 SCVAL(inbuf
.data
, 5, namelen
- 1);
3419 SSVAL(inbuf
.data
, 6, ea_len
);
3420 memcpy(inbuf
.data
+ 8, ea_name_ascii
, namelen
);
3421 memcpy(inbuf
.data
+ 8 + namelen
, ea_val
, ea_len
);
3423 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3424 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3426 status
= cli_smb2_set_info_fnum(
3429 1, /* in_info_type */
3430 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
3431 &inbuf
, /* in_input_buffer */
3432 0); /* in_additional_info */
3436 cli
->raw_status
= status
;
3442 /***************************************************************
3443 Wrapper that allows SMB2 to set an EA on a pathname.
3445 ***************************************************************/
3447 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
3449 const char *ea_name
,
3454 uint16_t fnum
= 0xffff;
3456 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3458 * Can't use sync call while an async call is in flight
3460 status
= NT_STATUS_INVALID_PARAMETER
;
3464 status
= get_fnum_from_path(cli
,
3469 if (!NT_STATUS_IS_OK(status
)) {
3473 status
= cli_set_ea_fnum(cli
,
3478 if (!NT_STATUS_IS_OK(status
)) {
3484 if (fnum
!= 0xffff) {
3485 cli_smb2_close_fnum(cli
, fnum
);
3488 cli
->raw_status
= status
;
3493 /***************************************************************
3494 Wrapper that allows SMB2 to get an EA list on a pathname.
3496 ***************************************************************/
3498 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
3502 struct ea_struct
**pea_array
)
3505 uint16_t fnum
= 0xffff;
3506 DATA_BLOB outbuf
= data_blob_null
;
3507 struct ea_list
*ea_list
= NULL
;
3508 struct ea_list
*eal
= NULL
;
3509 size_t ea_count
= 0;
3510 TALLOC_CTX
*frame
= talloc_stackframe();
3515 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3517 * Can't use sync call while an async call is in flight
3519 status
= NT_STATUS_INVALID_PARAMETER
;
3523 status
= get_fnum_from_path(cli
,
3528 if (!NT_STATUS_IS_OK(status
)) {
3532 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3533 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3535 status
= cli_smb2_query_info_fnum(
3538 1, /* in_info_type */
3539 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
3540 0xFFFF, /* in_max_output_length */
3541 NULL
, /* in_input_buffer */
3542 0, /* in_additional_info */
3547 if (!NT_STATUS_IS_OK(status
)) {
3551 /* Parse the reply. */
3552 ea_list
= read_nttrans_ea_list(ctx
,
3553 (const char *)outbuf
.data
,
3555 if (ea_list
== NULL
) {
3556 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3560 /* Convert to an array. */
3561 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
3566 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
3567 if (*pea_array
== NULL
) {
3568 status
= NT_STATUS_NO_MEMORY
;
3572 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
3573 (*pea_array
)[ea_count
++] = eal
->ea
;
3575 *pnum_eas
= ea_count
;
3580 if (fnum
!= 0xffff) {
3581 cli_smb2_close_fnum(cli
, fnum
);
3584 cli
->raw_status
= status
;
3590 /***************************************************************
3591 Wrapper that allows SMB2 to get user quota.
3593 ***************************************************************/
3595 NTSTATUS
cli_smb2_get_user_quota(struct cli_state
*cli
,
3597 SMB_NTQUOTA_STRUCT
*pqt
)
3600 DATA_BLOB inbuf
= data_blob_null
;
3601 DATA_BLOB info_blob
= data_blob_null
;
3602 DATA_BLOB outbuf
= data_blob_null
;
3603 TALLOC_CTX
*frame
= talloc_stackframe();
3605 unsigned int offset
;
3606 struct smb2_query_quota_info query
= {0};
3607 struct file_get_quota_info info
= {0};
3608 enum ndr_err_code err
;
3609 struct ndr_push
*ndr_push
= NULL
;
3611 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3613 * Can't use sync call while an async call is in flight
3615 status
= NT_STATUS_INVALID_PARAMETER
;
3619 sid_len
= ndr_size_dom_sid(&pqt
->sid
, 0);
3621 query
.return_single
= 1;
3623 info
.next_entry_offset
= 0;
3624 info
.sid_length
= sid_len
;
3625 info
.sid
= pqt
->sid
;
3627 err
= ndr_push_struct_blob(
3631 (ndr_push_flags_fn_t
)ndr_push_file_get_quota_info
);
3633 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3634 status
= NT_STATUS_INTERNAL_ERROR
;
3638 query
.sid_list_length
= info_blob
.length
;
3639 ndr_push
= ndr_push_init_ctx(frame
);
3641 status
= NT_STATUS_NO_MEMORY
;
3645 err
= ndr_push_smb2_query_quota_info(ndr_push
,
3646 NDR_SCALARS
| NDR_BUFFERS
,
3649 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3650 status
= NT_STATUS_INTERNAL_ERROR
;
3654 err
= ndr_push_array_uint8(ndr_push
, NDR_SCALARS
, info_blob
.data
,
3657 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3658 status
= NT_STATUS_INTERNAL_ERROR
;
3661 inbuf
.data
= ndr_push
->data
;
3662 inbuf
.length
= ndr_push
->offset
;
3664 status
= cli_smb2_query_info_fnum(
3667 4, /* in_info_type */
3668 0, /* in_file_info_class */
3669 0xFFFF, /* in_max_output_length */
3670 &inbuf
, /* in_input_buffer */
3671 0, /* in_additional_info */
3676 if (!NT_STATUS_IS_OK(status
)) {
3680 if (!parse_user_quota_record(outbuf
.data
, outbuf
.length
, &offset
,
3682 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3683 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3687 cli
->raw_status
= status
;
3693 /***************************************************************
3694 Wrapper that allows SMB2 to list user quota.
3696 ***************************************************************/
3698 NTSTATUS
cli_smb2_list_user_quota_step(struct cli_state
*cli
,
3699 TALLOC_CTX
*mem_ctx
,
3701 SMB_NTQUOTA_LIST
**pqt_list
,
3705 DATA_BLOB inbuf
= data_blob_null
;
3706 DATA_BLOB outbuf
= data_blob_null
;
3707 TALLOC_CTX
*frame
= talloc_stackframe();
3708 struct smb2_query_quota_info info
= {0};
3709 enum ndr_err_code err
;
3711 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3713 * Can't use sync call while an async call is in flight
3715 status
= NT_STATUS_INVALID_PARAMETER
;
3719 info
.restart_scan
= first
? 1 : 0;
3721 err
= ndr_push_struct_blob(
3725 (ndr_push_flags_fn_t
)ndr_push_smb2_query_quota_info
);
3727 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3728 status
= NT_STATUS_INTERNAL_ERROR
;
3732 status
= cli_smb2_query_info_fnum(
3735 4, /* in_info_type */
3736 0, /* in_file_info_class */
3737 0xFFFF, /* in_max_output_length */
3738 &inbuf
, /* in_input_buffer */
3739 0, /* in_additional_info */
3745 * safeguard against panic from calling parse_user_quota_list with
3748 if (NT_STATUS_IS_OK(status
) && outbuf
.length
== 0) {
3749 status
= NT_STATUS_NO_MORE_ENTRIES
;
3752 if (!NT_STATUS_IS_OK(status
)) {
3756 status
= parse_user_quota_list(outbuf
.data
, outbuf
.length
, mem_ctx
,
3760 cli
->raw_status
= status
;
3766 /***************************************************************
3767 Wrapper that allows SMB2 to get file system quota.
3769 ***************************************************************/
3771 NTSTATUS
cli_smb2_get_fs_quota_info(struct cli_state
*cli
,
3773 SMB_NTQUOTA_STRUCT
*pqt
)
3776 DATA_BLOB outbuf
= data_blob_null
;
3777 TALLOC_CTX
*frame
= talloc_stackframe();
3779 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3781 * Can't use sync call while an async call is in flight
3783 status
= NT_STATUS_INVALID_PARAMETER
;
3787 status
= cli_smb2_query_info_fnum(
3790 2, /* in_info_type */
3791 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
3792 0xFFFF, /* in_max_output_length */
3793 NULL
, /* in_input_buffer */
3794 0, /* in_additional_info */
3799 if (!NT_STATUS_IS_OK(status
)) {
3803 status
= parse_fs_quota_buffer(outbuf
.data
, outbuf
.length
, pqt
);
3806 cli
->raw_status
= status
;
3812 /***************************************************************
3813 Wrapper that allows SMB2 to set user quota.
3815 ***************************************************************/
3817 NTSTATUS
cli_smb2_set_user_quota(struct cli_state
*cli
,
3819 SMB_NTQUOTA_LIST
*qtl
)
3822 DATA_BLOB inbuf
= data_blob_null
;
3823 TALLOC_CTX
*frame
= talloc_stackframe();
3825 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3827 * Can't use sync call while an async call is in flight
3829 status
= NT_STATUS_INVALID_PARAMETER
;
3833 status
= build_user_quota_buffer(qtl
, 0, talloc_tos(), &inbuf
, NULL
);
3834 if (!NT_STATUS_IS_OK(status
)) {
3838 status
= cli_smb2_set_info_fnum(
3841 4, /* in_info_type */
3842 0, /* in_file_info_class */
3843 &inbuf
, /* in_input_buffer */
3844 0); /* in_additional_info */
3847 cli
->raw_status
= status
;
3854 NTSTATUS
cli_smb2_set_fs_quota_info(struct cli_state
*cli
,
3856 SMB_NTQUOTA_STRUCT
*pqt
)
3859 DATA_BLOB inbuf
= data_blob_null
;
3860 TALLOC_CTX
*frame
= talloc_stackframe();
3862 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3864 * Can't use sync call while an async call is in flight
3866 status
= NT_STATUS_INVALID_PARAMETER
;
3870 status
= build_fs_quota_buffer(talloc_tos(), pqt
, &inbuf
, 0);
3871 if (!NT_STATUS_IS_OK(status
)) {
3875 status
= cli_smb2_set_info_fnum(
3878 2, /* in_info_type */
3879 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
3880 &inbuf
, /* in_input_buffer */
3881 0); /* in_additional_info */
3883 cli
->raw_status
= status
;
3889 struct cli_smb2_read_state
{
3890 struct tevent_context
*ev
;
3891 struct cli_state
*cli
;
3892 struct smb2_hnd
*ph
;
3893 uint64_t start_offset
;
3899 static void cli_smb2_read_done(struct tevent_req
*subreq
);
3901 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
3902 struct tevent_context
*ev
,
3903 struct cli_state
*cli
,
3909 struct tevent_req
*req
, *subreq
;
3910 struct cli_smb2_read_state
*state
;
3912 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
3918 state
->start_offset
= (uint64_t)offset
;
3919 state
->size
= (uint32_t)size
;
3920 state
->received
= 0;
3923 status
= map_fnum_to_smb2_handle(cli
,
3926 if (tevent_req_nterror(req
, status
)) {
3927 return tevent_req_post(req
, ev
);
3930 subreq
= smb2cli_read_send(state
,
3933 state
->cli
->timeout
,
3934 state
->cli
->smb2
.session
,
3935 state
->cli
->smb2
.tcon
,
3937 state
->start_offset
,
3938 state
->ph
->fid_persistent
,
3939 state
->ph
->fid_volatile
,
3940 0, /* minimum_count */
3941 0); /* remaining_bytes */
3943 if (tevent_req_nomem(subreq
, req
)) {
3944 return tevent_req_post(req
, ev
);
3946 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
3950 static void cli_smb2_read_done(struct tevent_req
*subreq
)
3952 struct tevent_req
*req
= tevent_req_callback_data(
3953 subreq
, struct tevent_req
);
3954 struct cli_smb2_read_state
*state
= tevent_req_data(
3955 req
, struct cli_smb2_read_state
);
3958 status
= smb2cli_read_recv(subreq
, state
,
3959 &state
->buf
, &state
->received
);
3960 if (tevent_req_nterror(req
, status
)) {
3964 if (state
->received
> state
->size
) {
3965 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3969 tevent_req_done(req
);
3972 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
3977 struct cli_smb2_read_state
*state
= tevent_req_data(
3978 req
, struct cli_smb2_read_state
);
3980 if (tevent_req_is_nterror(req
, &status
)) {
3981 state
->cli
->raw_status
= status
;
3985 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3986 * better make sure that you copy it away before you talloc_free(req).
3987 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3989 *received
= (ssize_t
)state
->received
;
3990 *rcvbuf
= state
->buf
;
3991 state
->cli
->raw_status
= NT_STATUS_OK
;
3992 return NT_STATUS_OK
;
3995 struct cli_smb2_write_state
{
3996 struct tevent_context
*ev
;
3997 struct cli_state
*cli
;
3998 struct smb2_hnd
*ph
;
4006 static void cli_smb2_write_written(struct tevent_req
*req
);
4008 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
4009 struct tevent_context
*ev
,
4010 struct cli_state
*cli
,
4018 struct tevent_req
*req
, *subreq
= NULL
;
4019 struct cli_smb2_write_state
*state
= NULL
;
4021 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
4027 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4028 state
->flags
= (uint32_t)mode
;
4030 state
->offset
= (uint64_t)offset
;
4031 state
->size
= (uint32_t)size
;
4034 status
= map_fnum_to_smb2_handle(cli
,
4037 if (tevent_req_nterror(req
, status
)) {
4038 return tevent_req_post(req
, ev
);
4041 subreq
= smb2cli_write_send(state
,
4044 state
->cli
->timeout
,
4045 state
->cli
->smb2
.session
,
4046 state
->cli
->smb2
.tcon
,
4049 state
->ph
->fid_persistent
,
4050 state
->ph
->fid_volatile
,
4051 0, /* remaining_bytes */
4052 state
->flags
, /* flags */
4055 if (tevent_req_nomem(subreq
, req
)) {
4056 return tevent_req_post(req
, ev
);
4058 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
4062 static void cli_smb2_write_written(struct tevent_req
*subreq
)
4064 struct tevent_req
*req
= tevent_req_callback_data(
4065 subreq
, struct tevent_req
);
4066 struct cli_smb2_write_state
*state
= tevent_req_data(
4067 req
, struct cli_smb2_write_state
);
4071 status
= smb2cli_write_recv(subreq
, &written
);
4072 TALLOC_FREE(subreq
);
4073 if (tevent_req_nterror(req
, status
)) {
4077 state
->written
= written
;
4079 tevent_req_done(req
);
4082 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
4085 struct cli_smb2_write_state
*state
= tevent_req_data(
4086 req
, struct cli_smb2_write_state
);
4089 if (tevent_req_is_nterror(req
, &status
)) {
4090 state
->cli
->raw_status
= status
;
4091 tevent_req_received(req
);
4095 if (pwritten
!= NULL
) {
4096 *pwritten
= (size_t)state
->written
;
4098 state
->cli
->raw_status
= NT_STATUS_OK
;
4099 tevent_req_received(req
);
4100 return NT_STATUS_OK
;
4103 /***************************************************************
4104 Wrapper that allows SMB2 async write using an fnum.
4105 This is mostly cut-and-paste from Volker's code inside
4106 source3/libsmb/clireadwrite.c, adapted for SMB2.
4108 Done this way so I can reuse all the logic inside cli_push()
4110 ***************************************************************/
4112 struct cli_smb2_writeall_state
{
4113 struct tevent_context
*ev
;
4114 struct cli_state
*cli
;
4115 struct smb2_hnd
*ph
;
4123 static void cli_smb2_writeall_written(struct tevent_req
*req
);
4125 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
4126 struct tevent_context
*ev
,
4127 struct cli_state
*cli
,
4135 struct tevent_req
*req
, *subreq
= NULL
;
4136 struct cli_smb2_writeall_state
*state
= NULL
;
4141 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
4147 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4148 state
->flags
= (uint32_t)mode
;
4150 state
->offset
= (uint64_t)offset
;
4151 state
->size
= (uint32_t)size
;
4154 status
= map_fnum_to_smb2_handle(cli
,
4157 if (tevent_req_nterror(req
, status
)) {
4158 return tevent_req_post(req
, ev
);
4161 to_write
= state
->size
;
4162 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
4163 to_write
= MIN(max_size
, to_write
);
4164 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
4166 to_write
= MIN(max_size
, to_write
);
4169 subreq
= smb2cli_write_send(state
,
4172 state
->cli
->timeout
,
4173 state
->cli
->smb2
.session
,
4174 state
->cli
->smb2
.tcon
,
4177 state
->ph
->fid_persistent
,
4178 state
->ph
->fid_volatile
,
4179 0, /* remaining_bytes */
4180 state
->flags
, /* flags */
4181 state
->buf
+ state
->written
);
4183 if (tevent_req_nomem(subreq
, req
)) {
4184 return tevent_req_post(req
, ev
);
4186 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
4190 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
4192 struct tevent_req
*req
= tevent_req_callback_data(
4193 subreq
, struct tevent_req
);
4194 struct cli_smb2_writeall_state
*state
= tevent_req_data(
4195 req
, struct cli_smb2_writeall_state
);
4197 uint32_t written
, to_write
;
4201 status
= smb2cli_write_recv(subreq
, &written
);
4202 TALLOC_FREE(subreq
);
4203 if (tevent_req_nterror(req
, status
)) {
4207 state
->written
+= written
;
4209 if (state
->written
> state
->size
) {
4210 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4214 to_write
= state
->size
- state
->written
;
4216 if (to_write
== 0) {
4217 tevent_req_done(req
);
4221 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
4222 to_write
= MIN(max_size
, to_write
);
4223 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
4225 to_write
= MIN(max_size
, to_write
);
4228 subreq
= smb2cli_write_send(state
,
4231 state
->cli
->timeout
,
4232 state
->cli
->smb2
.session
,
4233 state
->cli
->smb2
.tcon
,
4235 state
->offset
+ state
->written
,
4236 state
->ph
->fid_persistent
,
4237 state
->ph
->fid_volatile
,
4238 0, /* remaining_bytes */
4239 state
->flags
, /* flags */
4240 state
->buf
+ state
->written
);
4242 if (tevent_req_nomem(subreq
, req
)) {
4245 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
4248 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
4251 struct cli_smb2_writeall_state
*state
= tevent_req_data(
4252 req
, struct cli_smb2_writeall_state
);
4255 if (tevent_req_is_nterror(req
, &status
)) {
4256 state
->cli
->raw_status
= status
;
4259 if (pwritten
!= NULL
) {
4260 *pwritten
= (size_t)state
->written
;
4262 state
->cli
->raw_status
= NT_STATUS_OK
;
4263 return NT_STATUS_OK
;
4266 struct cli_smb2_splice_state
{
4267 struct tevent_context
*ev
;
4268 struct cli_state
*cli
;
4269 struct smb2_hnd
*src_ph
;
4270 struct smb2_hnd
*dst_ph
;
4271 int (*splice_cb
)(off_t n
, void *priv
);
4278 struct req_resume_key_rsp resume_rsp
;
4279 struct srv_copychunk_copy cc_copy
;
4282 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
4283 struct tevent_req
*req
);
4285 static void cli_splice_copychunk_done(struct tevent_req
*subreq
)
4287 struct tevent_req
*req
= tevent_req_callback_data(
4288 subreq
, struct tevent_req
);
4289 struct cli_smb2_splice_state
*state
=
4290 tevent_req_data(req
,
4291 struct cli_smb2_splice_state
);
4292 struct smbXcli_conn
*conn
= state
->cli
->conn
;
4293 DATA_BLOB out_input_buffer
= data_blob_null
;
4294 DATA_BLOB out_output_buffer
= data_blob_null
;
4295 struct srv_copychunk_rsp cc_copy_rsp
;
4296 enum ndr_err_code ndr_ret
;
4299 status
= smb2cli_ioctl_recv(subreq
, state
,
4301 &out_output_buffer
);
4302 TALLOC_FREE(subreq
);
4303 if ((!NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
) ||
4304 state
->resized
) && tevent_req_nterror(req
, status
)) {
4308 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
, state
, &cc_copy_rsp
,
4309 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
4310 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4311 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4312 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4316 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
4317 uint32_t max_chunks
= MIN(cc_copy_rsp
.chunks_written
,
4318 cc_copy_rsp
.total_bytes_written
/ cc_copy_rsp
.chunk_bytes_written
);
4319 if ((cc_copy_rsp
.chunk_bytes_written
> smb2cli_conn_cc_chunk_len(conn
) ||
4320 max_chunks
> smb2cli_conn_cc_max_chunks(conn
)) &&
4321 tevent_req_nterror(req
, status
)) {
4325 state
->resized
= true;
4326 smb2cli_conn_set_cc_chunk_len(conn
, cc_copy_rsp
.chunk_bytes_written
);
4327 smb2cli_conn_set_cc_max_chunks(conn
, max_chunks
);
4329 if ((state
->src_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
4330 (state
->dst_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
4331 (state
->written
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
)) {
4332 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
4335 state
->src_offset
+= cc_copy_rsp
.total_bytes_written
;
4336 state
->dst_offset
+= cc_copy_rsp
.total_bytes_written
;
4337 state
->written
+= cc_copy_rsp
.total_bytes_written
;
4338 if (!state
->splice_cb(state
->written
, state
->priv
)) {
4339 tevent_req_nterror(req
, NT_STATUS_CANCELLED
);
4344 cli_splice_copychunk_send(state
, req
);
4347 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
4348 struct tevent_req
*req
)
4350 struct tevent_req
*subreq
;
4351 enum ndr_err_code ndr_ret
;
4352 struct smbXcli_conn
*conn
= state
->cli
->conn
;
4353 struct srv_copychunk_copy
*cc_copy
= &state
->cc_copy
;
4354 off_t src_offset
= state
->src_offset
;
4355 off_t dst_offset
= state
->dst_offset
;
4356 uint32_t req_len
= MIN(smb2cli_conn_cc_chunk_len(conn
) * smb2cli_conn_cc_max_chunks(conn
),
4357 state
->size
- state
->written
);
4358 DATA_BLOB in_input_buffer
= data_blob_null
;
4359 DATA_BLOB in_output_buffer
= data_blob_null
;
4361 if (state
->size
- state
->written
== 0) {
4362 tevent_req_done(req
);
4366 cc_copy
->chunk_count
= 0;
4368 cc_copy
->chunks
[cc_copy
->chunk_count
].source_off
= src_offset
;
4369 cc_copy
->chunks
[cc_copy
->chunk_count
].target_off
= dst_offset
;
4370 cc_copy
->chunks
[cc_copy
->chunk_count
].length
= MIN(req_len
,
4371 smb2cli_conn_cc_chunk_len(conn
));
4372 if (req_len
< cc_copy
->chunks
[cc_copy
->chunk_count
].length
) {
4373 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
4376 req_len
-= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4377 if ((src_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
) ||
4378 (dst_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
)) {
4379 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
4382 src_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4383 dst_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4384 cc_copy
->chunk_count
++;
4387 ndr_ret
= ndr_push_struct_blob(&in_input_buffer
, state
, cc_copy
,
4388 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
4389 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4390 DEBUG(0, ("failed to marshall copy chunk req\n"));
4391 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
4395 subreq
= smb2cli_ioctl_send(state
, state
->ev
, state
->cli
->conn
,
4396 state
->cli
->timeout
,
4397 state
->cli
->smb2
.session
,
4398 state
->cli
->smb2
.tcon
,
4399 state
->dst_ph
->fid_persistent
, /* in_fid_persistent */
4400 state
->dst_ph
->fid_volatile
, /* in_fid_volatile */
4401 FSCTL_SRV_COPYCHUNK_WRITE
,
4402 0, /* in_max_input_length */
4404 12, /* in_max_output_length */
4406 SMB2_IOCTL_FLAG_IS_FSCTL
);
4407 if (tevent_req_nomem(subreq
, req
)) {
4410 tevent_req_set_callback(subreq
,
4411 cli_splice_copychunk_done
,
4415 static void cli_splice_key_done(struct tevent_req
*subreq
)
4417 struct tevent_req
*req
= tevent_req_callback_data(
4418 subreq
, struct tevent_req
);
4419 struct cli_smb2_splice_state
*state
=
4420 tevent_req_data(req
,
4421 struct cli_smb2_splice_state
);
4422 enum ndr_err_code ndr_ret
;
4425 DATA_BLOB out_input_buffer
= data_blob_null
;
4426 DATA_BLOB out_output_buffer
= data_blob_null
;
4428 status
= smb2cli_ioctl_recv(subreq
, state
,
4430 &out_output_buffer
);
4431 TALLOC_FREE(subreq
);
4432 if (tevent_req_nterror(req
, status
)) {
4436 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
,
4437 state
, &state
->resume_rsp
,
4438 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
4439 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4440 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4441 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4445 memcpy(&state
->cc_copy
.source_key
,
4446 &state
->resume_rsp
.resume_key
,
4447 sizeof state
->resume_rsp
.resume_key
);
4449 cli_splice_copychunk_send(state
, req
);
4452 struct tevent_req
*cli_smb2_splice_send(TALLOC_CTX
*mem_ctx
,
4453 struct tevent_context
*ev
,
4454 struct cli_state
*cli
,
4455 uint16_t src_fnum
, uint16_t dst_fnum
,
4456 off_t size
, off_t src_offset
, off_t dst_offset
,
4457 int (*splice_cb
)(off_t n
, void *priv
),
4460 struct tevent_req
*req
;
4461 struct tevent_req
*subreq
;
4462 struct cli_smb2_splice_state
*state
;
4464 DATA_BLOB in_input_buffer
= data_blob_null
;
4465 DATA_BLOB in_output_buffer
= data_blob_null
;
4467 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_splice_state
);
4473 state
->splice_cb
= splice_cb
;
4477 state
->src_offset
= src_offset
;
4478 state
->dst_offset
= dst_offset
;
4479 state
->cc_copy
.chunks
= talloc_array(state
,
4480 struct srv_copychunk
,
4481 smb2cli_conn_cc_max_chunks(cli
->conn
));
4482 if (state
->cc_copy
.chunks
== NULL
) {
4486 status
= map_fnum_to_smb2_handle(cli
, src_fnum
, &state
->src_ph
);
4487 if (tevent_req_nterror(req
, status
))
4488 return tevent_req_post(req
, ev
);
4490 status
= map_fnum_to_smb2_handle(cli
, dst_fnum
, &state
->dst_ph
);
4491 if (tevent_req_nterror(req
, status
))
4492 return tevent_req_post(req
, ev
);
4494 subreq
= smb2cli_ioctl_send(state
, ev
, cli
->conn
,
4498 state
->src_ph
->fid_persistent
, /* in_fid_persistent */
4499 state
->src_ph
->fid_volatile
, /* in_fid_volatile */
4500 FSCTL_SRV_REQUEST_RESUME_KEY
,
4501 0, /* in_max_input_length */
4503 32, /* in_max_output_length */
4505 SMB2_IOCTL_FLAG_IS_FSCTL
);
4506 if (tevent_req_nomem(subreq
, req
)) {
4509 tevent_req_set_callback(subreq
,
4510 cli_splice_key_done
,
4516 NTSTATUS
cli_smb2_splice_recv(struct tevent_req
*req
, off_t
*written
)
4518 struct cli_smb2_splice_state
*state
= tevent_req_data(
4519 req
, struct cli_smb2_splice_state
);
4522 if (tevent_req_is_nterror(req
, &status
)) {
4523 state
->cli
->raw_status
= status
;
4524 tevent_req_received(req
);
4527 if (written
!= NULL
) {
4528 *written
= state
->written
;
4530 state
->cli
->raw_status
= NT_STATUS_OK
;
4531 tevent_req_received(req
);
4532 return NT_STATUS_OK
;
4535 /***************************************************************
4536 SMB2 enum shadow copy data.
4537 ***************************************************************/
4539 struct cli_smb2_shadow_copy_data_fnum_state
{
4540 struct cli_state
*cli
;
4542 struct smb2_hnd
*ph
;
4543 DATA_BLOB out_input_buffer
;
4544 DATA_BLOB out_output_buffer
;
4547 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
);
4549 static struct tevent_req
*cli_smb2_shadow_copy_data_fnum_send(
4550 TALLOC_CTX
*mem_ctx
,
4551 struct tevent_context
*ev
,
4552 struct cli_state
*cli
,
4556 struct tevent_req
*req
, *subreq
;
4557 struct cli_smb2_shadow_copy_data_fnum_state
*state
;
4560 req
= tevent_req_create(mem_ctx
, &state
,
4561 struct cli_smb2_shadow_copy_data_fnum_state
);
4569 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
4570 if (tevent_req_nterror(req
, status
)) {
4571 return tevent_req_post(req
, ev
);
4575 * TODO. Under SMB2 we should send a zero max_output_length
4576 * ioctl to get the required size, then send another ioctl
4577 * to get the data, but the current SMB1 implementation just
4578 * does one roundtrip with a 64K buffer size. Do the same
4582 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
4583 state
->cli
->timeout
,
4584 state
->cli
->smb2
.session
,
4585 state
->cli
->smb2
.tcon
,
4586 state
->ph
->fid_persistent
, /* in_fid_persistent */
4587 state
->ph
->fid_volatile
, /* in_fid_volatile */
4588 FSCTL_GET_SHADOW_COPY_DATA
,
4589 0, /* in_max_input_length */
4590 NULL
, /* in_input_buffer */
4592 CLI_BUFFER_SIZE
: 16, /* in_max_output_length */
4593 NULL
, /* in_output_buffer */
4594 SMB2_IOCTL_FLAG_IS_FSCTL
);
4596 if (tevent_req_nomem(subreq
, req
)) {
4597 return tevent_req_post(req
, ev
);
4599 tevent_req_set_callback(subreq
,
4600 cli_smb2_shadow_copy_data_fnum_done
,
4606 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
)
4608 struct tevent_req
*req
= tevent_req_callback_data(
4609 subreq
, struct tevent_req
);
4610 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
4611 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
4614 status
= smb2cli_ioctl_recv(subreq
, state
,
4615 &state
->out_input_buffer
,
4616 &state
->out_output_buffer
);
4617 tevent_req_simple_finish_ntstatus(subreq
, status
);
4620 static NTSTATUS
cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req
*req
,
4621 TALLOC_CTX
*mem_ctx
,
4626 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
4627 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
4628 char **names
= NULL
;
4629 uint32_t num_names
= 0;
4630 uint32_t num_names_returned
= 0;
4631 uint32_t dlength
= 0;
4633 uint8_t *endp
= NULL
;
4636 if (tevent_req_is_nterror(req
, &status
)) {
4640 if (state
->out_output_buffer
.length
< 16) {
4641 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4644 num_names
= IVAL(state
->out_output_buffer
.data
, 0);
4645 num_names_returned
= IVAL(state
->out_output_buffer
.data
, 4);
4646 dlength
= IVAL(state
->out_output_buffer
.data
, 8);
4648 if (num_names
> 0x7FFFFFFF) {
4649 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4652 if (get_names
== false) {
4653 *pnum_names
= (int)num_names
;
4654 return NT_STATUS_OK
;
4656 if (num_names
!= num_names_returned
) {
4657 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4659 if (dlength
+ 12 < 12) {
4660 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4663 * NB. The below is an allowable return if there are
4664 * more snapshots than the buffer size we told the
4665 * server we can receive. We currently don't support
4668 if (dlength
+ 12 > state
->out_output_buffer
.length
) {
4669 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4671 if (state
->out_output_buffer
.length
+
4672 (2 * sizeof(SHADOW_COPY_LABEL
)) <
4673 state
->out_output_buffer
.length
) {
4674 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4677 names
= talloc_array(mem_ctx
, char *, num_names_returned
);
4678 if (names
== NULL
) {
4679 return NT_STATUS_NO_MEMORY
;
4682 endp
= state
->out_output_buffer
.data
+
4683 state
->out_output_buffer
.length
;
4685 for (i
=0; i
<num_names_returned
; i
++) {
4688 size_t converted_size
;
4690 src
= state
->out_output_buffer
.data
+ 12 +
4691 (i
* 2 * sizeof(SHADOW_COPY_LABEL
));
4693 if (src
+ (2 * sizeof(SHADOW_COPY_LABEL
)) > endp
) {
4694 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4696 ret
= convert_string_talloc(
4697 names
, CH_UTF16LE
, CH_UNIX
,
4698 src
, 2 * sizeof(SHADOW_COPY_LABEL
),
4699 &names
[i
], &converted_size
);
4702 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4705 *pnum_names
= num_names
;
4707 return NT_STATUS_OK
;
4710 NTSTATUS
cli_smb2_shadow_copy_data(TALLOC_CTX
*mem_ctx
,
4711 struct cli_state
*cli
,
4717 TALLOC_CTX
*frame
= talloc_stackframe();
4718 struct tevent_context
*ev
;
4719 struct tevent_req
*req
;
4720 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
4722 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4724 * Can't use sync call while an async call is in flight
4726 status
= NT_STATUS_INVALID_PARAMETER
;
4729 ev
= samba_tevent_context_init(frame
);
4733 req
= cli_smb2_shadow_copy_data_fnum_send(frame
,
4741 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4744 status
= cli_smb2_shadow_copy_data_fnum_recv(req
,
4750 cli
->raw_status
= status
;
4756 /***************************************************************
4757 Wrapper that allows SMB2 to truncate a file.
4759 ***************************************************************/
4761 NTSTATUS
cli_smb2_ftruncate(struct cli_state
*cli
,
4766 uint8_t buf
[8] = {0};
4767 DATA_BLOB inbuf
= { .data
= buf
, .length
= sizeof(buf
) };
4768 TALLOC_CTX
*frame
= talloc_stackframe();
4770 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4772 * Can't use sync call while an async call is in flight
4774 status
= NT_STATUS_INVALID_PARAMETER
;
4778 SBVAL(buf
, 0, newsize
);
4780 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4781 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4783 status
= cli_smb2_set_info_fnum(
4786 1, /* in_info_type */
4787 SMB_FILE_END_OF_FILE_INFORMATION
-1000, /* in_file_info_class */
4788 &inbuf
, /* in_input_buffer */
4793 cli
->raw_status
= status
;
4799 struct cli_smb2_notify_state
{
4800 struct tevent_req
*subreq
;
4801 struct notify_change
*changes
;
4805 static void cli_smb2_notify_done(struct tevent_req
*subreq
);
4806 static bool cli_smb2_notify_cancel(struct tevent_req
*req
);
4808 struct tevent_req
*cli_smb2_notify_send(
4809 TALLOC_CTX
*mem_ctx
,
4810 struct tevent_context
*ev
,
4811 struct cli_state
*cli
,
4813 uint32_t buffer_size
,
4814 uint32_t completion_filter
,
4817 struct tevent_req
*req
= NULL
;
4818 struct cli_smb2_notify_state
*state
= NULL
;
4819 struct smb2_hnd
*ph
= NULL
;
4822 req
= tevent_req_create(mem_ctx
, &state
,
4823 struct cli_smb2_notify_state
);
4828 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
4829 if (tevent_req_nterror(req
, status
)) {
4830 return tevent_req_post(req
, ev
);
4833 state
->subreq
= smb2cli_notify_send(
4845 if (tevent_req_nomem(state
->subreq
, req
)) {
4846 return tevent_req_post(req
, ev
);
4848 tevent_req_set_callback(state
->subreq
, cli_smb2_notify_done
, req
);
4849 tevent_req_set_cancel_fn(req
, cli_smb2_notify_cancel
);
4853 static bool cli_smb2_notify_cancel(struct tevent_req
*req
)
4855 struct cli_smb2_notify_state
*state
= tevent_req_data(
4856 req
, struct cli_smb2_notify_state
);
4859 ok
= tevent_req_cancel(state
->subreq
);
4863 static void cli_smb2_notify_done(struct tevent_req
*subreq
)
4865 struct tevent_req
*req
= tevent_req_callback_data(
4866 subreq
, struct tevent_req
);
4867 struct cli_smb2_notify_state
*state
= tevent_req_data(
4868 req
, struct cli_smb2_notify_state
);
4874 status
= smb2cli_notify_recv(subreq
, state
, &base
, &len
);
4875 TALLOC_FREE(subreq
);
4877 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
4878 tevent_req_done(req
);
4881 if (tevent_req_nterror(req
, status
)) {
4887 while (len
- ofs
>= 12) {
4888 struct notify_change
*tmp
;
4889 struct notify_change
*c
;
4890 uint32_t next_ofs
= IVAL(base
, ofs
);
4891 uint32_t file_name_length
= IVAL(base
, ofs
+8);
4895 tmp
= talloc_realloc(
4898 struct notify_change
,
4899 state
->num_changes
+ 1);
4900 if (tevent_req_nomem(tmp
, req
)) {
4903 state
->changes
= tmp
;
4904 c
= &state
->changes
[state
->num_changes
];
4905 state
->num_changes
+= 1;
4907 if (smb_buffer_oob(len
, ofs
, next_ofs
) ||
4908 smb_buffer_oob(len
, ofs
+12, file_name_length
)) {
4910 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4914 c
->action
= IVAL(base
, ofs
+4);
4916 ok
= convert_string_talloc(
4926 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4930 if (next_ofs
== 0) {
4936 tevent_req_done(req
);
4939 NTSTATUS
cli_smb2_notify_recv(struct tevent_req
*req
,
4940 TALLOC_CTX
*mem_ctx
,
4941 struct notify_change
**pchanges
,
4942 uint32_t *pnum_changes
)
4944 struct cli_smb2_notify_state
*state
= tevent_req_data(
4945 req
, struct cli_smb2_notify_state
);
4948 if (tevent_req_is_nterror(req
, &status
)) {
4951 *pchanges
= talloc_move(mem_ctx
, &state
->changes
);
4952 *pnum_changes
= state
->num_changes
;
4953 return NT_STATUS_OK
;
4956 NTSTATUS
cli_smb2_notify(struct cli_state
*cli
, uint16_t fnum
,
4957 uint32_t buffer_size
, uint32_t completion_filter
,
4958 bool recursive
, TALLOC_CTX
*mem_ctx
,
4959 struct notify_change
**pchanges
,
4960 uint32_t *pnum_changes
)
4962 TALLOC_CTX
*frame
= talloc_stackframe();
4963 struct tevent_context
*ev
;
4964 struct tevent_req
*req
;
4965 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
4967 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4969 * Can't use sync call while an async call is in flight
4971 status
= NT_STATUS_INVALID_PARAMETER
;
4974 ev
= samba_tevent_context_init(frame
);
4978 req
= cli_smb2_notify_send(
4989 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4992 status
= cli_smb2_notify_recv(req
, mem_ctx
, pchanges
, pnum_changes
);
4998 struct cli_smb2_fsctl_state
{
5002 static void cli_smb2_fsctl_done(struct tevent_req
*subreq
);
5004 struct tevent_req
*cli_smb2_fsctl_send(
5005 TALLOC_CTX
*mem_ctx
,
5006 struct tevent_context
*ev
,
5007 struct cli_state
*cli
,
5010 const DATA_BLOB
*in
,
5013 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
5014 struct cli_smb2_fsctl_state
*state
= NULL
;
5015 struct smb2_hnd
*ph
= NULL
;
5018 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_fsctl_state
);
5023 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
5024 if (tevent_req_nterror(req
, status
)) {
5025 return tevent_req_post(req
, ev
);
5028 subreq
= smb2cli_ioctl_send(
5038 0, /* in_max_input_length */
5042 SMB2_IOCTL_FLAG_IS_FSCTL
);
5044 if (tevent_req_nomem(subreq
, req
)) {
5045 return tevent_req_post(req
, ev
);
5047 tevent_req_set_callback(subreq
, cli_smb2_fsctl_done
, req
);
5051 static void cli_smb2_fsctl_done(struct tevent_req
*subreq
)
5053 struct tevent_req
*req
= tevent_req_callback_data(
5054 subreq
, struct tevent_req
);
5055 struct cli_smb2_fsctl_state
*state
= tevent_req_data(
5056 req
, struct cli_smb2_fsctl_state
);
5059 status
= smb2cli_ioctl_recv(subreq
, state
, NULL
, &state
->out
);
5060 tevent_req_simple_finish_ntstatus(subreq
, status
);
5063 NTSTATUS
cli_smb2_fsctl_recv(
5064 struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
, DATA_BLOB
*out
)
5066 struct cli_smb2_fsctl_state
*state
= tevent_req_data(
5067 req
, struct cli_smb2_fsctl_state
);
5068 NTSTATUS status
= NT_STATUS_OK
;
5070 if (tevent_req_is_nterror(req
, &status
)) {
5071 tevent_req_received(req
);
5075 if (state
->out
.length
== 0) {
5076 *out
= (DATA_BLOB
) { .data
= NULL
, };
5079 * Can't use talloc_move() here, the outblobs from
5080 * smb2cli_ioctl_recv() are not standalone talloc
5081 * objects but just peek into the larger buffers
5082 * received, hanging off "state".
5084 *out
= data_blob_talloc(
5085 mem_ctx
, state
->out
.data
, state
->out
.length
);
5086 if (out
->data
== NULL
) {
5087 status
= NT_STATUS_NO_MEMORY
;
5091 tevent_req_received(req
);
5092 return NT_STATUS_OK
;