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"
46 #include "lib/util/idtree.h"
49 uint64_t fid_persistent
;
50 uint64_t fid_volatile
;
54 * Handle mapping code.
57 /***************************************************************
58 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
59 Ensures handle is owned by cli struct.
60 ***************************************************************/
62 static NTSTATUS
map_smb2_handle_to_fnum(struct cli_state
*cli
,
63 const struct smb2_hnd
*ph
, /* In */
64 uint16_t *pfnum
) /* Out */
67 struct idr_context
*idp
= cli
->smb2
.open_handles
;
68 struct smb2_hnd
*owned_h
= talloc_memdup(cli
,
70 sizeof(struct smb2_hnd
));
72 if (owned_h
== NULL
) {
73 return NT_STATUS_NO_MEMORY
;
78 cli
->smb2
.open_handles
= idr_init(cli
);
79 if (cli
->smb2
.open_handles
== NULL
) {
81 return NT_STATUS_NO_MEMORY
;
83 idp
= cli
->smb2
.open_handles
;
86 ret
= idr_get_new_above(idp
, owned_h
, 1, 0xFFFE);
89 return NT_STATUS_NO_MEMORY
;
92 *pfnum
= (uint16_t)ret
;
96 /***************************************************************
97 Return the smb2_hnd pointer associated with the given fnum.
98 ***************************************************************/
100 static NTSTATUS
map_fnum_to_smb2_handle(struct cli_state
*cli
,
101 uint16_t fnum
, /* In */
102 struct smb2_hnd
**pph
) /* Out */
104 struct idr_context
*idp
= cli
->smb2
.open_handles
;
107 return NT_STATUS_INVALID_PARAMETER
;
109 *pph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
111 return NT_STATUS_INVALID_HANDLE
;
116 /***************************************************************
117 Delete the fnum to smb2_hnd mapping. Zeros out handle on
119 ***************************************************************/
121 static NTSTATUS
delete_smb2_handle_mapping(struct cli_state
*cli
,
122 struct smb2_hnd
**pph
, /* In */
123 uint16_t fnum
) /* In */
125 struct idr_context
*idp
= cli
->smb2
.open_handles
;
129 return NT_STATUS_INVALID_PARAMETER
;
132 ph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
134 return NT_STATUS_INVALID_PARAMETER
;
136 idr_remove(idp
, fnum
);
141 /***************************************************************
143 ***************************************************************/
145 static uint8_t flags_to_smb2_oplock(struct cli_smb2_create_flags create_flags
)
147 if (create_flags
.batch_oplock
) {
148 return SMB2_OPLOCK_LEVEL_BATCH
;
149 } else if (create_flags
.exclusive_oplock
) {
150 return SMB2_OPLOCK_LEVEL_EXCLUSIVE
;
153 /* create_flags doesn't do a level2 request. */
154 return SMB2_OPLOCK_LEVEL_NONE
;
157 /***************************************************************
158 If we're on a DFS share, ensure we convert to a full DFS path
159 if this hasn't already been done.
160 ***************************************************************/
162 static char *smb2_dfs_share_path(TALLOC_CTX
*ctx
,
163 struct cli_state
*cli
,
166 bool is_dfs
= smbXcli_conn_dfs_supported(cli
->conn
) &&
167 smbXcli_tcon_is_dfs_share(cli
->smb2
.tcon
);
168 bool is_already_dfs_path
= false;
173 is_already_dfs_path
= cli_dfs_is_already_full_path(cli
, path
);
174 if (is_already_dfs_path
) {
177 if (path
[0] == '\0') {
178 return talloc_asprintf(ctx
,
180 smbXcli_conn_remote_name(cli
->conn
),
183 while (*path
== '\\') {
186 return talloc_asprintf(ctx
,
188 smbXcli_conn_remote_name(cli
->conn
),
193 /***************************************************************
194 Small wrapper that allows SMB2 create to return a uint16_t fnum.
195 ***************************************************************/
197 struct cli_smb2_create_fnum_state
{
198 struct cli_state
*cli
;
199 struct smb2_create_blobs in_cblobs
;
200 struct smb2_create_blobs out_cblobs
;
201 struct smb_create_returns cr
;
202 struct symlink_reparse_struct
*symlink
;
204 struct tevent_req
*subreq
;
207 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
);
208 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
);
210 struct tevent_req
*cli_smb2_create_fnum_send(
212 struct tevent_context
*ev
,
213 struct cli_state
*cli
,
214 const char *fname_in
,
215 struct cli_smb2_create_flags create_flags
,
216 uint32_t impersonation_level
,
217 uint32_t desired_access
,
218 uint32_t file_attributes
,
219 uint32_t share_access
,
220 uint32_t create_disposition
,
221 uint32_t create_options
,
222 const struct smb2_create_blobs
*in_cblobs
)
224 struct tevent_req
*req
, *subreq
;
225 struct cli_smb2_create_fnum_state
*state
;
227 size_t fname_len
= 0;
232 req
= tevent_req_create(mem_ctx
, &state
,
233 struct cli_smb2_create_fnum_state
);
239 fname
= talloc_strdup(state
, fname_in
);
240 if (tevent_req_nomem(fname
, req
)) {
241 return tevent_req_post(req
, ev
);
244 if (cli
->backup_intent
) {
245 create_options
|= FILE_OPEN_FOR_BACKUP_INTENT
;
248 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
249 have_twrp
= clistr_smb2_extract_snapshot_token(fname
, &ntt
);
251 status
= smb2_create_blob_add(
254 SMB2_CREATE_TAG_TWRP
,
256 .data
= (uint8_t *)&ntt
,
257 .length
= sizeof(ntt
),
259 if (tevent_req_nterror(req
, status
)) {
260 return tevent_req_post(req
, ev
);
264 if (in_cblobs
!= NULL
) {
266 for (i
=0; i
<in_cblobs
->num_blobs
; i
++) {
267 struct smb2_create_blob
*b
= &in_cblobs
->blobs
[i
];
268 status
= smb2_create_blob_add(
269 state
, &state
->in_cblobs
, b
->tag
, b
->data
);
270 if (!NT_STATUS_IS_OK(status
)) {
271 tevent_req_nterror(req
, status
);
272 return tevent_req_post(req
, ev
);
277 fname
= smb2_dfs_share_path(state
, cli
, fname
);
278 if (tevent_req_nomem(fname
, req
)) {
279 return tevent_req_post(req
, ev
);
281 fname_len
= strlen(fname
);
283 /* SMB2 is pickier about pathnames. Ensure it doesn't
285 if (*fname
== '\\') {
290 /* Or end in a '\' */
291 if (fname_len
> 0 && fname
[fname_len
-1] == '\\') {
292 fname
[fname_len
-1] = '\0';
295 subreq
= smb2cli_create_send(state
, ev
,
301 flags_to_smb2_oplock(create_flags
),
309 if (tevent_req_nomem(subreq
, req
)) {
310 return tevent_req_post(req
, ev
);
312 tevent_req_set_callback(subreq
, cli_smb2_create_fnum_done
, req
);
314 state
->subreq
= subreq
;
315 tevent_req_set_cancel_fn(req
, cli_smb2_create_fnum_cancel
);
320 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
)
322 struct tevent_req
*req
= tevent_req_callback_data(
323 subreq
, struct tevent_req
);
324 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
325 req
, struct cli_smb2_create_fnum_state
);
329 status
= smb2cli_create_recv(
332 &h
.fid_volatile
, &state
->cr
,
337 if (tevent_req_nterror(req
, status
)) {
341 status
= map_smb2_handle_to_fnum(state
->cli
, &h
, &state
->fnum
);
342 if (tevent_req_nterror(req
, status
)) {
345 tevent_req_done(req
);
348 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
)
350 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
351 req
, struct cli_smb2_create_fnum_state
);
352 return tevent_req_cancel(state
->subreq
);
355 NTSTATUS
cli_smb2_create_fnum_recv(
356 struct tevent_req
*req
,
358 struct smb_create_returns
*cr
,
360 struct smb2_create_blobs
*out_cblobs
,
361 struct symlink_reparse_struct
**symlink
)
363 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
364 req
, struct cli_smb2_create_fnum_state
);
367 if (tevent_req_is_nterror(req
, &status
)) {
368 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
) &&
370 *symlink
= talloc_move(mem_ctx
, &state
->symlink
);
372 state
->cli
->raw_status
= status
;
376 *pfnum
= state
->fnum
;
381 if (out_cblobs
!= NULL
) {
382 *out_cblobs
= (struct smb2_create_blobs
) {
383 .num_blobs
= state
->out_cblobs
.num_blobs
,
384 .blobs
= talloc_move(
385 mem_ctx
, &state
->out_cblobs
.blobs
),
388 state
->cli
->raw_status
= NT_STATUS_OK
;
392 NTSTATUS
cli_smb2_create_fnum(
393 struct cli_state
*cli
,
395 struct cli_smb2_create_flags create_flags
,
396 uint32_t impersonation_level
,
397 uint32_t desired_access
,
398 uint32_t file_attributes
,
399 uint32_t share_access
,
400 uint32_t create_disposition
,
401 uint32_t create_options
,
402 const struct smb2_create_blobs
*in_cblobs
,
404 struct smb_create_returns
*cr
,
406 struct smb2_create_blobs
*out_cblobs
)
408 TALLOC_CTX
*frame
= talloc_stackframe();
409 struct tevent_context
*ev
;
410 struct tevent_req
*req
;
411 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
413 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
415 * Can't use sync call while an async call is in flight
417 status
= NT_STATUS_INVALID_PARAMETER
;
420 ev
= samba_tevent_context_init(frame
);
424 req
= cli_smb2_create_fnum_send(
440 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
443 status
= cli_smb2_create_fnum_recv(
444 req
, pfid
, cr
, mem_ctx
, out_cblobs
, NULL
);
450 /***************************************************************
451 Small wrapper that allows SMB2 close to use a uint16_t fnum.
452 ***************************************************************/
454 struct cli_smb2_close_fnum_state
{
455 struct cli_state
*cli
;
460 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
);
462 struct tevent_req
*cli_smb2_close_fnum_send(TALLOC_CTX
*mem_ctx
,
463 struct tevent_context
*ev
,
464 struct cli_state
*cli
,
467 struct tevent_req
*req
, *subreq
;
468 struct cli_smb2_close_fnum_state
*state
;
471 req
= tevent_req_create(mem_ctx
, &state
,
472 struct cli_smb2_close_fnum_state
);
479 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
480 if (tevent_req_nterror(req
, status
)) {
481 return tevent_req_post(req
, ev
);
484 subreq
= smb2cli_close_send(state
, ev
, cli
->conn
, cli
->timeout
,
485 cli
->smb2
.session
, cli
->smb2
.tcon
,
486 0, state
->ph
->fid_persistent
,
487 state
->ph
->fid_volatile
);
488 if (tevent_req_nomem(subreq
, req
)) {
489 return tevent_req_post(req
, ev
);
491 tevent_req_set_callback(subreq
, cli_smb2_close_fnum_done
, req
);
495 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
)
497 struct tevent_req
*req
= tevent_req_callback_data(
498 subreq
, struct tevent_req
);
499 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
500 req
, struct cli_smb2_close_fnum_state
);
503 status
= smb2cli_close_recv(subreq
);
504 if (tevent_req_nterror(req
, status
)) {
508 /* Delete the fnum -> handle mapping. */
509 status
= delete_smb2_handle_mapping(state
->cli
, &state
->ph
,
511 if (tevent_req_nterror(req
, status
)) {
514 tevent_req_done(req
);
517 NTSTATUS
cli_smb2_close_fnum_recv(struct tevent_req
*req
)
519 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
520 req
, struct cli_smb2_close_fnum_state
);
521 NTSTATUS status
= NT_STATUS_OK
;
523 if (tevent_req_is_nterror(req
, &status
)) {
524 state
->cli
->raw_status
= status
;
526 tevent_req_received(req
);
530 NTSTATUS
cli_smb2_close_fnum(struct cli_state
*cli
, uint16_t fnum
)
532 TALLOC_CTX
*frame
= talloc_stackframe();
533 struct tevent_context
*ev
;
534 struct tevent_req
*req
;
535 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
537 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
539 * Can't use sync call while an async call is in flight
541 status
= NT_STATUS_INVALID_PARAMETER
;
544 ev
= samba_tevent_context_init(frame
);
548 req
= cli_smb2_close_fnum_send(frame
, ev
, cli
, fnum
);
552 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
555 status
= cli_smb2_close_fnum_recv(req
);
561 struct cli_smb2_set_info_fnum_state
{
565 static void cli_smb2_set_info_fnum_done(struct tevent_req
*subreq
);
567 struct tevent_req
*cli_smb2_set_info_fnum_send(
569 struct tevent_context
*ev
,
570 struct cli_state
*cli
,
572 uint8_t in_info_type
,
573 uint8_t in_info_class
,
574 const DATA_BLOB
*in_input_buffer
,
575 uint32_t in_additional_info
)
577 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
578 struct cli_smb2_set_info_fnum_state
*state
= NULL
;
579 struct smb2_hnd
*ph
= NULL
;
582 req
= tevent_req_create(
583 mem_ctx
, &state
, struct cli_smb2_set_info_fnum_state
);
588 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
589 if (tevent_req_nterror(req
, status
)) {
590 return tevent_req_post(req
, ev
);
593 subreq
= smb2cli_set_info_send(
606 if (tevent_req_nomem(subreq
, req
)) {
607 return tevent_req_post(req
, ev
);
609 tevent_req_set_callback(subreq
, cli_smb2_set_info_fnum_done
, req
);
613 static void cli_smb2_set_info_fnum_done(struct tevent_req
*subreq
)
615 NTSTATUS status
= smb2cli_set_info_recv(subreq
);
616 tevent_req_simple_finish_ntstatus(subreq
, status
);
619 NTSTATUS
cli_smb2_set_info_fnum_recv(struct tevent_req
*req
)
621 return tevent_req_simple_recv_ntstatus(req
);
624 NTSTATUS
cli_smb2_set_info_fnum(
625 struct cli_state
*cli
,
627 uint8_t in_info_type
,
628 uint8_t in_info_class
,
629 const DATA_BLOB
*in_input_buffer
,
630 uint32_t in_additional_info
)
632 TALLOC_CTX
*frame
= talloc_stackframe();
633 struct tevent_context
*ev
= NULL
;
634 struct tevent_req
*req
= NULL
;
635 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
638 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
640 * Can't use sync call while an async call is in flight
642 status
= NT_STATUS_INVALID_PARAMETER
;
645 ev
= samba_tevent_context_init(frame
);
649 req
= cli_smb2_set_info_fnum_send(
661 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
665 status
= cli_smb2_set_info_fnum_recv(req
);
671 struct cli_smb2_delete_on_close_state
{
672 struct cli_state
*cli
;
677 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
);
679 struct tevent_req
*cli_smb2_delete_on_close_send(TALLOC_CTX
*mem_ctx
,
680 struct tevent_context
*ev
,
681 struct cli_state
*cli
,
685 struct tevent_req
*req
= NULL
;
686 struct cli_smb2_delete_on_close_state
*state
= NULL
;
687 struct tevent_req
*subreq
= NULL
;
688 uint8_t in_info_type
;
689 uint8_t in_file_info_class
;
691 req
= tevent_req_create(mem_ctx
, &state
,
692 struct cli_smb2_delete_on_close_state
);
699 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
700 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
703 in_file_info_class
= SMB_FILE_DISPOSITION_INFORMATION
- 1000;
704 /* Setup data array. */
705 SCVAL(&state
->data
[0], 0, flag
? 1 : 0);
706 state
->inbuf
.data
= &state
->data
[0];
707 state
->inbuf
.length
= 1;
709 subreq
= cli_smb2_set_info_fnum_send(
718 if (tevent_req_nomem(subreq
, req
)) {
719 return tevent_req_post(req
, ev
);
721 tevent_req_set_callback(subreq
,
722 cli_smb2_delete_on_close_done
,
727 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
)
729 NTSTATUS status
= cli_smb2_set_info_fnum_recv(subreq
);
730 tevent_req_simple_finish_ntstatus(subreq
, status
);
733 NTSTATUS
cli_smb2_delete_on_close_recv(struct tevent_req
*req
)
735 struct cli_smb2_delete_on_close_state
*state
=
737 struct cli_smb2_delete_on_close_state
);
740 if (tevent_req_is_nterror(req
, &status
)) {
741 state
->cli
->raw_status
= status
;
742 tevent_req_received(req
);
746 state
->cli
->raw_status
= NT_STATUS_OK
;
747 tevent_req_received(req
);
751 NTSTATUS
cli_smb2_delete_on_close(struct cli_state
*cli
, uint16_t fnum
, bool flag
)
753 TALLOC_CTX
*frame
= talloc_stackframe();
754 struct tevent_context
*ev
;
755 struct tevent_req
*req
;
756 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
758 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
760 * Can't use sync call while an async call is in flight
762 status
= NT_STATUS_INVALID_PARAMETER
;
765 ev
= samba_tevent_context_init(frame
);
769 req
= cli_smb2_delete_on_close_send(frame
, ev
, cli
, fnum
, flag
);
773 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
776 status
= cli_smb2_delete_on_close_recv(req
);
782 struct cli_smb2_mkdir_state
{
783 struct tevent_context
*ev
;
784 struct cli_state
*cli
;
787 static void cli_smb2_mkdir_opened(struct tevent_req
*subreq
);
788 static void cli_smb2_mkdir_closed(struct tevent_req
*subreq
);
790 struct tevent_req
*cli_smb2_mkdir_send(
792 struct tevent_context
*ev
,
793 struct cli_state
*cli
,
796 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
797 struct cli_smb2_mkdir_state
*state
= NULL
;
799 req
= tevent_req_create(
800 mem_ctx
, &state
, struct cli_smb2_mkdir_state
);
807 /* Ensure this is a directory. */
808 subreq
= cli_smb2_create_fnum_send(
813 (struct cli_smb2_create_flags
){0}, /* create_flags */
814 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation_level */
815 FILE_READ_ATTRIBUTES
, /* desired_access */
816 FILE_ATTRIBUTE_DIRECTORY
, /* file_attributes */
818 FILE_SHARE_WRITE
, /* share_access */
819 FILE_CREATE
, /* create_disposition */
820 FILE_DIRECTORY_FILE
, /* create_options */
821 NULL
); /* in_cblobs */
822 if (tevent_req_nomem(subreq
, req
)) {
823 return tevent_req_post(req
, ev
);
825 tevent_req_set_callback(subreq
, cli_smb2_mkdir_opened
, req
);
829 static void cli_smb2_mkdir_opened(struct tevent_req
*subreq
)
831 struct tevent_req
*req
= tevent_req_callback_data(
832 subreq
, struct tevent_req
);
833 struct cli_smb2_mkdir_state
*state
= tevent_req_data(
834 req
, struct cli_smb2_mkdir_state
);
836 uint16_t fnum
= 0xffff;
838 status
= cli_smb2_create_fnum_recv(
839 subreq
, &fnum
, NULL
, NULL
, NULL
, NULL
);
841 if (tevent_req_nterror(req
, status
)) {
845 subreq
= cli_smb2_close_fnum_send(state
, state
->ev
, state
->cli
, fnum
);
846 if (tevent_req_nomem(subreq
, req
)) {
849 tevent_req_set_callback(subreq
, cli_smb2_mkdir_closed
, req
);
852 static void cli_smb2_mkdir_closed(struct tevent_req
*subreq
)
854 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
855 tevent_req_simple_finish_ntstatus(subreq
, status
);
858 NTSTATUS
cli_smb2_mkdir_recv(struct tevent_req
*req
)
860 return tevent_req_simple_recv_ntstatus(req
);
863 struct cli_smb2_rmdir_state
{
864 struct tevent_context
*ev
;
865 struct cli_state
*cli
;
867 const struct smb2_create_blobs
*in_cblobs
;
872 static void cli_smb2_rmdir_opened1(struct tevent_req
*subreq
);
873 static void cli_smb2_rmdir_opened2(struct tevent_req
*subreq
);
874 static void cli_smb2_rmdir_disp_set(struct tevent_req
*subreq
);
875 static void cli_smb2_rmdir_closed(struct tevent_req
*subreq
);
877 struct tevent_req
*cli_smb2_rmdir_send(
879 struct tevent_context
*ev
,
880 struct cli_state
*cli
,
882 const struct smb2_create_blobs
*in_cblobs
)
884 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
885 struct cli_smb2_rmdir_state
*state
= NULL
;
887 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_rmdir_state
);
893 state
->dname
= dname
;
894 state
->in_cblobs
= in_cblobs
;
896 subreq
= cli_smb2_create_fnum_send(
901 (struct cli_smb2_create_flags
){0},
902 SMB2_IMPERSONATION_IMPERSONATION
,
903 DELETE_ACCESS
, /* desired_access */
904 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
905 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
906 FILE_OPEN
, /* create_disposition */
907 FILE_DIRECTORY_FILE
, /* create_options */
908 state
->in_cblobs
); /* in_cblobs */
909 if (tevent_req_nomem(subreq
, req
)) {
910 return tevent_req_post(req
, ev
);
912 tevent_req_set_callback(subreq
, cli_smb2_rmdir_opened1
, req
);
916 static void cli_smb2_rmdir_opened1(struct tevent_req
*subreq
)
918 struct tevent_req
*req
= tevent_req_callback_data(
919 subreq
, struct tevent_req
);
920 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
921 req
, struct cli_smb2_rmdir_state
);
924 status
= cli_smb2_create_fnum_recv(
925 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
928 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
930 * Naive option to match our SMB1 code. Assume the
931 * symlink path that tripped us up was the last
932 * component and try again. Eventually we will have to
933 * deal with the returned path unprocessed component. JRA.
935 subreq
= cli_smb2_create_fnum_send(
940 (struct cli_smb2_create_flags
){0},
941 SMB2_IMPERSONATION_IMPERSONATION
,
942 DELETE_ACCESS
, /* desired_access */
943 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
944 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
945 FILE_OPEN
, /* create_disposition */
947 FILE_DELETE_ON_CLOSE
|
948 FILE_OPEN_REPARSE_POINT
, /* create_options */
949 state
->in_cblobs
); /* in_cblobs */
950 if (tevent_req_nomem(subreq
, req
)) {
953 tevent_req_set_callback(subreq
, cli_smb2_rmdir_opened2
, req
);
957 if (tevent_req_nterror(req
, status
)) {
961 subreq
= cli_smb2_delete_on_close_send(
962 state
, state
->ev
, state
->cli
, state
->fnum
, true);
963 if (tevent_req_nomem(subreq
, req
)) {
966 tevent_req_set_callback(subreq
, cli_smb2_rmdir_disp_set
, req
);
969 static void cli_smb2_rmdir_opened2(struct tevent_req
*subreq
)
971 struct tevent_req
*req
= tevent_req_callback_data(
972 subreq
, struct tevent_req
);
973 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
974 req
, struct cli_smb2_rmdir_state
);
977 status
= cli_smb2_create_fnum_recv(
978 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
980 if (tevent_req_nterror(req
, status
)) {
984 subreq
= cli_smb2_delete_on_close_send(
985 state
, state
->ev
, state
->cli
, state
->fnum
, true);
986 if (tevent_req_nomem(subreq
, req
)) {
989 tevent_req_set_callback(subreq
, cli_smb2_rmdir_disp_set
, req
);
992 static void cli_smb2_rmdir_disp_set(struct tevent_req
*subreq
)
994 struct tevent_req
*req
= tevent_req_callback_data(
995 subreq
, struct tevent_req
);
996 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
997 req
, struct cli_smb2_rmdir_state
);
999 state
->status
= cli_smb2_delete_on_close_recv(subreq
);
1000 TALLOC_FREE(subreq
);
1003 * Close the fd even if the set_disp failed
1006 subreq
= cli_smb2_close_fnum_send(
1007 state
, state
->ev
, state
->cli
, state
->fnum
);
1008 if (tevent_req_nomem(subreq
, req
)) {
1011 tevent_req_set_callback(subreq
, cli_smb2_rmdir_closed
, req
);
1014 static void cli_smb2_rmdir_closed(struct tevent_req
*subreq
)
1016 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
1017 tevent_req_simple_finish_ntstatus(subreq
, status
);
1020 NTSTATUS
cli_smb2_rmdir_recv(struct tevent_req
*req
)
1022 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
1023 req
, struct cli_smb2_rmdir_state
);
1026 if (tevent_req_is_nterror(req
, &status
)) {
1029 return state
->status
;
1032 /***************************************************************
1033 Small wrapper that allows SMB2 to unlink a pathname.
1034 ***************************************************************/
1036 struct cli_smb2_unlink_state
{
1037 struct tevent_context
*ev
;
1038 struct cli_state
*cli
;
1040 const struct smb2_create_blobs
*in_cblobs
;
1043 static void cli_smb2_unlink_opened1(struct tevent_req
*subreq
);
1044 static void cli_smb2_unlink_opened2(struct tevent_req
*subreq
);
1045 static void cli_smb2_unlink_closed(struct tevent_req
*subreq
);
1047 struct tevent_req
*cli_smb2_unlink_send(
1048 TALLOC_CTX
*mem_ctx
,
1049 struct tevent_context
*ev
,
1050 struct cli_state
*cli
,
1052 const struct smb2_create_blobs
*in_cblobs
)
1054 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1055 struct cli_smb2_unlink_state
*state
= NULL
;
1057 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_unlink_state
);
1063 state
->fname
= fname
;
1064 state
->in_cblobs
= in_cblobs
;
1066 subreq
= cli_smb2_create_fnum_send(
1067 state
, /* mem_ctx */
1068 state
->ev
, /* tevent_context */
1069 state
->cli
, /* cli_struct */
1070 state
->fname
, /* filename */
1071 (struct cli_smb2_create_flags
){0},
1072 SMB2_IMPERSONATION_IMPERSONATION
,
1073 DELETE_ACCESS
, /* desired_access */
1074 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
1077 FILE_SHARE_DELETE
, /* share_access */
1078 FILE_OPEN
, /* create_disposition */
1079 FILE_DELETE_ON_CLOSE
, /* create_options */
1080 state
->in_cblobs
); /* in_cblobs */
1081 if (tevent_req_nomem(subreq
, req
)) {
1082 return tevent_req_post(req
, ev
);
1084 tevent_req_set_callback(subreq
, cli_smb2_unlink_opened1
, req
);
1088 static void cli_smb2_unlink_opened1(struct tevent_req
*subreq
)
1090 struct tevent_req
*req
= tevent_req_callback_data(
1091 subreq
, struct tevent_req
);
1092 struct cli_smb2_unlink_state
*state
= tevent_req_data(
1093 req
, struct cli_smb2_unlink_state
);
1094 uint16_t fnum
= 0xffff;
1097 status
= cli_smb2_create_fnum_recv(
1098 subreq
, &fnum
, NULL
, NULL
, NULL
, NULL
);
1099 TALLOC_FREE(subreq
);
1101 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
) ||
1102 NT_STATUS_EQUAL(status
, NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED
)) {
1104 * Naive option to match our SMB1 code. Assume the
1105 * symlink path that tripped us up was the last
1106 * component and try again. Eventually we will have to
1107 * deal with the returned path unprocessed component. JRA.
1109 subreq
= cli_smb2_create_fnum_send(
1110 state
, /* mem_ctx */
1111 state
->ev
, /* tevent_context */
1112 state
->cli
, /* cli_struct */
1113 state
->fname
, /* filename */
1114 (struct cli_smb2_create_flags
){0},
1115 SMB2_IMPERSONATION_IMPERSONATION
,
1116 DELETE_ACCESS
, /* desired_access */
1117 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
1120 FILE_SHARE_DELETE
, /* share_access */
1121 FILE_OPEN
, /* create_disposition */
1122 FILE_DELETE_ON_CLOSE
|
1123 FILE_OPEN_REPARSE_POINT
, /* create_options */
1124 state
->in_cblobs
); /* in_cblobs */
1125 if (tevent_req_nomem(subreq
, req
)) {
1128 tevent_req_set_callback(subreq
, cli_smb2_unlink_opened2
, req
);
1132 if (tevent_req_nterror(req
, status
)) {
1136 subreq
= cli_smb2_close_fnum_send(state
, state
->ev
, state
->cli
, fnum
);
1137 if (tevent_req_nomem(subreq
, req
)) {
1140 tevent_req_set_callback(subreq
, cli_smb2_unlink_closed
, req
);
1143 static void cli_smb2_unlink_opened2(struct tevent_req
*subreq
)
1145 struct tevent_req
*req
= tevent_req_callback_data(
1146 subreq
, struct tevent_req
);
1147 struct cli_smb2_unlink_state
*state
= tevent_req_data(
1148 req
, struct cli_smb2_unlink_state
);
1149 uint16_t fnum
= 0xffff;
1152 status
= cli_smb2_create_fnum_recv(
1153 subreq
, &fnum
, NULL
, NULL
, NULL
, NULL
);
1154 TALLOC_FREE(subreq
);
1155 if (tevent_req_nterror(req
, status
)) {
1159 subreq
= cli_smb2_close_fnum_send(state
, state
->ev
, state
->cli
, fnum
);
1160 if (tevent_req_nomem(subreq
, req
)) {
1163 tevent_req_set_callback(subreq
, cli_smb2_unlink_closed
, req
);
1166 static void cli_smb2_unlink_closed(struct tevent_req
*subreq
)
1168 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
1169 tevent_req_simple_finish_ntstatus(subreq
, status
);
1172 NTSTATUS
cli_smb2_unlink_recv(struct tevent_req
*req
)
1174 return tevent_req_simple_recv_ntstatus(req
);
1177 static ssize_t
sid_parse_wire(TALLOC_CTX
*mem_ctx
, const uint8_t *data
,
1178 struct dom_sid
*sid
, size_t num_rdata
)
1181 enum ndr_err_code ndr_err
;
1182 DATA_BLOB in
= data_blob_const(data
, num_rdata
);
1184 ndr_err
= ndr_pull_struct_blob(&in
,
1187 (ndr_pull_flags_fn_t
)ndr_pull_dom_sid
);
1188 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1192 sid_size
= ndr_size_dom_sid(sid
, 0);
1193 if (sid_size
> num_rdata
) {
1200 /***************************************************************
1201 Utility function to parse a SMB2_FIND_POSIX_INFORMATION reply.
1202 ***************************************************************/
1204 static NTSTATUS
parse_finfo_posix_info(const uint8_t *dir_data
,
1205 uint32_t dir_data_length
,
1206 struct file_info
*finfo
,
1207 uint32_t *next_offset
)
1210 size_t slen
= 0, slen2
= 0;
1212 uint32_t _next_offset
= 0;
1214 if (dir_data_length
< 4) {
1215 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1218 _next_offset
= IVAL(dir_data
, 0);
1220 if (_next_offset
> dir_data_length
) {
1221 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1224 if (_next_offset
!= 0) {
1225 /* Ensure we only read what in this record. */
1226 dir_data_length
= _next_offset
;
1229 if (dir_data_length
< 92) {
1230 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1233 finfo
->btime_ts
= interpret_long_date((const char *)dir_data
+ 8);
1234 finfo
->atime_ts
= interpret_long_date((const char *)dir_data
+ 16);
1235 finfo
->mtime_ts
= interpret_long_date((const char *)dir_data
+ 24);
1236 finfo
->ctime_ts
= interpret_long_date((const char *)dir_data
+ 32);
1237 finfo
->allocated_size
= PULL_LE_U64(dir_data
, 40);
1238 finfo
->size
= PULL_LE_U64(dir_data
, 48);
1239 finfo
->mode
= PULL_LE_U32(dir_data
, 56);
1240 finfo
->ino
= PULL_LE_U64(dir_data
, 60);
1241 finfo
->st_ex_dev
= PULL_LE_U32(dir_data
, 68);
1242 finfo
->st_ex_nlink
= PULL_LE_U32(dir_data
, 76);
1243 finfo
->reparse_tag
= PULL_LE_U32(dir_data
, 80);
1244 finfo
->st_ex_mode
= wire_perms_to_unix(PULL_LE_U32(dir_data
, 84));
1246 slen
= sid_parse_wire(finfo
, dir_data
+88, &finfo
->owner_sid
,
1247 dir_data_length
-88);
1249 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1251 slen2
= sid_parse_wire(finfo
, dir_data
+88+slen
, &finfo
->group_sid
,
1252 dir_data_length
-88-slen
);
1254 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1258 namelen
= PULL_LE_U32(dir_data
, 88+slen
);
1259 ret
= pull_string_talloc(finfo
,
1261 FLAGS2_UNICODE_STRINGS
,
1266 if (ret
== (size_t)-1) {
1267 /* Bad conversion. */
1268 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1271 if (finfo
->name
== NULL
) {
1272 /* Bad conversion. */
1273 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1276 *next_offset
= _next_offset
;
1277 return NT_STATUS_OK
;
1280 /***************************************************************
1281 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1282 ***************************************************************/
1284 static NTSTATUS
parse_finfo_id_both_directory_info(const uint8_t *dir_data
,
1285 uint32_t dir_data_length
,
1286 struct file_info
*finfo
,
1287 uint32_t *next_offset
)
1293 if (dir_data_length
< 4) {
1294 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1297 *next_offset
= IVAL(dir_data
, 0);
1299 if (*next_offset
> dir_data_length
) {
1300 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1303 if (*next_offset
!= 0) {
1304 /* Ensure we only read what in this record. */
1305 dir_data_length
= *next_offset
;
1308 if (dir_data_length
< 105) {
1309 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1312 finfo
->btime_ts
= interpret_long_date((const char *)dir_data
+ 8);
1313 finfo
->atime_ts
= interpret_long_date((const char *)dir_data
+ 16);
1314 finfo
->mtime_ts
= interpret_long_date((const char *)dir_data
+ 24);
1315 finfo
->ctime_ts
= interpret_long_date((const char *)dir_data
+ 32);
1316 finfo
->size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 40, 0);
1317 finfo
->allocated_size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 48, 0);
1318 finfo
->attr
= IVAL(dir_data
+ 56, 0);
1319 finfo
->ino
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 96, 0);
1320 namelen
= IVAL(dir_data
+ 60,0);
1321 if (namelen
> (dir_data_length
- 104)) {
1322 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1324 slen
= CVAL(dir_data
+ 68, 0);
1326 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1328 ret
= pull_string_talloc(finfo
,
1330 FLAGS2_UNICODE_STRINGS
,
1335 if (ret
== (size_t)-1) {
1336 /* Bad conversion. */
1337 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1340 ret
= pull_string_talloc(finfo
,
1342 FLAGS2_UNICODE_STRINGS
,
1347 if (ret
== (size_t)-1) {
1348 /* Bad conversion. */
1349 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1352 if (finfo
->name
== NULL
) {
1353 /* Bad conversion. */
1354 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1357 return NT_STATUS_OK
;
1360 /*******************************************************************
1361 Given a filename - get its directory name
1362 ********************************************************************/
1364 static bool windows_parent_dirname(TALLOC_CTX
*mem_ctx
,
1372 p
= strrchr_m(dir
, '\\'); /* Find final '\\', if any */
1375 if (!(*parent
= talloc_strdup(mem_ctx
, "\\"))) {
1386 if (!(*parent
= (char *)talloc_memdup(mem_ctx
, dir
, len
+1))) {
1389 (*parent
)[len
] = '\0';
1397 struct cli_smb2_list_dir_data
{
1402 struct cli_smb2_list_state
{
1403 struct tevent_context
*ev
;
1404 struct cli_state
*cli
;
1410 struct cli_smb2_list_dir_data
*response
;
1412 unsigned int info_level
;
1415 static void cli_smb2_list_opened(struct tevent_req
*subreq
);
1416 static void cli_smb2_list_done(struct tevent_req
*subreq
);
1417 static void cli_smb2_list_closed(struct tevent_req
*subreq
);
1419 struct tevent_req
*cli_smb2_list_send(
1420 TALLOC_CTX
*mem_ctx
,
1421 struct tevent_context
*ev
,
1422 struct cli_state
*cli
,
1423 const char *pathname
,
1424 unsigned int info_level
,
1427 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1428 struct cli_smb2_list_state
*state
= NULL
;
1429 char *parent
= NULL
;
1431 struct smb2_create_blobs
*in_cblobs
= NULL
;
1433 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_list_state
);
1439 state
->status
= NT_STATUS_OK
;
1440 state
->info_level
= info_level
;
1442 ok
= windows_parent_dirname(state
, pathname
, &parent
, &state
->mask
);
1444 tevent_req_oom(req
);
1445 return tevent_req_post(req
, ev
);
1448 if (smbXcli_conn_have_posix(cli
->conn
) && posix
) {
1451 /* The mode MUST be 0 when opening an existing file/dir, and
1452 * will be ignored by the server.
1454 uint8_t linear_mode
[4] = { 0 };
1455 DATA_BLOB blob
= { .data
=linear_mode
,
1456 .length
=sizeof(linear_mode
) };
1458 in_cblobs
= talloc_zero(mem_ctx
, struct smb2_create_blobs
);
1459 if (in_cblobs
== NULL
) {
1463 status
= smb2_create_blob_add(in_cblobs
, in_cblobs
,
1464 SMB2_CREATE_TAG_POSIX
, blob
);
1465 if (!NT_STATUS_IS_OK(status
)) {
1466 tevent_req_nterror(req
, status
);
1467 return tevent_req_post(req
, ev
);
1471 subreq
= cli_smb2_create_fnum_send(
1472 state
, /* mem_ctx */
1476 (struct cli_smb2_create_flags
){0}, /* create_flags */
1477 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation_level */
1478 SEC_DIR_LIST
|SEC_DIR_READ_ATTRIBUTE
, /* desired_access */
1479 FILE_ATTRIBUTE_DIRECTORY
, /* file_attributes */
1480 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
1481 FILE_OPEN
, /* create_disposition */
1482 FILE_DIRECTORY_FILE
, /* create_options */
1483 in_cblobs
); /* in_cblobs */
1484 TALLOC_FREE(in_cblobs
);
1485 if (tevent_req_nomem(subreq
, req
)) {
1486 return tevent_req_post(req
, ev
);
1488 tevent_req_set_callback(subreq
, cli_smb2_list_opened
, req
);
1492 static void cli_smb2_list_opened(struct tevent_req
*subreq
)
1494 struct tevent_req
*req
= tevent_req_callback_data(
1495 subreq
, struct tevent_req
);
1496 struct cli_smb2_list_state
*state
= tevent_req_data(
1497 req
, struct cli_smb2_list_state
);
1500 status
= cli_smb2_create_fnum_recv(
1501 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
1502 TALLOC_FREE(subreq
);
1503 if (tevent_req_nterror(req
, status
)) {
1508 * Make our caller get back to us via cli_smb2_list_recv(),
1509 * triggering the smb2_query_directory_send()
1511 tevent_req_defer_callback(req
, state
->ev
);
1512 tevent_req_notify_callback(req
);
1515 static void cli_smb2_list_done(struct tevent_req
*subreq
)
1517 struct tevent_req
*req
= tevent_req_callback_data(
1518 subreq
, struct tevent_req
);
1519 struct cli_smb2_list_state
*state
= tevent_req_data(
1520 req
, struct cli_smb2_list_state
);
1521 struct cli_smb2_list_dir_data
*response
= NULL
;
1523 response
= talloc(state
, struct cli_smb2_list_dir_data
);
1524 if (tevent_req_nomem(response
, req
)) {
1528 state
->status
= smb2cli_query_directory_recv(
1529 subreq
, response
, &response
->data
, &response
->length
);
1530 TALLOC_FREE(subreq
);
1532 if (NT_STATUS_IS_OK(state
->status
)) {
1533 state
->response
= response
;
1536 tevent_req_defer_callback(req
, state
->ev
);
1537 tevent_req_notify_callback(req
);
1541 TALLOC_FREE(response
);
1543 subreq
= cli_smb2_close_fnum_send(
1544 state
, state
->ev
, state
->cli
, state
->fnum
);
1545 if (tevent_req_nomem(subreq
, req
)) {
1548 tevent_req_set_callback(subreq
, cli_smb2_list_closed
, req
);
1551 static void cli_smb2_list_closed(struct tevent_req
*subreq
)
1553 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
1554 tevent_req_simple_finish_ntstatus(subreq
, status
);
1558 * Return the next finfo directory.
1560 * This parses the blob returned from QUERY_DIRECTORY step by step. If
1561 * the blob ends, this triggers a fresh QUERY_DIRECTORY and returns
1562 * NT_STATUS_RETRY, which will then trigger the caller again when the
1563 * QUERY_DIRECTORY has returned with another buffer. This way we
1564 * guarantee that no asynchronous request is open after this call
1565 * returns an entry, so that other synchronous requests can be issued
1566 * on the same connection while the directoy listing proceeds.
1568 NTSTATUS
cli_smb2_list_recv(
1569 struct tevent_req
*req
,
1570 TALLOC_CTX
*mem_ctx
,
1571 struct file_info
**pfinfo
)
1573 struct cli_smb2_list_state
*state
= tevent_req_data(
1574 req
, struct cli_smb2_list_state
);
1575 struct cli_smb2_list_dir_data
*response
= NULL
;
1576 struct file_info
*finfo
= NULL
;
1578 uint32_t next_offset
= 0;
1581 in_progress
= tevent_req_is_in_progress(req
);
1584 if (!tevent_req_is_nterror(req
, &status
)) {
1585 status
= NT_STATUS_NO_MORE_FILES
;
1590 response
= state
->response
;
1591 if (response
== NULL
) {
1592 struct tevent_req
*subreq
= NULL
;
1593 struct cli_state
*cli
= state
->cli
;
1594 struct smb2_hnd
*ph
= NULL
;
1595 uint32_t max_trans
, max_avail_len
;
1598 if (!NT_STATUS_IS_OK(state
->status
)) {
1599 status
= state
->status
;
1603 status
= map_fnum_to_smb2_handle(cli
, state
->fnum
, &ph
);
1604 if (!NT_STATUS_IS_OK(status
)) {
1608 max_trans
= smb2cli_conn_max_trans_size(cli
->conn
);
1609 ok
= smb2cli_conn_req_possible(cli
->conn
, &max_avail_len
);
1611 max_trans
= MIN(max_trans
, max_avail_len
);
1614 subreq
= smb2cli_query_directory_send(
1615 state
, /* mem_ctx */
1617 cli
->conn
, /* conn */
1618 cli
->timeout
, /* timeout_msec */
1619 cli
->smb2
.session
, /* session */
1620 cli
->smb2
.tcon
, /* tcon */
1621 state
->info_level
, /* level */
1624 ph
->fid_persistent
, /* fid_persistent */
1625 ph
->fid_volatile
, /* fid_volatile */
1626 state
->mask
, /* mask */
1627 max_trans
); /* outbuf_len */
1628 if (subreq
== NULL
) {
1629 status
= NT_STATUS_NO_MEMORY
;
1632 tevent_req_set_callback(subreq
, cli_smb2_list_done
, req
);
1633 return NT_STATUS_RETRY
;
1636 SMB_ASSERT(response
->length
> state
->offset
);
1638 finfo
= talloc_zero(mem_ctx
, struct file_info
);
1639 if (finfo
== NULL
) {
1640 status
= NT_STATUS_NO_MEMORY
;
1644 if (state
->info_level
== SMB2_FIND_POSIX_INFORMATION
) {
1645 status
= parse_finfo_posix_info(
1646 response
->data
+ state
->offset
,
1647 response
->length
- state
->offset
,
1651 status
= parse_finfo_id_both_directory_info(
1652 response
->data
+ state
->offset
,
1653 response
->length
- state
->offset
,
1657 if (!NT_STATUS_IS_OK(status
)) {
1661 status
= is_bad_finfo_name(state
->cli
, finfo
);
1662 if (!NT_STATUS_IS_OK(status
)) {
1667 * parse_finfo_id_both_directory_info() checks for overflow,
1668 * no need to check again here.
1670 state
->offset
+= next_offset
;
1672 if (next_offset
== 0) {
1673 TALLOC_FREE(state
->response
);
1676 tevent_req_defer_callback(req
, state
->ev
);
1677 tevent_req_notify_callback(req
);
1680 return NT_STATUS_OK
;
1684 tevent_req_received(req
);
1688 /***************************************************************
1689 Wrapper that allows SMB2 to query a path info (basic level).
1691 ***************************************************************/
1693 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
1695 SMB_STRUCT_STAT
*sbuf
,
1696 uint32_t *attributes
)
1699 struct smb_create_returns cr
;
1700 uint16_t fnum
= 0xffff;
1701 size_t namelen
= strlen(name
);
1703 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1705 * Can't use sync call while an async call is in flight
1707 return NT_STATUS_INVALID_PARAMETER
;
1710 /* SMB2 is pickier about pathnames. Ensure it doesn't
1712 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1713 char *modname
= talloc_strndup(talloc_tos(), name
, namelen
-1);
1714 if (modname
== NULL
) {
1715 return NT_STATUS_NO_MEMORY
;
1720 /* This is commonly used as a 'cd'. Try qpathinfo on
1721 a directory handle first. */
1723 status
= cli_smb2_create_fnum(cli
,
1725 (struct cli_smb2_create_flags
){0},
1726 SMB2_IMPERSONATION_IMPERSONATION
,
1727 FILE_READ_ATTRIBUTES
, /* desired_access */
1728 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1729 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1730 FILE_OPEN
, /* create_disposition */
1731 FILE_DIRECTORY_FILE
, /* create_options */
1738 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
1739 /* Maybe a file ? */
1740 status
= cli_smb2_create_fnum(cli
,
1742 (struct cli_smb2_create_flags
){0},
1743 SMB2_IMPERSONATION_IMPERSONATION
,
1744 FILE_READ_ATTRIBUTES
, /* desired_access */
1745 0, /* file attributes */
1746 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1747 FILE_OPEN
, /* create_disposition */
1748 0, /* create_options */
1756 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
1757 /* Maybe a reparse point ? */
1758 status
= cli_smb2_create_fnum(cli
,
1760 (struct cli_smb2_create_flags
){0},
1761 SMB2_IMPERSONATION_IMPERSONATION
,
1762 FILE_READ_ATTRIBUTES
, /* desired_access */
1763 0, /* file attributes */
1764 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1765 FILE_OPEN
, /* create_disposition */
1766 FILE_OPEN_REPARSE_POINT
, /* create_options */
1774 if (!NT_STATUS_IS_OK(status
)) {
1778 status
= cli_smb2_close_fnum(cli
, fnum
);
1782 sbuf
->st_ex_atime
= nt_time_to_unix_timespec(cr
.last_access_time
);
1783 sbuf
->st_ex_mtime
= nt_time_to_unix_timespec(cr
.last_write_time
);
1784 sbuf
->st_ex_ctime
= nt_time_to_unix_timespec(cr
.change_time
);
1785 sbuf
->st_ex_size
= cr
.end_of_file
;
1786 *attributes
= cr
.file_attributes
;
1791 struct cli_smb2_query_info_fnum_state
{
1795 static void cli_smb2_query_info_fnum_done(struct tevent_req
*subreq
);
1797 struct tevent_req
*cli_smb2_query_info_fnum_send(
1798 TALLOC_CTX
*mem_ctx
,
1799 struct tevent_context
*ev
,
1800 struct cli_state
*cli
,
1802 uint8_t in_info_type
,
1803 uint8_t in_info_class
,
1804 uint32_t in_max_output_length
,
1805 const DATA_BLOB
*in_input_buffer
,
1806 uint32_t in_additional_info
,
1809 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1810 struct cli_smb2_query_info_fnum_state
*state
= NULL
;
1811 struct smb2_hnd
*ph
= NULL
;
1814 req
= tevent_req_create(
1815 mem_ctx
, &state
, struct cli_smb2_query_info_fnum_state
);
1820 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
1821 if (tevent_req_nterror(req
, status
)) {
1822 return tevent_req_post(req
, ev
);
1825 subreq
= smb2cli_query_info_send(
1834 in_max_output_length
,
1840 if (tevent_req_nomem(subreq
, req
)) {
1841 return tevent_req_post(req
, ev
);
1843 tevent_req_set_callback(subreq
, cli_smb2_query_info_fnum_done
, req
);
1847 static void cli_smb2_query_info_fnum_done(struct tevent_req
*subreq
)
1849 struct tevent_req
*req
= tevent_req_callback_data(
1850 subreq
, struct tevent_req
);
1851 struct cli_smb2_query_info_fnum_state
*state
= tevent_req_data(
1852 req
, struct cli_smb2_query_info_fnum_state
);
1856 status
= smb2cli_query_info_recv(subreq
, state
, &outbuf
);
1857 TALLOC_FREE(subreq
);
1858 if (tevent_req_nterror(req
, status
)) {
1863 * We have to dup the memory here because outbuf.data is not
1864 * returned as a talloc object by smb2cli_query_info_recv.
1865 * It's a pointer into the received buffer.
1867 state
->outbuf
= data_blob_dup_talloc(state
, outbuf
);
1869 if ((outbuf
.length
!= 0) &&
1870 tevent_req_nomem(state
->outbuf
.data
, req
)) {
1873 tevent_req_done(req
);
1876 NTSTATUS
cli_smb2_query_info_fnum_recv(
1877 struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
, DATA_BLOB
*outbuf
)
1879 struct cli_smb2_query_info_fnum_state
*state
= tevent_req_data(
1880 req
, struct cli_smb2_query_info_fnum_state
);
1883 if (tevent_req_is_nterror(req
, &status
)) {
1886 *outbuf
= (DATA_BLOB
) {
1887 .data
= talloc_move(mem_ctx
, &state
->outbuf
.data
),
1888 .length
= state
->outbuf
.length
,
1890 return NT_STATUS_OK
;
1893 NTSTATUS
cli_smb2_query_info_fnum(
1894 struct cli_state
*cli
,
1896 uint8_t in_info_type
,
1897 uint8_t in_info_class
,
1898 uint32_t in_max_output_length
,
1899 const DATA_BLOB
*in_input_buffer
,
1900 uint32_t in_additional_info
,
1902 TALLOC_CTX
*mem_ctx
,
1905 TALLOC_CTX
*frame
= talloc_stackframe();
1906 struct tevent_context
*ev
= NULL
;
1907 struct tevent_req
*req
= NULL
;
1908 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1911 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1913 * Can't use sync call while an async call is in flight
1915 status
= NT_STATUS_INVALID_PARAMETER
;
1918 ev
= samba_tevent_context_init(frame
);
1922 req
= cli_smb2_query_info_fnum_send(
1929 in_max_output_length
,
1936 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
1940 status
= cli_smb2_query_info_fnum_recv(req
, mem_ctx
, outbuf
);
1946 /***************************************************************
1947 Helper function for pathname operations.
1948 ***************************************************************/
1950 struct get_fnum_from_path_state
{
1951 struct tevent_context
*ev
;
1952 struct cli_state
*cli
;
1954 uint32_t desired_access
;
1958 static void get_fnum_from_path_opened_file(struct tevent_req
*subreq
);
1959 static void get_fnum_from_path_opened_reparse(struct tevent_req
*subreq
);
1960 static void get_fnum_from_path_opened_dir(struct tevent_req
*subreq
);
1962 static struct tevent_req
*get_fnum_from_path_send(
1963 TALLOC_CTX
*mem_ctx
,
1964 struct tevent_context
*ev
,
1965 struct cli_state
*cli
,
1967 uint32_t desired_access
)
1969 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1970 struct get_fnum_from_path_state
*state
= NULL
;
1971 size_t namelen
= strlen(name
);
1973 req
= tevent_req_create(
1974 mem_ctx
, &state
, struct get_fnum_from_path_state
);
1981 state
->desired_access
= desired_access
;
1984 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
1987 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1988 state
->name
= talloc_strndup(state
, name
, namelen
-1);
1989 if (tevent_req_nomem(state
->name
, req
)) {
1990 return tevent_req_post(req
, ev
);
1994 subreq
= cli_smb2_create_fnum_send(
1995 state
, /* mem_ctx, */
1998 state
->name
, /* fname */
1999 (struct cli_smb2_create_flags
){0}, /* create_flags */
2000 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation_level */
2001 desired_access
, /* desired_access */
2002 0, /* file_attributes */
2005 FILE_SHARE_DELETE
, /* share_access */
2006 FILE_OPEN
, /* create_disposition */
2007 0, /* create_options */
2008 NULL
); /* in_cblobs */
2009 if (tevent_req_nomem(subreq
, req
)) {
2010 return tevent_req_post(req
, ev
);
2012 tevent_req_set_callback(subreq
, get_fnum_from_path_opened_file
, req
);
2016 static void get_fnum_from_path_opened_file(struct tevent_req
*subreq
)
2018 struct tevent_req
*req
= tevent_req_callback_data(
2019 subreq
, struct tevent_req
);
2020 struct get_fnum_from_path_state
*state
= tevent_req_data(
2021 req
, struct get_fnum_from_path_state
);
2024 status
= cli_smb2_create_fnum_recv(
2025 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
2026 TALLOC_FREE(subreq
);
2028 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
2030 * Naive option to match our SMB1 code. Assume the
2031 * symlink path that tripped us up was the last
2032 * component and try again. Eventually we will have to
2033 * deal with the returned path unprocessed component. JRA.
2035 subreq
= cli_smb2_create_fnum_send(
2036 state
, /* mem_ctx, */
2038 state
->cli
, /* cli */
2039 state
->name
, /* fname */
2040 (struct cli_smb2_create_flags
){0}, /* create_flags */
2041 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation */
2042 state
->desired_access
, /* desired_access */
2043 0, /* file_attributes */
2046 FILE_SHARE_DELETE
, /* share_access */
2047 FILE_OPEN
, /* create_disposition */
2048 FILE_OPEN_REPARSE_POINT
, /* create_options */
2049 NULL
); /* in_cblobs */
2050 if (tevent_req_nomem(subreq
, req
)) {
2053 tevent_req_set_callback(
2054 subreq
, get_fnum_from_path_opened_reparse
, req
);
2058 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
2059 subreq
= cli_smb2_create_fnum_send(
2060 state
, /* mem_ctx, */
2062 state
->cli
, /* cli */
2063 state
->name
, /* fname */
2064 (struct cli_smb2_create_flags
){0}, /* create_flags */
2065 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation */
2066 state
->desired_access
, /* desired_access */
2067 0, /* file_attributes */
2070 FILE_SHARE_DELETE
, /* share_access */
2071 FILE_OPEN
, /* create_disposition */
2072 FILE_DIRECTORY_FILE
, /* create_options */
2073 NULL
); /* in_cblobs */
2074 if (tevent_req_nomem(subreq
, req
)) {
2077 tevent_req_set_callback(
2078 subreq
, get_fnum_from_path_opened_dir
, req
);
2082 if (tevent_req_nterror(req
, status
)) {
2085 tevent_req_done(req
);
2088 static void get_fnum_from_path_opened_reparse(struct tevent_req
*subreq
)
2090 struct tevent_req
*req
= tevent_req_callback_data(
2091 subreq
, struct tevent_req
);
2092 struct get_fnum_from_path_state
*state
= tevent_req_data(
2093 req
, struct get_fnum_from_path_state
);
2094 NTSTATUS status
= cli_smb2_create_fnum_recv(
2095 subreq
, &state
->fnum
, NULL
, NULL
, NULL
, NULL
);
2096 tevent_req_simple_finish_ntstatus(subreq
, status
);
2099 static void get_fnum_from_path_opened_dir(struct tevent_req
*subreq
)
2101 /* Abstraction violation, but these two are just the same... */
2102 get_fnum_from_path_opened_reparse(subreq
);
2105 static NTSTATUS
get_fnum_from_path_recv(
2106 struct tevent_req
*req
, uint16_t *pfnum
)
2108 struct get_fnum_from_path_state
*state
= tevent_req_data(
2109 req
, struct get_fnum_from_path_state
);
2110 NTSTATUS status
= NT_STATUS_OK
;
2112 if (!tevent_req_is_nterror(req
, &status
)) {
2113 *pfnum
= state
->fnum
;
2115 tevent_req_received(req
);
2119 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
2121 uint32_t desired_access
,
2124 TALLOC_CTX
*frame
= talloc_stackframe();
2125 struct tevent_context
*ev
= NULL
;
2126 struct tevent_req
*req
= NULL
;
2127 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
2129 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2130 status
= NT_STATUS_INVALID_PARAMETER
;
2133 ev
= samba_tevent_context_init(frame
);
2137 req
= get_fnum_from_path_send(frame
, ev
, cli
, name
, desired_access
);
2141 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2144 status
= get_fnum_from_path_recv(req
, pfnum
);
2150 /***************************************************************
2151 Wrapper that allows SMB2 to query a path info (ALTNAME level).
2153 ***************************************************************/
2155 NTSTATUS
cli_smb2_qpathinfo_alt_name(struct cli_state
*cli
,
2160 DATA_BLOB outbuf
= data_blob_null
;
2161 uint16_t fnum
= 0xffff;
2162 uint32_t altnamelen
= 0;
2163 TALLOC_CTX
*frame
= talloc_stackframe();
2165 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2167 * Can't use sync call while an async call is in flight
2169 status
= NT_STATUS_INVALID_PARAMETER
;
2173 status
= get_fnum_from_path(cli
,
2175 FILE_READ_ATTRIBUTES
,
2178 if (!NT_STATUS_IS_OK(status
)) {
2182 status
= cli_smb2_query_info_fnum(
2185 1, /* in_info_type */
2186 (SMB_FILE_ALTERNATE_NAME_INFORMATION
- 1000), /* in_file_info_class */
2187 0xFFFF, /* in_max_output_length */
2188 NULL
, /* in_input_buffer */
2189 0, /* in_additional_info */
2194 if (!NT_STATUS_IS_OK(status
)) {
2198 /* Parse the reply. */
2199 if (outbuf
.length
< 4) {
2200 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2204 altnamelen
= IVAL(outbuf
.data
, 0);
2205 if (altnamelen
> outbuf
.length
- 4) {
2206 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2210 if (altnamelen
> 0) {
2212 char *short_name
= NULL
;
2213 ret
= pull_string_talloc(frame
,
2215 FLAGS2_UNICODE_STRINGS
,
2220 if (ret
== (size_t)-1) {
2221 /* Bad conversion. */
2222 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2226 fstrcpy(alt_name
, short_name
);
2231 status
= NT_STATUS_OK
;
2235 if (fnum
!= 0xffff) {
2236 cli_smb2_close_fnum(cli
, fnum
);
2239 cli
->raw_status
= status
;
2245 /***************************************************************
2246 Wrapper that allows SMB2 to get pathname attributes.
2248 ***************************************************************/
2250 NTSTATUS
cli_smb2_getatr(struct cli_state
*cli
,
2257 uint16_t fnum
= 0xffff;
2258 struct timespec write_time_ts
;
2259 TALLOC_CTX
*frame
= talloc_stackframe();
2261 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2263 * Can't use sync call while an async call is in flight
2265 status
= NT_STATUS_INVALID_PARAMETER
;
2269 status
= get_fnum_from_path(cli
,
2271 FILE_READ_ATTRIBUTES
,
2274 if (!NT_STATUS_IS_OK(status
)) {
2278 status
= cli_qfileinfo_basic(
2283 NULL
, /* create_time */
2284 NULL
, /* access_time */
2286 NULL
, /* change_time */
2288 if (!NT_STATUS_IS_OK(status
)) {
2291 if (write_time
!= NULL
) {
2292 *write_time
= write_time_ts
.tv_sec
;
2297 if (fnum
!= 0xffff) {
2298 cli_smb2_close_fnum(cli
, fnum
);
2301 cli
->raw_status
= status
;
2307 struct cli_smb2_qpathinfo2_state
{
2308 struct tevent_context
*ev
;
2309 struct cli_state
*cli
;
2312 NTSTATUS queryinfo_status
;
2313 struct timespec create_time
;
2314 struct timespec access_time
;
2315 struct timespec write_time
;
2316 struct timespec change_time
;
2322 static void cli_smb2_qpathinfo2_opened(struct tevent_req
*subreq
);
2323 static void cli_smb2_qpathinfo2_done(struct tevent_req
*subreq
);
2324 static void cli_smb2_qpathinfo2_closed(struct tevent_req
*subreq
);
2326 struct tevent_req
*cli_smb2_qpathinfo2_send(TALLOC_CTX
*mem_ctx
,
2327 struct tevent_context
*ev
,
2328 struct cli_state
*cli
,
2331 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
2332 struct cli_smb2_qpathinfo2_state
*state
= NULL
;
2334 req
= tevent_req_create(mem_ctx
,
2336 struct cli_smb2_qpathinfo2_state
);
2343 subreq
= get_fnum_from_path_send(mem_ctx
,
2347 FILE_READ_ATTRIBUTES
);
2348 if (tevent_req_nomem(subreq
, req
)) {
2349 return tevent_req_post(req
, ev
);
2351 tevent_req_set_callback(subreq
, cli_smb2_qpathinfo2_opened
, req
);
2355 static void cli_smb2_qpathinfo2_opened(struct tevent_req
*subreq
)
2357 struct tevent_req
*req
=
2358 tevent_req_callback_data(subreq
, struct tevent_req
);
2359 struct cli_smb2_qpathinfo2_state
*state
=
2360 tevent_req_data(req
, struct cli_smb2_qpathinfo2_state
);
2363 status
= get_fnum_from_path_recv(subreq
, &state
->fnum
);
2364 TALLOC_FREE(subreq
);
2365 if (tevent_req_nterror(req
, status
)) {
2369 subreq
= cli_qfileinfo_basic_send(state
,
2373 if (tevent_req_nomem(subreq
, req
)) {
2376 tevent_req_set_callback(subreq
, cli_smb2_qpathinfo2_done
, req
);
2379 static void cli_smb2_qpathinfo2_done(struct tevent_req
*subreq
)
2381 struct tevent_req
*req
=
2382 tevent_req_callback_data(subreq
, struct tevent_req
);
2383 struct cli_smb2_qpathinfo2_state
*state
=
2384 tevent_req_data(req
, struct cli_smb2_qpathinfo2_state
);
2386 state
->queryinfo_status
= cli_qfileinfo_basic_recv(subreq
,
2389 &state
->create_time
,
2390 &state
->access_time
,
2392 &state
->change_time
,
2394 TALLOC_FREE(subreq
);
2396 subreq
= cli_smb2_close_fnum_send(state
,
2400 if (tevent_req_nomem(subreq
, req
)) {
2403 tevent_req_set_callback(subreq
, cli_smb2_qpathinfo2_closed
, req
);
2406 static void cli_smb2_qpathinfo2_closed(struct tevent_req
*subreq
)
2408 struct tevent_req
*req
=
2409 tevent_req_callback_data(subreq
, struct tevent_req
);
2410 struct cli_smb2_qpathinfo2_state
*state
=
2411 tevent_req_data(req
, struct cli_smb2_qpathinfo2_state
);
2414 status
= cli_smb2_close_fnum_recv(subreq
);
2415 TALLOC_FREE(subreq
);
2416 if (tevent_req_nterror(req
, status
)) {
2419 if (tevent_req_nterror(req
, state
->queryinfo_status
)) {
2422 tevent_req_done(req
);
2425 NTSTATUS
cli_smb2_qpathinfo2_recv(struct tevent_req
*req
,
2426 struct timespec
*create_time
,
2427 struct timespec
*access_time
,
2428 struct timespec
*write_time
,
2429 struct timespec
*change_time
,
2434 struct cli_smb2_qpathinfo2_state
*state
=
2435 tevent_req_data(req
, struct cli_smb2_qpathinfo2_state
);
2438 if (tevent_req_is_nterror(req
, &status
)) {
2442 if (create_time
!= NULL
) {
2443 *create_time
= state
->create_time
;
2445 if (access_time
!= NULL
) {
2446 *access_time
= state
->access_time
;
2448 if (write_time
!= NULL
) {
2449 *write_time
= state
->write_time
;
2451 if (change_time
!= NULL
) {
2452 *change_time
= state
->change_time
;
2455 *attr
= state
->attr
;
2458 *size
= state
->size
;
2464 return NT_STATUS_OK
;
2467 /***************************************************************
2468 Wrapper that allows SMB2 to query pathname streams.
2470 ***************************************************************/
2472 NTSTATUS
cli_smb2_qpathinfo_streams(struct cli_state
*cli
,
2474 TALLOC_CTX
*mem_ctx
,
2475 unsigned int *pnum_streams
,
2476 struct stream_struct
**pstreams
)
2479 uint16_t fnum
= 0xffff;
2480 DATA_BLOB outbuf
= data_blob_null
;
2481 TALLOC_CTX
*frame
= talloc_stackframe();
2483 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2485 * Can't use sync call while an async call is in flight
2487 status
= NT_STATUS_INVALID_PARAMETER
;
2491 status
= get_fnum_from_path(cli
,
2493 FILE_READ_ATTRIBUTES
,
2496 if (!NT_STATUS_IS_OK(status
)) {
2500 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2501 level 22 (SMB2_FILE_STREAM_INFORMATION). */
2503 status
= cli_smb2_query_info_fnum(
2506 1, /* in_info_type */
2507 (SMB_FILE_STREAM_INFORMATION
- 1000), /* in_file_info_class */
2508 0xFFFF, /* in_max_output_length */
2509 NULL
, /* in_input_buffer */
2510 0, /* in_additional_info */
2515 if (!NT_STATUS_IS_OK(status
)) {
2519 /* Parse the reply. */
2520 if (!parse_streams_blob(mem_ctx
,
2525 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2531 if (fnum
!= 0xffff) {
2532 cli_smb2_close_fnum(cli
, fnum
);
2535 cli
->raw_status
= status
;
2541 /***************************************************************
2542 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2545 ***************************************************************/
2547 NTSTATUS
cli_smb2_setpathinfo(struct cli_state
*cli
,
2549 uint8_t in_info_type
,
2550 uint8_t in_file_info_class
,
2551 const DATA_BLOB
*p_in_data
)
2554 uint16_t fnum
= 0xffff;
2555 TALLOC_CTX
*frame
= talloc_stackframe();
2557 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2559 * Can't use sync call while an async call is in flight
2561 status
= NT_STATUS_INVALID_PARAMETER
;
2565 status
= get_fnum_from_path(cli
,
2567 FILE_WRITE_ATTRIBUTES
,
2570 if (!NT_STATUS_IS_OK(status
)) {
2574 status
= cli_smb2_set_info_fnum(
2579 p_in_data
, /* in_input_buffer */
2580 0); /* in_additional_info */
2583 if (fnum
!= 0xffff) {
2584 cli_smb2_close_fnum(cli
, fnum
);
2587 cli
->raw_status
= status
;
2594 /***************************************************************
2595 Wrapper that allows SMB2 to set pathname attributes.
2597 ***************************************************************/
2599 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
2604 uint8_t inbuf_store
[40];
2605 DATA_BLOB inbuf
= data_blob_null
;
2607 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2608 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2610 inbuf
.data
= inbuf_store
;
2611 inbuf
.length
= sizeof(inbuf_store
);
2612 data_blob_clear(&inbuf
);
2615 * SMB1 uses attr == 0 to clear all attributes
2616 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2617 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2618 * request attribute change.
2620 * SMB2 uses exactly the reverse. Unfortunately as the
2621 * cli_setatr() ABI is exposed inside libsmbclient,
2622 * we must make the SMB2 cli_smb2_setatr() call
2623 * export the same ABI as the SMB1 cli_setatr()
2624 * which calls it. This means reversing the sense
2625 * of the requested attr argument if it's zero
2626 * or FILE_ATTRIBUTE_NORMAL.
2628 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2632 attr
= FILE_ATTRIBUTE_NORMAL
;
2633 } else if (attr
== FILE_ATTRIBUTE_NORMAL
) {
2637 SIVAL(inbuf
.data
, 32, attr
);
2639 put_long_date((char *)inbuf
.data
+ 16,mtime
);
2641 /* Set all the other times to -1. */
2642 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
2643 SBVAL(inbuf
.data
, 8, 0xFFFFFFFFFFFFFFFFLL
);
2644 SBVAL(inbuf
.data
, 24, 0xFFFFFFFFFFFFFFFFLL
);
2646 return cli_smb2_setpathinfo(cli
,
2648 1, /* in_info_type */
2649 /* in_file_info_class */
2650 SMB_FILE_BASIC_INFORMATION
- 1000,
2655 /***************************************************************
2656 Wrapper that allows SMB2 to set file handle times.
2658 ***************************************************************/
2660 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
2666 uint8_t inbuf_store
[40];
2667 DATA_BLOB inbuf
= data_blob_null
;
2669 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2671 * Can't use sync call while an async call is in flight
2673 return NT_STATUS_INVALID_PARAMETER
;
2676 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2677 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2679 inbuf
.data
= inbuf_store
;
2680 inbuf
.length
= sizeof(inbuf_store
);
2681 data_blob_clear(&inbuf
);
2683 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
2684 if (change_time
!= 0) {
2685 put_long_date((char *)inbuf
.data
+ 24, change_time
);
2687 if (access_time
!= 0) {
2688 put_long_date((char *)inbuf
.data
+ 8, access_time
);
2690 if (write_time
!= 0) {
2691 put_long_date((char *)inbuf
.data
+ 16, write_time
);
2694 cli
->raw_status
= cli_smb2_set_info_fnum(
2697 1, /* in_info_type */
2698 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
2699 &inbuf
, /* in_input_buffer */
2700 0); /* in_additional_info */
2702 return cli
->raw_status
;
2705 /***************************************************************
2706 Wrapper that allows SMB2 to query disk attributes (size).
2708 ***************************************************************/
2710 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, const char *path
,
2711 uint64_t *bsize
, uint64_t *total
, uint64_t *avail
)
2714 uint16_t fnum
= 0xffff;
2715 DATA_BLOB outbuf
= data_blob_null
;
2716 uint32_t sectors_per_unit
= 0;
2717 uint32_t bytes_per_sector
= 0;
2718 uint64_t total_size
= 0;
2719 uint64_t size_free
= 0;
2720 TALLOC_CTX
*frame
= talloc_stackframe();
2722 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2724 * Can't use sync call while an async call is in flight
2726 status
= NT_STATUS_INVALID_PARAMETER
;
2730 /* First open the top level directory. */
2731 status
= cli_smb2_create_fnum(cli
,
2733 (struct cli_smb2_create_flags
){0},
2734 SMB2_IMPERSONATION_IMPERSONATION
,
2735 FILE_READ_ATTRIBUTES
, /* desired_access */
2736 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2737 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
2738 FILE_OPEN
, /* create_disposition */
2739 FILE_DIRECTORY_FILE
, /* create_options */
2746 if (!NT_STATUS_IS_OK(status
)) {
2750 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2751 level 3 (SMB_FS_SIZE_INFORMATION). */
2753 status
= cli_smb2_query_info_fnum(
2756 2, /* in_info_type */
2757 3, /* in_file_info_class */
2758 0xFFFF, /* in_max_output_length */
2759 NULL
, /* in_input_buffer */
2760 0, /* in_additional_info */
2764 if (!NT_STATUS_IS_OK(status
)) {
2768 /* Parse the reply. */
2769 if (outbuf
.length
!= 24) {
2770 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2774 total_size
= BVAL(outbuf
.data
, 0);
2775 size_free
= BVAL(outbuf
.data
, 8);
2776 sectors_per_unit
= IVAL(outbuf
.data
, 16);
2777 bytes_per_sector
= IVAL(outbuf
.data
, 20);
2780 *bsize
= (uint64_t)sectors_per_unit
* (uint64_t)bytes_per_sector
;
2783 *total
= total_size
;
2789 status
= NT_STATUS_OK
;
2793 if (fnum
!= 0xffff) {
2794 cli_smb2_close_fnum(cli
, fnum
);
2797 cli
->raw_status
= status
;
2803 /***************************************************************
2804 Wrapper that allows SMB2 to query file system sizes.
2806 ***************************************************************/
2808 NTSTATUS
cli_smb2_get_fs_full_size_info(struct cli_state
*cli
,
2809 uint64_t *total_allocation_units
,
2810 uint64_t *caller_allocation_units
,
2811 uint64_t *actual_allocation_units
,
2812 uint64_t *sectors_per_allocation_unit
,
2813 uint64_t *bytes_per_sector
)
2816 uint16_t fnum
= 0xffff;
2817 DATA_BLOB outbuf
= data_blob_null
;
2818 TALLOC_CTX
*frame
= talloc_stackframe();
2820 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2822 * Can't use sync call while an async call is in flight
2824 status
= NT_STATUS_INVALID_PARAMETER
;
2828 /* First open the top level directory. */
2830 cli_smb2_create_fnum(cli
, "",
2831 (struct cli_smb2_create_flags
){0},
2832 SMB2_IMPERSONATION_IMPERSONATION
,
2833 FILE_READ_ATTRIBUTES
, /* desired_access */
2834 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2835 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2836 FILE_SHARE_DELETE
, /* share_access */
2837 FILE_OPEN
, /* create_disposition */
2838 FILE_DIRECTORY_FILE
, /* create_options */
2845 if (!NT_STATUS_IS_OK(status
)) {
2849 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2850 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2852 status
= cli_smb2_query_info_fnum(
2855 SMB2_0_INFO_FILESYSTEM
, /* in_info_type */
2856 SMB_FS_FULL_SIZE_INFORMATION
- 1000, /* in_file_info_class */
2857 0xFFFF, /* in_max_output_length */
2858 NULL
, /* in_input_buffer */
2859 0, /* in_additional_info */
2863 if (!NT_STATUS_IS_OK(status
)) {
2867 if (outbuf
.length
< 32) {
2868 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2872 *total_allocation_units
= BIG_UINT(outbuf
.data
, 0);
2873 *caller_allocation_units
= BIG_UINT(outbuf
.data
, 8);
2874 *actual_allocation_units
= BIG_UINT(outbuf
.data
, 16);
2875 *sectors_per_allocation_unit
= (uint64_t)IVAL(outbuf
.data
, 24);
2876 *bytes_per_sector
= (uint64_t)IVAL(outbuf
.data
, 28);
2880 if (fnum
!= 0xffff) {
2881 cli_smb2_close_fnum(cli
, fnum
);
2884 cli
->raw_status
= status
;
2890 /***************************************************************
2891 Wrapper that allows SMB2 to query file system attributes.
2893 ***************************************************************/
2895 NTSTATUS
cli_smb2_get_fs_attr_info(struct cli_state
*cli
, uint32_t *fs_attr
)
2898 uint16_t fnum
= 0xffff;
2899 DATA_BLOB outbuf
= data_blob_null
;
2900 TALLOC_CTX
*frame
= talloc_stackframe();
2902 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2904 * Can't use sync call while an async call is in flight
2906 status
= NT_STATUS_INVALID_PARAMETER
;
2910 /* First open the top level directory. */
2912 cli_smb2_create_fnum(cli
, "",
2913 (struct cli_smb2_create_flags
){0},
2914 SMB2_IMPERSONATION_IMPERSONATION
,
2915 FILE_READ_ATTRIBUTES
, /* desired_access */
2916 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2917 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2918 FILE_SHARE_DELETE
, /* share_access */
2919 FILE_OPEN
, /* create_disposition */
2920 FILE_DIRECTORY_FILE
, /* create_options */
2927 if (!NT_STATUS_IS_OK(status
)) {
2931 status
= cli_smb2_query_info_fnum(
2934 2, /* in_info_type */
2935 5, /* in_file_info_class */
2936 0xFFFF, /* in_max_output_length */
2937 NULL
, /* in_input_buffer */
2938 0, /* in_additional_info */
2942 if (!NT_STATUS_IS_OK(status
)) {
2946 if (outbuf
.length
< 12) {
2947 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2951 *fs_attr
= IVAL(outbuf
.data
, 0);
2955 if (fnum
!= 0xffff) {
2956 cli_smb2_close_fnum(cli
, fnum
);
2959 cli
->raw_status
= status
;
2965 /***************************************************************
2966 Wrapper that allows SMB2 to query file system volume info.
2968 ***************************************************************/
2970 NTSTATUS
cli_smb2_get_fs_volume_info(struct cli_state
*cli
,
2971 TALLOC_CTX
*mem_ctx
,
2972 char **_volume_name
,
2973 uint32_t *pserial_number
,
2977 uint16_t fnum
= 0xffff;
2978 DATA_BLOB outbuf
= data_blob_null
;
2980 char *volume_name
= NULL
;
2981 TALLOC_CTX
*frame
= talloc_stackframe();
2983 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2985 * Can't use sync call while an async call is in flight
2987 status
= NT_STATUS_INVALID_PARAMETER
;
2991 /* First open the top level directory. */
2993 cli_smb2_create_fnum(cli
, "",
2994 (struct cli_smb2_create_flags
){0},
2995 SMB2_IMPERSONATION_IMPERSONATION
,
2996 FILE_READ_ATTRIBUTES
, /* desired_access */
2997 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2998 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2999 FILE_SHARE_DELETE
, /* share_access */
3000 FILE_OPEN
, /* create_disposition */
3001 FILE_DIRECTORY_FILE
, /* create_options */
3008 if (!NT_STATUS_IS_OK(status
)) {
3012 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
3013 level 1 (SMB_FS_VOLUME_INFORMATION). */
3015 status
= cli_smb2_query_info_fnum(
3018 SMB2_0_INFO_FILESYSTEM
, /* in_info_type */
3019 /* in_file_info_class */
3020 SMB_FS_VOLUME_INFORMATION
- 1000,
3021 0xFFFF, /* in_max_output_length */
3022 NULL
, /* in_input_buffer */
3023 0, /* in_additional_info */
3027 if (!NT_STATUS_IS_OK(status
)) {
3031 if (outbuf
.length
< 24) {
3032 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3038 ts
= interpret_long_date((char *)outbuf
.data
);
3041 if (pserial_number
) {
3042 *pserial_number
= IVAL(outbuf
.data
,8);
3044 nlen
= IVAL(outbuf
.data
,12);
3045 if (nlen
+ 18 < 18) {
3047 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3051 * The next check is safe as we know outbuf.length >= 24
3054 if (nlen
> (outbuf
.length
- 18)) {
3055 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3059 pull_string_talloc(mem_ctx
,
3060 (const char *)outbuf
.data
,
3066 if (volume_name
== NULL
) {
3067 status
= map_nt_error_from_unix(errno
);
3071 *_volume_name
= volume_name
;
3075 if (fnum
!= 0xffff) {
3076 cli_smb2_close_fnum(cli
, fnum
);
3079 cli
->raw_status
= status
;
3085 struct cli_smb2_mxac_state
{
3086 struct tevent_context
*ev
;
3087 struct cli_state
*cli
;
3089 struct smb2_create_blobs in_cblobs
;
3095 static void cli_smb2_mxac_opened(struct tevent_req
*subreq
);
3096 static void cli_smb2_mxac_closed(struct tevent_req
*subreq
);
3098 struct tevent_req
*cli_smb2_query_mxac_send(TALLOC_CTX
*mem_ctx
,
3099 struct tevent_context
*ev
,
3100 struct cli_state
*cli
,
3103 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
3104 struct cli_smb2_mxac_state
*state
= NULL
;
3107 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_mxac_state
);
3111 *state
= (struct cli_smb2_mxac_state
) {
3117 status
= smb2_create_blob_add(state
,
3119 SMB2_CREATE_TAG_MXAC
,
3120 data_blob(NULL
, 0));
3121 if (tevent_req_nterror(req
, status
)) {
3122 return tevent_req_post(req
, ev
);
3125 subreq
= cli_smb2_create_fnum_send(
3130 (struct cli_smb2_create_flags
){0},
3131 SMB2_IMPERSONATION_IMPERSONATION
,
3132 FILE_READ_ATTRIBUTES
,
3133 0, /* file attributes */
3134 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
3136 0, /* create_options */
3138 if (tevent_req_nomem(subreq
, req
)) {
3139 return tevent_req_post(req
, ev
);
3141 tevent_req_set_callback(subreq
, cli_smb2_mxac_opened
, req
);
3145 static void cli_smb2_mxac_opened(struct tevent_req
*subreq
)
3147 struct tevent_req
*req
= tevent_req_callback_data(
3148 subreq
, struct tevent_req
);
3149 struct cli_smb2_mxac_state
*state
= tevent_req_data(
3150 req
, struct cli_smb2_mxac_state
);
3151 struct smb2_create_blobs out_cblobs
= {0};
3152 struct smb2_create_blob
*mxac_blob
= NULL
;
3155 status
= cli_smb2_create_fnum_recv(
3156 subreq
, &state
->fnum
, NULL
, state
, &out_cblobs
, NULL
);
3157 TALLOC_FREE(subreq
);
3159 if (tevent_req_nterror(req
, status
)) {
3163 mxac_blob
= smb2_create_blob_find(&out_cblobs
, SMB2_CREATE_TAG_MXAC
);
3164 if (mxac_blob
== NULL
) {
3165 state
->status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3168 if (mxac_blob
->data
.length
!= 8) {
3169 state
->status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3173 state
->status
= NT_STATUS(IVAL(mxac_blob
->data
.data
, 0));
3174 state
->mxac
= IVAL(mxac_blob
->data
.data
, 4);
3177 subreq
= cli_smb2_close_fnum_send(
3178 state
, state
->ev
, state
->cli
, state
->fnum
);
3179 if (tevent_req_nomem(subreq
, req
)) {
3182 tevent_req_set_callback(subreq
, cli_smb2_mxac_closed
, req
);
3187 static void cli_smb2_mxac_closed(struct tevent_req
*subreq
)
3189 struct tevent_req
*req
= tevent_req_callback_data(
3190 subreq
, struct tevent_req
);
3193 status
= cli_smb2_close_fnum_recv(subreq
);
3194 if (tevent_req_nterror(req
, status
)) {
3198 tevent_req_done(req
);
3201 NTSTATUS
cli_smb2_query_mxac_recv(struct tevent_req
*req
, uint32_t *mxac
)
3203 struct cli_smb2_mxac_state
*state
= tevent_req_data(
3204 req
, struct cli_smb2_mxac_state
);
3207 if (tevent_req_is_nterror(req
, &status
)) {
3211 if (!NT_STATUS_IS_OK(state
->status
)) {
3212 return state
->status
;
3215 *mxac
= state
->mxac
;
3216 return NT_STATUS_OK
;
3219 NTSTATUS
cli_smb2_query_mxac(struct cli_state
*cli
,
3223 TALLOC_CTX
*frame
= talloc_stackframe();
3224 struct tevent_context
*ev
= NULL
;
3225 struct tevent_req
*req
= NULL
;
3226 NTSTATUS status
= NT_STATUS_INTERNAL_ERROR
;
3229 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3231 * Can't use sync call while an async call is in flight
3233 status
= NT_STATUS_INVALID_PARAMETER
;
3237 ev
= samba_tevent_context_init(frame
);
3241 req
= cli_smb2_query_mxac_send(frame
, ev
, cli
, fname
);
3245 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
3249 status
= cli_smb2_query_mxac_recv(req
, _mxac
);
3252 cli
->raw_status
= status
;
3257 struct cli_smb2_rename_fnum_state
{
3261 static void cli_smb2_rename_fnum_done(struct tevent_req
*subreq
);
3263 static struct tevent_req
*cli_smb2_rename_fnum_send(
3264 TALLOC_CTX
*mem_ctx
,
3265 struct tevent_context
*ev
,
3266 struct cli_state
*cli
,
3268 const char *fname_dst
,
3271 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
3272 struct cli_smb2_rename_fnum_state
*state
= NULL
;
3273 size_t namelen
= strlen(fname_dst
);
3274 smb_ucs2_t
*converted_str
= NULL
;
3275 size_t converted_size_bytes
= 0;
3279 req
= tevent_req_create(
3280 mem_ctx
, &state
, struct cli_smb2_rename_fnum_state
);
3286 * SMB2 is pickier about pathnames. Ensure it doesn't start in
3289 if (*fname_dst
== '\\') {
3294 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
3297 if (namelen
> 0 && fname_dst
[namelen
-1] == '\\') {
3298 fname_dst
= talloc_strndup(state
, fname_dst
, namelen
-1);
3299 if (tevent_req_nomem(fname_dst
, req
)) {
3300 return tevent_req_post(req
, ev
);
3304 ok
= push_ucs2_talloc(
3305 state
, &converted_str
, fname_dst
, &converted_size_bytes
);
3307 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3308 return tevent_req_post(req
, ev
);
3312 * W2K8 insists the dest name is not null terminated. Remove
3313 * the last 2 zero bytes and reduce the name length.
3315 if (converted_size_bytes
< 2) {
3316 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3317 return tevent_req_post(req
, ev
);
3319 converted_size_bytes
-= 2;
3321 inbuf_size
= 20 + converted_size_bytes
;
3322 if (inbuf_size
< 20) {
3323 /* Integer wrap check. */
3324 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3325 return tevent_req_post(req
, ev
);
3329 * The Windows 10 SMB2 server has a minimum length
3330 * for a SMB2_FILE_RENAME_INFORMATION buffer of
3331 * 24 bytes. It returns NT_STATUS_INFO_LENGTH_MISMATCH
3332 * if the length is less. This isn't an alignment
3333 * issue as Windows client happily 2-byte align
3334 * for larget target name sizes. Also the Windows 10
3335 * SMB1 server doesn't have this restriction.
3337 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14403
3339 inbuf_size
= MAX(inbuf_size
, 24);
3341 state
->inbuf
= data_blob_talloc_zero(state
, inbuf_size
);
3342 if (tevent_req_nomem(state
->inbuf
.data
, req
)) {
3343 return tevent_req_post(req
, ev
);
3347 SCVAL(state
->inbuf
.data
, 0, 1);
3350 SIVAL(state
->inbuf
.data
, 16, converted_size_bytes
);
3351 memcpy(state
->inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
3353 TALLOC_FREE(converted_str
);
3355 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3356 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3358 subreq
= cli_smb2_set_info_fnum_send(
3359 state
, /* mem_ctx */
3363 1, /* in_info_type */
3364 SMB_FILE_RENAME_INFORMATION
- 1000, /* in_file_info_class */
3365 &state
->inbuf
, /* in_input_buffer */
3366 0); /* in_additional_info */
3367 if (tevent_req_nomem(subreq
, req
)) {
3368 return tevent_req_post(req
, ev
);
3370 tevent_req_set_callback(subreq
, cli_smb2_rename_fnum_done
, req
);
3374 static void cli_smb2_rename_fnum_done(struct tevent_req
*subreq
)
3376 NTSTATUS status
= cli_smb2_set_info_fnum_recv(subreq
);
3377 tevent_req_simple_finish_ntstatus(subreq
, status
);
3380 static NTSTATUS
cli_smb2_rename_fnum_recv(struct tevent_req
*req
)
3382 return tevent_req_simple_recv_ntstatus(req
);
3385 /***************************************************************
3386 Wrapper that allows SMB2 to rename a file.
3387 ***************************************************************/
3389 struct cli_smb2_rename_state
{
3390 struct tevent_context
*ev
;
3391 struct cli_state
*cli
;
3392 const char *fname_dst
;
3396 NTSTATUS rename_status
;
3399 static void cli_smb2_rename_opened(struct tevent_req
*subreq
);
3400 static void cli_smb2_rename_renamed(struct tevent_req
*subreq
);
3401 static void cli_smb2_rename_closed(struct tevent_req
*subreq
);
3403 struct tevent_req
*cli_smb2_rename_send(
3404 TALLOC_CTX
*mem_ctx
,
3405 struct tevent_context
*ev
,
3406 struct cli_state
*cli
,
3407 const char *fname_src
,
3408 const char *fname_dst
,
3411 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
3412 struct cli_smb2_rename_state
*state
= NULL
;
3415 req
= tevent_req_create(
3416 mem_ctx
, &state
, struct cli_smb2_rename_state
);
3422 * Strip a MSDFS path from fname_dst if we were given one.
3424 status
= cli_dfs_target_check(state
,
3428 if (tevent_req_nterror(req
, status
)) {
3429 return tevent_req_post(req
, ev
);
3434 state
->fname_dst
= fname_dst
;
3435 state
->replace
= replace
;
3437 subreq
= get_fnum_from_path_send(
3438 state
, ev
, cli
, fname_src
, DELETE_ACCESS
);
3439 if (tevent_req_nomem(subreq
, req
)) {
3440 return tevent_req_post(req
, ev
);
3442 tevent_req_set_callback(subreq
, cli_smb2_rename_opened
, req
);
3446 static void cli_smb2_rename_opened(struct tevent_req
*subreq
)
3448 struct tevent_req
*req
= tevent_req_callback_data(
3449 subreq
, struct tevent_req
);
3450 struct cli_smb2_rename_state
*state
= tevent_req_data(
3451 req
, struct cli_smb2_rename_state
);
3454 status
= get_fnum_from_path_recv(subreq
, &state
->fnum
);
3455 TALLOC_FREE(subreq
);
3456 if (tevent_req_nterror(req
, status
)) {
3460 subreq
= cli_smb2_rename_fnum_send(
3467 if (tevent_req_nomem(subreq
, req
)) {
3470 tevent_req_set_callback(subreq
, cli_smb2_rename_renamed
, req
);
3473 static void cli_smb2_rename_renamed(struct tevent_req
*subreq
)
3475 struct tevent_req
*req
= tevent_req_callback_data(
3476 subreq
, struct tevent_req
);
3477 struct cli_smb2_rename_state
*state
= tevent_req_data(
3478 req
, struct cli_smb2_rename_state
);
3480 state
->rename_status
= cli_smb2_rename_fnum_recv(subreq
);
3481 TALLOC_FREE(subreq
);
3483 subreq
= cli_smb2_close_fnum_send(
3484 state
, state
->ev
, state
->cli
, state
->fnum
);
3485 if (tevent_req_nomem(subreq
, req
)) {
3488 tevent_req_set_callback(subreq
, cli_smb2_rename_closed
, req
);
3491 static void cli_smb2_rename_closed(struct tevent_req
*subreq
)
3493 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
3494 tevent_req_simple_finish_ntstatus(subreq
, status
);
3497 NTSTATUS
cli_smb2_rename_recv(struct tevent_req
*req
)
3499 struct cli_smb2_rename_state
*state
= tevent_req_data(
3500 req
, struct cli_smb2_rename_state
);
3501 NTSTATUS status
= NT_STATUS_OK
;
3503 if (!tevent_req_is_nterror(req
, &status
)) {
3504 status
= state
->rename_status
;
3506 tevent_req_received(req
);
3510 /***************************************************************
3511 Wrapper that allows SMB2 to set an EA on a fnum.
3513 ***************************************************************/
3515 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
3517 const char *ea_name
,
3522 DATA_BLOB inbuf
= data_blob_null
;
3524 char *ea_name_ascii
= NULL
;
3526 TALLOC_CTX
*frame
= talloc_stackframe();
3528 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3530 * Can't use sync call while an async call is in flight
3532 status
= NT_STATUS_INVALID_PARAMETER
;
3536 /* Marshall the SMB2 EA data. */
3537 if (ea_len
> 0xFFFF) {
3538 status
= NT_STATUS_INVALID_PARAMETER
;
3542 if (!push_ascii_talloc(frame
,
3546 status
= NT_STATUS_INVALID_PARAMETER
;
3550 if (namelen
< 2 || namelen
> 0xFF) {
3551 status
= NT_STATUS_INVALID_PARAMETER
;
3555 bloblen
= 8 + ea_len
+ namelen
;
3556 /* Round up to a 4 byte boundary. */
3557 bloblen
= ((bloblen
+ 3)&~3);
3559 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
3560 if (inbuf
.data
== NULL
) {
3561 status
= NT_STATUS_NO_MEMORY
;
3564 /* namelen doesn't include the NULL byte. */
3565 SCVAL(inbuf
.data
, 5, namelen
- 1);
3566 SSVAL(inbuf
.data
, 6, ea_len
);
3567 memcpy(inbuf
.data
+ 8, ea_name_ascii
, namelen
);
3568 memcpy(inbuf
.data
+ 8 + namelen
, ea_val
, ea_len
);
3570 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3571 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3573 status
= cli_smb2_set_info_fnum(
3576 1, /* in_info_type */
3577 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
3578 &inbuf
, /* in_input_buffer */
3579 0); /* in_additional_info */
3583 cli
->raw_status
= status
;
3589 /***************************************************************
3590 Wrapper that allows SMB2 to set an EA on a pathname.
3592 ***************************************************************/
3594 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
3596 const char *ea_name
,
3601 uint16_t fnum
= 0xffff;
3603 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3605 * Can't use sync call while an async call is in flight
3607 status
= NT_STATUS_INVALID_PARAMETER
;
3611 status
= get_fnum_from_path(cli
,
3616 if (!NT_STATUS_IS_OK(status
)) {
3620 status
= cli_set_ea_fnum(cli
,
3625 if (!NT_STATUS_IS_OK(status
)) {
3631 if (fnum
!= 0xffff) {
3632 cli_smb2_close_fnum(cli
, fnum
);
3635 cli
->raw_status
= status
;
3640 /***************************************************************
3641 Wrapper that allows SMB2 to get an EA list on a pathname.
3643 ***************************************************************/
3645 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
3649 struct ea_struct
**pea_array
)
3652 uint16_t fnum
= 0xffff;
3653 DATA_BLOB outbuf
= data_blob_null
;
3654 struct ea_list
*ea_list
= NULL
;
3655 struct ea_list
*eal
= NULL
;
3656 size_t ea_count
= 0;
3657 TALLOC_CTX
*frame
= talloc_stackframe();
3662 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3664 * Can't use sync call while an async call is in flight
3666 status
= NT_STATUS_INVALID_PARAMETER
;
3670 status
= get_fnum_from_path(cli
,
3675 if (!NT_STATUS_IS_OK(status
)) {
3679 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3680 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3682 status
= cli_smb2_query_info_fnum(
3685 1, /* in_info_type */
3686 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
3687 0xFFFF, /* in_max_output_length */
3688 NULL
, /* in_input_buffer */
3689 0, /* in_additional_info */
3694 if (!NT_STATUS_IS_OK(status
)) {
3698 /* Parse the reply. */
3699 ea_list
= read_nttrans_ea_list(ctx
,
3700 (const char *)outbuf
.data
,
3702 if (ea_list
== NULL
) {
3703 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3707 /* Convert to an array. */
3708 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
3713 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
3714 if (*pea_array
== NULL
) {
3715 status
= NT_STATUS_NO_MEMORY
;
3719 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
3720 (*pea_array
)[ea_count
++] = eal
->ea
;
3722 *pnum_eas
= ea_count
;
3727 if (fnum
!= 0xffff) {
3728 cli_smb2_close_fnum(cli
, fnum
);
3731 cli
->raw_status
= status
;
3737 /***************************************************************
3738 Wrapper that allows SMB2 to get user quota.
3740 ***************************************************************/
3742 NTSTATUS
cli_smb2_get_user_quota(struct cli_state
*cli
,
3744 SMB_NTQUOTA_STRUCT
*pqt
)
3747 DATA_BLOB inbuf
= data_blob_null
;
3748 DATA_BLOB info_blob
= data_blob_null
;
3749 DATA_BLOB outbuf
= data_blob_null
;
3750 TALLOC_CTX
*frame
= talloc_stackframe();
3752 unsigned int offset
;
3753 struct smb2_query_quota_info query
= {0};
3754 struct file_get_quota_info info
= {0};
3755 enum ndr_err_code err
;
3756 struct ndr_push
*ndr_push
= NULL
;
3758 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3760 * Can't use sync call while an async call is in flight
3762 status
= NT_STATUS_INVALID_PARAMETER
;
3766 sid_len
= ndr_size_dom_sid(&pqt
->sid
, 0);
3768 query
.return_single
= 1;
3770 info
.next_entry_offset
= 0;
3771 info
.sid_length
= sid_len
;
3772 info
.sid
= pqt
->sid
;
3774 err
= ndr_push_struct_blob(
3778 (ndr_push_flags_fn_t
)ndr_push_file_get_quota_info
);
3780 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3781 status
= NT_STATUS_INTERNAL_ERROR
;
3785 query
.sid_list_length
= info_blob
.length
;
3786 ndr_push
= ndr_push_init_ctx(frame
);
3788 status
= NT_STATUS_NO_MEMORY
;
3792 err
= ndr_push_smb2_query_quota_info(ndr_push
,
3793 NDR_SCALARS
| NDR_BUFFERS
,
3796 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3797 status
= NT_STATUS_INTERNAL_ERROR
;
3801 err
= ndr_push_array_uint8(ndr_push
, NDR_SCALARS
, info_blob
.data
,
3804 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3805 status
= NT_STATUS_INTERNAL_ERROR
;
3808 inbuf
.data
= ndr_push
->data
;
3809 inbuf
.length
= ndr_push
->offset
;
3811 status
= cli_smb2_query_info_fnum(
3814 4, /* in_info_type */
3815 0, /* in_file_info_class */
3816 0xFFFF, /* in_max_output_length */
3817 &inbuf
, /* in_input_buffer */
3818 0, /* in_additional_info */
3823 if (!NT_STATUS_IS_OK(status
)) {
3827 if (!parse_user_quota_record(outbuf
.data
, outbuf
.length
, &offset
,
3829 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3830 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3834 cli
->raw_status
= status
;
3840 /***************************************************************
3841 Wrapper that allows SMB2 to list user quota.
3843 ***************************************************************/
3845 NTSTATUS
cli_smb2_list_user_quota_step(struct cli_state
*cli
,
3846 TALLOC_CTX
*mem_ctx
,
3848 SMB_NTQUOTA_LIST
**pqt_list
,
3852 DATA_BLOB inbuf
= data_blob_null
;
3853 DATA_BLOB outbuf
= data_blob_null
;
3854 TALLOC_CTX
*frame
= talloc_stackframe();
3855 struct smb2_query_quota_info info
= {0};
3856 enum ndr_err_code err
;
3858 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3860 * Can't use sync call while an async call is in flight
3862 status
= NT_STATUS_INVALID_PARAMETER
;
3866 info
.restart_scan
= first
? 1 : 0;
3868 err
= ndr_push_struct_blob(
3872 (ndr_push_flags_fn_t
)ndr_push_smb2_query_quota_info
);
3874 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3875 status
= NT_STATUS_INTERNAL_ERROR
;
3879 status
= cli_smb2_query_info_fnum(
3882 4, /* in_info_type */
3883 0, /* in_file_info_class */
3884 0xFFFF, /* in_max_output_length */
3885 &inbuf
, /* in_input_buffer */
3886 0, /* in_additional_info */
3892 * safeguard against panic from calling parse_user_quota_list with
3895 if (NT_STATUS_IS_OK(status
) && outbuf
.length
== 0) {
3896 status
= NT_STATUS_NO_MORE_ENTRIES
;
3899 if (!NT_STATUS_IS_OK(status
)) {
3903 status
= parse_user_quota_list(outbuf
.data
, outbuf
.length
, mem_ctx
,
3907 cli
->raw_status
= status
;
3913 /***************************************************************
3914 Wrapper that allows SMB2 to get file system quota.
3916 ***************************************************************/
3918 NTSTATUS
cli_smb2_get_fs_quota_info(struct cli_state
*cli
,
3920 SMB_NTQUOTA_STRUCT
*pqt
)
3923 DATA_BLOB outbuf
= data_blob_null
;
3924 TALLOC_CTX
*frame
= talloc_stackframe();
3926 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3928 * Can't use sync call while an async call is in flight
3930 status
= NT_STATUS_INVALID_PARAMETER
;
3934 status
= cli_smb2_query_info_fnum(
3937 2, /* in_info_type */
3938 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
3939 0xFFFF, /* in_max_output_length */
3940 NULL
, /* in_input_buffer */
3941 0, /* in_additional_info */
3946 if (!NT_STATUS_IS_OK(status
)) {
3950 status
= parse_fs_quota_buffer(outbuf
.data
, outbuf
.length
, pqt
);
3953 cli
->raw_status
= status
;
3959 /***************************************************************
3960 Wrapper that allows SMB2 to set user quota.
3962 ***************************************************************/
3964 NTSTATUS
cli_smb2_set_user_quota(struct cli_state
*cli
,
3966 SMB_NTQUOTA_LIST
*qtl
)
3969 DATA_BLOB inbuf
= data_blob_null
;
3970 TALLOC_CTX
*frame
= talloc_stackframe();
3972 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3974 * Can't use sync call while an async call is in flight
3976 status
= NT_STATUS_INVALID_PARAMETER
;
3980 status
= build_user_quota_buffer(qtl
, 0, talloc_tos(), &inbuf
, NULL
);
3981 if (!NT_STATUS_IS_OK(status
)) {
3985 status
= cli_smb2_set_info_fnum(
3988 4, /* in_info_type */
3989 0, /* in_file_info_class */
3990 &inbuf
, /* in_input_buffer */
3991 0); /* in_additional_info */
3994 cli
->raw_status
= status
;
4001 NTSTATUS
cli_smb2_set_fs_quota_info(struct cli_state
*cli
,
4003 SMB_NTQUOTA_STRUCT
*pqt
)
4006 DATA_BLOB inbuf
= data_blob_null
;
4007 TALLOC_CTX
*frame
= talloc_stackframe();
4009 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4011 * Can't use sync call while an async call is in flight
4013 status
= NT_STATUS_INVALID_PARAMETER
;
4017 status
= build_fs_quota_buffer(talloc_tos(), pqt
, &inbuf
, 0);
4018 if (!NT_STATUS_IS_OK(status
)) {
4022 status
= cli_smb2_set_info_fnum(
4025 2, /* in_info_type */
4026 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
4027 &inbuf
, /* in_input_buffer */
4028 0); /* in_additional_info */
4030 cli
->raw_status
= status
;
4036 struct cli_smb2_read_state
{
4037 struct tevent_context
*ev
;
4038 struct cli_state
*cli
;
4039 struct smb2_hnd
*ph
;
4040 uint64_t start_offset
;
4046 static void cli_smb2_read_done(struct tevent_req
*subreq
);
4048 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
4049 struct tevent_context
*ev
,
4050 struct cli_state
*cli
,
4056 struct tevent_req
*req
, *subreq
;
4057 struct cli_smb2_read_state
*state
;
4059 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
4065 state
->start_offset
= (uint64_t)offset
;
4066 state
->size
= (uint32_t)size
;
4067 state
->received
= 0;
4070 status
= map_fnum_to_smb2_handle(cli
,
4073 if (tevent_req_nterror(req
, status
)) {
4074 return tevent_req_post(req
, ev
);
4077 subreq
= smb2cli_read_send(state
,
4080 state
->cli
->timeout
,
4081 state
->cli
->smb2
.session
,
4082 state
->cli
->smb2
.tcon
,
4084 state
->start_offset
,
4085 state
->ph
->fid_persistent
,
4086 state
->ph
->fid_volatile
,
4087 0, /* minimum_count */
4088 0); /* remaining_bytes */
4090 if (tevent_req_nomem(subreq
, req
)) {
4091 return tevent_req_post(req
, ev
);
4093 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
4097 static void cli_smb2_read_done(struct tevent_req
*subreq
)
4099 struct tevent_req
*req
= tevent_req_callback_data(
4100 subreq
, struct tevent_req
);
4101 struct cli_smb2_read_state
*state
= tevent_req_data(
4102 req
, struct cli_smb2_read_state
);
4105 status
= smb2cli_read_recv(subreq
, state
,
4106 &state
->buf
, &state
->received
);
4107 if (tevent_req_nterror(req
, status
)) {
4111 if (state
->received
> state
->size
) {
4112 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4116 tevent_req_done(req
);
4119 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
4124 struct cli_smb2_read_state
*state
= tevent_req_data(
4125 req
, struct cli_smb2_read_state
);
4127 if (tevent_req_is_nterror(req
, &status
)) {
4128 state
->cli
->raw_status
= status
;
4132 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
4133 * better make sure that you copy it away before you talloc_free(req).
4134 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
4136 *received
= (ssize_t
)state
->received
;
4137 *rcvbuf
= state
->buf
;
4138 state
->cli
->raw_status
= NT_STATUS_OK
;
4139 return NT_STATUS_OK
;
4142 struct cli_smb2_write_state
{
4143 struct tevent_context
*ev
;
4144 struct cli_state
*cli
;
4145 struct smb2_hnd
*ph
;
4153 static void cli_smb2_write_written(struct tevent_req
*req
);
4155 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
4156 struct tevent_context
*ev
,
4157 struct cli_state
*cli
,
4165 struct tevent_req
*req
, *subreq
= NULL
;
4166 struct cli_smb2_write_state
*state
= NULL
;
4168 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
4174 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4175 state
->flags
= (uint32_t)mode
;
4177 state
->offset
= (uint64_t)offset
;
4178 state
->size
= (uint32_t)size
;
4181 status
= map_fnum_to_smb2_handle(cli
,
4184 if (tevent_req_nterror(req
, status
)) {
4185 return tevent_req_post(req
, ev
);
4188 subreq
= smb2cli_write_send(state
,
4191 state
->cli
->timeout
,
4192 state
->cli
->smb2
.session
,
4193 state
->cli
->smb2
.tcon
,
4196 state
->ph
->fid_persistent
,
4197 state
->ph
->fid_volatile
,
4198 0, /* remaining_bytes */
4199 state
->flags
, /* flags */
4202 if (tevent_req_nomem(subreq
, req
)) {
4203 return tevent_req_post(req
, ev
);
4205 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
4209 static void cli_smb2_write_written(struct tevent_req
*subreq
)
4211 struct tevent_req
*req
= tevent_req_callback_data(
4212 subreq
, struct tevent_req
);
4213 struct cli_smb2_write_state
*state
= tevent_req_data(
4214 req
, struct cli_smb2_write_state
);
4218 status
= smb2cli_write_recv(subreq
, &written
);
4219 TALLOC_FREE(subreq
);
4220 if (tevent_req_nterror(req
, status
)) {
4224 state
->written
= written
;
4226 tevent_req_done(req
);
4229 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
4232 struct cli_smb2_write_state
*state
= tevent_req_data(
4233 req
, struct cli_smb2_write_state
);
4236 if (tevent_req_is_nterror(req
, &status
)) {
4237 state
->cli
->raw_status
= status
;
4238 tevent_req_received(req
);
4242 if (pwritten
!= NULL
) {
4243 *pwritten
= (size_t)state
->written
;
4245 state
->cli
->raw_status
= NT_STATUS_OK
;
4246 tevent_req_received(req
);
4247 return NT_STATUS_OK
;
4250 /***************************************************************
4251 Wrapper that allows SMB2 async write using an fnum.
4252 This is mostly cut-and-paste from Volker's code inside
4253 source3/libsmb/clireadwrite.c, adapted for SMB2.
4255 Done this way so I can reuse all the logic inside cli_push()
4257 ***************************************************************/
4259 struct cli_smb2_writeall_state
{
4260 struct tevent_context
*ev
;
4261 struct cli_state
*cli
;
4262 struct smb2_hnd
*ph
;
4270 static void cli_smb2_writeall_written(struct tevent_req
*req
);
4272 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
4273 struct tevent_context
*ev
,
4274 struct cli_state
*cli
,
4282 struct tevent_req
*req
, *subreq
= NULL
;
4283 struct cli_smb2_writeall_state
*state
= NULL
;
4288 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
4294 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4295 state
->flags
= (uint32_t)mode
;
4297 state
->offset
= (uint64_t)offset
;
4298 state
->size
= (uint32_t)size
;
4301 status
= map_fnum_to_smb2_handle(cli
,
4304 if (tevent_req_nterror(req
, status
)) {
4305 return tevent_req_post(req
, ev
);
4308 to_write
= state
->size
;
4309 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
4310 to_write
= MIN(max_size
, to_write
);
4311 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
4313 to_write
= MIN(max_size
, to_write
);
4316 subreq
= smb2cli_write_send(state
,
4319 state
->cli
->timeout
,
4320 state
->cli
->smb2
.session
,
4321 state
->cli
->smb2
.tcon
,
4324 state
->ph
->fid_persistent
,
4325 state
->ph
->fid_volatile
,
4326 0, /* remaining_bytes */
4327 state
->flags
, /* flags */
4328 state
->buf
+ state
->written
);
4330 if (tevent_req_nomem(subreq
, req
)) {
4331 return tevent_req_post(req
, ev
);
4333 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
4337 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
4339 struct tevent_req
*req
= tevent_req_callback_data(
4340 subreq
, struct tevent_req
);
4341 struct cli_smb2_writeall_state
*state
= tevent_req_data(
4342 req
, struct cli_smb2_writeall_state
);
4344 uint32_t written
, to_write
;
4348 status
= smb2cli_write_recv(subreq
, &written
);
4349 TALLOC_FREE(subreq
);
4350 if (tevent_req_nterror(req
, status
)) {
4354 state
->written
+= written
;
4356 if (state
->written
> state
->size
) {
4357 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4361 to_write
= state
->size
- state
->written
;
4363 if (to_write
== 0) {
4364 tevent_req_done(req
);
4368 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
4369 to_write
= MIN(max_size
, to_write
);
4370 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
4372 to_write
= MIN(max_size
, to_write
);
4375 subreq
= smb2cli_write_send(state
,
4378 state
->cli
->timeout
,
4379 state
->cli
->smb2
.session
,
4380 state
->cli
->smb2
.tcon
,
4382 state
->offset
+ state
->written
,
4383 state
->ph
->fid_persistent
,
4384 state
->ph
->fid_volatile
,
4385 0, /* remaining_bytes */
4386 state
->flags
, /* flags */
4387 state
->buf
+ state
->written
);
4389 if (tevent_req_nomem(subreq
, req
)) {
4392 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
4395 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
4398 struct cli_smb2_writeall_state
*state
= tevent_req_data(
4399 req
, struct cli_smb2_writeall_state
);
4402 if (tevent_req_is_nterror(req
, &status
)) {
4403 state
->cli
->raw_status
= status
;
4406 if (pwritten
!= NULL
) {
4407 *pwritten
= (size_t)state
->written
;
4409 state
->cli
->raw_status
= NT_STATUS_OK
;
4410 return NT_STATUS_OK
;
4413 struct cli_smb2_splice_state
{
4414 struct tevent_context
*ev
;
4415 struct cli_state
*cli
;
4416 struct smb2_hnd
*src_ph
;
4417 struct smb2_hnd
*dst_ph
;
4418 int (*splice_cb
)(off_t n
, void *priv
);
4425 struct req_resume_key_rsp resume_rsp
;
4426 struct srv_copychunk_copy cc_copy
;
4429 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
4430 struct tevent_req
*req
);
4432 static void cli_splice_copychunk_done(struct tevent_req
*subreq
)
4434 struct tevent_req
*req
= tevent_req_callback_data(
4435 subreq
, struct tevent_req
);
4436 struct cli_smb2_splice_state
*state
=
4437 tevent_req_data(req
,
4438 struct cli_smb2_splice_state
);
4439 struct smbXcli_conn
*conn
= state
->cli
->conn
;
4440 DATA_BLOB out_input_buffer
= data_blob_null
;
4441 DATA_BLOB out_output_buffer
= data_blob_null
;
4442 struct srv_copychunk_rsp cc_copy_rsp
;
4443 enum ndr_err_code ndr_ret
;
4446 status
= smb2cli_ioctl_recv(subreq
, state
,
4448 &out_output_buffer
);
4449 TALLOC_FREE(subreq
);
4450 if ((!NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
) ||
4451 state
->resized
) && tevent_req_nterror(req
, status
)) {
4455 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
, state
, &cc_copy_rsp
,
4456 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
4457 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4458 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4459 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4463 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
4464 uint32_t max_chunks
= MIN(cc_copy_rsp
.chunks_written
,
4465 cc_copy_rsp
.total_bytes_written
/ cc_copy_rsp
.chunk_bytes_written
);
4466 if ((cc_copy_rsp
.chunk_bytes_written
> smb2cli_conn_cc_chunk_len(conn
) ||
4467 max_chunks
> smb2cli_conn_cc_max_chunks(conn
)) &&
4468 tevent_req_nterror(req
, status
)) {
4472 state
->resized
= true;
4473 smb2cli_conn_set_cc_chunk_len(conn
, cc_copy_rsp
.chunk_bytes_written
);
4474 smb2cli_conn_set_cc_max_chunks(conn
, max_chunks
);
4476 if ((state
->src_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
4477 (state
->dst_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
4478 (state
->written
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
)) {
4479 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
4482 state
->src_offset
+= cc_copy_rsp
.total_bytes_written
;
4483 state
->dst_offset
+= cc_copy_rsp
.total_bytes_written
;
4484 state
->written
+= cc_copy_rsp
.total_bytes_written
;
4485 if (!state
->splice_cb(state
->written
, state
->priv
)) {
4486 tevent_req_nterror(req
, NT_STATUS_CANCELLED
);
4491 cli_splice_copychunk_send(state
, req
);
4494 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
4495 struct tevent_req
*req
)
4497 struct tevent_req
*subreq
;
4498 enum ndr_err_code ndr_ret
;
4499 struct smbXcli_conn
*conn
= state
->cli
->conn
;
4500 struct srv_copychunk_copy
*cc_copy
= &state
->cc_copy
;
4501 off_t src_offset
= state
->src_offset
;
4502 off_t dst_offset
= state
->dst_offset
;
4503 uint32_t req_len
= MIN(smb2cli_conn_cc_chunk_len(conn
) * smb2cli_conn_cc_max_chunks(conn
),
4504 state
->size
- state
->written
);
4505 DATA_BLOB in_input_buffer
= data_blob_null
;
4506 DATA_BLOB in_output_buffer
= data_blob_null
;
4508 if (state
->size
- state
->written
== 0) {
4509 tevent_req_done(req
);
4513 cc_copy
->chunk_count
= 0;
4515 cc_copy
->chunks
[cc_copy
->chunk_count
].source_off
= src_offset
;
4516 cc_copy
->chunks
[cc_copy
->chunk_count
].target_off
= dst_offset
;
4517 cc_copy
->chunks
[cc_copy
->chunk_count
].length
= MIN(req_len
,
4518 smb2cli_conn_cc_chunk_len(conn
));
4519 if (req_len
< cc_copy
->chunks
[cc_copy
->chunk_count
].length
) {
4520 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
4523 req_len
-= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4524 if ((src_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
) ||
4525 (dst_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
)) {
4526 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
4529 src_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4530 dst_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4531 cc_copy
->chunk_count
++;
4534 ndr_ret
= ndr_push_struct_blob(&in_input_buffer
, state
, cc_copy
,
4535 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
4536 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4537 DEBUG(0, ("failed to marshall copy chunk req\n"));
4538 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
4542 subreq
= smb2cli_ioctl_send(state
, state
->ev
, state
->cli
->conn
,
4543 state
->cli
->timeout
,
4544 state
->cli
->smb2
.session
,
4545 state
->cli
->smb2
.tcon
,
4546 state
->dst_ph
->fid_persistent
, /* in_fid_persistent */
4547 state
->dst_ph
->fid_volatile
, /* in_fid_volatile */
4548 FSCTL_SRV_COPYCHUNK_WRITE
,
4549 0, /* in_max_input_length */
4551 12, /* 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_copychunk_done
,
4562 static void cli_splice_key_done(struct tevent_req
*subreq
)
4564 struct tevent_req
*req
= tevent_req_callback_data(
4565 subreq
, struct tevent_req
);
4566 struct cli_smb2_splice_state
*state
=
4567 tevent_req_data(req
,
4568 struct cli_smb2_splice_state
);
4569 enum ndr_err_code ndr_ret
;
4572 DATA_BLOB out_input_buffer
= data_blob_null
;
4573 DATA_BLOB out_output_buffer
= data_blob_null
;
4575 status
= smb2cli_ioctl_recv(subreq
, state
,
4577 &out_output_buffer
);
4578 TALLOC_FREE(subreq
);
4579 if (tevent_req_nterror(req
, status
)) {
4583 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
,
4584 state
, &state
->resume_rsp
,
4585 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
4586 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4587 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4588 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4592 memcpy(&state
->cc_copy
.source_key
,
4593 &state
->resume_rsp
.resume_key
,
4594 sizeof state
->resume_rsp
.resume_key
);
4596 cli_splice_copychunk_send(state
, req
);
4599 struct tevent_req
*cli_smb2_splice_send(TALLOC_CTX
*mem_ctx
,
4600 struct tevent_context
*ev
,
4601 struct cli_state
*cli
,
4602 uint16_t src_fnum
, uint16_t dst_fnum
,
4603 off_t size
, off_t src_offset
, off_t dst_offset
,
4604 int (*splice_cb
)(off_t n
, void *priv
),
4607 struct tevent_req
*req
;
4608 struct tevent_req
*subreq
;
4609 struct cli_smb2_splice_state
*state
;
4611 DATA_BLOB in_input_buffer
= data_blob_null
;
4612 DATA_BLOB in_output_buffer
= data_blob_null
;
4614 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_splice_state
);
4620 state
->splice_cb
= splice_cb
;
4624 state
->src_offset
= src_offset
;
4625 state
->dst_offset
= dst_offset
;
4626 state
->cc_copy
.chunks
= talloc_array(state
,
4627 struct srv_copychunk
,
4628 smb2cli_conn_cc_max_chunks(cli
->conn
));
4629 if (state
->cc_copy
.chunks
== NULL
) {
4633 status
= map_fnum_to_smb2_handle(cli
, src_fnum
, &state
->src_ph
);
4634 if (tevent_req_nterror(req
, status
))
4635 return tevent_req_post(req
, ev
);
4637 status
= map_fnum_to_smb2_handle(cli
, dst_fnum
, &state
->dst_ph
);
4638 if (tevent_req_nterror(req
, status
))
4639 return tevent_req_post(req
, ev
);
4641 subreq
= smb2cli_ioctl_send(state
, ev
, cli
->conn
,
4645 state
->src_ph
->fid_persistent
, /* in_fid_persistent */
4646 state
->src_ph
->fid_volatile
, /* in_fid_volatile */
4647 FSCTL_SRV_REQUEST_RESUME_KEY
,
4648 0, /* in_max_input_length */
4650 32, /* in_max_output_length */
4652 SMB2_IOCTL_FLAG_IS_FSCTL
);
4653 if (tevent_req_nomem(subreq
, req
)) {
4656 tevent_req_set_callback(subreq
,
4657 cli_splice_key_done
,
4663 NTSTATUS
cli_smb2_splice_recv(struct tevent_req
*req
, off_t
*written
)
4665 struct cli_smb2_splice_state
*state
= tevent_req_data(
4666 req
, struct cli_smb2_splice_state
);
4669 if (tevent_req_is_nterror(req
, &status
)) {
4670 state
->cli
->raw_status
= status
;
4671 tevent_req_received(req
);
4674 if (written
!= NULL
) {
4675 *written
= state
->written
;
4677 state
->cli
->raw_status
= NT_STATUS_OK
;
4678 tevent_req_received(req
);
4679 return NT_STATUS_OK
;
4682 /***************************************************************
4683 SMB2 enum shadow copy data.
4684 ***************************************************************/
4686 struct cli_smb2_shadow_copy_data_fnum_state
{
4687 struct cli_state
*cli
;
4689 struct smb2_hnd
*ph
;
4690 DATA_BLOB out_input_buffer
;
4691 DATA_BLOB out_output_buffer
;
4694 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
);
4696 static struct tevent_req
*cli_smb2_shadow_copy_data_fnum_send(
4697 TALLOC_CTX
*mem_ctx
,
4698 struct tevent_context
*ev
,
4699 struct cli_state
*cli
,
4703 struct tevent_req
*req
, *subreq
;
4704 struct cli_smb2_shadow_copy_data_fnum_state
*state
;
4707 req
= tevent_req_create(mem_ctx
, &state
,
4708 struct cli_smb2_shadow_copy_data_fnum_state
);
4716 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
4717 if (tevent_req_nterror(req
, status
)) {
4718 return tevent_req_post(req
, ev
);
4722 * TODO. Under SMB2 we should send a zero max_output_length
4723 * ioctl to get the required size, then send another ioctl
4724 * to get the data, but the current SMB1 implementation just
4725 * does one roundtrip with a 64K buffer size. Do the same
4729 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
4730 state
->cli
->timeout
,
4731 state
->cli
->smb2
.session
,
4732 state
->cli
->smb2
.tcon
,
4733 state
->ph
->fid_persistent
, /* in_fid_persistent */
4734 state
->ph
->fid_volatile
, /* in_fid_volatile */
4735 FSCTL_GET_SHADOW_COPY_DATA
,
4736 0, /* in_max_input_length */
4737 NULL
, /* in_input_buffer */
4739 CLI_BUFFER_SIZE
: 16, /* in_max_output_length */
4740 NULL
, /* in_output_buffer */
4741 SMB2_IOCTL_FLAG_IS_FSCTL
);
4743 if (tevent_req_nomem(subreq
, req
)) {
4744 return tevent_req_post(req
, ev
);
4746 tevent_req_set_callback(subreq
,
4747 cli_smb2_shadow_copy_data_fnum_done
,
4753 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
)
4755 struct tevent_req
*req
= tevent_req_callback_data(
4756 subreq
, struct tevent_req
);
4757 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
4758 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
4761 status
= smb2cli_ioctl_recv(subreq
, state
,
4762 &state
->out_input_buffer
,
4763 &state
->out_output_buffer
);
4764 tevent_req_simple_finish_ntstatus(subreq
, status
);
4767 static NTSTATUS
cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req
*req
,
4768 TALLOC_CTX
*mem_ctx
,
4773 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
4774 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
4775 char **names
= NULL
;
4776 uint32_t num_names
= 0;
4777 uint32_t num_names_returned
= 0;
4778 uint32_t dlength
= 0;
4780 uint8_t *endp
= NULL
;
4783 if (tevent_req_is_nterror(req
, &status
)) {
4787 if (state
->out_output_buffer
.length
< 16) {
4788 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4791 num_names
= IVAL(state
->out_output_buffer
.data
, 0);
4792 num_names_returned
= IVAL(state
->out_output_buffer
.data
, 4);
4793 dlength
= IVAL(state
->out_output_buffer
.data
, 8);
4795 if (num_names
> 0x7FFFFFFF) {
4796 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4799 if (get_names
== false) {
4800 *pnum_names
= (int)num_names
;
4801 return NT_STATUS_OK
;
4803 if (num_names
!= num_names_returned
) {
4804 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4806 if (dlength
+ 12 < 12) {
4807 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4810 * NB. The below is an allowable return if there are
4811 * more snapshots than the buffer size we told the
4812 * server we can receive. We currently don't support
4815 if (dlength
+ 12 > state
->out_output_buffer
.length
) {
4816 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4818 if (state
->out_output_buffer
.length
+
4819 (2 * sizeof(SHADOW_COPY_LABEL
)) <
4820 state
->out_output_buffer
.length
) {
4821 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4824 names
= talloc_array(mem_ctx
, char *, num_names_returned
);
4825 if (names
== NULL
) {
4826 return NT_STATUS_NO_MEMORY
;
4829 endp
= state
->out_output_buffer
.data
+
4830 state
->out_output_buffer
.length
;
4832 for (i
=0; i
<num_names_returned
; i
++) {
4835 size_t converted_size
;
4837 src
= state
->out_output_buffer
.data
+ 12 +
4838 (i
* 2 * sizeof(SHADOW_COPY_LABEL
));
4840 if (src
+ (2 * sizeof(SHADOW_COPY_LABEL
)) > endp
) {
4841 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4843 ret
= convert_string_talloc(
4844 names
, CH_UTF16LE
, CH_UNIX
,
4845 src
, 2 * sizeof(SHADOW_COPY_LABEL
),
4846 &names
[i
], &converted_size
);
4849 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4852 *pnum_names
= num_names
;
4854 return NT_STATUS_OK
;
4857 NTSTATUS
cli_smb2_shadow_copy_data(TALLOC_CTX
*mem_ctx
,
4858 struct cli_state
*cli
,
4864 TALLOC_CTX
*frame
= talloc_stackframe();
4865 struct tevent_context
*ev
;
4866 struct tevent_req
*req
;
4867 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
4869 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4871 * Can't use sync call while an async call is in flight
4873 status
= NT_STATUS_INVALID_PARAMETER
;
4876 ev
= samba_tevent_context_init(frame
);
4880 req
= cli_smb2_shadow_copy_data_fnum_send(frame
,
4888 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4891 status
= cli_smb2_shadow_copy_data_fnum_recv(req
,
4897 cli
->raw_status
= status
;
4903 /***************************************************************
4904 Wrapper that allows SMB2 to truncate a file.
4906 ***************************************************************/
4908 NTSTATUS
cli_smb2_ftruncate(struct cli_state
*cli
,
4913 uint8_t buf
[8] = {0};
4914 DATA_BLOB inbuf
= { .data
= buf
, .length
= sizeof(buf
) };
4915 TALLOC_CTX
*frame
= talloc_stackframe();
4917 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4919 * Can't use sync call while an async call is in flight
4921 status
= NT_STATUS_INVALID_PARAMETER
;
4925 SBVAL(buf
, 0, newsize
);
4927 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4928 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4930 status
= cli_smb2_set_info_fnum(
4933 1, /* in_info_type */
4934 SMB_FILE_END_OF_FILE_INFORMATION
-1000, /* in_file_info_class */
4935 &inbuf
, /* in_input_buffer */
4940 cli
->raw_status
= status
;
4946 struct cli_smb2_notify_state
{
4947 struct tevent_req
*subreq
;
4948 struct notify_change
*changes
;
4952 static void cli_smb2_notify_done(struct tevent_req
*subreq
);
4953 static bool cli_smb2_notify_cancel(struct tevent_req
*req
);
4955 struct tevent_req
*cli_smb2_notify_send(
4956 TALLOC_CTX
*mem_ctx
,
4957 struct tevent_context
*ev
,
4958 struct cli_state
*cli
,
4960 uint32_t buffer_size
,
4961 uint32_t completion_filter
,
4964 struct tevent_req
*req
= NULL
;
4965 struct cli_smb2_notify_state
*state
= NULL
;
4966 struct smb2_hnd
*ph
= NULL
;
4969 req
= tevent_req_create(mem_ctx
, &state
,
4970 struct cli_smb2_notify_state
);
4975 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
4976 if (tevent_req_nterror(req
, status
)) {
4977 return tevent_req_post(req
, ev
);
4980 state
->subreq
= smb2cli_notify_send(
4992 if (tevent_req_nomem(state
->subreq
, req
)) {
4993 return tevent_req_post(req
, ev
);
4995 tevent_req_set_callback(state
->subreq
, cli_smb2_notify_done
, req
);
4996 tevent_req_set_cancel_fn(req
, cli_smb2_notify_cancel
);
5000 static bool cli_smb2_notify_cancel(struct tevent_req
*req
)
5002 struct cli_smb2_notify_state
*state
= tevent_req_data(
5003 req
, struct cli_smb2_notify_state
);
5006 ok
= tevent_req_cancel(state
->subreq
);
5010 static void cli_smb2_notify_done(struct tevent_req
*subreq
)
5012 struct tevent_req
*req
= tevent_req_callback_data(
5013 subreq
, struct tevent_req
);
5014 struct cli_smb2_notify_state
*state
= tevent_req_data(
5015 req
, struct cli_smb2_notify_state
);
5021 status
= smb2cli_notify_recv(subreq
, state
, &base
, &len
);
5022 TALLOC_FREE(subreq
);
5024 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
5025 tevent_req_done(req
);
5028 if (tevent_req_nterror(req
, status
)) {
5034 while (len
- ofs
>= 12) {
5035 struct notify_change
*tmp
;
5036 struct notify_change
*c
;
5037 uint32_t next_ofs
= IVAL(base
, ofs
);
5038 uint32_t file_name_length
= IVAL(base
, ofs
+8);
5042 tmp
= talloc_realloc(
5045 struct notify_change
,
5046 state
->num_changes
+ 1);
5047 if (tevent_req_nomem(tmp
, req
)) {
5050 state
->changes
= tmp
;
5051 c
= &state
->changes
[state
->num_changes
];
5052 state
->num_changes
+= 1;
5054 if (smb_buffer_oob(len
, ofs
, next_ofs
) ||
5055 smb_buffer_oob(len
, ofs
+12, file_name_length
)) {
5057 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
5061 c
->action
= IVAL(base
, ofs
+4);
5063 ok
= convert_string_talloc(
5073 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
5077 if (next_ofs
== 0) {
5083 tevent_req_done(req
);
5086 NTSTATUS
cli_smb2_notify_recv(struct tevent_req
*req
,
5087 TALLOC_CTX
*mem_ctx
,
5088 struct notify_change
**pchanges
,
5089 uint32_t *pnum_changes
)
5091 struct cli_smb2_notify_state
*state
= tevent_req_data(
5092 req
, struct cli_smb2_notify_state
);
5095 if (tevent_req_is_nterror(req
, &status
)) {
5098 *pchanges
= talloc_move(mem_ctx
, &state
->changes
);
5099 *pnum_changes
= state
->num_changes
;
5100 return NT_STATUS_OK
;
5103 NTSTATUS
cli_smb2_notify(struct cli_state
*cli
, uint16_t fnum
,
5104 uint32_t buffer_size
, uint32_t completion_filter
,
5105 bool recursive
, TALLOC_CTX
*mem_ctx
,
5106 struct notify_change
**pchanges
,
5107 uint32_t *pnum_changes
)
5109 TALLOC_CTX
*frame
= talloc_stackframe();
5110 struct tevent_context
*ev
;
5111 struct tevent_req
*req
;
5112 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
5114 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
5116 * Can't use sync call while an async call is in flight
5118 status
= NT_STATUS_INVALID_PARAMETER
;
5121 ev
= samba_tevent_context_init(frame
);
5125 req
= cli_smb2_notify_send(
5136 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
5139 status
= cli_smb2_notify_recv(req
, mem_ctx
, pchanges
, pnum_changes
);
5145 struct cli_smb2_fsctl_state
{
5149 static void cli_smb2_fsctl_done(struct tevent_req
*subreq
);
5151 struct tevent_req
*cli_smb2_fsctl_send(
5152 TALLOC_CTX
*mem_ctx
,
5153 struct tevent_context
*ev
,
5154 struct cli_state
*cli
,
5157 const DATA_BLOB
*in
,
5160 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
5161 struct cli_smb2_fsctl_state
*state
= NULL
;
5162 struct smb2_hnd
*ph
= NULL
;
5165 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_fsctl_state
);
5170 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
5171 if (tevent_req_nterror(req
, status
)) {
5172 return tevent_req_post(req
, ev
);
5175 subreq
= smb2cli_ioctl_send(
5185 0, /* in_max_input_length */
5189 SMB2_IOCTL_FLAG_IS_FSCTL
);
5191 if (tevent_req_nomem(subreq
, req
)) {
5192 return tevent_req_post(req
, ev
);
5194 tevent_req_set_callback(subreq
, cli_smb2_fsctl_done
, req
);
5198 static void cli_smb2_fsctl_done(struct tevent_req
*subreq
)
5200 struct tevent_req
*req
= tevent_req_callback_data(
5201 subreq
, struct tevent_req
);
5202 struct cli_smb2_fsctl_state
*state
= tevent_req_data(
5203 req
, struct cli_smb2_fsctl_state
);
5206 status
= smb2cli_ioctl_recv(subreq
, state
, NULL
, &state
->out
);
5207 tevent_req_simple_finish_ntstatus(subreq
, status
);
5210 NTSTATUS
cli_smb2_fsctl_recv(
5211 struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
, DATA_BLOB
*out
)
5213 struct cli_smb2_fsctl_state
*state
= tevent_req_data(
5214 req
, struct cli_smb2_fsctl_state
);
5215 NTSTATUS status
= NT_STATUS_OK
;
5217 if (tevent_req_is_nterror(req
, &status
)) {
5218 tevent_req_received(req
);
5222 if (state
->out
.length
== 0) {
5223 *out
= (DATA_BLOB
) { .data
= NULL
, };
5226 * Can't use talloc_move() here, the outblobs from
5227 * smb2cli_ioctl_recv() are not standalone talloc
5228 * objects but just peek into the larger buffers
5229 * received, hanging off "state".
5231 *out
= data_blob_talloc(
5232 mem_ctx
, state
->out
.data
, state
->out
.length
);
5233 if (out
->data
== NULL
) {
5234 status
= NT_STATUS_NO_MEMORY
;
5238 tevent_req_received(req
);
5239 return NT_STATUS_OK
;