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 "lib/util/string_wrappers.h"
48 uint64_t fid_persistent
;
49 uint64_t fid_volatile
;
53 * Handle mapping code.
56 /***************************************************************
57 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
58 Ensures handle is owned by cli struct.
59 ***************************************************************/
61 static NTSTATUS
map_smb2_handle_to_fnum(struct cli_state
*cli
,
62 const struct smb2_hnd
*ph
, /* In */
63 uint16_t *pfnum
) /* Out */
66 struct idr_context
*idp
= cli
->smb2
.open_handles
;
67 struct smb2_hnd
*owned_h
= talloc_memdup(cli
,
69 sizeof(struct smb2_hnd
));
71 if (owned_h
== NULL
) {
72 return NT_STATUS_NO_MEMORY
;
77 cli
->smb2
.open_handles
= idr_init(cli
);
78 if (cli
->smb2
.open_handles
== NULL
) {
80 return NT_STATUS_NO_MEMORY
;
82 idp
= cli
->smb2
.open_handles
;
85 ret
= idr_get_new_above(idp
, owned_h
, 1, 0xFFFE);
88 return NT_STATUS_NO_MEMORY
;
91 *pfnum
= (uint16_t)ret
;
95 /***************************************************************
96 Return the smb2_hnd pointer associated with the given fnum.
97 ***************************************************************/
99 static NTSTATUS
map_fnum_to_smb2_handle(struct cli_state
*cli
,
100 uint16_t fnum
, /* In */
101 struct smb2_hnd
**pph
) /* Out */
103 struct idr_context
*idp
= cli
->smb2
.open_handles
;
106 return NT_STATUS_INVALID_PARAMETER
;
108 *pph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
110 return NT_STATUS_INVALID_HANDLE
;
115 /***************************************************************
116 Delete the fnum to smb2_hnd mapping. Zeros out handle on
118 ***************************************************************/
120 static NTSTATUS
delete_smb2_handle_mapping(struct cli_state
*cli
,
121 struct smb2_hnd
**pph
, /* In */
122 uint16_t fnum
) /* In */
124 struct idr_context
*idp
= cli
->smb2
.open_handles
;
128 return NT_STATUS_INVALID_PARAMETER
;
131 ph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
133 return NT_STATUS_INVALID_PARAMETER
;
135 idr_remove(idp
, fnum
);
140 /***************************************************************
142 ***************************************************************/
144 static uint8_t flags_to_smb2_oplock(uint32_t create_flags
)
146 if (create_flags
& REQUEST_BATCH_OPLOCK
) {
147 return SMB2_OPLOCK_LEVEL_BATCH
;
148 } else if (create_flags
& REQUEST_OPLOCK
) {
149 return SMB2_OPLOCK_LEVEL_EXCLUSIVE
;
152 /* create_flags doesn't do a level2 request. */
153 return SMB2_OPLOCK_LEVEL_NONE
;
156 /***************************************************************
157 If we're on a DFS share, ensure we convert to a full DFS path
158 if this hasn't already been done.
159 ***************************************************************/
161 static char *smb2_dfs_share_path(TALLOC_CTX
*ctx
,
162 struct cli_state
*cli
,
165 bool is_dfs
= smbXcli_conn_dfs_supported(cli
->conn
) &&
166 smbXcli_tcon_is_dfs_share(cli
->smb2
.tcon
);
167 bool is_already_dfs_path
= false;
172 is_already_dfs_path
= cli_dfs_is_already_full_path(cli
, path
);
173 if (is_already_dfs_path
) {
176 if (path
[0] == '\0') {
177 return talloc_asprintf(ctx
,
179 smbXcli_conn_remote_name(cli
->conn
),
182 while (*path
== '\\') {
185 return talloc_asprintf(ctx
,
187 smbXcli_conn_remote_name(cli
->conn
),
192 /***************************************************************
193 Small wrapper that allows SMB2 create to return a uint16_t fnum.
194 ***************************************************************/
196 struct cli_smb2_create_fnum_state
{
197 struct cli_state
*cli
;
198 struct smb2_create_blobs in_cblobs
;
199 struct smb2_create_blobs out_cblobs
;
200 struct smb_create_returns cr
;
201 struct symlink_reparse_struct
*symlink
;
203 struct tevent_req
*subreq
;
206 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
);
207 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
);
209 struct tevent_req
*cli_smb2_create_fnum_send(
211 struct tevent_context
*ev
,
212 struct cli_state
*cli
,
213 const char *fname_in
,
214 uint32_t create_flags
,
215 uint32_t impersonation_level
,
216 uint32_t desired_access
,
217 uint32_t file_attributes
,
218 uint32_t share_access
,
219 uint32_t create_disposition
,
220 uint32_t create_options
,
221 const struct smb2_create_blobs
*in_cblobs
)
223 struct tevent_req
*req
, *subreq
;
224 struct cli_smb2_create_fnum_state
*state
;
226 size_t fname_len
= 0;
231 req
= tevent_req_create(mem_ctx
, &state
,
232 struct cli_smb2_create_fnum_state
);
238 fname
= talloc_strdup(state
, fname_in
);
239 if (tevent_req_nomem(fname
, req
)) {
240 return tevent_req_post(req
, ev
);
243 if (cli
->backup_intent
) {
244 create_options
|= FILE_OPEN_FOR_BACKUP_INTENT
;
247 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
248 have_twrp
= clistr_smb2_extract_snapshot_token(fname
, &ntt
);
250 status
= smb2_create_blob_add(
253 SMB2_CREATE_TAG_TWRP
,
255 .data
= (uint8_t *)&ntt
,
256 .length
= sizeof(ntt
),
258 if (tevent_req_nterror(req
, status
)) {
259 return tevent_req_post(req
, ev
);
263 if (in_cblobs
!= NULL
) {
265 for (i
=0; i
<in_cblobs
->num_blobs
; i
++) {
266 struct smb2_create_blob
*b
= &in_cblobs
->blobs
[i
];
267 status
= smb2_create_blob_add(
268 state
, &state
->in_cblobs
, b
->tag
, b
->data
);
269 if (!NT_STATUS_IS_OK(status
)) {
270 tevent_req_nterror(req
, status
);
271 return tevent_req_post(req
, ev
);
276 fname
= smb2_dfs_share_path(state
, cli
, fname
);
277 if (tevent_req_nomem(fname
, req
)) {
278 return tevent_req_post(req
, ev
);
280 fname_len
= strlen(fname
);
282 /* SMB2 is pickier about pathnames. Ensure it doesn't
284 if (*fname
== '\\') {
289 /* Or end in a '\' */
290 if (fname_len
> 0 && fname
[fname_len
-1] == '\\') {
291 char *new_fname
= talloc_strdup(state
, fname
);
292 if (tevent_req_nomem(new_fname
, req
)) {
293 return tevent_req_post(req
, ev
);
295 new_fname
[fname_len
-1] = '\0';
299 subreq
= smb2cli_create_send(state
, ev
,
305 flags_to_smb2_oplock(create_flags
),
313 if (tevent_req_nomem(subreq
, req
)) {
314 return tevent_req_post(req
, ev
);
316 tevent_req_set_callback(subreq
, cli_smb2_create_fnum_done
, req
);
318 state
->subreq
= subreq
;
319 tevent_req_set_cancel_fn(req
, cli_smb2_create_fnum_cancel
);
324 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
)
326 struct tevent_req
*req
= tevent_req_callback_data(
327 subreq
, struct tevent_req
);
328 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
329 req
, struct cli_smb2_create_fnum_state
);
333 status
= smb2cli_create_recv(
336 &h
.fid_volatile
, &state
->cr
,
341 if (tevent_req_nterror(req
, status
)) {
345 status
= map_smb2_handle_to_fnum(state
->cli
, &h
, &state
->fnum
);
346 if (tevent_req_nterror(req
, status
)) {
349 tevent_req_done(req
);
352 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
)
354 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
355 req
, struct cli_smb2_create_fnum_state
);
356 return tevent_req_cancel(state
->subreq
);
359 NTSTATUS
cli_smb2_create_fnum_recv(
360 struct tevent_req
*req
,
362 struct smb_create_returns
*cr
,
364 struct smb2_create_blobs
*out_cblobs
,
365 struct symlink_reparse_struct
**symlink
)
367 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
368 req
, struct cli_smb2_create_fnum_state
);
371 if (tevent_req_is_nterror(req
, &status
)) {
372 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
) &&
374 *symlink
= talloc_move(mem_ctx
, &state
->symlink
);
376 state
->cli
->raw_status
= status
;
380 *pfnum
= state
->fnum
;
385 if (out_cblobs
!= NULL
) {
386 *out_cblobs
= (struct smb2_create_blobs
) {
387 .num_blobs
= state
->out_cblobs
.num_blobs
,
388 .blobs
= talloc_move(
389 mem_ctx
, &state
->out_cblobs
.blobs
),
392 state
->cli
->raw_status
= NT_STATUS_OK
;
396 NTSTATUS
cli_smb2_create_fnum(
397 struct cli_state
*cli
,
399 uint32_t create_flags
,
400 uint32_t impersonation_level
,
401 uint32_t desired_access
,
402 uint32_t file_attributes
,
403 uint32_t share_access
,
404 uint32_t create_disposition
,
405 uint32_t create_options
,
406 const struct smb2_create_blobs
*in_cblobs
,
408 struct smb_create_returns
*cr
,
410 struct smb2_create_blobs
*out_cblobs
)
412 TALLOC_CTX
*frame
= talloc_stackframe();
413 struct tevent_context
*ev
;
414 struct tevent_req
*req
;
415 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
417 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
419 * Can't use sync call while an async call is in flight
421 status
= NT_STATUS_INVALID_PARAMETER
;
424 ev
= samba_tevent_context_init(frame
);
428 req
= cli_smb2_create_fnum_send(
444 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
447 status
= cli_smb2_create_fnum_recv(
448 req
, pfid
, cr
, mem_ctx
, out_cblobs
, NULL
);
454 /***************************************************************
455 Small wrapper that allows SMB2 close to use a uint16_t fnum.
456 ***************************************************************/
458 struct cli_smb2_close_fnum_state
{
459 struct cli_state
*cli
;
464 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
);
466 struct tevent_req
*cli_smb2_close_fnum_send(TALLOC_CTX
*mem_ctx
,
467 struct tevent_context
*ev
,
468 struct cli_state
*cli
,
471 struct tevent_req
*req
, *subreq
;
472 struct cli_smb2_close_fnum_state
*state
;
475 req
= tevent_req_create(mem_ctx
, &state
,
476 struct cli_smb2_close_fnum_state
);
483 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
484 if (tevent_req_nterror(req
, status
)) {
485 return tevent_req_post(req
, ev
);
488 subreq
= smb2cli_close_send(state
, ev
, cli
->conn
, cli
->timeout
,
489 cli
->smb2
.session
, cli
->smb2
.tcon
,
490 0, state
->ph
->fid_persistent
,
491 state
->ph
->fid_volatile
);
492 if (tevent_req_nomem(subreq
, req
)) {
493 return tevent_req_post(req
, ev
);
495 tevent_req_set_callback(subreq
, cli_smb2_close_fnum_done
, req
);
499 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
)
501 struct tevent_req
*req
= tevent_req_callback_data(
502 subreq
, struct tevent_req
);
503 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
504 req
, struct cli_smb2_close_fnum_state
);
507 status
= smb2cli_close_recv(subreq
);
508 if (tevent_req_nterror(req
, status
)) {
512 /* Delete the fnum -> handle mapping. */
513 status
= delete_smb2_handle_mapping(state
->cli
, &state
->ph
,
515 if (tevent_req_nterror(req
, status
)) {
518 tevent_req_done(req
);
521 NTSTATUS
cli_smb2_close_fnum_recv(struct tevent_req
*req
)
523 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
524 req
, struct cli_smb2_close_fnum_state
);
525 NTSTATUS status
= NT_STATUS_OK
;
527 if (tevent_req_is_nterror(req
, &status
)) {
528 state
->cli
->raw_status
= status
;
530 tevent_req_received(req
);
534 NTSTATUS
cli_smb2_close_fnum(struct cli_state
*cli
, uint16_t fnum
)
536 TALLOC_CTX
*frame
= talloc_stackframe();
537 struct tevent_context
*ev
;
538 struct tevent_req
*req
;
539 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
541 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
543 * Can't use sync call while an async call is in flight
545 status
= NT_STATUS_INVALID_PARAMETER
;
548 ev
= samba_tevent_context_init(frame
);
552 req
= cli_smb2_close_fnum_send(frame
, ev
, cli
, fnum
);
556 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
559 status
= cli_smb2_close_fnum_recv(req
);
565 struct cli_smb2_set_info_fnum_state
{
569 static void cli_smb2_set_info_fnum_done(struct tevent_req
*subreq
);
571 struct tevent_req
*cli_smb2_set_info_fnum_send(
573 struct tevent_context
*ev
,
574 struct cli_state
*cli
,
576 uint8_t in_info_type
,
577 uint8_t in_info_class
,
578 const DATA_BLOB
*in_input_buffer
,
579 uint32_t in_additional_info
)
581 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
582 struct cli_smb2_set_info_fnum_state
*state
= NULL
;
583 struct smb2_hnd
*ph
= NULL
;
586 req
= tevent_req_create(
587 mem_ctx
, &state
, struct cli_smb2_set_info_fnum_state
);
592 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
593 if (tevent_req_nterror(req
, status
)) {
594 return tevent_req_post(req
, ev
);
597 subreq
= smb2cli_set_info_send(
610 if (tevent_req_nomem(subreq
, req
)) {
611 return tevent_req_post(req
, ev
);
613 tevent_req_set_callback(subreq
, cli_smb2_set_info_fnum_done
, req
);
617 static void cli_smb2_set_info_fnum_done(struct tevent_req
*subreq
)
619 NTSTATUS status
= smb2cli_set_info_recv(subreq
);
620 tevent_req_simple_finish_ntstatus(subreq
, status
);
623 NTSTATUS
cli_smb2_set_info_fnum_recv(struct tevent_req
*req
)
625 return tevent_req_simple_recv_ntstatus(req
);
628 NTSTATUS
cli_smb2_set_info_fnum(
629 struct cli_state
*cli
,
631 uint8_t in_info_type
,
632 uint8_t in_info_class
,
633 const DATA_BLOB
*in_input_buffer
,
634 uint32_t in_additional_info
)
636 TALLOC_CTX
*frame
= talloc_stackframe();
637 struct tevent_context
*ev
= NULL
;
638 struct tevent_req
*req
= NULL
;
639 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
642 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
644 * Can't use sync call while an async call is in flight
646 status
= NT_STATUS_INVALID_PARAMETER
;
649 ev
= samba_tevent_context_init(frame
);
653 req
= cli_smb2_set_info_fnum_send(
665 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
669 status
= cli_smb2_set_info_fnum_recv(req
);
675 struct cli_smb2_delete_on_close_state
{
676 struct cli_state
*cli
;
681 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
);
683 struct tevent_req
*cli_smb2_delete_on_close_send(TALLOC_CTX
*mem_ctx
,
684 struct tevent_context
*ev
,
685 struct cli_state
*cli
,
689 struct tevent_req
*req
= NULL
;
690 struct cli_smb2_delete_on_close_state
*state
= NULL
;
691 struct tevent_req
*subreq
= NULL
;
692 uint8_t in_info_type
;
693 uint8_t in_file_info_class
;
695 req
= tevent_req_create(mem_ctx
, &state
,
696 struct cli_smb2_delete_on_close_state
);
703 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
704 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
707 in_file_info_class
= SMB_FILE_DISPOSITION_INFORMATION
- 1000;
708 /* Setup data array. */
709 SCVAL(&state
->data
[0], 0, flag
? 1 : 0);
710 state
->inbuf
.data
= &state
->data
[0];
711 state
->inbuf
.length
= 1;
713 subreq
= cli_smb2_set_info_fnum_send(
722 if (tevent_req_nomem(subreq
, req
)) {
723 return tevent_req_post(req
, ev
);
725 tevent_req_set_callback(subreq
,
726 cli_smb2_delete_on_close_done
,
731 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
)
733 NTSTATUS status
= cli_smb2_set_info_fnum_recv(subreq
);
734 tevent_req_simple_finish_ntstatus(subreq
, status
);
737 NTSTATUS
cli_smb2_delete_on_close_recv(struct tevent_req
*req
)
739 struct cli_smb2_delete_on_close_state
*state
=
741 struct cli_smb2_delete_on_close_state
);
744 if (tevent_req_is_nterror(req
, &status
)) {
745 state
->cli
->raw_status
= status
;
746 tevent_req_received(req
);
750 state
->cli
->raw_status
= NT_STATUS_OK
;
751 tevent_req_received(req
);
755 NTSTATUS
cli_smb2_delete_on_close(struct cli_state
*cli
, uint16_t fnum
, bool flag
)
757 TALLOC_CTX
*frame
= talloc_stackframe();
758 struct tevent_context
*ev
;
759 struct tevent_req
*req
;
760 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
762 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
764 * Can't use sync call while an async call is in flight
766 status
= NT_STATUS_INVALID_PARAMETER
;
769 ev
= samba_tevent_context_init(frame
);
773 req
= cli_smb2_delete_on_close_send(frame
, ev
, cli
, fnum
, flag
);
777 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
780 status
= cli_smb2_delete_on_close_recv(req
);
786 struct cli_smb2_mkdir_state
{
787 struct tevent_context
*ev
;
788 struct cli_state
*cli
;
791 static void cli_smb2_mkdir_opened(struct tevent_req
*subreq
);
792 static void cli_smb2_mkdir_closed(struct tevent_req
*subreq
);
794 struct tevent_req
*cli_smb2_mkdir_send(
796 struct tevent_context
*ev
,
797 struct cli_state
*cli
,
800 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
801 struct cli_smb2_mkdir_state
*state
= NULL
;
803 req
= tevent_req_create(
804 mem_ctx
, &state
, struct cli_smb2_mkdir_state
);
811 /* Ensure this is a directory. */
812 subreq
= cli_smb2_create_fnum_send(
817 0, /* create_flags */
818 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation_level */
819 FILE_READ_ATTRIBUTES
, /* desired_access */
820 FILE_ATTRIBUTE_DIRECTORY
, /* file_attributes */
822 FILE_SHARE_WRITE
, /* share_access */
823 FILE_CREATE
, /* create_disposition */
824 FILE_DIRECTORY_FILE
, /* create_options */
825 NULL
); /* in_cblobs */
826 if (tevent_req_nomem(subreq
, req
)) {
827 return tevent_req_post(req
, ev
);
829 tevent_req_set_callback(subreq
, cli_smb2_mkdir_opened
, req
);
833 static void cli_smb2_mkdir_opened(struct tevent_req
*subreq
)
835 struct tevent_req
*req
= tevent_req_callback_data(
836 subreq
, struct tevent_req
);
837 struct cli_smb2_mkdir_state
*state
= tevent_req_data(
838 req
, struct cli_smb2_mkdir_state
);
840 uint16_t fnum
= 0xffff;
842 status
= cli_smb2_create_fnum_recv(
843 subreq
, &fnum
, NULL
, NULL
, NULL
, NULL
);
845 if (tevent_req_nterror(req
, status
)) {
849 subreq
= cli_smb2_close_fnum_send(state
, state
->ev
, state
->cli
, fnum
);
850 if (tevent_req_nomem(subreq
, req
)) {
853 tevent_req_set_callback(subreq
, cli_smb2_mkdir_closed
, req
);
856 static void cli_smb2_mkdir_closed(struct tevent_req
*subreq
)
858 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
859 tevent_req_simple_finish_ntstatus(subreq
, status
);
862 NTSTATUS
cli_smb2_mkdir_recv(struct tevent_req
*req
)
864 return tevent_req_simple_recv_ntstatus(req
);
867 struct cli_smb2_rmdir_state
{
868 struct tevent_context
*ev
;
869 struct cli_state
*cli
;
871 const struct smb2_create_blobs
*in_cblobs
;
876 static void cli_smb2_rmdir_opened1(struct tevent_req
*subreq
);
877 static void cli_smb2_rmdir_opened2(struct tevent_req
*subreq
);
878 static void cli_smb2_rmdir_disp_set(struct tevent_req
*subreq
);
879 static void cli_smb2_rmdir_closed(struct tevent_req
*subreq
);
881 struct tevent_req
*cli_smb2_rmdir_send(
883 struct tevent_context
*ev
,
884 struct cli_state
*cli
,
886 const struct smb2_create_blobs
*in_cblobs
)
888 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
889 struct cli_smb2_rmdir_state
*state
= NULL
;
891 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_rmdir_state
);
897 state
->dname
= dname
;
898 state
->in_cblobs
= in_cblobs
;
900 subreq
= cli_smb2_create_fnum_send(
905 0, /* create_flags */
906 SMB2_IMPERSONATION_IMPERSONATION
,
907 DELETE_ACCESS
, /* desired_access */
908 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
909 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
910 FILE_OPEN
, /* create_disposition */
911 FILE_DIRECTORY_FILE
, /* create_options */
912 state
->in_cblobs
); /* in_cblobs */
913 if (tevent_req_nomem(subreq
, req
)) {
914 return tevent_req_post(req
, ev
);
916 tevent_req_set_callback(subreq
, cli_smb2_rmdir_opened1
, req
);
920 static void cli_smb2_rmdir_opened1(struct tevent_req
*subreq
)
922 struct tevent_req
*req
= tevent_req_callback_data(
923 subreq
, struct tevent_req
);
924 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
925 req
, struct cli_smb2_rmdir_state
);
928 status
= cli_smb2_create_fnum_recv(
929 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
932 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
934 * Naive option to match our SMB1 code. Assume the
935 * symlink path that tripped us up was the last
936 * component and try again. Eventually we will have to
937 * deal with the returned path unprocessed component. JRA.
939 subreq
= cli_smb2_create_fnum_send(
944 0, /* create_flags */
945 SMB2_IMPERSONATION_IMPERSONATION
,
946 DELETE_ACCESS
, /* desired_access */
947 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
948 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
949 FILE_OPEN
, /* create_disposition */
951 FILE_DELETE_ON_CLOSE
|
952 FILE_OPEN_REPARSE_POINT
, /* create_options */
953 state
->in_cblobs
); /* in_cblobs */
954 if (tevent_req_nomem(subreq
, req
)) {
957 tevent_req_set_callback(subreq
, cli_smb2_rmdir_opened2
, req
);
961 if (tevent_req_nterror(req
, status
)) {
965 subreq
= cli_smb2_delete_on_close_send(
966 state
, state
->ev
, state
->cli
, state
->fnum
, true);
967 if (tevent_req_nomem(subreq
, req
)) {
970 tevent_req_set_callback(subreq
, cli_smb2_rmdir_disp_set
, req
);
973 static void cli_smb2_rmdir_opened2(struct tevent_req
*subreq
)
975 struct tevent_req
*req
= tevent_req_callback_data(
976 subreq
, struct tevent_req
);
977 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
978 req
, struct cli_smb2_rmdir_state
);
981 status
= cli_smb2_create_fnum_recv(
982 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
984 if (tevent_req_nterror(req
, status
)) {
988 subreq
= cli_smb2_delete_on_close_send(
989 state
, state
->ev
, state
->cli
, state
->fnum
, true);
990 if (tevent_req_nomem(subreq
, req
)) {
993 tevent_req_set_callback(subreq
, cli_smb2_rmdir_disp_set
, req
);
996 static void cli_smb2_rmdir_disp_set(struct tevent_req
*subreq
)
998 struct tevent_req
*req
= tevent_req_callback_data(
999 subreq
, struct tevent_req
);
1000 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
1001 req
, struct cli_smb2_rmdir_state
);
1003 state
->status
= cli_smb2_delete_on_close_recv(subreq
);
1004 TALLOC_FREE(subreq
);
1007 * Close the fd even if the set_disp failed
1010 subreq
= cli_smb2_close_fnum_send(
1011 state
, state
->ev
, state
->cli
, state
->fnum
);
1012 if (tevent_req_nomem(subreq
, req
)) {
1015 tevent_req_set_callback(subreq
, cli_smb2_rmdir_closed
, req
);
1018 static void cli_smb2_rmdir_closed(struct tevent_req
*subreq
)
1020 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
1021 tevent_req_simple_finish_ntstatus(subreq
, status
);
1024 NTSTATUS
cli_smb2_rmdir_recv(struct tevent_req
*req
)
1026 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
1027 req
, struct cli_smb2_rmdir_state
);
1030 if (tevent_req_is_nterror(req
, &status
)) {
1033 return state
->status
;
1036 /***************************************************************
1037 Small wrapper that allows SMB2 to unlink a pathname.
1038 ***************************************************************/
1040 struct cli_smb2_unlink_state
{
1041 struct tevent_context
*ev
;
1042 struct cli_state
*cli
;
1044 const struct smb2_create_blobs
*in_cblobs
;
1047 static void cli_smb2_unlink_opened1(struct tevent_req
*subreq
);
1048 static void cli_smb2_unlink_opened2(struct tevent_req
*subreq
);
1049 static void cli_smb2_unlink_closed(struct tevent_req
*subreq
);
1051 struct tevent_req
*cli_smb2_unlink_send(
1052 TALLOC_CTX
*mem_ctx
,
1053 struct tevent_context
*ev
,
1054 struct cli_state
*cli
,
1056 const struct smb2_create_blobs
*in_cblobs
)
1058 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1059 struct cli_smb2_unlink_state
*state
= NULL
;
1061 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_unlink_state
);
1067 state
->fname
= fname
;
1068 state
->in_cblobs
= in_cblobs
;
1070 subreq
= cli_smb2_create_fnum_send(
1071 state
, /* mem_ctx */
1072 state
->ev
, /* tevent_context */
1073 state
->cli
, /* cli_struct */
1074 state
->fname
, /* filename */
1075 0, /* create_flags */
1076 SMB2_IMPERSONATION_IMPERSONATION
,
1077 DELETE_ACCESS
, /* desired_access */
1078 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
1081 FILE_SHARE_DELETE
, /* share_access */
1082 FILE_OPEN
, /* create_disposition */
1083 FILE_DELETE_ON_CLOSE
, /* create_options */
1084 state
->in_cblobs
); /* in_cblobs */
1085 if (tevent_req_nomem(subreq
, req
)) {
1086 return tevent_req_post(req
, ev
);
1088 tevent_req_set_callback(subreq
, cli_smb2_unlink_opened1
, req
);
1092 static void cli_smb2_unlink_opened1(struct tevent_req
*subreq
)
1094 struct tevent_req
*req
= tevent_req_callback_data(
1095 subreq
, struct tevent_req
);
1096 struct cli_smb2_unlink_state
*state
= tevent_req_data(
1097 req
, struct cli_smb2_unlink_state
);
1098 uint16_t fnum
= 0xffff;
1101 status
= cli_smb2_create_fnum_recv(
1102 subreq
, &fnum
, NULL
, NULL
, NULL
, NULL
);
1103 TALLOC_FREE(subreq
);
1105 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
) ||
1106 NT_STATUS_EQUAL(status
, NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED
)) {
1108 * Naive option to match our SMB1 code. Assume the
1109 * symlink path that tripped us up was the last
1110 * component and try again. Eventually we will have to
1111 * deal with the returned path unprocessed component. JRA.
1113 subreq
= cli_smb2_create_fnum_send(
1114 state
, /* mem_ctx */
1115 state
->ev
, /* tevent_context */
1116 state
->cli
, /* cli_struct */
1117 state
->fname
, /* filename */
1118 0, /* create_flags */
1119 SMB2_IMPERSONATION_IMPERSONATION
,
1120 DELETE_ACCESS
, /* desired_access */
1121 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
1124 FILE_SHARE_DELETE
, /* share_access */
1125 FILE_OPEN
, /* create_disposition */
1126 FILE_DELETE_ON_CLOSE
|
1127 FILE_OPEN_REPARSE_POINT
, /* create_options */
1128 state
->in_cblobs
); /* in_cblobs */
1129 if (tevent_req_nomem(subreq
, req
)) {
1132 tevent_req_set_callback(subreq
, cli_smb2_unlink_opened2
, req
);
1136 if (tevent_req_nterror(req
, status
)) {
1140 subreq
= cli_smb2_close_fnum_send(state
, state
->ev
, state
->cli
, fnum
);
1141 if (tevent_req_nomem(subreq
, req
)) {
1144 tevent_req_set_callback(subreq
, cli_smb2_unlink_closed
, req
);
1147 static void cli_smb2_unlink_opened2(struct tevent_req
*subreq
)
1149 struct tevent_req
*req
= tevent_req_callback_data(
1150 subreq
, struct tevent_req
);
1151 struct cli_smb2_unlink_state
*state
= tevent_req_data(
1152 req
, struct cli_smb2_unlink_state
);
1153 uint16_t fnum
= 0xffff;
1156 status
= cli_smb2_create_fnum_recv(
1157 subreq
, &fnum
, NULL
, NULL
, NULL
, NULL
);
1158 TALLOC_FREE(subreq
);
1159 if (tevent_req_nterror(req
, status
)) {
1163 subreq
= cli_smb2_close_fnum_send(state
, state
->ev
, state
->cli
, fnum
);
1164 if (tevent_req_nomem(subreq
, req
)) {
1167 tevent_req_set_callback(subreq
, cli_smb2_unlink_closed
, req
);
1170 static void cli_smb2_unlink_closed(struct tevent_req
*subreq
)
1172 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
1173 tevent_req_simple_finish_ntstatus(subreq
, status
);
1176 NTSTATUS
cli_smb2_unlink_recv(struct tevent_req
*req
)
1178 return tevent_req_simple_recv_ntstatus(req
);
1181 static ssize_t
sid_parse_wire(TALLOC_CTX
*mem_ctx
, const uint8_t *data
,
1182 struct dom_sid
*sid
, size_t num_rdata
)
1185 enum ndr_err_code ndr_err
;
1186 DATA_BLOB in
= data_blob_const(data
, num_rdata
);
1188 ndr_err
= ndr_pull_struct_blob(&in
,
1191 (ndr_pull_flags_fn_t
)ndr_pull_dom_sid
);
1192 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1196 sid_size
= ndr_size_dom_sid(sid
, 0);
1197 if (sid_size
> num_rdata
) {
1204 /***************************************************************
1205 Utility function to parse a SMB2_FIND_POSIX_INFORMATION reply.
1206 ***************************************************************/
1208 static NTSTATUS
parse_finfo_posix_info(const uint8_t *dir_data
,
1209 uint32_t dir_data_length
,
1210 struct file_info
*finfo
,
1211 uint32_t *next_offset
)
1214 size_t slen
= 0, slen2
= 0;
1216 uint32_t _next_offset
= 0;
1218 if (dir_data_length
< 4) {
1219 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1222 _next_offset
= IVAL(dir_data
, 0);
1224 if (_next_offset
> dir_data_length
) {
1225 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1228 if (_next_offset
!= 0) {
1229 /* Ensure we only read what in this record. */
1230 dir_data_length
= _next_offset
;
1233 if (dir_data_length
< 92) {
1234 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1237 finfo
->btime_ts
= interpret_long_date((const char *)dir_data
+ 8);
1238 finfo
->atime_ts
= interpret_long_date((const char *)dir_data
+ 16);
1239 finfo
->mtime_ts
= interpret_long_date((const char *)dir_data
+ 24);
1240 finfo
->ctime_ts
= interpret_long_date((const char *)dir_data
+ 32);
1241 finfo
->allocated_size
= PULL_LE_U64(dir_data
, 40);
1242 finfo
->size
= PULL_LE_U64(dir_data
, 48);
1243 finfo
->mode
= PULL_LE_U32(dir_data
, 56);
1244 finfo
->ino
= PULL_LE_U64(dir_data
, 60);
1245 finfo
->st_ex_dev
= PULL_LE_U32(dir_data
, 68);
1246 finfo
->st_ex_nlink
= PULL_LE_U32(dir_data
, 76);
1247 finfo
->reparse_tag
= PULL_LE_U32(dir_data
, 80);
1248 finfo
->st_ex_mode
= wire_perms_to_unix(PULL_LE_U32(dir_data
, 84));
1250 slen
= sid_parse_wire(finfo
, dir_data
+88, &finfo
->owner_sid
,
1251 dir_data_length
-88);
1253 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1255 slen2
= sid_parse_wire(finfo
, dir_data
+88+slen
, &finfo
->group_sid
,
1256 dir_data_length
-88-slen
);
1258 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1262 namelen
= PULL_LE_U32(dir_data
, 88+slen
);
1263 ret
= pull_string_talloc(finfo
,
1265 FLAGS2_UNICODE_STRINGS
,
1270 if (ret
== (size_t)-1) {
1271 /* Bad conversion. */
1272 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1275 if (finfo
->name
== NULL
) {
1276 /* Bad conversion. */
1277 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1280 *next_offset
= _next_offset
;
1281 return NT_STATUS_OK
;
1284 /***************************************************************
1285 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1286 ***************************************************************/
1288 static NTSTATUS
parse_finfo_id_both_directory_info(const uint8_t *dir_data
,
1289 uint32_t dir_data_length
,
1290 struct file_info
*finfo
,
1291 uint32_t *next_offset
)
1297 if (dir_data_length
< 4) {
1298 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1301 *next_offset
= IVAL(dir_data
, 0);
1303 if (*next_offset
> dir_data_length
) {
1304 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1307 if (*next_offset
!= 0) {
1308 /* Ensure we only read what in this record. */
1309 dir_data_length
= *next_offset
;
1312 if (dir_data_length
< 105) {
1313 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1316 finfo
->btime_ts
= interpret_long_date((const char *)dir_data
+ 8);
1317 finfo
->atime_ts
= interpret_long_date((const char *)dir_data
+ 16);
1318 finfo
->mtime_ts
= interpret_long_date((const char *)dir_data
+ 24);
1319 finfo
->ctime_ts
= interpret_long_date((const char *)dir_data
+ 32);
1320 finfo
->size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 40, 0);
1321 finfo
->allocated_size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 48, 0);
1322 finfo
->attr
= IVAL(dir_data
+ 56, 0);
1323 finfo
->ino
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 96, 0);
1324 namelen
= IVAL(dir_data
+ 60,0);
1325 if (namelen
> (dir_data_length
- 104)) {
1326 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1328 slen
= CVAL(dir_data
+ 68, 0);
1330 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1332 ret
= pull_string_talloc(finfo
,
1334 FLAGS2_UNICODE_STRINGS
,
1339 if (ret
== (size_t)-1) {
1340 /* Bad conversion. */
1341 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1344 ret
= pull_string_talloc(finfo
,
1346 FLAGS2_UNICODE_STRINGS
,
1351 if (ret
== (size_t)-1) {
1352 /* Bad conversion. */
1353 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1356 if (finfo
->name
== NULL
) {
1357 /* Bad conversion. */
1358 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1361 return NT_STATUS_OK
;
1364 /*******************************************************************
1365 Given a filename - get its directory name
1366 ********************************************************************/
1368 static bool windows_parent_dirname(TALLOC_CTX
*mem_ctx
,
1376 p
= strrchr_m(dir
, '\\'); /* Find final '\\', if any */
1379 if (!(*parent
= talloc_strdup(mem_ctx
, "\\"))) {
1390 if (!(*parent
= (char *)talloc_memdup(mem_ctx
, dir
, len
+1))) {
1393 (*parent
)[len
] = '\0';
1401 struct cli_smb2_list_dir_data
{
1406 struct cli_smb2_list_state
{
1407 struct tevent_context
*ev
;
1408 struct cli_state
*cli
;
1414 struct cli_smb2_list_dir_data
*response
;
1416 unsigned int info_level
;
1419 static void cli_smb2_list_opened(struct tevent_req
*subreq
);
1420 static void cli_smb2_list_done(struct tevent_req
*subreq
);
1421 static void cli_smb2_list_closed(struct tevent_req
*subreq
);
1423 struct tevent_req
*cli_smb2_list_send(
1424 TALLOC_CTX
*mem_ctx
,
1425 struct tevent_context
*ev
,
1426 struct cli_state
*cli
,
1427 const char *pathname
,
1428 unsigned int info_level
,
1431 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1432 struct cli_smb2_list_state
*state
= NULL
;
1433 char *parent
= NULL
;
1435 struct smb2_create_blobs
*in_cblobs
= NULL
;
1437 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_list_state
);
1443 state
->status
= NT_STATUS_OK
;
1444 state
->info_level
= info_level
;
1446 ok
= windows_parent_dirname(state
, pathname
, &parent
, &state
->mask
);
1448 tevent_req_oom(req
);
1449 return tevent_req_post(req
, ev
);
1452 if (smbXcli_conn_have_posix(cli
->conn
) && posix
) {
1455 /* The mode MUST be 0 when opening an existing file/dir, and
1456 * will be ignored by the server.
1458 uint8_t linear_mode
[4] = { 0 };
1459 DATA_BLOB blob
= { .data
=linear_mode
,
1460 .length
=sizeof(linear_mode
) };
1462 in_cblobs
= talloc_zero(mem_ctx
, struct smb2_create_blobs
);
1463 if (in_cblobs
== NULL
) {
1467 status
= smb2_create_blob_add(in_cblobs
, in_cblobs
,
1468 SMB2_CREATE_TAG_POSIX
, blob
);
1469 if (!NT_STATUS_IS_OK(status
)) {
1470 tevent_req_nterror(req
, status
);
1471 return tevent_req_post(req
, ev
);
1475 subreq
= cli_smb2_create_fnum_send(
1476 state
, /* mem_ctx */
1480 0, /* create_flags */
1481 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation_level */
1482 SEC_DIR_LIST
|SEC_DIR_READ_ATTRIBUTE
, /* desired_access */
1483 FILE_ATTRIBUTE_DIRECTORY
, /* file_attributes */
1484 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
1485 FILE_OPEN
, /* create_disposition */
1486 FILE_DIRECTORY_FILE
, /* create_options */
1487 in_cblobs
); /* in_cblobs */
1488 TALLOC_FREE(in_cblobs
);
1489 if (tevent_req_nomem(subreq
, req
)) {
1490 return tevent_req_post(req
, ev
);
1492 tevent_req_set_callback(subreq
, cli_smb2_list_opened
, req
);
1496 static void cli_smb2_list_opened(struct tevent_req
*subreq
)
1498 struct tevent_req
*req
= tevent_req_callback_data(
1499 subreq
, struct tevent_req
);
1500 struct cli_smb2_list_state
*state
= tevent_req_data(
1501 req
, struct cli_smb2_list_state
);
1504 status
= cli_smb2_create_fnum_recv(
1505 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
1506 TALLOC_FREE(subreq
);
1507 if (tevent_req_nterror(req
, status
)) {
1512 * Make our caller get back to us via cli_smb2_list_recv(),
1513 * triggering the smb2_query_directory_send()
1515 tevent_req_defer_callback(req
, state
->ev
);
1516 tevent_req_notify_callback(req
);
1519 static void cli_smb2_list_done(struct tevent_req
*subreq
)
1521 struct tevent_req
*req
= tevent_req_callback_data(
1522 subreq
, struct tevent_req
);
1523 struct cli_smb2_list_state
*state
= tevent_req_data(
1524 req
, struct cli_smb2_list_state
);
1525 struct cli_smb2_list_dir_data
*response
= NULL
;
1527 response
= talloc(state
, struct cli_smb2_list_dir_data
);
1528 if (tevent_req_nomem(response
, req
)) {
1532 state
->status
= smb2cli_query_directory_recv(
1533 subreq
, response
, &response
->data
, &response
->length
);
1534 TALLOC_FREE(subreq
);
1536 if (NT_STATUS_IS_OK(state
->status
)) {
1537 state
->response
= response
;
1540 tevent_req_defer_callback(req
, state
->ev
);
1541 tevent_req_notify_callback(req
);
1545 TALLOC_FREE(response
);
1547 subreq
= cli_smb2_close_fnum_send(
1548 state
, state
->ev
, state
->cli
, state
->fnum
);
1549 if (tevent_req_nomem(subreq
, req
)) {
1552 tevent_req_set_callback(subreq
, cli_smb2_list_closed
, req
);
1555 static void cli_smb2_list_closed(struct tevent_req
*subreq
)
1557 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
1558 tevent_req_simple_finish_ntstatus(subreq
, status
);
1562 * Return the next finfo directory.
1564 * This parses the blob returned from QUERY_DIRECTORY step by step. If
1565 * the blob ends, this triggers a fresh QUERY_DIRECTORY and returns
1566 * NT_STATUS_RETRY, which will then trigger the caller again when the
1567 * QUERY_DIRECTORY has returned with another buffer. This way we
1568 * guarantee that no asynchronous request is open after this call
1569 * returns an entry, so that other synchronous requests can be issued
1570 * on the same connection while the directoy listing proceeds.
1572 NTSTATUS
cli_smb2_list_recv(
1573 struct tevent_req
*req
,
1574 TALLOC_CTX
*mem_ctx
,
1575 struct file_info
**pfinfo
)
1577 struct cli_smb2_list_state
*state
= tevent_req_data(
1578 req
, struct cli_smb2_list_state
);
1579 struct cli_smb2_list_dir_data
*response
= NULL
;
1580 struct file_info
*finfo
= NULL
;
1582 uint32_t next_offset
= 0;
1585 in_progress
= tevent_req_is_in_progress(req
);
1588 if (!tevent_req_is_nterror(req
, &status
)) {
1589 status
= NT_STATUS_NO_MORE_FILES
;
1594 response
= state
->response
;
1595 if (response
== NULL
) {
1596 struct tevent_req
*subreq
= NULL
;
1597 struct cli_state
*cli
= state
->cli
;
1598 struct smb2_hnd
*ph
= NULL
;
1599 uint32_t max_trans
, max_avail_len
;
1602 if (!NT_STATUS_IS_OK(state
->status
)) {
1603 status
= state
->status
;
1607 status
= map_fnum_to_smb2_handle(cli
, state
->fnum
, &ph
);
1608 if (!NT_STATUS_IS_OK(status
)) {
1612 max_trans
= smb2cli_conn_max_trans_size(cli
->conn
);
1613 ok
= smb2cli_conn_req_possible(cli
->conn
, &max_avail_len
);
1615 max_trans
= MIN(max_trans
, max_avail_len
);
1618 subreq
= smb2cli_query_directory_send(
1619 state
, /* mem_ctx */
1621 cli
->conn
, /* conn */
1622 cli
->timeout
, /* timeout_msec */
1623 cli
->smb2
.session
, /* session */
1624 cli
->smb2
.tcon
, /* tcon */
1625 state
->info_level
, /* level */
1628 ph
->fid_persistent
, /* fid_persistent */
1629 ph
->fid_volatile
, /* fid_volatile */
1630 state
->mask
, /* mask */
1631 max_trans
); /* outbuf_len */
1632 if (subreq
== NULL
) {
1633 status
= NT_STATUS_NO_MEMORY
;
1636 tevent_req_set_callback(subreq
, cli_smb2_list_done
, req
);
1637 return NT_STATUS_RETRY
;
1640 SMB_ASSERT(response
->length
> state
->offset
);
1642 finfo
= talloc_zero(mem_ctx
, struct file_info
);
1643 if (finfo
== NULL
) {
1644 status
= NT_STATUS_NO_MEMORY
;
1648 if (state
->info_level
== SMB2_FIND_POSIX_INFORMATION
) {
1649 status
= parse_finfo_posix_info(
1650 response
->data
+ state
->offset
,
1651 response
->length
- state
->offset
,
1655 status
= parse_finfo_id_both_directory_info(
1656 response
->data
+ state
->offset
,
1657 response
->length
- state
->offset
,
1661 if (!NT_STATUS_IS_OK(status
)) {
1665 status
= is_bad_finfo_name(state
->cli
, finfo
);
1666 if (!NT_STATUS_IS_OK(status
)) {
1671 * parse_finfo_id_both_directory_info() checks for overflow,
1672 * no need to check again here.
1674 state
->offset
+= next_offset
;
1676 if (next_offset
== 0) {
1677 TALLOC_FREE(state
->response
);
1680 tevent_req_defer_callback(req
, state
->ev
);
1681 tevent_req_notify_callback(req
);
1684 return NT_STATUS_OK
;
1688 tevent_req_received(req
);
1692 /***************************************************************
1693 Wrapper that allows SMB2 to query a path info (basic level).
1695 ***************************************************************/
1697 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
1699 SMB_STRUCT_STAT
*sbuf
,
1700 uint32_t *attributes
)
1703 struct smb_create_returns cr
;
1704 uint16_t fnum
= 0xffff;
1705 size_t namelen
= strlen(name
);
1707 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1709 * Can't use sync call while an async call is in flight
1711 return NT_STATUS_INVALID_PARAMETER
;
1714 /* SMB2 is pickier about pathnames. Ensure it doesn't
1716 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1717 char *modname
= talloc_strndup(talloc_tos(), name
, namelen
-1);
1718 if (modname
== NULL
) {
1719 return NT_STATUS_NO_MEMORY
;
1724 /* This is commonly used as a 'cd'. Try qpathinfo on
1725 a directory handle first. */
1727 status
= cli_smb2_create_fnum(cli
,
1729 0, /* create_flags */
1730 SMB2_IMPERSONATION_IMPERSONATION
,
1731 FILE_READ_ATTRIBUTES
, /* desired_access */
1732 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1733 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1734 FILE_OPEN
, /* create_disposition */
1735 FILE_DIRECTORY_FILE
, /* create_options */
1742 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
1743 /* Maybe a file ? */
1744 status
= cli_smb2_create_fnum(cli
,
1746 0, /* create_flags */
1747 SMB2_IMPERSONATION_IMPERSONATION
,
1748 FILE_READ_ATTRIBUTES
, /* desired_access */
1749 0, /* file attributes */
1750 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1751 FILE_OPEN
, /* create_disposition */
1752 0, /* create_options */
1760 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
1761 /* Maybe a reparse point ? */
1762 status
= cli_smb2_create_fnum(cli
,
1764 0, /* create_flags */
1765 SMB2_IMPERSONATION_IMPERSONATION
,
1766 FILE_READ_ATTRIBUTES
, /* desired_access */
1767 0, /* file attributes */
1768 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1769 FILE_OPEN
, /* create_disposition */
1770 FILE_OPEN_REPARSE_POINT
, /* create_options */
1778 if (!NT_STATUS_IS_OK(status
)) {
1782 status
= cli_smb2_close_fnum(cli
, fnum
);
1786 sbuf
->st_ex_atime
= nt_time_to_unix_timespec(cr
.last_access_time
);
1787 sbuf
->st_ex_mtime
= nt_time_to_unix_timespec(cr
.last_write_time
);
1788 sbuf
->st_ex_ctime
= nt_time_to_unix_timespec(cr
.change_time
);
1789 sbuf
->st_ex_size
= cr
.end_of_file
;
1790 *attributes
= cr
.file_attributes
;
1795 struct cli_smb2_query_info_fnum_state
{
1799 static void cli_smb2_query_info_fnum_done(struct tevent_req
*subreq
);
1801 struct tevent_req
*cli_smb2_query_info_fnum_send(
1802 TALLOC_CTX
*mem_ctx
,
1803 struct tevent_context
*ev
,
1804 struct cli_state
*cli
,
1806 uint8_t in_info_type
,
1807 uint8_t in_info_class
,
1808 uint32_t in_max_output_length
,
1809 const DATA_BLOB
*in_input_buffer
,
1810 uint32_t in_additional_info
,
1813 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1814 struct cli_smb2_query_info_fnum_state
*state
= NULL
;
1815 struct smb2_hnd
*ph
= NULL
;
1818 req
= tevent_req_create(
1819 mem_ctx
, &state
, struct cli_smb2_query_info_fnum_state
);
1824 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
1825 if (tevent_req_nterror(req
, status
)) {
1826 return tevent_req_post(req
, ev
);
1829 subreq
= smb2cli_query_info_send(
1838 in_max_output_length
,
1844 if (tevent_req_nomem(subreq
, req
)) {
1845 return tevent_req_post(req
, ev
);
1847 tevent_req_set_callback(subreq
, cli_smb2_query_info_fnum_done
, req
);
1851 static void cli_smb2_query_info_fnum_done(struct tevent_req
*subreq
)
1853 struct tevent_req
*req
= tevent_req_callback_data(
1854 subreq
, struct tevent_req
);
1855 struct cli_smb2_query_info_fnum_state
*state
= tevent_req_data(
1856 req
, struct cli_smb2_query_info_fnum_state
);
1860 status
= smb2cli_query_info_recv(subreq
, state
, &outbuf
);
1861 TALLOC_FREE(subreq
);
1862 if (tevent_req_nterror(req
, status
)) {
1867 * We have to dup the memory here because outbuf.data is not
1868 * returned as a talloc object by smb2cli_query_info_recv.
1869 * It's a pointer into the received buffer.
1871 state
->outbuf
= data_blob_dup_talloc(state
, outbuf
);
1873 if ((outbuf
.length
!= 0) &&
1874 tevent_req_nomem(state
->outbuf
.data
, req
)) {
1877 tevent_req_done(req
);
1880 NTSTATUS
cli_smb2_query_info_fnum_recv(
1881 struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
, DATA_BLOB
*outbuf
)
1883 struct cli_smb2_query_info_fnum_state
*state
= tevent_req_data(
1884 req
, struct cli_smb2_query_info_fnum_state
);
1887 if (tevent_req_is_nterror(req
, &status
)) {
1890 *outbuf
= (DATA_BLOB
) {
1891 .data
= talloc_move(mem_ctx
, &state
->outbuf
.data
),
1892 .length
= state
->outbuf
.length
,
1894 return NT_STATUS_OK
;
1897 NTSTATUS
cli_smb2_query_info_fnum(
1898 struct cli_state
*cli
,
1900 uint8_t in_info_type
,
1901 uint8_t in_info_class
,
1902 uint32_t in_max_output_length
,
1903 const DATA_BLOB
*in_input_buffer
,
1904 uint32_t in_additional_info
,
1906 TALLOC_CTX
*mem_ctx
,
1909 TALLOC_CTX
*frame
= talloc_stackframe();
1910 struct tevent_context
*ev
= NULL
;
1911 struct tevent_req
*req
= NULL
;
1912 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1915 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1917 * Can't use sync call while an async call is in flight
1919 status
= NT_STATUS_INVALID_PARAMETER
;
1922 ev
= samba_tevent_context_init(frame
);
1926 req
= cli_smb2_query_info_fnum_send(
1933 in_max_output_length
,
1940 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
1944 status
= cli_smb2_query_info_fnum_recv(req
, mem_ctx
, outbuf
);
1950 /***************************************************************
1951 Helper function for pathname operations.
1952 ***************************************************************/
1954 struct get_fnum_from_path_state
{
1955 struct tevent_context
*ev
;
1956 struct cli_state
*cli
;
1958 uint32_t desired_access
;
1962 static void get_fnum_from_path_opened_file(struct tevent_req
*subreq
);
1963 static void get_fnum_from_path_opened_reparse(struct tevent_req
*subreq
);
1964 static void get_fnum_from_path_opened_dir(struct tevent_req
*subreq
);
1966 static struct tevent_req
*get_fnum_from_path_send(
1967 TALLOC_CTX
*mem_ctx
,
1968 struct tevent_context
*ev
,
1969 struct cli_state
*cli
,
1971 uint32_t desired_access
)
1973 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1974 struct get_fnum_from_path_state
*state
= NULL
;
1975 size_t namelen
= strlen(name
);
1977 req
= tevent_req_create(
1978 mem_ctx
, &state
, struct get_fnum_from_path_state
);
1985 state
->desired_access
= desired_access
;
1988 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
1991 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1992 state
->name
= talloc_strndup(state
, name
, namelen
-1);
1993 if (tevent_req_nomem(state
->name
, req
)) {
1994 return tevent_req_post(req
, ev
);
1998 subreq
= cli_smb2_create_fnum_send(
1999 state
, /* mem_ctx, */
2002 state
->name
, /* fname */
2003 0, /* create_flags */
2004 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation_level */
2005 desired_access
, /* desired_access */
2006 0, /* file_attributes */
2009 FILE_SHARE_DELETE
, /* share_access */
2010 FILE_OPEN
, /* create_disposition */
2011 0, /* create_options */
2012 NULL
); /* in_cblobs */
2013 if (tevent_req_nomem(subreq
, req
)) {
2014 return tevent_req_post(req
, ev
);
2016 tevent_req_set_callback(subreq
, get_fnum_from_path_opened_file
, req
);
2020 static void get_fnum_from_path_opened_file(struct tevent_req
*subreq
)
2022 struct tevent_req
*req
= tevent_req_callback_data(
2023 subreq
, struct tevent_req
);
2024 struct get_fnum_from_path_state
*state
= tevent_req_data(
2025 req
, struct get_fnum_from_path_state
);
2028 status
= cli_smb2_create_fnum_recv(
2029 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
2030 TALLOC_FREE(subreq
);
2032 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
2034 * Naive option to match our SMB1 code. Assume the
2035 * symlink path that tripped us up was the last
2036 * component and try again. Eventually we will have to
2037 * deal with the returned path unprocessed component. JRA.
2039 subreq
= cli_smb2_create_fnum_send(
2040 state
, /* mem_ctx, */
2042 state
->cli
, /* cli */
2043 state
->name
, /* fname */
2044 0, /* create_flags */
2045 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation */
2046 state
->desired_access
, /* desired_access */
2047 0, /* file_attributes */
2050 FILE_SHARE_DELETE
, /* share_access */
2051 FILE_OPEN
, /* create_disposition */
2052 FILE_OPEN_REPARSE_POINT
, /* create_options */
2053 NULL
); /* in_cblobs */
2054 if (tevent_req_nomem(subreq
, req
)) {
2057 tevent_req_set_callback(
2058 subreq
, get_fnum_from_path_opened_reparse
, req
);
2062 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
2063 subreq
= cli_smb2_create_fnum_send(
2064 state
, /* mem_ctx, */
2066 state
->cli
, /* cli */
2067 state
->name
, /* fname */
2068 0, /* create_flags */
2069 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation */
2070 state
->desired_access
, /* desired_access */
2071 0, /* file_attributes */
2074 FILE_SHARE_DELETE
, /* share_access */
2075 FILE_OPEN
, /* create_disposition */
2076 FILE_DIRECTORY_FILE
, /* create_options */
2077 NULL
); /* in_cblobs */
2078 if (tevent_req_nomem(subreq
, req
)) {
2081 tevent_req_set_callback(
2082 subreq
, get_fnum_from_path_opened_dir
, req
);
2086 if (tevent_req_nterror(req
, status
)) {
2089 tevent_req_done(req
);
2092 static void get_fnum_from_path_opened_reparse(struct tevent_req
*subreq
)
2094 struct tevent_req
*req
= tevent_req_callback_data(
2095 subreq
, struct tevent_req
);
2096 struct get_fnum_from_path_state
*state
= tevent_req_data(
2097 req
, struct get_fnum_from_path_state
);
2098 NTSTATUS status
= cli_smb2_create_fnum_recv(
2099 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
2100 tevent_req_simple_finish_ntstatus(subreq
, status
);
2103 static void get_fnum_from_path_opened_dir(struct tevent_req
*subreq
)
2105 /* Abstraction violation, but these two are just the same... */
2106 get_fnum_from_path_opened_reparse(subreq
);
2109 static NTSTATUS
get_fnum_from_path_recv(
2110 struct tevent_req
*req
, uint16_t *pfnum
)
2112 struct get_fnum_from_path_state
*state
= tevent_req_data(
2113 req
, struct get_fnum_from_path_state
);
2114 NTSTATUS status
= NT_STATUS_OK
;
2116 if (!tevent_req_is_nterror(req
, &status
)) {
2117 *pfnum
= state
->fnum
;
2119 tevent_req_received(req
);
2123 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
2125 uint32_t desired_access
,
2128 TALLOC_CTX
*frame
= talloc_stackframe();
2129 struct tevent_context
*ev
= NULL
;
2130 struct tevent_req
*req
= NULL
;
2131 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
2133 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2134 status
= NT_STATUS_INVALID_PARAMETER
;
2137 ev
= samba_tevent_context_init(frame
);
2141 req
= get_fnum_from_path_send(frame
, ev
, cli
, name
, desired_access
);
2145 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2148 status
= get_fnum_from_path_recv(req
, pfnum
);
2154 /***************************************************************
2155 Wrapper that allows SMB2 to query a path info (ALTNAME level).
2157 ***************************************************************/
2159 NTSTATUS
cli_smb2_qpathinfo_alt_name(struct cli_state
*cli
,
2164 DATA_BLOB outbuf
= data_blob_null
;
2165 uint16_t fnum
= 0xffff;
2166 uint32_t altnamelen
= 0;
2167 TALLOC_CTX
*frame
= talloc_stackframe();
2169 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2171 * Can't use sync call while an async call is in flight
2173 status
= NT_STATUS_INVALID_PARAMETER
;
2177 status
= get_fnum_from_path(cli
,
2179 FILE_READ_ATTRIBUTES
,
2182 if (!NT_STATUS_IS_OK(status
)) {
2186 status
= cli_smb2_query_info_fnum(
2189 1, /* in_info_type */
2190 (SMB_FILE_ALTERNATE_NAME_INFORMATION
- 1000), /* in_file_info_class */
2191 0xFFFF, /* in_max_output_length */
2192 NULL
, /* in_input_buffer */
2193 0, /* in_additional_info */
2198 if (!NT_STATUS_IS_OK(status
)) {
2202 /* Parse the reply. */
2203 if (outbuf
.length
< 4) {
2204 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2208 altnamelen
= IVAL(outbuf
.data
, 0);
2209 if (altnamelen
> outbuf
.length
- 4) {
2210 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2214 if (altnamelen
> 0) {
2216 char *short_name
= NULL
;
2217 ret
= pull_string_talloc(frame
,
2219 FLAGS2_UNICODE_STRINGS
,
2224 if (ret
== (size_t)-1) {
2225 /* Bad conversion. */
2226 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2230 fstrcpy(alt_name
, short_name
);
2235 status
= NT_STATUS_OK
;
2239 if (fnum
!= 0xffff) {
2240 cli_smb2_close_fnum(cli
, fnum
);
2243 cli
->raw_status
= status
;
2249 /***************************************************************
2250 Wrapper that allows SMB2 to get pathname attributes.
2252 ***************************************************************/
2254 NTSTATUS
cli_smb2_getatr(struct cli_state
*cli
,
2261 uint16_t fnum
= 0xffff;
2262 struct timespec write_time_ts
;
2263 TALLOC_CTX
*frame
= talloc_stackframe();
2265 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2267 * Can't use sync call while an async call is in flight
2269 status
= NT_STATUS_INVALID_PARAMETER
;
2273 status
= get_fnum_from_path(cli
,
2275 FILE_READ_ATTRIBUTES
,
2278 if (!NT_STATUS_IS_OK(status
)) {
2282 status
= cli_qfileinfo_basic(
2287 NULL
, /* create_time */
2288 NULL
, /* access_time */
2290 NULL
, /* change_time */
2292 if (!NT_STATUS_IS_OK(status
)) {
2295 if (write_time
!= NULL
) {
2296 *write_time
= write_time_ts
.tv_sec
;
2301 if (fnum
!= 0xffff) {
2302 cli_smb2_close_fnum(cli
, fnum
);
2305 cli
->raw_status
= status
;
2311 /***************************************************************
2312 Wrapper that allows SMB2 to query a pathname info (basic level).
2313 Implement on top of cli_qfileinfo_basic().
2315 ***************************************************************/
2317 NTSTATUS
cli_smb2_qpathinfo2(struct cli_state
*cli
,
2319 struct timespec
*create_time
,
2320 struct timespec
*access_time
,
2321 struct timespec
*write_time
,
2322 struct timespec
*change_time
,
2328 uint16_t fnum
= 0xffff;
2329 TALLOC_CTX
*frame
= talloc_stackframe();
2331 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2333 * Can't use sync call while an async call is in flight
2335 status
= NT_STATUS_INVALID_PARAMETER
;
2339 status
= get_fnum_from_path(cli
,
2341 FILE_READ_ATTRIBUTES
,
2344 if (!NT_STATUS_IS_OK(status
)) {
2348 status
= cli_qfileinfo_basic(
2361 if (fnum
!= 0xffff) {
2362 cli_smb2_close_fnum(cli
, fnum
);
2365 cli
->raw_status
= status
;
2371 /***************************************************************
2372 Wrapper that allows SMB2 to query pathname streams.
2374 ***************************************************************/
2376 NTSTATUS
cli_smb2_qpathinfo_streams(struct cli_state
*cli
,
2378 TALLOC_CTX
*mem_ctx
,
2379 unsigned int *pnum_streams
,
2380 struct stream_struct
**pstreams
)
2383 uint16_t fnum
= 0xffff;
2384 DATA_BLOB outbuf
= data_blob_null
;
2385 TALLOC_CTX
*frame
= talloc_stackframe();
2387 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2389 * Can't use sync call while an async call is in flight
2391 status
= NT_STATUS_INVALID_PARAMETER
;
2395 status
= get_fnum_from_path(cli
,
2397 FILE_READ_ATTRIBUTES
,
2400 if (!NT_STATUS_IS_OK(status
)) {
2404 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2405 level 22 (SMB2_FILE_STREAM_INFORMATION). */
2407 status
= cli_smb2_query_info_fnum(
2410 1, /* in_info_type */
2411 (SMB_FILE_STREAM_INFORMATION
- 1000), /* in_file_info_class */
2412 0xFFFF, /* in_max_output_length */
2413 NULL
, /* in_input_buffer */
2414 0, /* in_additional_info */
2419 if (!NT_STATUS_IS_OK(status
)) {
2423 /* Parse the reply. */
2424 if (!parse_streams_blob(mem_ctx
,
2429 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2435 if (fnum
!= 0xffff) {
2436 cli_smb2_close_fnum(cli
, fnum
);
2439 cli
->raw_status
= status
;
2445 /***************************************************************
2446 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2449 ***************************************************************/
2451 NTSTATUS
cli_smb2_setpathinfo(struct cli_state
*cli
,
2453 uint8_t in_info_type
,
2454 uint8_t in_file_info_class
,
2455 const DATA_BLOB
*p_in_data
)
2458 uint16_t fnum
= 0xffff;
2459 TALLOC_CTX
*frame
= talloc_stackframe();
2461 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2463 * Can't use sync call while an async call is in flight
2465 status
= NT_STATUS_INVALID_PARAMETER
;
2469 status
= get_fnum_from_path(cli
,
2471 FILE_WRITE_ATTRIBUTES
,
2474 if (!NT_STATUS_IS_OK(status
)) {
2478 status
= cli_smb2_set_info_fnum(
2483 p_in_data
, /* in_input_buffer */
2484 0); /* in_additional_info */
2487 if (fnum
!= 0xffff) {
2488 cli_smb2_close_fnum(cli
, fnum
);
2491 cli
->raw_status
= status
;
2498 /***************************************************************
2499 Wrapper that allows SMB2 to set pathname attributes.
2501 ***************************************************************/
2503 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
2508 uint8_t inbuf_store
[40];
2509 DATA_BLOB inbuf
= data_blob_null
;
2511 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2512 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2514 inbuf
.data
= inbuf_store
;
2515 inbuf
.length
= sizeof(inbuf_store
);
2516 data_blob_clear(&inbuf
);
2519 * SMB1 uses attr == 0 to clear all attributes
2520 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2521 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2522 * request attribute change.
2524 * SMB2 uses exactly the reverse. Unfortunately as the
2525 * cli_setatr() ABI is exposed inside libsmbclient,
2526 * we must make the SMB2 cli_smb2_setatr() call
2527 * export the same ABI as the SMB1 cli_setatr()
2528 * which calls it. This means reversing the sense
2529 * of the requested attr argument if it's zero
2530 * or FILE_ATTRIBUTE_NORMAL.
2532 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2536 attr
= FILE_ATTRIBUTE_NORMAL
;
2537 } else if (attr
== FILE_ATTRIBUTE_NORMAL
) {
2541 SIVAL(inbuf
.data
, 32, attr
);
2543 put_long_date((char *)inbuf
.data
+ 16,mtime
);
2545 /* Set all the other times to -1. */
2546 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
2547 SBVAL(inbuf
.data
, 8, 0xFFFFFFFFFFFFFFFFLL
);
2548 SBVAL(inbuf
.data
, 24, 0xFFFFFFFFFFFFFFFFLL
);
2550 return cli_smb2_setpathinfo(cli
,
2552 1, /* in_info_type */
2553 /* in_file_info_class */
2554 SMB_FILE_BASIC_INFORMATION
- 1000,
2559 /***************************************************************
2560 Wrapper that allows SMB2 to set file handle times.
2562 ***************************************************************/
2564 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
2570 uint8_t inbuf_store
[40];
2571 DATA_BLOB inbuf
= data_blob_null
;
2573 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2575 * Can't use sync call while an async call is in flight
2577 return NT_STATUS_INVALID_PARAMETER
;
2580 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2581 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2583 inbuf
.data
= inbuf_store
;
2584 inbuf
.length
= sizeof(inbuf_store
);
2585 data_blob_clear(&inbuf
);
2587 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
2588 if (change_time
!= 0) {
2589 put_long_date((char *)inbuf
.data
+ 24, change_time
);
2591 if (access_time
!= 0) {
2592 put_long_date((char *)inbuf
.data
+ 8, access_time
);
2594 if (write_time
!= 0) {
2595 put_long_date((char *)inbuf
.data
+ 16, write_time
);
2598 cli
->raw_status
= cli_smb2_set_info_fnum(
2601 1, /* in_info_type */
2602 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
2603 &inbuf
, /* in_input_buffer */
2604 0); /* in_additional_info */
2606 return cli
->raw_status
;
2609 /***************************************************************
2610 Wrapper that allows SMB2 to query disk attributes (size).
2612 ***************************************************************/
2614 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, const char *path
,
2615 uint64_t *bsize
, uint64_t *total
, uint64_t *avail
)
2618 uint16_t fnum
= 0xffff;
2619 DATA_BLOB outbuf
= data_blob_null
;
2620 uint32_t sectors_per_unit
= 0;
2621 uint32_t bytes_per_sector
= 0;
2622 uint64_t total_size
= 0;
2623 uint64_t size_free
= 0;
2624 TALLOC_CTX
*frame
= talloc_stackframe();
2626 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2628 * Can't use sync call while an async call is in flight
2630 status
= NT_STATUS_INVALID_PARAMETER
;
2634 /* First open the top level directory. */
2635 status
= cli_smb2_create_fnum(cli
,
2637 0, /* create_flags */
2638 SMB2_IMPERSONATION_IMPERSONATION
,
2639 FILE_READ_ATTRIBUTES
, /* desired_access */
2640 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2641 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
2642 FILE_OPEN
, /* create_disposition */
2643 FILE_DIRECTORY_FILE
, /* create_options */
2650 if (!NT_STATUS_IS_OK(status
)) {
2654 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2655 level 3 (SMB_FS_SIZE_INFORMATION). */
2657 status
= cli_smb2_query_info_fnum(
2660 2, /* in_info_type */
2661 3, /* in_file_info_class */
2662 0xFFFF, /* in_max_output_length */
2663 NULL
, /* in_input_buffer */
2664 0, /* in_additional_info */
2668 if (!NT_STATUS_IS_OK(status
)) {
2672 /* Parse the reply. */
2673 if (outbuf
.length
!= 24) {
2674 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2678 total_size
= BVAL(outbuf
.data
, 0);
2679 size_free
= BVAL(outbuf
.data
, 8);
2680 sectors_per_unit
= IVAL(outbuf
.data
, 16);
2681 bytes_per_sector
= IVAL(outbuf
.data
, 20);
2684 *bsize
= (uint64_t)sectors_per_unit
* (uint64_t)bytes_per_sector
;
2687 *total
= total_size
;
2693 status
= NT_STATUS_OK
;
2697 if (fnum
!= 0xffff) {
2698 cli_smb2_close_fnum(cli
, fnum
);
2701 cli
->raw_status
= status
;
2707 /***************************************************************
2708 Wrapper that allows SMB2 to query file system sizes.
2710 ***************************************************************/
2712 NTSTATUS
cli_smb2_get_fs_full_size_info(struct cli_state
*cli
,
2713 uint64_t *total_allocation_units
,
2714 uint64_t *caller_allocation_units
,
2715 uint64_t *actual_allocation_units
,
2716 uint64_t *sectors_per_allocation_unit
,
2717 uint64_t *bytes_per_sector
)
2720 uint16_t fnum
= 0xffff;
2721 DATA_BLOB outbuf
= data_blob_null
;
2722 TALLOC_CTX
*frame
= talloc_stackframe();
2724 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2726 * Can't use sync call while an async call is in flight
2728 status
= NT_STATUS_INVALID_PARAMETER
;
2732 /* First open the top level directory. */
2734 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2735 SMB2_IMPERSONATION_IMPERSONATION
,
2736 FILE_READ_ATTRIBUTES
, /* desired_access */
2737 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2738 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2739 FILE_SHARE_DELETE
, /* share_access */
2740 FILE_OPEN
, /* create_disposition */
2741 FILE_DIRECTORY_FILE
, /* create_options */
2748 if (!NT_STATUS_IS_OK(status
)) {
2752 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2753 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2755 status
= cli_smb2_query_info_fnum(
2758 SMB2_0_INFO_FILESYSTEM
, /* in_info_type */
2759 SMB_FS_FULL_SIZE_INFORMATION
- 1000, /* in_file_info_class */
2760 0xFFFF, /* in_max_output_length */
2761 NULL
, /* in_input_buffer */
2762 0, /* in_additional_info */
2766 if (!NT_STATUS_IS_OK(status
)) {
2770 if (outbuf
.length
< 32) {
2771 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2775 *total_allocation_units
= BIG_UINT(outbuf
.data
, 0);
2776 *caller_allocation_units
= BIG_UINT(outbuf
.data
, 8);
2777 *actual_allocation_units
= BIG_UINT(outbuf
.data
, 16);
2778 *sectors_per_allocation_unit
= (uint64_t)IVAL(outbuf
.data
, 24);
2779 *bytes_per_sector
= (uint64_t)IVAL(outbuf
.data
, 28);
2783 if (fnum
!= 0xffff) {
2784 cli_smb2_close_fnum(cli
, fnum
);
2787 cli
->raw_status
= status
;
2793 /***************************************************************
2794 Wrapper that allows SMB2 to query file system attributes.
2796 ***************************************************************/
2798 NTSTATUS
cli_smb2_get_fs_attr_info(struct cli_state
*cli
, uint32_t *fs_attr
)
2801 uint16_t fnum
= 0xffff;
2802 DATA_BLOB outbuf
= data_blob_null
;
2803 TALLOC_CTX
*frame
= talloc_stackframe();
2805 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2807 * Can't use sync call while an async call is in flight
2809 status
= NT_STATUS_INVALID_PARAMETER
;
2813 /* First open the top level directory. */
2815 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2816 SMB2_IMPERSONATION_IMPERSONATION
,
2817 FILE_READ_ATTRIBUTES
, /* desired_access */
2818 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2819 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2820 FILE_SHARE_DELETE
, /* share_access */
2821 FILE_OPEN
, /* create_disposition */
2822 FILE_DIRECTORY_FILE
, /* create_options */
2829 if (!NT_STATUS_IS_OK(status
)) {
2833 status
= cli_smb2_query_info_fnum(
2836 2, /* in_info_type */
2837 5, /* in_file_info_class */
2838 0xFFFF, /* in_max_output_length */
2839 NULL
, /* in_input_buffer */
2840 0, /* in_additional_info */
2844 if (!NT_STATUS_IS_OK(status
)) {
2848 if (outbuf
.length
< 12) {
2849 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2853 *fs_attr
= IVAL(outbuf
.data
, 0);
2857 if (fnum
!= 0xffff) {
2858 cli_smb2_close_fnum(cli
, fnum
);
2861 cli
->raw_status
= status
;
2867 /***************************************************************
2868 Wrapper that allows SMB2 to query file system volume info.
2870 ***************************************************************/
2872 NTSTATUS
cli_smb2_get_fs_volume_info(struct cli_state
*cli
,
2873 TALLOC_CTX
*mem_ctx
,
2874 char **_volume_name
,
2875 uint32_t *pserial_number
,
2879 uint16_t fnum
= 0xffff;
2880 DATA_BLOB outbuf
= data_blob_null
;
2882 char *volume_name
= NULL
;
2883 TALLOC_CTX
*frame
= talloc_stackframe();
2885 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2887 * Can't use sync call while an async call is in flight
2889 status
= NT_STATUS_INVALID_PARAMETER
;
2893 /* First open the top level directory. */
2895 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2896 SMB2_IMPERSONATION_IMPERSONATION
,
2897 FILE_READ_ATTRIBUTES
, /* desired_access */
2898 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2899 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2900 FILE_SHARE_DELETE
, /* share_access */
2901 FILE_OPEN
, /* create_disposition */
2902 FILE_DIRECTORY_FILE
, /* create_options */
2909 if (!NT_STATUS_IS_OK(status
)) {
2913 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2914 level 1 (SMB_FS_VOLUME_INFORMATION). */
2916 status
= cli_smb2_query_info_fnum(
2919 SMB2_0_INFO_FILESYSTEM
, /* in_info_type */
2920 /* in_file_info_class */
2921 SMB_FS_VOLUME_INFORMATION
- 1000,
2922 0xFFFF, /* in_max_output_length */
2923 NULL
, /* in_input_buffer */
2924 0, /* in_additional_info */
2928 if (!NT_STATUS_IS_OK(status
)) {
2932 if (outbuf
.length
< 24) {
2933 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2939 ts
= interpret_long_date((char *)outbuf
.data
);
2942 if (pserial_number
) {
2943 *pserial_number
= IVAL(outbuf
.data
,8);
2945 nlen
= IVAL(outbuf
.data
,12);
2946 if (nlen
+ 18 < 18) {
2948 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2952 * The next check is safe as we know outbuf.length >= 24
2955 if (nlen
> (outbuf
.length
- 18)) {
2956 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2960 pull_string_talloc(mem_ctx
,
2961 (const char *)outbuf
.data
,
2967 if (volume_name
== NULL
) {
2968 status
= map_nt_error_from_unix(errno
);
2972 *_volume_name
= volume_name
;
2976 if (fnum
!= 0xffff) {
2977 cli_smb2_close_fnum(cli
, fnum
);
2980 cli
->raw_status
= status
;
2986 struct cli_smb2_mxac_state
{
2987 struct tevent_context
*ev
;
2988 struct cli_state
*cli
;
2990 struct smb2_create_blobs in_cblobs
;
2996 static void cli_smb2_mxac_opened(struct tevent_req
*subreq
);
2997 static void cli_smb2_mxac_closed(struct tevent_req
*subreq
);
2999 struct tevent_req
*cli_smb2_query_mxac_send(TALLOC_CTX
*mem_ctx
,
3000 struct tevent_context
*ev
,
3001 struct cli_state
*cli
,
3004 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
3005 struct cli_smb2_mxac_state
*state
= NULL
;
3008 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_mxac_state
);
3012 *state
= (struct cli_smb2_mxac_state
) {
3018 status
= smb2_create_blob_add(state
,
3020 SMB2_CREATE_TAG_MXAC
,
3021 data_blob(NULL
, 0));
3022 if (tevent_req_nterror(req
, status
)) {
3023 return tevent_req_post(req
, ev
);
3026 subreq
= cli_smb2_create_fnum_send(
3031 0, /* create_flags */
3032 SMB2_IMPERSONATION_IMPERSONATION
,
3033 FILE_READ_ATTRIBUTES
,
3034 0, /* file attributes */
3035 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
3037 0, /* create_options */
3039 if (tevent_req_nomem(subreq
, req
)) {
3040 return tevent_req_post(req
, ev
);
3042 tevent_req_set_callback(subreq
, cli_smb2_mxac_opened
, req
);
3046 static void cli_smb2_mxac_opened(struct tevent_req
*subreq
)
3048 struct tevent_req
*req
= tevent_req_callback_data(
3049 subreq
, struct tevent_req
);
3050 struct cli_smb2_mxac_state
*state
= tevent_req_data(
3051 req
, struct cli_smb2_mxac_state
);
3052 struct smb2_create_blobs out_cblobs
= {0};
3053 struct smb2_create_blob
*mxac_blob
= NULL
;
3056 status
= cli_smb2_create_fnum_recv(
3057 subreq
, &state
->fnum
, NULL
, state
, &out_cblobs
, NULL
);
3058 TALLOC_FREE(subreq
);
3060 if (tevent_req_nterror(req
, status
)) {
3064 mxac_blob
= smb2_create_blob_find(&out_cblobs
, SMB2_CREATE_TAG_MXAC
);
3065 if (mxac_blob
== NULL
) {
3066 state
->status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3069 if (mxac_blob
->data
.length
!= 8) {
3070 state
->status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3074 state
->status
= NT_STATUS(IVAL(mxac_blob
->data
.data
, 0));
3075 state
->mxac
= IVAL(mxac_blob
->data
.data
, 4);
3078 subreq
= cli_smb2_close_fnum_send(
3079 state
, state
->ev
, state
->cli
, state
->fnum
);
3080 if (tevent_req_nomem(subreq
, req
)) {
3083 tevent_req_set_callback(subreq
, cli_smb2_mxac_closed
, req
);
3088 static void cli_smb2_mxac_closed(struct tevent_req
*subreq
)
3090 struct tevent_req
*req
= tevent_req_callback_data(
3091 subreq
, struct tevent_req
);
3094 status
= cli_smb2_close_fnum_recv(subreq
);
3095 if (tevent_req_nterror(req
, status
)) {
3099 tevent_req_done(req
);
3102 NTSTATUS
cli_smb2_query_mxac_recv(struct tevent_req
*req
, uint32_t *mxac
)
3104 struct cli_smb2_mxac_state
*state
= tevent_req_data(
3105 req
, struct cli_smb2_mxac_state
);
3108 if (tevent_req_is_nterror(req
, &status
)) {
3112 if (!NT_STATUS_IS_OK(state
->status
)) {
3113 return state
->status
;
3116 *mxac
= state
->mxac
;
3117 return NT_STATUS_OK
;
3120 NTSTATUS
cli_smb2_query_mxac(struct cli_state
*cli
,
3124 TALLOC_CTX
*frame
= talloc_stackframe();
3125 struct tevent_context
*ev
= NULL
;
3126 struct tevent_req
*req
= NULL
;
3127 NTSTATUS status
= NT_STATUS_INTERNAL_ERROR
;
3130 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3132 * Can't use sync call while an async call is in flight
3134 status
= NT_STATUS_INVALID_PARAMETER
;
3138 ev
= samba_tevent_context_init(frame
);
3142 req
= cli_smb2_query_mxac_send(frame
, ev
, cli
, fname
);
3146 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
3150 status
= cli_smb2_query_mxac_recv(req
, _mxac
);
3153 cli
->raw_status
= status
;
3158 struct cli_smb2_rename_fnum_state
{
3162 static void cli_smb2_rename_fnum_done(struct tevent_req
*subreq
);
3164 static struct tevent_req
*cli_smb2_rename_fnum_send(
3165 TALLOC_CTX
*mem_ctx
,
3166 struct tevent_context
*ev
,
3167 struct cli_state
*cli
,
3169 const char *fname_dst
,
3172 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
3173 struct cli_smb2_rename_fnum_state
*state
= NULL
;
3174 size_t namelen
= strlen(fname_dst
);
3175 smb_ucs2_t
*converted_str
= NULL
;
3176 size_t converted_size_bytes
= 0;
3180 req
= tevent_req_create(
3181 mem_ctx
, &state
, struct cli_smb2_rename_fnum_state
);
3187 * SMB2 is pickier about pathnames. Ensure it doesn't start in
3190 if (*fname_dst
== '\\') {
3195 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
3198 if (namelen
> 0 && fname_dst
[namelen
-1] == '\\') {
3199 fname_dst
= talloc_strndup(state
, fname_dst
, namelen
-1);
3200 if (tevent_req_nomem(fname_dst
, req
)) {
3201 return tevent_req_post(req
, ev
);
3205 ok
= push_ucs2_talloc(
3206 state
, &converted_str
, fname_dst
, &converted_size_bytes
);
3208 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3209 return tevent_req_post(req
, ev
);
3213 * W2K8 insists the dest name is not null terminated. Remove
3214 * the last 2 zero bytes and reduce the name length.
3216 if (converted_size_bytes
< 2) {
3217 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3218 return tevent_req_post(req
, ev
);
3220 converted_size_bytes
-= 2;
3222 inbuf_size
= 20 + converted_size_bytes
;
3223 if (inbuf_size
< 20) {
3224 /* Integer wrap check. */
3225 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3226 return tevent_req_post(req
, ev
);
3230 * The Windows 10 SMB2 server has a minimum length
3231 * for a SMB2_FILE_RENAME_INFORMATION buffer of
3232 * 24 bytes. It returns NT_STATUS_INFO_LENGTH_MISMATCH
3233 * if the length is less. This isn't an alignment
3234 * issue as Windows client happily 2-byte align
3235 * for larget target name sizes. Also the Windows 10
3236 * SMB1 server doesn't have this restriction.
3238 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14403
3240 inbuf_size
= MAX(inbuf_size
, 24);
3242 state
->inbuf
= data_blob_talloc_zero(state
, inbuf_size
);
3243 if (tevent_req_nomem(state
->inbuf
.data
, req
)) {
3244 return tevent_req_post(req
, ev
);
3248 SCVAL(state
->inbuf
.data
, 0, 1);
3251 SIVAL(state
->inbuf
.data
, 16, converted_size_bytes
);
3252 memcpy(state
->inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
3254 TALLOC_FREE(converted_str
);
3256 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3257 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3259 subreq
= cli_smb2_set_info_fnum_send(
3260 state
, /* mem_ctx */
3264 1, /* in_info_type */
3265 SMB_FILE_RENAME_INFORMATION
- 1000, /* in_file_info_class */
3266 &state
->inbuf
, /* in_input_buffer */
3267 0); /* in_additional_info */
3268 if (tevent_req_nomem(subreq
, req
)) {
3269 return tevent_req_post(req
, ev
);
3271 tevent_req_set_callback(subreq
, cli_smb2_rename_fnum_done
, req
);
3275 static void cli_smb2_rename_fnum_done(struct tevent_req
*subreq
)
3277 NTSTATUS status
= cli_smb2_set_info_fnum_recv(subreq
);
3278 tevent_req_simple_finish_ntstatus(subreq
, status
);
3281 static NTSTATUS
cli_smb2_rename_fnum_recv(struct tevent_req
*req
)
3283 return tevent_req_simple_recv_ntstatus(req
);
3286 /***************************************************************
3287 Wrapper that allows SMB2 to rename a file.
3288 ***************************************************************/
3290 struct cli_smb2_rename_state
{
3291 struct tevent_context
*ev
;
3292 struct cli_state
*cli
;
3293 const char *fname_dst
;
3297 NTSTATUS rename_status
;
3300 static void cli_smb2_rename_opened(struct tevent_req
*subreq
);
3301 static void cli_smb2_rename_renamed(struct tevent_req
*subreq
);
3302 static void cli_smb2_rename_closed(struct tevent_req
*subreq
);
3304 struct tevent_req
*cli_smb2_rename_send(
3305 TALLOC_CTX
*mem_ctx
,
3306 struct tevent_context
*ev
,
3307 struct cli_state
*cli
,
3308 const char *fname_src
,
3309 const char *fname_dst
,
3312 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
3313 struct cli_smb2_rename_state
*state
= NULL
;
3316 req
= tevent_req_create(
3317 mem_ctx
, &state
, struct cli_smb2_rename_state
);
3323 * Strip a MSDFS path from fname_dst if we were given one.
3325 status
= cli_dfs_target_check(state
,
3329 if (tevent_req_nterror(req
, status
)) {
3330 return tevent_req_post(req
, ev
);
3335 state
->fname_dst
= fname_dst
;
3336 state
->replace
= replace
;
3338 subreq
= get_fnum_from_path_send(
3339 state
, ev
, cli
, fname_src
, DELETE_ACCESS
);
3340 if (tevent_req_nomem(subreq
, req
)) {
3341 return tevent_req_post(req
, ev
);
3343 tevent_req_set_callback(subreq
, cli_smb2_rename_opened
, req
);
3347 static void cli_smb2_rename_opened(struct tevent_req
*subreq
)
3349 struct tevent_req
*req
= tevent_req_callback_data(
3350 subreq
, struct tevent_req
);
3351 struct cli_smb2_rename_state
*state
= tevent_req_data(
3352 req
, struct cli_smb2_rename_state
);
3355 status
= get_fnum_from_path_recv(subreq
, &state
->fnum
);
3356 TALLOC_FREE(subreq
);
3357 if (tevent_req_nterror(req
, status
)) {
3361 subreq
= cli_smb2_rename_fnum_send(
3368 if (tevent_req_nomem(subreq
, req
)) {
3371 tevent_req_set_callback(subreq
, cli_smb2_rename_renamed
, req
);
3374 static void cli_smb2_rename_renamed(struct tevent_req
*subreq
)
3376 struct tevent_req
*req
= tevent_req_callback_data(
3377 subreq
, struct tevent_req
);
3378 struct cli_smb2_rename_state
*state
= tevent_req_data(
3379 req
, struct cli_smb2_rename_state
);
3381 state
->rename_status
= cli_smb2_rename_fnum_recv(subreq
);
3382 TALLOC_FREE(subreq
);
3384 subreq
= cli_smb2_close_fnum_send(
3385 state
, state
->ev
, state
->cli
, state
->fnum
);
3386 if (tevent_req_nomem(subreq
, req
)) {
3389 tevent_req_set_callback(subreq
, cli_smb2_rename_closed
, req
);
3392 static void cli_smb2_rename_closed(struct tevent_req
*subreq
)
3394 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
3395 tevent_req_simple_finish_ntstatus(subreq
, status
);
3398 NTSTATUS
cli_smb2_rename_recv(struct tevent_req
*req
)
3400 struct cli_smb2_rename_state
*state
= tevent_req_data(
3401 req
, struct cli_smb2_rename_state
);
3402 NTSTATUS status
= NT_STATUS_OK
;
3404 if (!tevent_req_is_nterror(req
, &status
)) {
3405 status
= state
->rename_status
;
3407 tevent_req_received(req
);
3411 /***************************************************************
3412 Wrapper that allows SMB2 to set an EA on a fnum.
3414 ***************************************************************/
3416 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
3418 const char *ea_name
,
3423 DATA_BLOB inbuf
= data_blob_null
;
3425 char *ea_name_ascii
= NULL
;
3427 TALLOC_CTX
*frame
= talloc_stackframe();
3429 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3431 * Can't use sync call while an async call is in flight
3433 status
= NT_STATUS_INVALID_PARAMETER
;
3437 /* Marshall the SMB2 EA data. */
3438 if (ea_len
> 0xFFFF) {
3439 status
= NT_STATUS_INVALID_PARAMETER
;
3443 if (!push_ascii_talloc(frame
,
3447 status
= NT_STATUS_INVALID_PARAMETER
;
3451 if (namelen
< 2 || namelen
> 0xFF) {
3452 status
= NT_STATUS_INVALID_PARAMETER
;
3456 bloblen
= 8 + ea_len
+ namelen
;
3457 /* Round up to a 4 byte boundary. */
3458 bloblen
= ((bloblen
+ 3)&~3);
3460 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
3461 if (inbuf
.data
== NULL
) {
3462 status
= NT_STATUS_NO_MEMORY
;
3465 /* namelen doesn't include the NULL byte. */
3466 SCVAL(inbuf
.data
, 5, namelen
- 1);
3467 SSVAL(inbuf
.data
, 6, ea_len
);
3468 memcpy(inbuf
.data
+ 8, ea_name_ascii
, namelen
);
3469 memcpy(inbuf
.data
+ 8 + namelen
, ea_val
, ea_len
);
3471 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3472 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3474 status
= cli_smb2_set_info_fnum(
3477 1, /* in_info_type */
3478 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
3479 &inbuf
, /* in_input_buffer */
3480 0); /* in_additional_info */
3484 cli
->raw_status
= status
;
3490 /***************************************************************
3491 Wrapper that allows SMB2 to set an EA on a pathname.
3493 ***************************************************************/
3495 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
3497 const char *ea_name
,
3502 uint16_t fnum
= 0xffff;
3504 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3506 * Can't use sync call while an async call is in flight
3508 status
= NT_STATUS_INVALID_PARAMETER
;
3512 status
= get_fnum_from_path(cli
,
3517 if (!NT_STATUS_IS_OK(status
)) {
3521 status
= cli_set_ea_fnum(cli
,
3526 if (!NT_STATUS_IS_OK(status
)) {
3532 if (fnum
!= 0xffff) {
3533 cli_smb2_close_fnum(cli
, fnum
);
3536 cli
->raw_status
= status
;
3541 /***************************************************************
3542 Wrapper that allows SMB2 to get an EA list on a pathname.
3544 ***************************************************************/
3546 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
3550 struct ea_struct
**pea_array
)
3553 uint16_t fnum
= 0xffff;
3554 DATA_BLOB outbuf
= data_blob_null
;
3555 struct ea_list
*ea_list
= NULL
;
3556 struct ea_list
*eal
= NULL
;
3557 size_t ea_count
= 0;
3558 TALLOC_CTX
*frame
= talloc_stackframe();
3563 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3565 * Can't use sync call while an async call is in flight
3567 status
= NT_STATUS_INVALID_PARAMETER
;
3571 status
= get_fnum_from_path(cli
,
3576 if (!NT_STATUS_IS_OK(status
)) {
3580 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3581 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3583 status
= cli_smb2_query_info_fnum(
3586 1, /* in_info_type */
3587 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
3588 0xFFFF, /* in_max_output_length */
3589 NULL
, /* in_input_buffer */
3590 0, /* in_additional_info */
3595 if (!NT_STATUS_IS_OK(status
)) {
3599 /* Parse the reply. */
3600 ea_list
= read_nttrans_ea_list(ctx
,
3601 (const char *)outbuf
.data
,
3603 if (ea_list
== NULL
) {
3604 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3608 /* Convert to an array. */
3609 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
3614 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
3615 if (*pea_array
== NULL
) {
3616 status
= NT_STATUS_NO_MEMORY
;
3620 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
3621 (*pea_array
)[ea_count
++] = eal
->ea
;
3623 *pnum_eas
= ea_count
;
3628 if (fnum
!= 0xffff) {
3629 cli_smb2_close_fnum(cli
, fnum
);
3632 cli
->raw_status
= status
;
3638 /***************************************************************
3639 Wrapper that allows SMB2 to get user quota.
3641 ***************************************************************/
3643 NTSTATUS
cli_smb2_get_user_quota(struct cli_state
*cli
,
3645 SMB_NTQUOTA_STRUCT
*pqt
)
3648 DATA_BLOB inbuf
= data_blob_null
;
3649 DATA_BLOB info_blob
= data_blob_null
;
3650 DATA_BLOB outbuf
= data_blob_null
;
3651 TALLOC_CTX
*frame
= talloc_stackframe();
3653 unsigned int offset
;
3654 struct smb2_query_quota_info query
= {0};
3655 struct file_get_quota_info info
= {0};
3656 enum ndr_err_code err
;
3657 struct ndr_push
*ndr_push
= NULL
;
3659 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3661 * Can't use sync call while an async call is in flight
3663 status
= NT_STATUS_INVALID_PARAMETER
;
3667 sid_len
= ndr_size_dom_sid(&pqt
->sid
, 0);
3669 query
.return_single
= 1;
3671 info
.next_entry_offset
= 0;
3672 info
.sid_length
= sid_len
;
3673 info
.sid
= pqt
->sid
;
3675 err
= ndr_push_struct_blob(
3679 (ndr_push_flags_fn_t
)ndr_push_file_get_quota_info
);
3681 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3682 status
= NT_STATUS_INTERNAL_ERROR
;
3686 query
.sid_list_length
= info_blob
.length
;
3687 ndr_push
= ndr_push_init_ctx(frame
);
3689 status
= NT_STATUS_NO_MEMORY
;
3693 err
= ndr_push_smb2_query_quota_info(ndr_push
,
3694 NDR_SCALARS
| NDR_BUFFERS
,
3697 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3698 status
= NT_STATUS_INTERNAL_ERROR
;
3702 err
= ndr_push_array_uint8(ndr_push
, NDR_SCALARS
, info_blob
.data
,
3705 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3706 status
= NT_STATUS_INTERNAL_ERROR
;
3709 inbuf
.data
= ndr_push
->data
;
3710 inbuf
.length
= ndr_push
->offset
;
3712 status
= cli_smb2_query_info_fnum(
3715 4, /* in_info_type */
3716 0, /* in_file_info_class */
3717 0xFFFF, /* in_max_output_length */
3718 &inbuf
, /* in_input_buffer */
3719 0, /* in_additional_info */
3724 if (!NT_STATUS_IS_OK(status
)) {
3728 if (!parse_user_quota_record(outbuf
.data
, outbuf
.length
, &offset
,
3730 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3731 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3735 cli
->raw_status
= status
;
3741 /***************************************************************
3742 Wrapper that allows SMB2 to list user quota.
3744 ***************************************************************/
3746 NTSTATUS
cli_smb2_list_user_quota_step(struct cli_state
*cli
,
3747 TALLOC_CTX
*mem_ctx
,
3749 SMB_NTQUOTA_LIST
**pqt_list
,
3753 DATA_BLOB inbuf
= data_blob_null
;
3754 DATA_BLOB outbuf
= data_blob_null
;
3755 TALLOC_CTX
*frame
= talloc_stackframe();
3756 struct smb2_query_quota_info info
= {0};
3757 enum ndr_err_code err
;
3759 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3761 * Can't use sync call while an async call is in flight
3763 status
= NT_STATUS_INVALID_PARAMETER
;
3767 info
.restart_scan
= first
? 1 : 0;
3769 err
= ndr_push_struct_blob(
3773 (ndr_push_flags_fn_t
)ndr_push_smb2_query_quota_info
);
3775 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3776 status
= NT_STATUS_INTERNAL_ERROR
;
3780 status
= cli_smb2_query_info_fnum(
3783 4, /* in_info_type */
3784 0, /* in_file_info_class */
3785 0xFFFF, /* in_max_output_length */
3786 &inbuf
, /* in_input_buffer */
3787 0, /* in_additional_info */
3793 * safeguard against panic from calling parse_user_quota_list with
3796 if (NT_STATUS_IS_OK(status
) && outbuf
.length
== 0) {
3797 status
= NT_STATUS_NO_MORE_ENTRIES
;
3800 if (!NT_STATUS_IS_OK(status
)) {
3804 status
= parse_user_quota_list(outbuf
.data
, outbuf
.length
, mem_ctx
,
3808 cli
->raw_status
= status
;
3814 /***************************************************************
3815 Wrapper that allows SMB2 to get file system quota.
3817 ***************************************************************/
3819 NTSTATUS
cli_smb2_get_fs_quota_info(struct cli_state
*cli
,
3821 SMB_NTQUOTA_STRUCT
*pqt
)
3824 DATA_BLOB outbuf
= data_blob_null
;
3825 TALLOC_CTX
*frame
= talloc_stackframe();
3827 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3829 * Can't use sync call while an async call is in flight
3831 status
= NT_STATUS_INVALID_PARAMETER
;
3835 status
= cli_smb2_query_info_fnum(
3838 2, /* in_info_type */
3839 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
3840 0xFFFF, /* in_max_output_length */
3841 NULL
, /* in_input_buffer */
3842 0, /* in_additional_info */
3847 if (!NT_STATUS_IS_OK(status
)) {
3851 status
= parse_fs_quota_buffer(outbuf
.data
, outbuf
.length
, pqt
);
3854 cli
->raw_status
= status
;
3860 /***************************************************************
3861 Wrapper that allows SMB2 to set user quota.
3863 ***************************************************************/
3865 NTSTATUS
cli_smb2_set_user_quota(struct cli_state
*cli
,
3867 SMB_NTQUOTA_LIST
*qtl
)
3870 DATA_BLOB inbuf
= data_blob_null
;
3871 TALLOC_CTX
*frame
= talloc_stackframe();
3873 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3875 * Can't use sync call while an async call is in flight
3877 status
= NT_STATUS_INVALID_PARAMETER
;
3881 status
= build_user_quota_buffer(qtl
, 0, talloc_tos(), &inbuf
, NULL
);
3882 if (!NT_STATUS_IS_OK(status
)) {
3886 status
= cli_smb2_set_info_fnum(
3889 4, /* in_info_type */
3890 0, /* in_file_info_class */
3891 &inbuf
, /* in_input_buffer */
3892 0); /* in_additional_info */
3895 cli
->raw_status
= status
;
3902 NTSTATUS
cli_smb2_set_fs_quota_info(struct cli_state
*cli
,
3904 SMB_NTQUOTA_STRUCT
*pqt
)
3907 DATA_BLOB inbuf
= data_blob_null
;
3908 TALLOC_CTX
*frame
= talloc_stackframe();
3910 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3912 * Can't use sync call while an async call is in flight
3914 status
= NT_STATUS_INVALID_PARAMETER
;
3918 status
= build_fs_quota_buffer(talloc_tos(), pqt
, &inbuf
, 0);
3919 if (!NT_STATUS_IS_OK(status
)) {
3923 status
= cli_smb2_set_info_fnum(
3926 2, /* in_info_type */
3927 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
3928 &inbuf
, /* in_input_buffer */
3929 0); /* in_additional_info */
3931 cli
->raw_status
= status
;
3937 struct cli_smb2_read_state
{
3938 struct tevent_context
*ev
;
3939 struct cli_state
*cli
;
3940 struct smb2_hnd
*ph
;
3941 uint64_t start_offset
;
3947 static void cli_smb2_read_done(struct tevent_req
*subreq
);
3949 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
3950 struct tevent_context
*ev
,
3951 struct cli_state
*cli
,
3957 struct tevent_req
*req
, *subreq
;
3958 struct cli_smb2_read_state
*state
;
3960 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
3966 state
->start_offset
= (uint64_t)offset
;
3967 state
->size
= (uint32_t)size
;
3968 state
->received
= 0;
3971 status
= map_fnum_to_smb2_handle(cli
,
3974 if (tevent_req_nterror(req
, status
)) {
3975 return tevent_req_post(req
, ev
);
3978 subreq
= smb2cli_read_send(state
,
3981 state
->cli
->timeout
,
3982 state
->cli
->smb2
.session
,
3983 state
->cli
->smb2
.tcon
,
3985 state
->start_offset
,
3986 state
->ph
->fid_persistent
,
3987 state
->ph
->fid_volatile
,
3988 0, /* minimum_count */
3989 0); /* remaining_bytes */
3991 if (tevent_req_nomem(subreq
, req
)) {
3992 return tevent_req_post(req
, ev
);
3994 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
3998 static void cli_smb2_read_done(struct tevent_req
*subreq
)
4000 struct tevent_req
*req
= tevent_req_callback_data(
4001 subreq
, struct tevent_req
);
4002 struct cli_smb2_read_state
*state
= tevent_req_data(
4003 req
, struct cli_smb2_read_state
);
4006 status
= smb2cli_read_recv(subreq
, state
,
4007 &state
->buf
, &state
->received
);
4008 if (tevent_req_nterror(req
, status
)) {
4012 if (state
->received
> state
->size
) {
4013 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4017 tevent_req_done(req
);
4020 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
4025 struct cli_smb2_read_state
*state
= tevent_req_data(
4026 req
, struct cli_smb2_read_state
);
4028 if (tevent_req_is_nterror(req
, &status
)) {
4029 state
->cli
->raw_status
= status
;
4033 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
4034 * better make sure that you copy it away before you talloc_free(req).
4035 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
4037 *received
= (ssize_t
)state
->received
;
4038 *rcvbuf
= state
->buf
;
4039 state
->cli
->raw_status
= NT_STATUS_OK
;
4040 return NT_STATUS_OK
;
4043 struct cli_smb2_write_state
{
4044 struct tevent_context
*ev
;
4045 struct cli_state
*cli
;
4046 struct smb2_hnd
*ph
;
4054 static void cli_smb2_write_written(struct tevent_req
*req
);
4056 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
4057 struct tevent_context
*ev
,
4058 struct cli_state
*cli
,
4066 struct tevent_req
*req
, *subreq
= NULL
;
4067 struct cli_smb2_write_state
*state
= NULL
;
4069 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
4075 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4076 state
->flags
= (uint32_t)mode
;
4078 state
->offset
= (uint64_t)offset
;
4079 state
->size
= (uint32_t)size
;
4082 status
= map_fnum_to_smb2_handle(cli
,
4085 if (tevent_req_nterror(req
, status
)) {
4086 return tevent_req_post(req
, ev
);
4089 subreq
= smb2cli_write_send(state
,
4092 state
->cli
->timeout
,
4093 state
->cli
->smb2
.session
,
4094 state
->cli
->smb2
.tcon
,
4097 state
->ph
->fid_persistent
,
4098 state
->ph
->fid_volatile
,
4099 0, /* remaining_bytes */
4100 state
->flags
, /* flags */
4103 if (tevent_req_nomem(subreq
, req
)) {
4104 return tevent_req_post(req
, ev
);
4106 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
4110 static void cli_smb2_write_written(struct tevent_req
*subreq
)
4112 struct tevent_req
*req
= tevent_req_callback_data(
4113 subreq
, struct tevent_req
);
4114 struct cli_smb2_write_state
*state
= tevent_req_data(
4115 req
, struct cli_smb2_write_state
);
4119 status
= smb2cli_write_recv(subreq
, &written
);
4120 TALLOC_FREE(subreq
);
4121 if (tevent_req_nterror(req
, status
)) {
4125 state
->written
= written
;
4127 tevent_req_done(req
);
4130 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
4133 struct cli_smb2_write_state
*state
= tevent_req_data(
4134 req
, struct cli_smb2_write_state
);
4137 if (tevent_req_is_nterror(req
, &status
)) {
4138 state
->cli
->raw_status
= status
;
4139 tevent_req_received(req
);
4143 if (pwritten
!= NULL
) {
4144 *pwritten
= (size_t)state
->written
;
4146 state
->cli
->raw_status
= NT_STATUS_OK
;
4147 tevent_req_received(req
);
4148 return NT_STATUS_OK
;
4151 /***************************************************************
4152 Wrapper that allows SMB2 async write using an fnum.
4153 This is mostly cut-and-paste from Volker's code inside
4154 source3/libsmb/clireadwrite.c, adapted for SMB2.
4156 Done this way so I can reuse all the logic inside cli_push()
4158 ***************************************************************/
4160 struct cli_smb2_writeall_state
{
4161 struct tevent_context
*ev
;
4162 struct cli_state
*cli
;
4163 struct smb2_hnd
*ph
;
4171 static void cli_smb2_writeall_written(struct tevent_req
*req
);
4173 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
4174 struct tevent_context
*ev
,
4175 struct cli_state
*cli
,
4183 struct tevent_req
*req
, *subreq
= NULL
;
4184 struct cli_smb2_writeall_state
*state
= NULL
;
4189 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
4195 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4196 state
->flags
= (uint32_t)mode
;
4198 state
->offset
= (uint64_t)offset
;
4199 state
->size
= (uint32_t)size
;
4202 status
= map_fnum_to_smb2_handle(cli
,
4205 if (tevent_req_nterror(req
, status
)) {
4206 return tevent_req_post(req
, ev
);
4209 to_write
= state
->size
;
4210 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
4211 to_write
= MIN(max_size
, to_write
);
4212 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
4214 to_write
= MIN(max_size
, to_write
);
4217 subreq
= smb2cli_write_send(state
,
4220 state
->cli
->timeout
,
4221 state
->cli
->smb2
.session
,
4222 state
->cli
->smb2
.tcon
,
4225 state
->ph
->fid_persistent
,
4226 state
->ph
->fid_volatile
,
4227 0, /* remaining_bytes */
4228 state
->flags
, /* flags */
4229 state
->buf
+ state
->written
);
4231 if (tevent_req_nomem(subreq
, req
)) {
4232 return tevent_req_post(req
, ev
);
4234 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
4238 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
4240 struct tevent_req
*req
= tevent_req_callback_data(
4241 subreq
, struct tevent_req
);
4242 struct cli_smb2_writeall_state
*state
= tevent_req_data(
4243 req
, struct cli_smb2_writeall_state
);
4245 uint32_t written
, to_write
;
4249 status
= smb2cli_write_recv(subreq
, &written
);
4250 TALLOC_FREE(subreq
);
4251 if (tevent_req_nterror(req
, status
)) {
4255 state
->written
+= written
;
4257 if (state
->written
> state
->size
) {
4258 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4262 to_write
= state
->size
- state
->written
;
4264 if (to_write
== 0) {
4265 tevent_req_done(req
);
4269 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
4270 to_write
= MIN(max_size
, to_write
);
4271 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
4273 to_write
= MIN(max_size
, to_write
);
4276 subreq
= smb2cli_write_send(state
,
4279 state
->cli
->timeout
,
4280 state
->cli
->smb2
.session
,
4281 state
->cli
->smb2
.tcon
,
4283 state
->offset
+ state
->written
,
4284 state
->ph
->fid_persistent
,
4285 state
->ph
->fid_volatile
,
4286 0, /* remaining_bytes */
4287 state
->flags
, /* flags */
4288 state
->buf
+ state
->written
);
4290 if (tevent_req_nomem(subreq
, req
)) {
4293 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
4296 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
4299 struct cli_smb2_writeall_state
*state
= tevent_req_data(
4300 req
, struct cli_smb2_writeall_state
);
4303 if (tevent_req_is_nterror(req
, &status
)) {
4304 state
->cli
->raw_status
= status
;
4307 if (pwritten
!= NULL
) {
4308 *pwritten
= (size_t)state
->written
;
4310 state
->cli
->raw_status
= NT_STATUS_OK
;
4311 return NT_STATUS_OK
;
4314 struct cli_smb2_splice_state
{
4315 struct tevent_context
*ev
;
4316 struct cli_state
*cli
;
4317 struct smb2_hnd
*src_ph
;
4318 struct smb2_hnd
*dst_ph
;
4319 int (*splice_cb
)(off_t n
, void *priv
);
4326 struct req_resume_key_rsp resume_rsp
;
4327 struct srv_copychunk_copy cc_copy
;
4330 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
4331 struct tevent_req
*req
);
4333 static void cli_splice_copychunk_done(struct tevent_req
*subreq
)
4335 struct tevent_req
*req
= tevent_req_callback_data(
4336 subreq
, struct tevent_req
);
4337 struct cli_smb2_splice_state
*state
=
4338 tevent_req_data(req
,
4339 struct cli_smb2_splice_state
);
4340 struct smbXcli_conn
*conn
= state
->cli
->conn
;
4341 DATA_BLOB out_input_buffer
= data_blob_null
;
4342 DATA_BLOB out_output_buffer
= data_blob_null
;
4343 struct srv_copychunk_rsp cc_copy_rsp
;
4344 enum ndr_err_code ndr_ret
;
4347 status
= smb2cli_ioctl_recv(subreq
, state
,
4349 &out_output_buffer
);
4350 TALLOC_FREE(subreq
);
4351 if ((!NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
) ||
4352 state
->resized
) && tevent_req_nterror(req
, status
)) {
4356 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
, state
, &cc_copy_rsp
,
4357 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
4358 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4359 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4360 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4364 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
4365 uint32_t max_chunks
= MIN(cc_copy_rsp
.chunks_written
,
4366 cc_copy_rsp
.total_bytes_written
/ cc_copy_rsp
.chunk_bytes_written
);
4367 if ((cc_copy_rsp
.chunk_bytes_written
> smb2cli_conn_cc_chunk_len(conn
) ||
4368 max_chunks
> smb2cli_conn_cc_max_chunks(conn
)) &&
4369 tevent_req_nterror(req
, status
)) {
4373 state
->resized
= true;
4374 smb2cli_conn_set_cc_chunk_len(conn
, cc_copy_rsp
.chunk_bytes_written
);
4375 smb2cli_conn_set_cc_max_chunks(conn
, max_chunks
);
4377 if ((state
->src_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
4378 (state
->dst_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
4379 (state
->written
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
)) {
4380 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
4383 state
->src_offset
+= cc_copy_rsp
.total_bytes_written
;
4384 state
->dst_offset
+= cc_copy_rsp
.total_bytes_written
;
4385 state
->written
+= cc_copy_rsp
.total_bytes_written
;
4386 if (!state
->splice_cb(state
->written
, state
->priv
)) {
4387 tevent_req_nterror(req
, NT_STATUS_CANCELLED
);
4392 cli_splice_copychunk_send(state
, req
);
4395 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
4396 struct tevent_req
*req
)
4398 struct tevent_req
*subreq
;
4399 enum ndr_err_code ndr_ret
;
4400 struct smbXcli_conn
*conn
= state
->cli
->conn
;
4401 struct srv_copychunk_copy
*cc_copy
= &state
->cc_copy
;
4402 off_t src_offset
= state
->src_offset
;
4403 off_t dst_offset
= state
->dst_offset
;
4404 uint32_t req_len
= MIN(smb2cli_conn_cc_chunk_len(conn
) * smb2cli_conn_cc_max_chunks(conn
),
4405 state
->size
- state
->written
);
4406 DATA_BLOB in_input_buffer
= data_blob_null
;
4407 DATA_BLOB in_output_buffer
= data_blob_null
;
4409 if (state
->size
- state
->written
== 0) {
4410 tevent_req_done(req
);
4414 cc_copy
->chunk_count
= 0;
4416 cc_copy
->chunks
[cc_copy
->chunk_count
].source_off
= src_offset
;
4417 cc_copy
->chunks
[cc_copy
->chunk_count
].target_off
= dst_offset
;
4418 cc_copy
->chunks
[cc_copy
->chunk_count
].length
= MIN(req_len
,
4419 smb2cli_conn_cc_chunk_len(conn
));
4420 if (req_len
< cc_copy
->chunks
[cc_copy
->chunk_count
].length
) {
4421 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
4424 req_len
-= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4425 if ((src_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
) ||
4426 (dst_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
)) {
4427 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
4430 src_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4431 dst_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4432 cc_copy
->chunk_count
++;
4435 ndr_ret
= ndr_push_struct_blob(&in_input_buffer
, state
, cc_copy
,
4436 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
4437 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4438 DEBUG(0, ("failed to marshall copy chunk req\n"));
4439 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
4443 subreq
= smb2cli_ioctl_send(state
, state
->ev
, state
->cli
->conn
,
4444 state
->cli
->timeout
,
4445 state
->cli
->smb2
.session
,
4446 state
->cli
->smb2
.tcon
,
4447 state
->dst_ph
->fid_persistent
, /* in_fid_persistent */
4448 state
->dst_ph
->fid_volatile
, /* in_fid_volatile */
4449 FSCTL_SRV_COPYCHUNK_WRITE
,
4450 0, /* in_max_input_length */
4452 12, /* in_max_output_length */
4454 SMB2_IOCTL_FLAG_IS_FSCTL
);
4455 if (tevent_req_nomem(subreq
, req
)) {
4458 tevent_req_set_callback(subreq
,
4459 cli_splice_copychunk_done
,
4463 static void cli_splice_key_done(struct tevent_req
*subreq
)
4465 struct tevent_req
*req
= tevent_req_callback_data(
4466 subreq
, struct tevent_req
);
4467 struct cli_smb2_splice_state
*state
=
4468 tevent_req_data(req
,
4469 struct cli_smb2_splice_state
);
4470 enum ndr_err_code ndr_ret
;
4473 DATA_BLOB out_input_buffer
= data_blob_null
;
4474 DATA_BLOB out_output_buffer
= data_blob_null
;
4476 status
= smb2cli_ioctl_recv(subreq
, state
,
4478 &out_output_buffer
);
4479 TALLOC_FREE(subreq
);
4480 if (tevent_req_nterror(req
, status
)) {
4484 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
,
4485 state
, &state
->resume_rsp
,
4486 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
4487 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4488 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4489 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4493 memcpy(&state
->cc_copy
.source_key
,
4494 &state
->resume_rsp
.resume_key
,
4495 sizeof state
->resume_rsp
.resume_key
);
4497 cli_splice_copychunk_send(state
, req
);
4500 struct tevent_req
*cli_smb2_splice_send(TALLOC_CTX
*mem_ctx
,
4501 struct tevent_context
*ev
,
4502 struct cli_state
*cli
,
4503 uint16_t src_fnum
, uint16_t dst_fnum
,
4504 off_t size
, off_t src_offset
, off_t dst_offset
,
4505 int (*splice_cb
)(off_t n
, void *priv
),
4508 struct tevent_req
*req
;
4509 struct tevent_req
*subreq
;
4510 struct cli_smb2_splice_state
*state
;
4512 DATA_BLOB in_input_buffer
= data_blob_null
;
4513 DATA_BLOB in_output_buffer
= data_blob_null
;
4515 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_splice_state
);
4521 state
->splice_cb
= splice_cb
;
4525 state
->src_offset
= src_offset
;
4526 state
->dst_offset
= dst_offset
;
4527 state
->cc_copy
.chunks
= talloc_array(state
,
4528 struct srv_copychunk
,
4529 smb2cli_conn_cc_max_chunks(cli
->conn
));
4530 if (state
->cc_copy
.chunks
== NULL
) {
4534 status
= map_fnum_to_smb2_handle(cli
, src_fnum
, &state
->src_ph
);
4535 if (tevent_req_nterror(req
, status
))
4536 return tevent_req_post(req
, ev
);
4538 status
= map_fnum_to_smb2_handle(cli
, dst_fnum
, &state
->dst_ph
);
4539 if (tevent_req_nterror(req
, status
))
4540 return tevent_req_post(req
, ev
);
4542 subreq
= smb2cli_ioctl_send(state
, ev
, cli
->conn
,
4546 state
->src_ph
->fid_persistent
, /* in_fid_persistent */
4547 state
->src_ph
->fid_volatile
, /* in_fid_volatile */
4548 FSCTL_SRV_REQUEST_RESUME_KEY
,
4549 0, /* in_max_input_length */
4551 32, /* in_max_output_length */
4553 SMB2_IOCTL_FLAG_IS_FSCTL
);
4554 if (tevent_req_nomem(subreq
, req
)) {
4557 tevent_req_set_callback(subreq
,
4558 cli_splice_key_done
,
4564 NTSTATUS
cli_smb2_splice_recv(struct tevent_req
*req
, off_t
*written
)
4566 struct cli_smb2_splice_state
*state
= tevent_req_data(
4567 req
, struct cli_smb2_splice_state
);
4570 if (tevent_req_is_nterror(req
, &status
)) {
4571 state
->cli
->raw_status
= status
;
4572 tevent_req_received(req
);
4575 if (written
!= NULL
) {
4576 *written
= state
->written
;
4578 state
->cli
->raw_status
= NT_STATUS_OK
;
4579 tevent_req_received(req
);
4580 return NT_STATUS_OK
;
4583 /***************************************************************
4584 SMB2 enum shadow copy data.
4585 ***************************************************************/
4587 struct cli_smb2_shadow_copy_data_fnum_state
{
4588 struct cli_state
*cli
;
4590 struct smb2_hnd
*ph
;
4591 DATA_BLOB out_input_buffer
;
4592 DATA_BLOB out_output_buffer
;
4595 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
);
4597 static struct tevent_req
*cli_smb2_shadow_copy_data_fnum_send(
4598 TALLOC_CTX
*mem_ctx
,
4599 struct tevent_context
*ev
,
4600 struct cli_state
*cli
,
4604 struct tevent_req
*req
, *subreq
;
4605 struct cli_smb2_shadow_copy_data_fnum_state
*state
;
4608 req
= tevent_req_create(mem_ctx
, &state
,
4609 struct cli_smb2_shadow_copy_data_fnum_state
);
4617 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
4618 if (tevent_req_nterror(req
, status
)) {
4619 return tevent_req_post(req
, ev
);
4623 * TODO. Under SMB2 we should send a zero max_output_length
4624 * ioctl to get the required size, then send another ioctl
4625 * to get the data, but the current SMB1 implementation just
4626 * does one roundtrip with a 64K buffer size. Do the same
4630 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
4631 state
->cli
->timeout
,
4632 state
->cli
->smb2
.session
,
4633 state
->cli
->smb2
.tcon
,
4634 state
->ph
->fid_persistent
, /* in_fid_persistent */
4635 state
->ph
->fid_volatile
, /* in_fid_volatile */
4636 FSCTL_GET_SHADOW_COPY_DATA
,
4637 0, /* in_max_input_length */
4638 NULL
, /* in_input_buffer */
4640 CLI_BUFFER_SIZE
: 16, /* in_max_output_length */
4641 NULL
, /* in_output_buffer */
4642 SMB2_IOCTL_FLAG_IS_FSCTL
);
4644 if (tevent_req_nomem(subreq
, req
)) {
4645 return tevent_req_post(req
, ev
);
4647 tevent_req_set_callback(subreq
,
4648 cli_smb2_shadow_copy_data_fnum_done
,
4654 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
)
4656 struct tevent_req
*req
= tevent_req_callback_data(
4657 subreq
, struct tevent_req
);
4658 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
4659 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
4662 status
= smb2cli_ioctl_recv(subreq
, state
,
4663 &state
->out_input_buffer
,
4664 &state
->out_output_buffer
);
4665 tevent_req_simple_finish_ntstatus(subreq
, status
);
4668 static NTSTATUS
cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req
*req
,
4669 TALLOC_CTX
*mem_ctx
,
4674 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
4675 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
4676 char **names
= NULL
;
4677 uint32_t num_names
= 0;
4678 uint32_t num_names_returned
= 0;
4679 uint32_t dlength
= 0;
4681 uint8_t *endp
= NULL
;
4684 if (tevent_req_is_nterror(req
, &status
)) {
4688 if (state
->out_output_buffer
.length
< 16) {
4689 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4692 num_names
= IVAL(state
->out_output_buffer
.data
, 0);
4693 num_names_returned
= IVAL(state
->out_output_buffer
.data
, 4);
4694 dlength
= IVAL(state
->out_output_buffer
.data
, 8);
4696 if (num_names
> 0x7FFFFFFF) {
4697 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4700 if (get_names
== false) {
4701 *pnum_names
= (int)num_names
;
4702 return NT_STATUS_OK
;
4704 if (num_names
!= num_names_returned
) {
4705 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4707 if (dlength
+ 12 < 12) {
4708 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4711 * NB. The below is an allowable return if there are
4712 * more snapshots than the buffer size we told the
4713 * server we can receive. We currently don't support
4716 if (dlength
+ 12 > state
->out_output_buffer
.length
) {
4717 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4719 if (state
->out_output_buffer
.length
+
4720 (2 * sizeof(SHADOW_COPY_LABEL
)) <
4721 state
->out_output_buffer
.length
) {
4722 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4725 names
= talloc_array(mem_ctx
, char *, num_names_returned
);
4726 if (names
== NULL
) {
4727 return NT_STATUS_NO_MEMORY
;
4730 endp
= state
->out_output_buffer
.data
+
4731 state
->out_output_buffer
.length
;
4733 for (i
=0; i
<num_names_returned
; i
++) {
4736 size_t converted_size
;
4738 src
= state
->out_output_buffer
.data
+ 12 +
4739 (i
* 2 * sizeof(SHADOW_COPY_LABEL
));
4741 if (src
+ (2 * sizeof(SHADOW_COPY_LABEL
)) > endp
) {
4742 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4744 ret
= convert_string_talloc(
4745 names
, CH_UTF16LE
, CH_UNIX
,
4746 src
, 2 * sizeof(SHADOW_COPY_LABEL
),
4747 &names
[i
], &converted_size
);
4750 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4753 *pnum_names
= num_names
;
4755 return NT_STATUS_OK
;
4758 NTSTATUS
cli_smb2_shadow_copy_data(TALLOC_CTX
*mem_ctx
,
4759 struct cli_state
*cli
,
4765 TALLOC_CTX
*frame
= talloc_stackframe();
4766 struct tevent_context
*ev
;
4767 struct tevent_req
*req
;
4768 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
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
;
4777 ev
= samba_tevent_context_init(frame
);
4781 req
= cli_smb2_shadow_copy_data_fnum_send(frame
,
4789 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4792 status
= cli_smb2_shadow_copy_data_fnum_recv(req
,
4798 cli
->raw_status
= status
;
4804 /***************************************************************
4805 Wrapper that allows SMB2 to truncate a file.
4807 ***************************************************************/
4809 NTSTATUS
cli_smb2_ftruncate(struct cli_state
*cli
,
4814 uint8_t buf
[8] = {0};
4815 DATA_BLOB inbuf
= { .data
= buf
, .length
= sizeof(buf
) };
4816 TALLOC_CTX
*frame
= talloc_stackframe();
4818 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4820 * Can't use sync call while an async call is in flight
4822 status
= NT_STATUS_INVALID_PARAMETER
;
4826 SBVAL(buf
, 0, newsize
);
4828 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4829 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4831 status
= cli_smb2_set_info_fnum(
4834 1, /* in_info_type */
4835 SMB_FILE_END_OF_FILE_INFORMATION
-1000, /* in_file_info_class */
4836 &inbuf
, /* in_input_buffer */
4841 cli
->raw_status
= status
;
4847 struct cli_smb2_notify_state
{
4848 struct tevent_req
*subreq
;
4849 struct notify_change
*changes
;
4853 static void cli_smb2_notify_done(struct tevent_req
*subreq
);
4854 static bool cli_smb2_notify_cancel(struct tevent_req
*req
);
4856 struct tevent_req
*cli_smb2_notify_send(
4857 TALLOC_CTX
*mem_ctx
,
4858 struct tevent_context
*ev
,
4859 struct cli_state
*cli
,
4861 uint32_t buffer_size
,
4862 uint32_t completion_filter
,
4865 struct tevent_req
*req
= NULL
;
4866 struct cli_smb2_notify_state
*state
= NULL
;
4867 struct smb2_hnd
*ph
= NULL
;
4870 req
= tevent_req_create(mem_ctx
, &state
,
4871 struct cli_smb2_notify_state
);
4876 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
4877 if (tevent_req_nterror(req
, status
)) {
4878 return tevent_req_post(req
, ev
);
4881 state
->subreq
= smb2cli_notify_send(
4893 if (tevent_req_nomem(state
->subreq
, req
)) {
4894 return tevent_req_post(req
, ev
);
4896 tevent_req_set_callback(state
->subreq
, cli_smb2_notify_done
, req
);
4897 tevent_req_set_cancel_fn(req
, cli_smb2_notify_cancel
);
4901 static bool cli_smb2_notify_cancel(struct tevent_req
*req
)
4903 struct cli_smb2_notify_state
*state
= tevent_req_data(
4904 req
, struct cli_smb2_notify_state
);
4907 ok
= tevent_req_cancel(state
->subreq
);
4911 static void cli_smb2_notify_done(struct tevent_req
*subreq
)
4913 struct tevent_req
*req
= tevent_req_callback_data(
4914 subreq
, struct tevent_req
);
4915 struct cli_smb2_notify_state
*state
= tevent_req_data(
4916 req
, struct cli_smb2_notify_state
);
4922 status
= smb2cli_notify_recv(subreq
, state
, &base
, &len
);
4923 TALLOC_FREE(subreq
);
4925 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
4926 tevent_req_done(req
);
4929 if (tevent_req_nterror(req
, status
)) {
4935 while (len
- ofs
>= 12) {
4936 struct notify_change
*tmp
;
4937 struct notify_change
*c
;
4938 uint32_t next_ofs
= IVAL(base
, ofs
);
4939 uint32_t file_name_length
= IVAL(base
, ofs
+8);
4943 tmp
= talloc_realloc(
4946 struct notify_change
,
4947 state
->num_changes
+ 1);
4948 if (tevent_req_nomem(tmp
, req
)) {
4951 state
->changes
= tmp
;
4952 c
= &state
->changes
[state
->num_changes
];
4953 state
->num_changes
+= 1;
4955 if (smb_buffer_oob(len
, ofs
, next_ofs
) ||
4956 smb_buffer_oob(len
, ofs
+12, file_name_length
)) {
4958 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4962 c
->action
= IVAL(base
, ofs
+4);
4964 ok
= convert_string_talloc(
4974 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4978 if (next_ofs
== 0) {
4984 tevent_req_done(req
);
4987 NTSTATUS
cli_smb2_notify_recv(struct tevent_req
*req
,
4988 TALLOC_CTX
*mem_ctx
,
4989 struct notify_change
**pchanges
,
4990 uint32_t *pnum_changes
)
4992 struct cli_smb2_notify_state
*state
= tevent_req_data(
4993 req
, struct cli_smb2_notify_state
);
4996 if (tevent_req_is_nterror(req
, &status
)) {
4999 *pchanges
= talloc_move(mem_ctx
, &state
->changes
);
5000 *pnum_changes
= state
->num_changes
;
5001 return NT_STATUS_OK
;
5004 NTSTATUS
cli_smb2_notify(struct cli_state
*cli
, uint16_t fnum
,
5005 uint32_t buffer_size
, uint32_t completion_filter
,
5006 bool recursive
, TALLOC_CTX
*mem_ctx
,
5007 struct notify_change
**pchanges
,
5008 uint32_t *pnum_changes
)
5010 TALLOC_CTX
*frame
= talloc_stackframe();
5011 struct tevent_context
*ev
;
5012 struct tevent_req
*req
;
5013 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
5015 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
5017 * Can't use sync call while an async call is in flight
5019 status
= NT_STATUS_INVALID_PARAMETER
;
5022 ev
= samba_tevent_context_init(frame
);
5026 req
= cli_smb2_notify_send(
5037 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
5040 status
= cli_smb2_notify_recv(req
, mem_ctx
, pchanges
, pnum_changes
);
5046 struct cli_smb2_fsctl_state
{
5050 static void cli_smb2_fsctl_done(struct tevent_req
*subreq
);
5052 struct tevent_req
*cli_smb2_fsctl_send(
5053 TALLOC_CTX
*mem_ctx
,
5054 struct tevent_context
*ev
,
5055 struct cli_state
*cli
,
5058 const DATA_BLOB
*in
,
5061 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
5062 struct cli_smb2_fsctl_state
*state
= NULL
;
5063 struct smb2_hnd
*ph
= NULL
;
5066 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_fsctl_state
);
5071 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
5072 if (tevent_req_nterror(req
, status
)) {
5073 return tevent_req_post(req
, ev
);
5076 subreq
= smb2cli_ioctl_send(
5086 0, /* in_max_input_length */
5090 SMB2_IOCTL_FLAG_IS_FSCTL
);
5092 if (tevent_req_nomem(subreq
, req
)) {
5093 return tevent_req_post(req
, ev
);
5095 tevent_req_set_callback(subreq
, cli_smb2_fsctl_done
, req
);
5099 static void cli_smb2_fsctl_done(struct tevent_req
*subreq
)
5101 struct tevent_req
*req
= tevent_req_callback_data(
5102 subreq
, struct tevent_req
);
5103 struct cli_smb2_fsctl_state
*state
= tevent_req_data(
5104 req
, struct cli_smb2_fsctl_state
);
5107 status
= smb2cli_ioctl_recv(subreq
, state
, NULL
, &state
->out
);
5108 tevent_req_simple_finish_ntstatus(subreq
, status
);
5111 NTSTATUS
cli_smb2_fsctl_recv(
5112 struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
, DATA_BLOB
*out
)
5114 struct cli_smb2_fsctl_state
*state
= tevent_req_data(
5115 req
, struct cli_smb2_fsctl_state
);
5116 NTSTATUS status
= NT_STATUS_OK
;
5118 if (tevent_req_is_nterror(req
, &status
)) {
5119 tevent_req_received(req
);
5123 if (state
->out
.length
== 0) {
5124 *out
= (DATA_BLOB
) { .data
= NULL
, };
5127 * Can't use talloc_move() here, the outblobs from
5128 * smb2cli_ioctl_recv() are not standalone talloc
5129 * objects but just peek into the larger buffers
5130 * received, hanging off "state".
5132 *out
= data_blob_talloc(
5133 mem_ctx
, state
->out
.data
, state
->out
.length
);
5134 if (out
->data
== NULL
) {
5135 status
= NT_STATUS_NO_MEMORY
;
5139 tevent_req_received(req
);
5140 return NT_STATUS_OK
;