2 Unix SMB/CIFS implementation.
4 Copyright (C) Jeremy Allison 2013
5 Copyright (C) Volker Lendecke 2013
6 Copyright (C) Stefan Metzmacher 2013
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This code is a thin wrapper around the existing
24 cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c,
25 but allows the handles to be mapped to uint16_t fnums,
26 which are easier for smbclient to use.
31 #include "async_smb.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "cli_smb2_fnum.h"
36 #include "../libcli/smb/smb2_create_blob.h"
37 #include "libsmb/proto.h"
38 #include "lib/util/tevent_ntstatus.h"
39 #include "../libcli/security/security.h"
40 #include "../librpc/gen_ndr/ndr_security.h"
41 #include "lib/util_ea.h"
42 #include "librpc/gen_ndr/ndr_ioctl.h"
44 #include "librpc/gen_ndr/ndr_quota.h"
45 #include "lib/util/string_wrappers.h"
48 uint64_t fid_persistent
;
49 uint64_t fid_volatile
;
53 * Handle mapping code.
56 /***************************************************************
57 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
58 Ensures handle is owned by cli struct.
59 ***************************************************************/
61 static NTSTATUS
map_smb2_handle_to_fnum(struct cli_state
*cli
,
62 const struct smb2_hnd
*ph
, /* In */
63 uint16_t *pfnum
) /* Out */
66 struct idr_context
*idp
= cli
->smb2
.open_handles
;
67 struct smb2_hnd
*owned_h
= talloc_memdup(cli
,
69 sizeof(struct smb2_hnd
));
71 if (owned_h
== NULL
) {
72 return NT_STATUS_NO_MEMORY
;
77 cli
->smb2
.open_handles
= idr_init(cli
);
78 if (cli
->smb2
.open_handles
== NULL
) {
80 return NT_STATUS_NO_MEMORY
;
82 idp
= cli
->smb2
.open_handles
;
85 ret
= idr_get_new_above(idp
, owned_h
, 1, 0xFFFE);
88 return NT_STATUS_NO_MEMORY
;
91 *pfnum
= (uint16_t)ret
;
95 /***************************************************************
96 Return the smb2_hnd pointer associated with the given fnum.
97 ***************************************************************/
99 static NTSTATUS
map_fnum_to_smb2_handle(struct cli_state
*cli
,
100 uint16_t fnum
, /* In */
101 struct smb2_hnd
**pph
) /* Out */
103 struct idr_context
*idp
= cli
->smb2
.open_handles
;
106 return NT_STATUS_INVALID_PARAMETER
;
108 *pph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
110 return NT_STATUS_INVALID_HANDLE
;
115 /***************************************************************
116 Delete the fnum to smb2_hnd mapping. Zeros out handle on
118 ***************************************************************/
120 static NTSTATUS
delete_smb2_handle_mapping(struct cli_state
*cli
,
121 struct smb2_hnd
**pph
, /* In */
122 uint16_t fnum
) /* In */
124 struct idr_context
*idp
= cli
->smb2
.open_handles
;
128 return NT_STATUS_INVALID_PARAMETER
;
131 ph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
133 return NT_STATUS_INVALID_PARAMETER
;
135 idr_remove(idp
, fnum
);
140 /***************************************************************
142 ***************************************************************/
144 static uint8_t flags_to_smb2_oplock(uint32_t create_flags
)
146 if (create_flags
& REQUEST_BATCH_OPLOCK
) {
147 return SMB2_OPLOCK_LEVEL_BATCH
;
148 } else if (create_flags
& REQUEST_OPLOCK
) {
149 return SMB2_OPLOCK_LEVEL_EXCLUSIVE
;
152 /* create_flags doesn't do a level2 request. */
153 return SMB2_OPLOCK_LEVEL_NONE
;
156 /***************************************************************
157 Small wrapper that allows SMB2 create to return a uint16_t fnum.
158 ***************************************************************/
160 struct cli_smb2_create_fnum_state
{
161 struct cli_state
*cli
;
162 struct smb2_create_blobs in_cblobs
;
163 struct smb2_create_blobs out_cblobs
;
164 struct smb_create_returns cr
;
166 struct tevent_req
*subreq
;
169 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
);
170 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
);
172 struct tevent_req
*cli_smb2_create_fnum_send(
174 struct tevent_context
*ev
,
175 struct cli_state
*cli
,
177 uint32_t create_flags
,
178 uint32_t impersonation_level
,
179 uint32_t desired_access
,
180 uint32_t file_attributes
,
181 uint32_t share_access
,
182 uint32_t create_disposition
,
183 uint32_t create_options
,
184 const struct smb2_create_blobs
*in_cblobs
)
186 struct tevent_req
*req
, *subreq
;
187 struct cli_smb2_create_fnum_state
*state
;
188 size_t fname_len
= 0;
189 const char *startp
= NULL
;
190 const char *endp
= NULL
;
191 time_t tstamp
= (time_t)0;
194 req
= tevent_req_create(mem_ctx
, &state
,
195 struct cli_smb2_create_fnum_state
);
201 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
202 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
203 return tevent_req_post(req
, ev
);
206 if (cli
->backup_intent
) {
207 create_options
|= FILE_OPEN_FOR_BACKUP_INTENT
;
210 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
211 fname_len
= strlen(fname
);
212 if (clistr_is_previous_version_path(fname
, &startp
, &endp
, &tstamp
)) {
213 size_t len_before_gmt
= startp
- fname
;
214 size_t len_after_gmt
= fname
+ fname_len
- endp
;
218 char *new_fname
= talloc_array(state
, char,
219 len_before_gmt
+ len_after_gmt
+ 1);
221 if (tevent_req_nomem(new_fname
, req
)) {
222 return tevent_req_post(req
, ev
);
225 memcpy(new_fname
, fname
, len_before_gmt
);
226 memcpy(new_fname
+ len_before_gmt
, endp
, len_after_gmt
+ 1);
228 fname_len
= len_before_gmt
+ len_after_gmt
;
230 unix_to_nt_time(&ntt
, tstamp
);
231 twrp_blob
= data_blob_const((const void *)&ntt
, 8);
233 status
= smb2_create_blob_add(
236 SMB2_CREATE_TAG_TWRP
,
238 if (!NT_STATUS_IS_OK(status
)) {
239 tevent_req_nterror(req
, status
);
240 return tevent_req_post(req
, ev
);
244 if (in_cblobs
!= NULL
) {
246 for (i
=0; i
<in_cblobs
->num_blobs
; i
++) {
247 struct smb2_create_blob
*b
= &in_cblobs
->blobs
[i
];
248 status
= smb2_create_blob_add(
249 state
, &state
->in_cblobs
, b
->tag
, b
->data
);
250 if (!NT_STATUS_IS_OK(status
)) {
251 tevent_req_nterror(req
, status
);
252 return tevent_req_post(req
, ev
);
257 /* SMB2 is pickier about pathnames. Ensure it doesn't
259 if (*fname
== '\\') {
264 /* Or end in a '\' */
265 if (fname_len
> 0 && fname
[fname_len
-1] == '\\') {
266 char *new_fname
= talloc_strdup(state
, fname
);
267 if (tevent_req_nomem(new_fname
, req
)) {
268 return tevent_req_post(req
, ev
);
270 new_fname
[fname_len
-1] = '\0';
274 subreq
= smb2cli_create_send(state
, ev
,
280 flags_to_smb2_oplock(create_flags
),
288 if (tevent_req_nomem(subreq
, req
)) {
289 return tevent_req_post(req
, ev
);
291 tevent_req_set_callback(subreq
, cli_smb2_create_fnum_done
, req
);
293 state
->subreq
= subreq
;
294 tevent_req_set_cancel_fn(req
, cli_smb2_create_fnum_cancel
);
299 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
)
301 struct tevent_req
*req
= tevent_req_callback_data(
302 subreq
, struct tevent_req
);
303 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
304 req
, struct cli_smb2_create_fnum_state
);
308 status
= smb2cli_create_recv(
311 &h
.fid_volatile
, &state
->cr
,
315 if (tevent_req_nterror(req
, status
)) {
319 status
= map_smb2_handle_to_fnum(state
->cli
, &h
, &state
->fnum
);
320 if (tevent_req_nterror(req
, status
)) {
323 tevent_req_done(req
);
326 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
)
328 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
329 req
, struct cli_smb2_create_fnum_state
);
330 return tevent_req_cancel(state
->subreq
);
333 NTSTATUS
cli_smb2_create_fnum_recv(
334 struct tevent_req
*req
,
336 struct smb_create_returns
*cr
,
338 struct smb2_create_blobs
*out_cblobs
)
340 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
341 req
, struct cli_smb2_create_fnum_state
);
344 if (tevent_req_is_nterror(req
, &status
)) {
345 state
->cli
->raw_status
= status
;
349 *pfnum
= state
->fnum
;
354 if (out_cblobs
!= NULL
) {
355 *out_cblobs
= (struct smb2_create_blobs
) {
356 .num_blobs
= state
->out_cblobs
.num_blobs
,
357 .blobs
= talloc_move(
358 mem_ctx
, &state
->out_cblobs
.blobs
),
361 state
->cli
->raw_status
= NT_STATUS_OK
;
365 NTSTATUS
cli_smb2_create_fnum(
366 struct cli_state
*cli
,
368 uint32_t create_flags
,
369 uint32_t impersonation_level
,
370 uint32_t desired_access
,
371 uint32_t file_attributes
,
372 uint32_t share_access
,
373 uint32_t create_disposition
,
374 uint32_t create_options
,
375 const struct smb2_create_blobs
*in_cblobs
,
377 struct smb_create_returns
*cr
,
379 struct smb2_create_blobs
*out_cblobs
)
381 TALLOC_CTX
*frame
= talloc_stackframe();
382 struct tevent_context
*ev
;
383 struct tevent_req
*req
;
384 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
386 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
388 * Can't use sync call while an async call is in flight
390 status
= NT_STATUS_INVALID_PARAMETER
;
393 ev
= samba_tevent_context_init(frame
);
397 req
= cli_smb2_create_fnum_send(
413 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
416 status
= cli_smb2_create_fnum_recv(req
, pfid
, cr
, mem_ctx
, out_cblobs
);
422 /***************************************************************
423 Small wrapper that allows SMB2 close to use a uint16_t fnum.
424 ***************************************************************/
426 struct cli_smb2_close_fnum_state
{
427 struct cli_state
*cli
;
432 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
);
434 struct tevent_req
*cli_smb2_close_fnum_send(TALLOC_CTX
*mem_ctx
,
435 struct tevent_context
*ev
,
436 struct cli_state
*cli
,
439 struct tevent_req
*req
, *subreq
;
440 struct cli_smb2_close_fnum_state
*state
;
443 req
= tevent_req_create(mem_ctx
, &state
,
444 struct cli_smb2_close_fnum_state
);
451 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
452 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
453 return tevent_req_post(req
, ev
);
456 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
457 if (tevent_req_nterror(req
, status
)) {
458 return tevent_req_post(req
, ev
);
461 subreq
= smb2cli_close_send(state
, ev
, cli
->conn
, cli
->timeout
,
462 cli
->smb2
.session
, cli
->smb2
.tcon
,
463 0, state
->ph
->fid_persistent
,
464 state
->ph
->fid_volatile
);
465 if (tevent_req_nomem(subreq
, req
)) {
466 return tevent_req_post(req
, ev
);
468 tevent_req_set_callback(subreq
, cli_smb2_close_fnum_done
, req
);
472 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
)
474 struct tevent_req
*req
= tevent_req_callback_data(
475 subreq
, struct tevent_req
);
476 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
477 req
, struct cli_smb2_close_fnum_state
);
480 status
= smb2cli_close_recv(subreq
);
481 if (tevent_req_nterror(req
, status
)) {
485 /* Delete the fnum -> handle mapping. */
486 status
= delete_smb2_handle_mapping(state
->cli
, &state
->ph
,
488 if (tevent_req_nterror(req
, status
)) {
491 tevent_req_done(req
);
494 NTSTATUS
cli_smb2_close_fnum_recv(struct tevent_req
*req
)
496 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
497 req
, struct cli_smb2_close_fnum_state
);
498 NTSTATUS status
= NT_STATUS_OK
;
500 if (tevent_req_is_nterror(req
, &status
)) {
501 state
->cli
->raw_status
= status
;
503 tevent_req_received(req
);
507 NTSTATUS
cli_smb2_close_fnum(struct cli_state
*cli
, uint16_t fnum
)
509 TALLOC_CTX
*frame
= talloc_stackframe();
510 struct tevent_context
*ev
;
511 struct tevent_req
*req
;
512 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
514 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
516 * Can't use sync call while an async call is in flight
518 status
= NT_STATUS_INVALID_PARAMETER
;
521 ev
= samba_tevent_context_init(frame
);
525 req
= cli_smb2_close_fnum_send(frame
, ev
, cli
, fnum
);
529 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
532 status
= cli_smb2_close_fnum_recv(req
);
538 struct cli_smb2_set_info_fnum_state
{
542 static void cli_smb2_set_info_fnum_done(struct tevent_req
*subreq
);
544 struct tevent_req
*cli_smb2_set_info_fnum_send(
546 struct tevent_context
*ev
,
547 struct cli_state
*cli
,
549 uint8_t in_info_type
,
550 uint8_t in_info_class
,
551 const DATA_BLOB
*in_input_buffer
,
552 uint32_t in_additional_info
)
554 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
555 struct cli_smb2_set_info_fnum_state
*state
= NULL
;
556 struct smb2_hnd
*ph
= NULL
;
559 req
= tevent_req_create(
560 mem_ctx
, &state
, struct cli_smb2_set_info_fnum_state
);
565 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
566 if (tevent_req_nterror(req
, status
)) {
567 return tevent_req_post(req
, ev
);
570 subreq
= smb2cli_set_info_send(
583 if (tevent_req_nomem(subreq
, req
)) {
584 return tevent_req_post(req
, ev
);
586 tevent_req_set_callback(subreq
, cli_smb2_set_info_fnum_done
, req
);
590 static void cli_smb2_set_info_fnum_done(struct tevent_req
*subreq
)
592 NTSTATUS status
= smb2cli_set_info_recv(subreq
);
593 tevent_req_simple_finish_ntstatus(subreq
, status
);
596 NTSTATUS
cli_smb2_set_info_fnum_recv(struct tevent_req
*req
)
598 return tevent_req_simple_recv_ntstatus(req
);
601 NTSTATUS
cli_smb2_set_info_fnum(
602 struct cli_state
*cli
,
604 uint8_t in_info_type
,
605 uint8_t in_info_class
,
606 const DATA_BLOB
*in_input_buffer
,
607 uint32_t in_additional_info
)
609 TALLOC_CTX
*frame
= talloc_stackframe();
610 struct tevent_context
*ev
= NULL
;
611 struct tevent_req
*req
= NULL
;
612 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
615 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
617 * Can't use sync call while an async call is in flight
619 status
= NT_STATUS_INVALID_PARAMETER
;
622 ev
= samba_tevent_context_init(frame
);
626 req
= cli_smb2_set_info_fnum_send(
638 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
642 status
= cli_smb2_set_info_fnum_recv(req
);
648 struct cli_smb2_delete_on_close_state
{
649 struct cli_state
*cli
;
654 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
);
656 struct tevent_req
*cli_smb2_delete_on_close_send(TALLOC_CTX
*mem_ctx
,
657 struct tevent_context
*ev
,
658 struct cli_state
*cli
,
662 struct tevent_req
*req
= NULL
;
663 struct cli_smb2_delete_on_close_state
*state
= NULL
;
664 struct tevent_req
*subreq
= NULL
;
665 uint8_t in_info_type
;
666 uint8_t in_file_info_class
;
668 req
= tevent_req_create(mem_ctx
, &state
,
669 struct cli_smb2_delete_on_close_state
);
675 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
676 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
677 return tevent_req_post(req
, ev
);
681 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
682 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
685 in_file_info_class
= SMB_FILE_DISPOSITION_INFORMATION
- 1000;
686 /* Setup data array. */
687 SCVAL(&state
->data
[0], 0, flag
? 1 : 0);
688 state
->inbuf
.data
= &state
->data
[0];
689 state
->inbuf
.length
= 1;
691 subreq
= cli_smb2_set_info_fnum_send(
700 if (tevent_req_nomem(subreq
, req
)) {
701 return tevent_req_post(req
, ev
);
703 tevent_req_set_callback(subreq
,
704 cli_smb2_delete_on_close_done
,
709 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
)
711 NTSTATUS status
= cli_smb2_set_info_fnum_recv(subreq
);
712 tevent_req_simple_finish_ntstatus(subreq
, status
);
715 NTSTATUS
cli_smb2_delete_on_close_recv(struct tevent_req
*req
)
717 struct cli_smb2_delete_on_close_state
*state
=
719 struct cli_smb2_delete_on_close_state
);
722 if (tevent_req_is_nterror(req
, &status
)) {
723 state
->cli
->raw_status
= status
;
724 tevent_req_received(req
);
728 state
->cli
->raw_status
= NT_STATUS_OK
;
729 tevent_req_received(req
);
733 NTSTATUS
cli_smb2_delete_on_close(struct cli_state
*cli
, uint16_t fnum
, bool flag
)
735 TALLOC_CTX
*frame
= talloc_stackframe();
736 struct tevent_context
*ev
;
737 struct tevent_req
*req
;
738 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
740 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
742 * Can't use sync call while an async call is in flight
744 status
= NT_STATUS_INVALID_PARAMETER
;
747 ev
= samba_tevent_context_init(frame
);
751 req
= cli_smb2_delete_on_close_send(frame
, ev
, cli
, fnum
, flag
);
755 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
758 status
= cli_smb2_delete_on_close_recv(req
);
764 struct cli_smb2_mkdir_state
{
765 struct tevent_context
*ev
;
766 struct cli_state
*cli
;
769 static void cli_smb2_mkdir_opened(struct tevent_req
*subreq
);
770 static void cli_smb2_mkdir_closed(struct tevent_req
*subreq
);
772 struct tevent_req
*cli_smb2_mkdir_send(
774 struct tevent_context
*ev
,
775 struct cli_state
*cli
,
778 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
779 struct cli_smb2_mkdir_state
*state
= NULL
;
781 req
= tevent_req_create(
782 mem_ctx
, &state
, struct cli_smb2_mkdir_state
);
789 /* Ensure this is a directory. */
790 subreq
= cli_smb2_create_fnum_send(
795 0, /* create_flags */
796 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation_level */
797 FILE_READ_ATTRIBUTES
, /* desired_access */
798 FILE_ATTRIBUTE_DIRECTORY
, /* file_attributes */
800 FILE_SHARE_WRITE
, /* share_access */
801 FILE_CREATE
, /* create_disposition */
802 FILE_DIRECTORY_FILE
, /* create_options */
803 NULL
); /* in_cblobs */
804 if (tevent_req_nomem(subreq
, req
)) {
805 return tevent_req_post(req
, ev
);
807 tevent_req_set_callback(subreq
, cli_smb2_mkdir_opened
, req
);
811 static void cli_smb2_mkdir_opened(struct tevent_req
*subreq
)
813 struct tevent_req
*req
= tevent_req_callback_data(
814 subreq
, struct tevent_req
);
815 struct cli_smb2_mkdir_state
*state
= tevent_req_data(
816 req
, struct cli_smb2_mkdir_state
);
818 uint16_t fnum
= 0xffff;
820 status
= cli_smb2_create_fnum_recv(subreq
, &fnum
, NULL
, NULL
, NULL
);
822 if (tevent_req_nterror(req
, status
)) {
826 subreq
= cli_smb2_close_fnum_send(state
, state
->ev
, state
->cli
, fnum
);
827 if (tevent_req_nomem(subreq
, req
)) {
830 tevent_req_set_callback(subreq
, cli_smb2_mkdir_closed
, req
);
833 static void cli_smb2_mkdir_closed(struct tevent_req
*subreq
)
835 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
836 tevent_req_simple_finish_ntstatus(subreq
, status
);
839 NTSTATUS
cli_smb2_mkdir_recv(struct tevent_req
*req
)
841 return tevent_req_simple_recv_ntstatus(req
);
844 struct cli_smb2_rmdir_state
{
845 struct tevent_context
*ev
;
846 struct cli_state
*cli
;
848 const struct smb2_create_blobs
*in_cblobs
;
853 static void cli_smb2_rmdir_opened1(struct tevent_req
*subreq
);
854 static void cli_smb2_rmdir_opened2(struct tevent_req
*subreq
);
855 static void cli_smb2_rmdir_disp_set(struct tevent_req
*subreq
);
856 static void cli_smb2_rmdir_closed(struct tevent_req
*subreq
);
858 struct tevent_req
*cli_smb2_rmdir_send(
860 struct tevent_context
*ev
,
861 struct cli_state
*cli
,
863 const struct smb2_create_blobs
*in_cblobs
)
865 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
866 struct cli_smb2_rmdir_state
*state
= NULL
;
868 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_rmdir_state
);
874 state
->dname
= dname
;
875 state
->in_cblobs
= in_cblobs
;
877 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
878 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
879 return tevent_req_post(req
, ev
);
882 subreq
= cli_smb2_create_fnum_send(
887 0, /* create_flags */
888 SMB2_IMPERSONATION_IMPERSONATION
,
889 DELETE_ACCESS
, /* desired_access */
890 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
891 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
892 FILE_OPEN
, /* create_disposition */
893 FILE_DIRECTORY_FILE
, /* create_options */
894 state
->in_cblobs
); /* in_cblobs */
895 if (tevent_req_nomem(subreq
, req
)) {
896 return tevent_req_post(req
, ev
);
898 tevent_req_set_callback(subreq
, cli_smb2_rmdir_opened1
, req
);
902 static void cli_smb2_rmdir_opened1(struct tevent_req
*subreq
)
904 struct tevent_req
*req
= tevent_req_callback_data(
905 subreq
, struct tevent_req
);
906 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
907 req
, struct cli_smb2_rmdir_state
);
910 status
= cli_smb2_create_fnum_recv(
911 subreq
, &state
->fnum
, NULL
, NULL
, NULL
);
914 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
916 * Naive option to match our SMB1 code. Assume the
917 * symlink path that tripped us up was the last
918 * component and try again. Eventually we will have to
919 * deal with the returned path unprocessed component. JRA.
921 subreq
= cli_smb2_create_fnum_send(
926 0, /* create_flags */
927 SMB2_IMPERSONATION_IMPERSONATION
,
928 DELETE_ACCESS
, /* desired_access */
929 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
930 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
931 FILE_OPEN
, /* create_disposition */
933 FILE_DELETE_ON_CLOSE
|
934 FILE_OPEN_REPARSE_POINT
, /* create_options */
935 state
->in_cblobs
); /* in_cblobs */
936 if (tevent_req_nomem(subreq
, req
)) {
939 tevent_req_set_callback(subreq
, cli_smb2_rmdir_opened2
, req
);
943 if (tevent_req_nterror(req
, status
)) {
947 subreq
= cli_smb2_delete_on_close_send(
948 state
, state
->ev
, state
->cli
, state
->fnum
, true);
949 if (tevent_req_nomem(subreq
, req
)) {
952 tevent_req_set_callback(subreq
, cli_smb2_rmdir_disp_set
, req
);
955 static void cli_smb2_rmdir_opened2(struct tevent_req
*subreq
)
957 struct tevent_req
*req
= tevent_req_callback_data(
958 subreq
, struct tevent_req
);
959 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
960 req
, struct cli_smb2_rmdir_state
);
963 status
= cli_smb2_create_fnum_recv(
964 subreq
, &state
->fnum
, NULL
, NULL
, NULL
);
966 if (tevent_req_nterror(req
, status
)) {
970 subreq
= cli_smb2_delete_on_close_send(
971 state
, state
->ev
, state
->cli
, state
->fnum
, true);
972 if (tevent_req_nomem(subreq
, req
)) {
975 tevent_req_set_callback(subreq
, cli_smb2_rmdir_disp_set
, req
);
978 static void cli_smb2_rmdir_disp_set(struct tevent_req
*subreq
)
980 struct tevent_req
*req
= tevent_req_callback_data(
981 subreq
, struct tevent_req
);
982 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
983 req
, struct cli_smb2_rmdir_state
);
985 state
->status
= cli_smb2_delete_on_close_recv(subreq
);
989 * Close the fd even if the set_disp failed
992 subreq
= cli_smb2_close_fnum_send(
993 state
, state
->ev
, state
->cli
, state
->fnum
);
994 if (tevent_req_nomem(subreq
, req
)) {
997 tevent_req_set_callback(subreq
, cli_smb2_rmdir_closed
, req
);
1000 static void cli_smb2_rmdir_closed(struct tevent_req
*subreq
)
1002 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
1003 tevent_req_simple_finish_ntstatus(subreq
, status
);
1006 NTSTATUS
cli_smb2_rmdir_recv(struct tevent_req
*req
)
1008 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
1009 req
, struct cli_smb2_rmdir_state
);
1012 if (tevent_req_is_nterror(req
, &status
)) {
1015 return state
->status
;
1018 /***************************************************************
1019 Small wrapper that allows SMB2 to unlink a pathname.
1020 ***************************************************************/
1022 struct cli_smb2_unlink_state
{
1023 struct tevent_context
*ev
;
1024 struct cli_state
*cli
;
1026 const struct smb2_create_blobs
*in_cblobs
;
1029 static void cli_smb2_unlink_opened1(struct tevent_req
*subreq
);
1030 static void cli_smb2_unlink_opened2(struct tevent_req
*subreq
);
1031 static void cli_smb2_unlink_closed(struct tevent_req
*subreq
);
1033 struct tevent_req
*cli_smb2_unlink_send(
1034 TALLOC_CTX
*mem_ctx
,
1035 struct tevent_context
*ev
,
1036 struct cli_state
*cli
,
1038 const struct smb2_create_blobs
*in_cblobs
)
1040 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1041 struct cli_smb2_unlink_state
*state
= NULL
;
1043 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_unlink_state
);
1049 state
->fname
= fname
;
1050 state
->in_cblobs
= in_cblobs
;
1052 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1053 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1054 return tevent_req_post(req
, ev
);
1057 subreq
= cli_smb2_create_fnum_send(
1058 state
, /* mem_ctx */
1059 state
->ev
, /* tevent_context */
1060 state
->cli
, /* cli_struct */
1061 state
->fname
, /* filename */
1062 0, /* create_flags */
1063 SMB2_IMPERSONATION_IMPERSONATION
,
1064 DELETE_ACCESS
, /* desired_access */
1065 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
1068 FILE_SHARE_DELETE
, /* share_access */
1069 FILE_OPEN
, /* create_disposition */
1070 FILE_DELETE_ON_CLOSE
, /* create_options */
1071 state
->in_cblobs
); /* in_cblobs */
1072 if (tevent_req_nomem(subreq
, req
)) {
1073 return tevent_req_post(req
, ev
);
1075 tevent_req_set_callback(subreq
, cli_smb2_unlink_opened1
, req
);
1079 static void cli_smb2_unlink_opened1(struct tevent_req
*subreq
)
1081 struct tevent_req
*req
= tevent_req_callback_data(
1082 subreq
, struct tevent_req
);
1083 struct cli_smb2_unlink_state
*state
= tevent_req_data(
1084 req
, struct cli_smb2_unlink_state
);
1085 uint16_t fnum
= 0xffff;
1088 status
= cli_smb2_create_fnum_recv(subreq
, &fnum
, NULL
, NULL
, NULL
);
1089 TALLOC_FREE(subreq
);
1091 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
1093 * Naive option to match our SMB1 code. Assume the
1094 * symlink path that tripped us up was the last
1095 * component and try again. Eventually we will have to
1096 * deal with the returned path unprocessed component. JRA.
1098 subreq
= cli_smb2_create_fnum_send(
1099 state
, /* mem_ctx */
1100 state
->ev
, /* tevent_context */
1101 state
->cli
, /* cli_struct */
1102 state
->fname
, /* filename */
1103 0, /* create_flags */
1104 SMB2_IMPERSONATION_IMPERSONATION
,
1105 DELETE_ACCESS
, /* desired_access */
1106 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
1109 FILE_SHARE_DELETE
, /* share_access */
1110 FILE_OPEN
, /* create_disposition */
1111 FILE_DELETE_ON_CLOSE
|
1112 FILE_OPEN_REPARSE_POINT
, /* create_options */
1113 state
->in_cblobs
); /* in_cblobs */
1114 if (tevent_req_nomem(subreq
, req
)) {
1117 tevent_req_set_callback(subreq
, cli_smb2_unlink_opened2
, req
);
1121 if (tevent_req_nterror(req
, status
)) {
1125 subreq
= cli_smb2_close_fnum_send(state
, state
->ev
, state
->cli
, fnum
);
1126 if (tevent_req_nomem(subreq
, req
)) {
1129 tevent_req_set_callback(subreq
, cli_smb2_unlink_closed
, req
);
1132 static void cli_smb2_unlink_opened2(struct tevent_req
*subreq
)
1134 struct tevent_req
*req
= tevent_req_callback_data(
1135 subreq
, struct tevent_req
);
1136 struct cli_smb2_unlink_state
*state
= tevent_req_data(
1137 req
, struct cli_smb2_unlink_state
);
1138 uint16_t fnum
= 0xffff;
1141 status
= cli_smb2_create_fnum_recv(subreq
, &fnum
, NULL
, NULL
, NULL
);
1142 TALLOC_FREE(subreq
);
1143 if (tevent_req_nterror(req
, status
)) {
1147 subreq
= cli_smb2_close_fnum_send(state
, state
->ev
, state
->cli
, fnum
);
1148 if (tevent_req_nomem(subreq
, req
)) {
1151 tevent_req_set_callback(subreq
, cli_smb2_unlink_closed
, req
);
1154 static void cli_smb2_unlink_closed(struct tevent_req
*subreq
)
1156 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
1157 tevent_req_simple_finish_ntstatus(subreq
, status
);
1160 NTSTATUS
cli_smb2_unlink_recv(struct tevent_req
*req
)
1162 return tevent_req_simple_recv_ntstatus(req
);
1165 /***************************************************************
1166 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1167 ***************************************************************/
1169 static NTSTATUS
parse_finfo_id_both_directory_info(const uint8_t *dir_data
,
1170 uint32_t dir_data_length
,
1171 struct file_info
*finfo
,
1172 uint32_t *next_offset
)
1178 if (dir_data_length
< 4) {
1179 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1182 *next_offset
= IVAL(dir_data
, 0);
1184 if (*next_offset
> dir_data_length
) {
1185 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1188 if (*next_offset
!= 0) {
1189 /* Ensure we only read what in this record. */
1190 dir_data_length
= *next_offset
;
1193 if (dir_data_length
< 105) {
1194 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1197 finfo
->btime_ts
= interpret_long_date((const char *)dir_data
+ 8);
1198 finfo
->atime_ts
= interpret_long_date((const char *)dir_data
+ 16);
1199 finfo
->mtime_ts
= interpret_long_date((const char *)dir_data
+ 24);
1200 finfo
->ctime_ts
= interpret_long_date((const char *)dir_data
+ 32);
1201 finfo
->size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 40, 0);
1202 finfo
->allocated_size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 48, 0);
1203 finfo
->attr
= IVAL(dir_data
+ 56, 0);
1204 finfo
->ino
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 96, 0);
1205 namelen
= IVAL(dir_data
+ 60,0);
1206 if (namelen
> (dir_data_length
- 104)) {
1207 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1209 slen
= CVAL(dir_data
+ 68, 0);
1211 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1213 ret
= pull_string_talloc(finfo
,
1215 FLAGS2_UNICODE_STRINGS
,
1220 if (ret
== (size_t)-1) {
1221 /* Bad conversion. */
1222 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1225 ret
= pull_string_talloc(finfo
,
1227 FLAGS2_UNICODE_STRINGS
,
1232 if (ret
== (size_t)-1) {
1233 /* Bad conversion. */
1234 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1237 if (finfo
->name
== NULL
) {
1238 /* Bad conversion. */
1239 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1242 return NT_STATUS_OK
;
1245 /*******************************************************************
1246 Given a filename - get its directory name
1247 ********************************************************************/
1249 static bool windows_parent_dirname(TALLOC_CTX
*mem_ctx
,
1257 p
= strrchr_m(dir
, '\\'); /* Find final '\\', if any */
1260 if (!(*parent
= talloc_strdup(mem_ctx
, "\\"))) {
1271 if (!(*parent
= (char *)talloc_memdup(mem_ctx
, dir
, len
+1))) {
1274 (*parent
)[len
] = '\0';
1282 struct cli_smb2_list_dir_data
{
1287 struct cli_smb2_list_state
{
1288 struct tevent_context
*ev
;
1289 struct cli_state
*cli
;
1295 struct cli_smb2_list_dir_data
*response
;
1299 static void cli_smb2_list_opened(struct tevent_req
*subreq
);
1300 static void cli_smb2_list_done(struct tevent_req
*subreq
);
1301 static void cli_smb2_list_closed(struct tevent_req
*subreq
);
1303 struct tevent_req
*cli_smb2_list_send(
1304 TALLOC_CTX
*mem_ctx
,
1305 struct tevent_context
*ev
,
1306 struct cli_state
*cli
,
1307 const char *pathname
)
1309 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1310 struct cli_smb2_list_state
*state
= NULL
;
1311 char *parent
= NULL
;
1314 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_list_state
);
1320 state
->status
= NT_STATUS_OK
;
1322 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1323 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1324 return tevent_req_post(req
, ev
);
1327 ok
= windows_parent_dirname(state
, pathname
, &parent
, &state
->mask
);
1329 tevent_req_oom(req
);
1330 return tevent_req_post(req
, ev
);
1333 subreq
= cli_smb2_create_fnum_send(
1334 state
, /* mem_ctx */
1338 0, /* create_flags */
1339 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation_level */
1340 SEC_DIR_LIST
|SEC_DIR_READ_ATTRIBUTE
, /* desired_access */
1341 FILE_ATTRIBUTE_DIRECTORY
, /* file_attributes */
1342 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
1343 FILE_OPEN
, /* create_disposition */
1344 FILE_DIRECTORY_FILE
, /* create_options */
1345 NULL
); /* in_cblobs */
1346 if (tevent_req_nomem(subreq
, req
)) {
1347 return tevent_req_post(req
, ev
);
1349 tevent_req_set_callback(subreq
, cli_smb2_list_opened
, req
);
1353 static void cli_smb2_list_opened(struct tevent_req
*subreq
)
1355 struct tevent_req
*req
= tevent_req_callback_data(
1356 subreq
, struct tevent_req
);
1357 struct cli_smb2_list_state
*state
= tevent_req_data(
1358 req
, struct cli_smb2_list_state
);
1361 status
= cli_smb2_create_fnum_recv(
1362 subreq
, &state
->fnum
, NULL
, NULL
, NULL
);
1363 TALLOC_FREE(subreq
);
1364 if (tevent_req_nterror(req
, status
)) {
1369 * Make our caller get back to us via cli_smb2_list_recv(),
1370 * triggering the smb2_query_directory_send()
1372 tevent_req_defer_callback(req
, state
->ev
);
1373 tevent_req_notify_callback(req
);
1376 static void cli_smb2_list_done(struct tevent_req
*subreq
)
1378 struct tevent_req
*req
= tevent_req_callback_data(
1379 subreq
, struct tevent_req
);
1380 struct cli_smb2_list_state
*state
= tevent_req_data(
1381 req
, struct cli_smb2_list_state
);
1382 struct cli_smb2_list_dir_data
*response
= NULL
;
1384 response
= talloc(state
, struct cli_smb2_list_dir_data
);
1385 if (tevent_req_nomem(response
, req
)) {
1389 state
->status
= smb2cli_query_directory_recv(
1390 subreq
, response
, &response
->data
, &response
->length
);
1391 TALLOC_FREE(subreq
);
1393 if (NT_STATUS_IS_OK(state
->status
)) {
1394 state
->response
= response
;
1397 tevent_req_defer_callback(req
, state
->ev
);
1398 tevent_req_notify_callback(req
);
1402 TALLOC_FREE(response
);
1404 subreq
= cli_smb2_close_fnum_send(
1405 state
, state
->ev
, state
->cli
, state
->fnum
);
1406 if (tevent_req_nomem(subreq
, req
)) {
1409 tevent_req_set_callback(subreq
, cli_smb2_list_closed
, req
);
1412 static void cli_smb2_list_closed(struct tevent_req
*subreq
)
1414 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
1415 tevent_req_simple_finish_ntstatus(subreq
, status
);
1419 * Return the next finfo directory.
1421 * This parses the blob returned from QUERY_DIRECTORY step by step. If
1422 * the blob ends, this triggers a fresh QUERY_DIRECTORY and returns
1423 * NT_STATUS_RETRY, which will then trigger the caller again when the
1424 * QUERY_DIRECTORY has returned with another buffer. This way we
1425 * guarantee that no asynchronous request is open after this call
1426 * returns an entry, so that other synchronous requests can be issued
1427 * on the same connection while the directoy listing proceeds.
1429 NTSTATUS
cli_smb2_list_recv(
1430 struct tevent_req
*req
,
1431 TALLOC_CTX
*mem_ctx
,
1432 struct file_info
**pfinfo
)
1434 struct cli_smb2_list_state
*state
= tevent_req_data(
1435 req
, struct cli_smb2_list_state
);
1436 struct cli_smb2_list_dir_data
*response
= NULL
;
1437 struct file_info
*finfo
= NULL
;
1439 uint32_t next_offset
= 0;
1442 in_progress
= tevent_req_is_in_progress(req
);
1445 if (!tevent_req_is_nterror(req
, &status
)) {
1446 status
= NT_STATUS_NO_MORE_FILES
;
1451 response
= state
->response
;
1452 if (response
== NULL
) {
1453 struct tevent_req
*subreq
= NULL
;
1454 struct cli_state
*cli
= state
->cli
;
1455 struct smb2_hnd
*ph
= NULL
;
1456 uint32_t max_trans
, max_avail_len
;
1459 if (!NT_STATUS_IS_OK(state
->status
)) {
1460 status
= state
->status
;
1464 status
= map_fnum_to_smb2_handle(cli
, state
->fnum
, &ph
);
1465 if (!NT_STATUS_IS_OK(status
)) {
1469 max_trans
= smb2cli_conn_max_trans_size(cli
->conn
);
1470 ok
= smb2cli_conn_req_possible(cli
->conn
, &max_avail_len
);
1472 max_trans
= MIN(max_trans
, max_avail_len
);
1475 subreq
= smb2cli_query_directory_send(
1476 state
, /* mem_ctx */
1478 cli
->conn
, /* conn */
1479 cli
->timeout
, /* timeout_msec */
1480 cli
->smb2
.session
, /* session */
1481 cli
->smb2
.tcon
, /* tcon */
1482 SMB2_FIND_ID_BOTH_DIRECTORY_INFO
, /* level */
1485 ph
->fid_persistent
, /* fid_persistent */
1486 ph
->fid_volatile
, /* fid_volatile */
1487 state
->mask
, /* mask */
1488 max_trans
); /* outbuf_len */
1489 if (subreq
== NULL
) {
1490 status
= NT_STATUS_NO_MEMORY
;
1493 tevent_req_set_callback(subreq
, cli_smb2_list_done
, req
);
1494 return NT_STATUS_RETRY
;
1497 SMB_ASSERT(response
->length
> state
->offset
);
1499 finfo
= talloc_zero(mem_ctx
, struct file_info
);
1500 if (finfo
== NULL
) {
1501 status
= NT_STATUS_NO_MEMORY
;
1505 status
= parse_finfo_id_both_directory_info(
1506 response
->data
+ state
->offset
,
1507 response
->length
- state
->offset
,
1510 if (!NT_STATUS_IS_OK(status
)) {
1514 status
= is_bad_finfo_name(state
->cli
, finfo
);
1515 if (!NT_STATUS_IS_OK(status
)) {
1520 * parse_finfo_id_both_directory_info() checks for overflow,
1521 * no need to check again here.
1523 state
->offset
+= next_offset
;
1525 if (next_offset
== 0) {
1526 TALLOC_FREE(state
->response
);
1529 tevent_req_defer_callback(req
, state
->ev
);
1530 tevent_req_notify_callback(req
);
1533 return NT_STATUS_OK
;
1537 tevent_req_received(req
);
1541 /***************************************************************
1542 Wrapper that allows SMB2 to query a path info (basic level).
1544 ***************************************************************/
1546 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
1548 SMB_STRUCT_STAT
*sbuf
,
1549 uint32_t *attributes
)
1552 struct smb_create_returns cr
;
1553 uint16_t fnum
= 0xffff;
1554 size_t namelen
= strlen(name
);
1556 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1558 * Can't use sync call while an async call is in flight
1560 return NT_STATUS_INVALID_PARAMETER
;
1563 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1564 return NT_STATUS_INVALID_PARAMETER
;
1567 /* SMB2 is pickier about pathnames. Ensure it doesn't
1569 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1570 char *modname
= talloc_strndup(talloc_tos(), name
, namelen
-1);
1571 if (modname
== NULL
) {
1572 return NT_STATUS_NO_MEMORY
;
1577 /* This is commonly used as a 'cd'. Try qpathinfo on
1578 a directory handle first. */
1580 status
= cli_smb2_create_fnum(cli
,
1582 0, /* create_flags */
1583 SMB2_IMPERSONATION_IMPERSONATION
,
1584 FILE_READ_ATTRIBUTES
, /* desired_access */
1585 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1586 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1587 FILE_OPEN
, /* create_disposition */
1588 FILE_DIRECTORY_FILE
, /* create_options */
1595 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
1596 /* Maybe a file ? */
1597 status
= cli_smb2_create_fnum(cli
,
1599 0, /* create_flags */
1600 SMB2_IMPERSONATION_IMPERSONATION
,
1601 FILE_READ_ATTRIBUTES
, /* desired_access */
1602 0, /* file attributes */
1603 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1604 FILE_OPEN
, /* create_disposition */
1605 0, /* create_options */
1613 if (!NT_STATUS_IS_OK(status
)) {
1617 status
= cli_smb2_close_fnum(cli
, fnum
);
1621 sbuf
->st_ex_atime
= nt_time_to_unix_timespec(cr
.last_access_time
);
1622 sbuf
->st_ex_mtime
= nt_time_to_unix_timespec(cr
.last_write_time
);
1623 sbuf
->st_ex_ctime
= nt_time_to_unix_timespec(cr
.change_time
);
1624 sbuf
->st_ex_size
= cr
.end_of_file
;
1625 *attributes
= cr
.file_attributes
;
1630 struct cli_smb2_query_info_fnum_state
{
1634 static void cli_smb2_query_info_fnum_done(struct tevent_req
*subreq
);
1636 struct tevent_req
*cli_smb2_query_info_fnum_send(
1637 TALLOC_CTX
*mem_ctx
,
1638 struct tevent_context
*ev
,
1639 struct cli_state
*cli
,
1641 uint8_t in_info_type
,
1642 uint8_t in_info_class
,
1643 uint32_t in_max_output_length
,
1644 const DATA_BLOB
*in_input_buffer
,
1645 uint32_t in_additional_info
,
1648 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1649 struct cli_smb2_query_info_fnum_state
*state
= NULL
;
1650 struct smb2_hnd
*ph
= NULL
;
1653 req
= tevent_req_create(
1654 mem_ctx
, &state
, struct cli_smb2_query_info_fnum_state
);
1659 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
1660 if (tevent_req_nterror(req
, status
)) {
1661 return tevent_req_post(req
, ev
);
1664 subreq
= smb2cli_query_info_send(
1673 in_max_output_length
,
1679 if (tevent_req_nomem(subreq
, req
)) {
1680 return tevent_req_post(req
, ev
);
1682 tevent_req_set_callback(subreq
, cli_smb2_query_info_fnum_done
, req
);
1686 static void cli_smb2_query_info_fnum_done(struct tevent_req
*subreq
)
1688 struct tevent_req
*req
= tevent_req_callback_data(
1689 subreq
, struct tevent_req
);
1690 struct cli_smb2_query_info_fnum_state
*state
= tevent_req_data(
1691 req
, struct cli_smb2_query_info_fnum_state
);
1695 status
= smb2cli_query_info_recv(subreq
, state
, &outbuf
);
1696 TALLOC_FREE(subreq
);
1697 if (tevent_req_nterror(req
, status
)) {
1702 * We have to dup the memory here because outbuf.data is not
1703 * returned as a talloc object by smb2cli_query_info_recv.
1704 * It's a pointer into the received buffer.
1706 state
->outbuf
= data_blob_dup_talloc(state
, outbuf
);
1708 if ((outbuf
.length
!= 0) &&
1709 tevent_req_nomem(state
->outbuf
.data
, req
)) {
1712 tevent_req_done(req
);
1715 NTSTATUS
cli_smb2_query_info_fnum_recv(
1716 struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
, DATA_BLOB
*outbuf
)
1718 struct cli_smb2_query_info_fnum_state
*state
= tevent_req_data(
1719 req
, struct cli_smb2_query_info_fnum_state
);
1722 if (tevent_req_is_nterror(req
, &status
)) {
1725 *outbuf
= (DATA_BLOB
) {
1726 .data
= talloc_move(mem_ctx
, &state
->outbuf
.data
),
1727 .length
= state
->outbuf
.length
,
1729 return NT_STATUS_OK
;
1732 NTSTATUS
cli_smb2_query_info_fnum(
1733 struct cli_state
*cli
,
1735 uint8_t in_info_type
,
1736 uint8_t in_info_class
,
1737 uint32_t in_max_output_length
,
1738 const DATA_BLOB
*in_input_buffer
,
1739 uint32_t in_additional_info
,
1741 TALLOC_CTX
*mem_ctx
,
1744 TALLOC_CTX
*frame
= talloc_stackframe();
1745 struct tevent_context
*ev
= NULL
;
1746 struct tevent_req
*req
= NULL
;
1747 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1750 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1752 * Can't use sync call while an async call is in flight
1754 status
= NT_STATUS_INVALID_PARAMETER
;
1757 ev
= samba_tevent_context_init(frame
);
1761 req
= cli_smb2_query_info_fnum_send(
1768 in_max_output_length
,
1775 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
1779 status
= cli_smb2_query_info_fnum_recv(req
, mem_ctx
, outbuf
);
1785 /***************************************************************
1786 Helper function for pathname operations.
1787 ***************************************************************/
1789 struct get_fnum_from_path_state
{
1790 struct tevent_context
*ev
;
1791 struct cli_state
*cli
;
1793 uint32_t desired_access
;
1797 static void get_fnum_from_path_opened_file(struct tevent_req
*subreq
);
1798 static void get_fnum_from_path_opened_reparse(struct tevent_req
*subreq
);
1799 static void get_fnum_from_path_opened_dir(struct tevent_req
*subreq
);
1801 static struct tevent_req
*get_fnum_from_path_send(
1802 TALLOC_CTX
*mem_ctx
,
1803 struct tevent_context
*ev
,
1804 struct cli_state
*cli
,
1806 uint32_t desired_access
)
1808 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1809 struct get_fnum_from_path_state
*state
= NULL
;
1810 size_t namelen
= strlen(name
);
1812 req
= tevent_req_create(
1813 mem_ctx
, &state
, struct get_fnum_from_path_state
);
1820 state
->desired_access
= desired_access
;
1823 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
1826 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1827 state
->name
= talloc_strndup(state
, name
, namelen
-1);
1828 if (tevent_req_nomem(state
->name
, req
)) {
1829 return tevent_req_post(req
, ev
);
1833 subreq
= cli_smb2_create_fnum_send(
1834 state
, /* mem_ctx, */
1837 state
->name
, /* fname */
1838 0, /* create_flags */
1839 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation_level */
1840 desired_access
, /* desired_access */
1841 0, /* file_attributes */
1844 FILE_SHARE_DELETE
, /* share_access */
1845 FILE_OPEN
, /* create_disposition */
1846 0, /* create_options */
1847 NULL
); /* in_cblobs */
1848 if (tevent_req_nomem(subreq
, req
)) {
1849 return tevent_req_post(req
, ev
);
1851 tevent_req_set_callback(subreq
, get_fnum_from_path_opened_file
, req
);
1855 static void get_fnum_from_path_opened_file(struct tevent_req
*subreq
)
1857 struct tevent_req
*req
= tevent_req_callback_data(
1858 subreq
, struct tevent_req
);
1859 struct get_fnum_from_path_state
*state
= tevent_req_data(
1860 req
, struct get_fnum_from_path_state
);
1863 status
= cli_smb2_create_fnum_recv(
1864 subreq
, &state
->fnum
, NULL
, NULL
, NULL
);
1865 TALLOC_FREE(subreq
);
1867 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
1869 * Naive option to match our SMB1 code. Assume the
1870 * symlink path that tripped us up was the last
1871 * component and try again. Eventually we will have to
1872 * deal with the returned path unprocessed component. JRA.
1874 subreq
= cli_smb2_create_fnum_send(
1875 state
, /* mem_ctx, */
1877 state
->cli
, /* cli */
1878 state
->name
, /* fname */
1879 0, /* create_flags */
1880 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation */
1881 state
->desired_access
, /* desired_access */
1882 0, /* file_attributes */
1885 FILE_SHARE_DELETE
, /* share_access */
1886 FILE_OPEN
, /* create_disposition */
1887 FILE_OPEN_REPARSE_POINT
, /* create_options */
1888 NULL
); /* in_cblobs */
1889 if (tevent_req_nomem(subreq
, req
)) {
1892 tevent_req_set_callback(
1893 subreq
, get_fnum_from_path_opened_reparse
, req
);
1897 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
1898 subreq
= cli_smb2_create_fnum_send(
1899 state
, /* mem_ctx, */
1901 state
->cli
, /* cli */
1902 state
->name
, /* fname */
1903 0, /* create_flags */
1904 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation */
1905 state
->desired_access
, /* desired_access */
1906 0, /* file_attributes */
1909 FILE_SHARE_DELETE
, /* share_access */
1910 FILE_OPEN
, /* create_disposition */
1911 FILE_DIRECTORY_FILE
, /* create_options */
1912 NULL
); /* in_cblobs */
1913 if (tevent_req_nomem(subreq
, req
)) {
1916 tevent_req_set_callback(
1917 subreq
, get_fnum_from_path_opened_dir
, req
);
1921 if (tevent_req_nterror(req
, status
)) {
1924 tevent_req_done(req
);
1927 static void get_fnum_from_path_opened_reparse(struct tevent_req
*subreq
)
1929 struct tevent_req
*req
= tevent_req_callback_data(
1930 subreq
, struct tevent_req
);
1931 struct get_fnum_from_path_state
*state
= tevent_req_data(
1932 req
, struct get_fnum_from_path_state
);
1933 NTSTATUS status
= cli_smb2_create_fnum_recv(
1934 subreq
, &state
->fnum
, NULL
, NULL
, NULL
);
1935 tevent_req_simple_finish_ntstatus(subreq
, status
);
1938 static void get_fnum_from_path_opened_dir(struct tevent_req
*subreq
)
1940 /* Abstraction violation, but these two are just the same... */
1941 get_fnum_from_path_opened_reparse(subreq
);
1944 static NTSTATUS
get_fnum_from_path_recv(
1945 struct tevent_req
*req
, uint16_t *pfnum
)
1947 struct get_fnum_from_path_state
*state
= tevent_req_data(
1948 req
, struct get_fnum_from_path_state
);
1949 NTSTATUS status
= NT_STATUS_OK
;
1951 if (!tevent_req_is_nterror(req
, &status
)) {
1952 *pfnum
= state
->fnum
;
1954 tevent_req_received(req
);
1958 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
1960 uint32_t desired_access
,
1963 TALLOC_CTX
*frame
= talloc_stackframe();
1964 struct tevent_context
*ev
= NULL
;
1965 struct tevent_req
*req
= NULL
;
1966 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1968 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1969 status
= NT_STATUS_INVALID_PARAMETER
;
1972 ev
= samba_tevent_context_init(frame
);
1976 req
= get_fnum_from_path_send(frame
, ev
, cli
, name
, desired_access
);
1980 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
1983 status
= get_fnum_from_path_recv(req
, pfnum
);
1989 /***************************************************************
1990 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1992 ***************************************************************/
1994 NTSTATUS
cli_smb2_qpathinfo_alt_name(struct cli_state
*cli
,
1999 DATA_BLOB outbuf
= data_blob_null
;
2000 uint16_t fnum
= 0xffff;
2001 uint32_t altnamelen
= 0;
2002 TALLOC_CTX
*frame
= talloc_stackframe();
2004 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2006 * Can't use sync call while an async call is in flight
2008 status
= NT_STATUS_INVALID_PARAMETER
;
2012 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2013 status
= NT_STATUS_INVALID_PARAMETER
;
2017 status
= get_fnum_from_path(cli
,
2019 FILE_READ_ATTRIBUTES
,
2022 if (!NT_STATUS_IS_OK(status
)) {
2026 status
= cli_smb2_query_info_fnum(
2029 1, /* in_info_type */
2030 (SMB_FILE_ALTERNATE_NAME_INFORMATION
- 1000), /* in_file_info_class */
2031 0xFFFF, /* in_max_output_length */
2032 NULL
, /* in_input_buffer */
2033 0, /* in_additional_info */
2038 if (!NT_STATUS_IS_OK(status
)) {
2042 /* Parse the reply. */
2043 if (outbuf
.length
< 4) {
2044 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2048 altnamelen
= IVAL(outbuf
.data
, 0);
2049 if (altnamelen
> outbuf
.length
- 4) {
2050 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2054 if (altnamelen
> 0) {
2056 char *short_name
= NULL
;
2057 ret
= pull_string_talloc(frame
,
2059 FLAGS2_UNICODE_STRINGS
,
2064 if (ret
== (size_t)-1) {
2065 /* Bad conversion. */
2066 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2070 fstrcpy(alt_name
, short_name
);
2075 status
= NT_STATUS_OK
;
2079 if (fnum
!= 0xffff) {
2080 cli_smb2_close_fnum(cli
, fnum
);
2083 cli
->raw_status
= status
;
2089 /***************************************************************
2090 Wrapper that allows SMB2 to get pathname attributes.
2092 ***************************************************************/
2094 NTSTATUS
cli_smb2_getatr(struct cli_state
*cli
,
2101 uint16_t fnum
= 0xffff;
2102 struct smb2_hnd
*ph
= NULL
;
2103 struct timespec write_time_ts
;
2104 TALLOC_CTX
*frame
= talloc_stackframe();
2106 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2108 * Can't use sync call while an async call is in flight
2110 status
= NT_STATUS_INVALID_PARAMETER
;
2114 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2115 status
= NT_STATUS_INVALID_PARAMETER
;
2119 status
= get_fnum_from_path(cli
,
2121 FILE_READ_ATTRIBUTES
,
2124 if (!NT_STATUS_IS_OK(status
)) {
2128 status
= map_fnum_to_smb2_handle(cli
,
2131 if (!NT_STATUS_IS_OK(status
)) {
2134 status
= cli_qfileinfo_basic(
2139 NULL
, /* create_time */
2140 NULL
, /* access_time */
2142 NULL
, /* change_time */
2144 if (!NT_STATUS_IS_OK(status
)) {
2147 if (write_time
!= NULL
) {
2148 *write_time
= write_time_ts
.tv_sec
;
2153 if (fnum
!= 0xffff) {
2154 cli_smb2_close_fnum(cli
, fnum
);
2157 cli
->raw_status
= status
;
2163 /***************************************************************
2164 Wrapper that allows SMB2 to query a pathname info (basic level).
2165 Implement on top of cli_qfileinfo_basic().
2167 ***************************************************************/
2169 NTSTATUS
cli_smb2_qpathinfo2(struct cli_state
*cli
,
2171 struct timespec
*create_time
,
2172 struct timespec
*access_time
,
2173 struct timespec
*write_time
,
2174 struct timespec
*change_time
,
2180 struct smb2_hnd
*ph
= NULL
;
2181 uint16_t fnum
= 0xffff;
2182 TALLOC_CTX
*frame
= talloc_stackframe();
2184 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2186 * Can't use sync call while an async call is in flight
2188 status
= NT_STATUS_INVALID_PARAMETER
;
2192 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2193 status
= NT_STATUS_INVALID_PARAMETER
;
2197 status
= get_fnum_from_path(cli
,
2199 FILE_READ_ATTRIBUTES
,
2202 if (!NT_STATUS_IS_OK(status
)) {
2206 status
= map_fnum_to_smb2_handle(cli
,
2209 if (!NT_STATUS_IS_OK(status
)) {
2213 status
= cli_qfileinfo_basic(
2226 if (fnum
!= 0xffff) {
2227 cli_smb2_close_fnum(cli
, fnum
);
2230 cli
->raw_status
= status
;
2236 /***************************************************************
2237 Wrapper that allows SMB2 to query pathname streams.
2239 ***************************************************************/
2241 NTSTATUS
cli_smb2_qpathinfo_streams(struct cli_state
*cli
,
2243 TALLOC_CTX
*mem_ctx
,
2244 unsigned int *pnum_streams
,
2245 struct stream_struct
**pstreams
)
2248 uint16_t fnum
= 0xffff;
2249 DATA_BLOB outbuf
= data_blob_null
;
2250 TALLOC_CTX
*frame
= talloc_stackframe();
2252 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2254 * Can't use sync call while an async call is in flight
2256 status
= NT_STATUS_INVALID_PARAMETER
;
2260 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2261 status
= NT_STATUS_INVALID_PARAMETER
;
2265 status
= get_fnum_from_path(cli
,
2267 FILE_READ_ATTRIBUTES
,
2270 if (!NT_STATUS_IS_OK(status
)) {
2274 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2275 level 22 (SMB2_FILE_STREAM_INFORMATION). */
2277 status
= cli_smb2_query_info_fnum(
2280 1, /* in_info_type */
2281 (SMB_FILE_STREAM_INFORMATION
- 1000), /* in_file_info_class */
2282 0xFFFF, /* in_max_output_length */
2283 NULL
, /* in_input_buffer */
2284 0, /* in_additional_info */
2289 if (!NT_STATUS_IS_OK(status
)) {
2293 /* Parse the reply. */
2294 if (!parse_streams_blob(mem_ctx
,
2299 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2305 if (fnum
!= 0xffff) {
2306 cli_smb2_close_fnum(cli
, fnum
);
2309 cli
->raw_status
= status
;
2315 /***************************************************************
2316 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2319 ***************************************************************/
2321 NTSTATUS
cli_smb2_setpathinfo(struct cli_state
*cli
,
2323 uint8_t in_info_type
,
2324 uint8_t in_file_info_class
,
2325 const DATA_BLOB
*p_in_data
)
2328 uint16_t fnum
= 0xffff;
2329 TALLOC_CTX
*frame
= talloc_stackframe();
2331 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2333 * Can't use sync call while an async call is in flight
2335 status
= NT_STATUS_INVALID_PARAMETER
;
2339 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2340 status
= NT_STATUS_INVALID_PARAMETER
;
2344 status
= get_fnum_from_path(cli
,
2346 FILE_WRITE_ATTRIBUTES
,
2349 if (!NT_STATUS_IS_OK(status
)) {
2353 status
= cli_smb2_set_info_fnum(
2358 p_in_data
, /* in_input_buffer */
2359 0); /* in_additional_info */
2362 if (fnum
!= 0xffff) {
2363 cli_smb2_close_fnum(cli
, fnum
);
2366 cli
->raw_status
= status
;
2373 /***************************************************************
2374 Wrapper that allows SMB2 to set pathname attributes.
2376 ***************************************************************/
2378 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
2383 uint8_t inbuf_store
[40];
2384 DATA_BLOB inbuf
= data_blob_null
;
2386 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2387 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2389 inbuf
.data
= inbuf_store
;
2390 inbuf
.length
= sizeof(inbuf_store
);
2391 data_blob_clear(&inbuf
);
2394 * SMB1 uses attr == 0 to clear all attributes
2395 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2396 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2397 * request attribute change.
2399 * SMB2 uses exactly the reverse. Unfortunately as the
2400 * cli_setatr() ABI is exposed inside libsmbclient,
2401 * we must make the SMB2 cli_smb2_setatr() call
2402 * export the same ABI as the SMB1 cli_setatr()
2403 * which calls it. This means reversing the sense
2404 * of the requested attr argument if it's zero
2405 * or FILE_ATTRIBUTE_NORMAL.
2407 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2411 attr
= FILE_ATTRIBUTE_NORMAL
;
2412 } else if (attr
== FILE_ATTRIBUTE_NORMAL
) {
2416 SIVAL(inbuf
.data
, 32, attr
);
2418 put_long_date((char *)inbuf
.data
+ 16,mtime
);
2420 /* Set all the other times to -1. */
2421 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
2422 SBVAL(inbuf
.data
, 8, 0xFFFFFFFFFFFFFFFFLL
);
2423 SBVAL(inbuf
.data
, 24, 0xFFFFFFFFFFFFFFFFLL
);
2425 return cli_smb2_setpathinfo(cli
,
2427 1, /* in_info_type */
2428 /* in_file_info_class */
2429 SMB_FILE_BASIC_INFORMATION
- 1000,
2434 /***************************************************************
2435 Wrapper that allows SMB2 to set file handle times.
2437 ***************************************************************/
2439 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
2445 uint8_t inbuf_store
[40];
2446 DATA_BLOB inbuf
= data_blob_null
;
2448 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2450 * Can't use sync call while an async call is in flight
2452 return NT_STATUS_INVALID_PARAMETER
;
2455 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2456 return NT_STATUS_INVALID_PARAMETER
;
2459 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2460 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2462 inbuf
.data
= inbuf_store
;
2463 inbuf
.length
= sizeof(inbuf_store
);
2464 data_blob_clear(&inbuf
);
2466 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
2467 if (change_time
!= 0) {
2468 put_long_date((char *)inbuf
.data
+ 24, change_time
);
2470 if (access_time
!= 0) {
2471 put_long_date((char *)inbuf
.data
+ 8, access_time
);
2473 if (write_time
!= 0) {
2474 put_long_date((char *)inbuf
.data
+ 16, write_time
);
2477 cli
->raw_status
= cli_smb2_set_info_fnum(
2480 1, /* in_info_type */
2481 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
2482 &inbuf
, /* in_input_buffer */
2483 0); /* in_additional_info */
2485 return cli
->raw_status
;
2488 /***************************************************************
2489 Wrapper that allows SMB2 to query disk attributes (size).
2491 ***************************************************************/
2493 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, const char *path
,
2494 uint64_t *bsize
, uint64_t *total
, uint64_t *avail
)
2497 uint16_t fnum
= 0xffff;
2498 DATA_BLOB outbuf
= data_blob_null
;
2499 uint32_t sectors_per_unit
= 0;
2500 uint32_t bytes_per_sector
= 0;
2501 uint64_t total_size
= 0;
2502 uint64_t size_free
= 0;
2503 TALLOC_CTX
*frame
= talloc_stackframe();
2505 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2507 * Can't use sync call while an async call is in flight
2509 status
= NT_STATUS_INVALID_PARAMETER
;
2513 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2514 status
= NT_STATUS_INVALID_PARAMETER
;
2518 /* First open the top level directory. */
2519 status
= cli_smb2_create_fnum(cli
,
2521 0, /* create_flags */
2522 SMB2_IMPERSONATION_IMPERSONATION
,
2523 FILE_READ_ATTRIBUTES
, /* desired_access */
2524 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2525 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
2526 FILE_OPEN
, /* create_disposition */
2527 FILE_DIRECTORY_FILE
, /* create_options */
2534 if (!NT_STATUS_IS_OK(status
)) {
2538 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2539 level 3 (SMB_FS_SIZE_INFORMATION). */
2541 status
= cli_smb2_query_info_fnum(
2544 2, /* in_info_type */
2545 3, /* in_file_info_class */
2546 0xFFFF, /* in_max_output_length */
2547 NULL
, /* in_input_buffer */
2548 0, /* in_additional_info */
2552 if (!NT_STATUS_IS_OK(status
)) {
2556 /* Parse the reply. */
2557 if (outbuf
.length
!= 24) {
2558 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2562 total_size
= BVAL(outbuf
.data
, 0);
2563 size_free
= BVAL(outbuf
.data
, 8);
2564 sectors_per_unit
= IVAL(outbuf
.data
, 16);
2565 bytes_per_sector
= IVAL(outbuf
.data
, 20);
2568 *bsize
= (uint64_t)sectors_per_unit
* (uint64_t)bytes_per_sector
;
2571 *total
= total_size
;
2577 status
= NT_STATUS_OK
;
2581 if (fnum
!= 0xffff) {
2582 cli_smb2_close_fnum(cli
, fnum
);
2585 cli
->raw_status
= status
;
2591 /***************************************************************
2592 Wrapper that allows SMB2 to query file system sizes.
2594 ***************************************************************/
2596 NTSTATUS
cli_smb2_get_fs_full_size_info(struct cli_state
*cli
,
2597 uint64_t *total_allocation_units
,
2598 uint64_t *caller_allocation_units
,
2599 uint64_t *actual_allocation_units
,
2600 uint64_t *sectors_per_allocation_unit
,
2601 uint64_t *bytes_per_sector
)
2604 uint16_t fnum
= 0xffff;
2605 DATA_BLOB outbuf
= data_blob_null
;
2606 TALLOC_CTX
*frame
= talloc_stackframe();
2608 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2610 * Can't use sync call while an async call is in flight
2612 status
= NT_STATUS_INVALID_PARAMETER
;
2616 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2617 status
= NT_STATUS_INVALID_PARAMETER
;
2621 /* First open the top level directory. */
2623 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2624 SMB2_IMPERSONATION_IMPERSONATION
,
2625 FILE_READ_ATTRIBUTES
, /* desired_access */
2626 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2627 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2628 FILE_SHARE_DELETE
, /* share_access */
2629 FILE_OPEN
, /* create_disposition */
2630 FILE_DIRECTORY_FILE
, /* create_options */
2637 if (!NT_STATUS_IS_OK(status
)) {
2641 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2642 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2644 status
= cli_smb2_query_info_fnum(
2647 SMB2_0_INFO_FILESYSTEM
, /* in_info_type */
2648 SMB_FS_FULL_SIZE_INFORMATION
- 1000, /* in_file_info_class */
2649 0xFFFF, /* in_max_output_length */
2650 NULL
, /* in_input_buffer */
2651 0, /* in_additional_info */
2655 if (!NT_STATUS_IS_OK(status
)) {
2659 if (outbuf
.length
< 32) {
2660 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2664 *total_allocation_units
= BIG_UINT(outbuf
.data
, 0);
2665 *caller_allocation_units
= BIG_UINT(outbuf
.data
, 8);
2666 *actual_allocation_units
= BIG_UINT(outbuf
.data
, 16);
2667 *sectors_per_allocation_unit
= (uint64_t)IVAL(outbuf
.data
, 24);
2668 *bytes_per_sector
= (uint64_t)IVAL(outbuf
.data
, 28);
2672 if (fnum
!= 0xffff) {
2673 cli_smb2_close_fnum(cli
, fnum
);
2676 cli
->raw_status
= status
;
2682 /***************************************************************
2683 Wrapper that allows SMB2 to query file system attributes.
2685 ***************************************************************/
2687 NTSTATUS
cli_smb2_get_fs_attr_info(struct cli_state
*cli
, uint32_t *fs_attr
)
2690 uint16_t fnum
= 0xffff;
2691 DATA_BLOB outbuf
= data_blob_null
;
2692 TALLOC_CTX
*frame
= talloc_stackframe();
2694 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2696 * Can't use sync call while an async call is in flight
2698 status
= NT_STATUS_INVALID_PARAMETER
;
2702 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2703 status
= NT_STATUS_INVALID_PARAMETER
;
2707 /* First open the top level directory. */
2709 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2710 SMB2_IMPERSONATION_IMPERSONATION
,
2711 FILE_READ_ATTRIBUTES
, /* desired_access */
2712 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2713 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2714 FILE_SHARE_DELETE
, /* share_access */
2715 FILE_OPEN
, /* create_disposition */
2716 FILE_DIRECTORY_FILE
, /* create_options */
2723 if (!NT_STATUS_IS_OK(status
)) {
2727 status
= cli_smb2_query_info_fnum(
2730 2, /* in_info_type */
2731 5, /* in_file_info_class */
2732 0xFFFF, /* in_max_output_length */
2733 NULL
, /* in_input_buffer */
2734 0, /* in_additional_info */
2738 if (!NT_STATUS_IS_OK(status
)) {
2742 if (outbuf
.length
< 12) {
2743 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2747 *fs_attr
= IVAL(outbuf
.data
, 0);
2751 if (fnum
!= 0xffff) {
2752 cli_smb2_close_fnum(cli
, fnum
);
2755 cli
->raw_status
= status
;
2761 /***************************************************************
2762 Wrapper that allows SMB2 to query file system volume info.
2764 ***************************************************************/
2766 NTSTATUS
cli_smb2_get_fs_volume_info(struct cli_state
*cli
,
2767 TALLOC_CTX
*mem_ctx
,
2768 char **_volume_name
,
2769 uint32_t *pserial_number
,
2773 uint16_t fnum
= 0xffff;
2774 DATA_BLOB outbuf
= data_blob_null
;
2776 char *volume_name
= NULL
;
2777 TALLOC_CTX
*frame
= talloc_stackframe();
2779 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2781 * Can't use sync call while an async call is in flight
2783 status
= NT_STATUS_INVALID_PARAMETER
;
2787 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2788 status
= NT_STATUS_INVALID_PARAMETER
;
2792 /* First open the top level directory. */
2794 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2795 SMB2_IMPERSONATION_IMPERSONATION
,
2796 FILE_READ_ATTRIBUTES
, /* desired_access */
2797 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2798 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2799 FILE_SHARE_DELETE
, /* share_access */
2800 FILE_OPEN
, /* create_disposition */
2801 FILE_DIRECTORY_FILE
, /* create_options */
2808 if (!NT_STATUS_IS_OK(status
)) {
2812 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2813 level 1 (SMB_FS_VOLUME_INFORMATION). */
2815 status
= cli_smb2_query_info_fnum(
2818 SMB2_0_INFO_FILESYSTEM
, /* in_info_type */
2819 /* in_file_info_class */
2820 SMB_FS_VOLUME_INFORMATION
- 1000,
2821 0xFFFF, /* in_max_output_length */
2822 NULL
, /* in_input_buffer */
2823 0, /* in_additional_info */
2827 if (!NT_STATUS_IS_OK(status
)) {
2831 if (outbuf
.length
< 24) {
2832 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2838 ts
= interpret_long_date((char *)outbuf
.data
);
2841 if (pserial_number
) {
2842 *pserial_number
= IVAL(outbuf
.data
,8);
2844 nlen
= IVAL(outbuf
.data
,12);
2845 if (nlen
+ 18 < 18) {
2847 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2851 * The next check is safe as we know outbuf.length >= 24
2854 if (nlen
> (outbuf
.length
- 18)) {
2855 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2859 pull_string_talloc(mem_ctx
,
2860 (const char *)outbuf
.data
,
2866 if (volume_name
== NULL
) {
2867 status
= map_nt_error_from_unix(errno
);
2871 *_volume_name
= volume_name
;
2875 if (fnum
!= 0xffff) {
2876 cli_smb2_close_fnum(cli
, fnum
);
2879 cli
->raw_status
= status
;
2885 struct cli_smb2_mxac_state
{
2886 struct tevent_context
*ev
;
2887 struct cli_state
*cli
;
2889 struct smb2_create_blobs in_cblobs
;
2895 static void cli_smb2_mxac_opened(struct tevent_req
*subreq
);
2896 static void cli_smb2_mxac_closed(struct tevent_req
*subreq
);
2898 struct tevent_req
*cli_smb2_query_mxac_send(TALLOC_CTX
*mem_ctx
,
2899 struct tevent_context
*ev
,
2900 struct cli_state
*cli
,
2903 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
2904 struct cli_smb2_mxac_state
*state
= NULL
;
2907 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_mxac_state
);
2911 *state
= (struct cli_smb2_mxac_state
) {
2917 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2918 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
2919 return tevent_req_post(req
, ev
);
2922 status
= smb2_create_blob_add(state
,
2924 SMB2_CREATE_TAG_MXAC
,
2925 data_blob(NULL
, 0));
2926 if (tevent_req_nterror(req
, status
)) {
2927 return tevent_req_post(req
, ev
);
2930 subreq
= cli_smb2_create_fnum_send(
2935 0, /* create_flags */
2936 SMB2_IMPERSONATION_IMPERSONATION
,
2937 FILE_READ_ATTRIBUTES
,
2938 0, /* file attributes */
2939 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
2941 0, /* create_options */
2943 if (tevent_req_nomem(subreq
, req
)) {
2944 return tevent_req_post(req
, ev
);
2946 tevent_req_set_callback(subreq
, cli_smb2_mxac_opened
, req
);
2950 static void cli_smb2_mxac_opened(struct tevent_req
*subreq
)
2952 struct tevent_req
*req
= tevent_req_callback_data(
2953 subreq
, struct tevent_req
);
2954 struct cli_smb2_mxac_state
*state
= tevent_req_data(
2955 req
, struct cli_smb2_mxac_state
);
2956 struct smb2_create_blobs out_cblobs
= {0};
2957 struct smb2_create_blob
*mxac_blob
= NULL
;
2960 status
= cli_smb2_create_fnum_recv(
2961 subreq
, &state
->fnum
, NULL
, state
, &out_cblobs
);
2962 TALLOC_FREE(subreq
);
2964 if (tevent_req_nterror(req
, status
)) {
2968 mxac_blob
= smb2_create_blob_find(&out_cblobs
, SMB2_CREATE_TAG_MXAC
);
2969 if (mxac_blob
== NULL
) {
2970 state
->status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2973 if (mxac_blob
->data
.length
!= 8) {
2974 state
->status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2978 state
->status
= NT_STATUS(IVAL(mxac_blob
->data
.data
, 0));
2979 state
->mxac
= IVAL(mxac_blob
->data
.data
, 4);
2982 subreq
= cli_smb2_close_fnum_send(
2983 state
, state
->ev
, state
->cli
, state
->fnum
);
2984 if (tevent_req_nomem(subreq
, req
)) {
2987 tevent_req_set_callback(subreq
, cli_smb2_mxac_closed
, req
);
2992 static void cli_smb2_mxac_closed(struct tevent_req
*subreq
)
2994 struct tevent_req
*req
= tevent_req_callback_data(
2995 subreq
, struct tevent_req
);
2998 status
= cli_smb2_close_fnum_recv(subreq
);
2999 if (tevent_req_nterror(req
, status
)) {
3003 tevent_req_done(req
);
3006 NTSTATUS
cli_smb2_query_mxac_recv(struct tevent_req
*req
, uint32_t *mxac
)
3008 struct cli_smb2_mxac_state
*state
= tevent_req_data(
3009 req
, struct cli_smb2_mxac_state
);
3012 if (tevent_req_is_nterror(req
, &status
)) {
3016 if (!NT_STATUS_IS_OK(state
->status
)) {
3017 return state
->status
;
3020 *mxac
= state
->mxac
;
3021 return NT_STATUS_OK
;
3024 NTSTATUS
cli_smb2_query_mxac(struct cli_state
*cli
,
3028 TALLOC_CTX
*frame
= talloc_stackframe();
3029 struct tevent_context
*ev
= NULL
;
3030 struct tevent_req
*req
= NULL
;
3031 NTSTATUS status
= NT_STATUS_INTERNAL_ERROR
;
3034 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3036 * Can't use sync call while an async call is in flight
3038 status
= NT_STATUS_INVALID_PARAMETER
;
3042 ev
= samba_tevent_context_init(frame
);
3046 req
= cli_smb2_query_mxac_send(frame
, ev
, cli
, fname
);
3050 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
3054 status
= cli_smb2_query_mxac_recv(req
, _mxac
);
3057 cli
->raw_status
= status
;
3062 struct cli_smb2_rename_fnum_state
{
3066 static void cli_smb2_rename_fnum_done(struct tevent_req
*subreq
);
3068 static struct tevent_req
*cli_smb2_rename_fnum_send(
3069 TALLOC_CTX
*mem_ctx
,
3070 struct tevent_context
*ev
,
3071 struct cli_state
*cli
,
3073 const char *fname_dst
,
3076 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
3077 struct cli_smb2_rename_fnum_state
*state
= NULL
;
3078 size_t namelen
= strlen(fname_dst
);
3079 smb_ucs2_t
*converted_str
= NULL
;
3080 size_t converted_size_bytes
= 0;
3084 req
= tevent_req_create(
3085 mem_ctx
, &state
, struct cli_smb2_rename_fnum_state
);
3091 * SMB2 is pickier about pathnames. Ensure it doesn't start in
3094 if (*fname_dst
== '\\') {
3099 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
3102 if (namelen
> 0 && fname_dst
[namelen
-1] == '\\') {
3103 fname_dst
= talloc_strndup(state
, fname_dst
, namelen
-1);
3104 if (tevent_req_nomem(fname_dst
, req
)) {
3105 return tevent_req_post(req
, ev
);
3109 ok
= push_ucs2_talloc(
3110 state
, &converted_str
, fname_dst
, &converted_size_bytes
);
3112 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3113 return tevent_req_post(req
, ev
);
3117 * W2K8 insists the dest name is not null terminated. Remove
3118 * the last 2 zero bytes and reduce the name length.
3120 if (converted_size_bytes
< 2) {
3121 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3122 return tevent_req_post(req
, ev
);
3124 converted_size_bytes
-= 2;
3126 inbuf_size
= 20 + converted_size_bytes
;
3127 if (inbuf_size
< 20) {
3128 /* Integer wrap check. */
3129 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3130 return tevent_req_post(req
, ev
);
3134 * The Windows 10 SMB2 server has a minimum length
3135 * for a SMB2_FILE_RENAME_INFORMATION buffer of
3136 * 24 bytes. It returns NT_STATUS_INFO_LENGTH_MISMATCH
3137 * if the length is less. This isn't an alignment
3138 * issue as Windows client happily 2-byte align
3139 * for larget target name sizes. Also the Windows 10
3140 * SMB1 server doesn't have this restriction.
3142 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14403
3144 inbuf_size
= MAX(inbuf_size
, 24);
3146 state
->inbuf
= data_blob_talloc_zero(state
, inbuf_size
);
3147 if (tevent_req_nomem(state
->inbuf
.data
, req
)) {
3148 return tevent_req_post(req
, ev
);
3152 SCVAL(state
->inbuf
.data
, 0, 1);
3155 SIVAL(state
->inbuf
.data
, 16, converted_size_bytes
);
3156 memcpy(state
->inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
3158 TALLOC_FREE(converted_str
);
3160 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3161 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3163 subreq
= cli_smb2_set_info_fnum_send(
3164 state
, /* mem_ctx */
3168 1, /* in_info_type */
3169 SMB_FILE_RENAME_INFORMATION
- 1000, /* in_file_info_class */
3170 &state
->inbuf
, /* in_input_buffer */
3171 0); /* in_additional_info */
3172 if (tevent_req_nomem(subreq
, req
)) {
3173 return tevent_req_post(req
, ev
);
3175 tevent_req_set_callback(subreq
, cli_smb2_rename_fnum_done
, req
);
3179 static void cli_smb2_rename_fnum_done(struct tevent_req
*subreq
)
3181 NTSTATUS status
= cli_smb2_set_info_fnum_recv(subreq
);
3182 tevent_req_simple_finish_ntstatus(subreq
, status
);
3185 static NTSTATUS
cli_smb2_rename_fnum_recv(struct tevent_req
*req
)
3187 return tevent_req_simple_recv_ntstatus(req
);
3190 /***************************************************************
3191 Wrapper that allows SMB2 to rename a file.
3192 ***************************************************************/
3194 struct cli_smb2_rename_state
{
3195 struct tevent_context
*ev
;
3196 struct cli_state
*cli
;
3197 const char *fname_dst
;
3201 NTSTATUS rename_status
;
3204 static void cli_smb2_rename_opened(struct tevent_req
*subreq
);
3205 static void cli_smb2_rename_renamed(struct tevent_req
*subreq
);
3206 static void cli_smb2_rename_closed(struct tevent_req
*subreq
);
3208 struct tevent_req
*cli_smb2_rename_send(
3209 TALLOC_CTX
*mem_ctx
,
3210 struct tevent_context
*ev
,
3211 struct cli_state
*cli
,
3212 const char *fname_src
,
3213 const char *fname_dst
,
3216 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
3217 struct cli_smb2_rename_state
*state
= NULL
;
3220 req
= tevent_req_create(
3221 mem_ctx
, &state
, struct cli_smb2_rename_state
);
3227 * Strip a MSDFS path from fname_dst if we were given one.
3229 status
= cli_dfs_target_check(state
,
3234 if (tevent_req_nterror(req
, status
)) {
3235 return tevent_req_post(req
, ev
);
3240 state
->fname_dst
= fname_dst
;
3241 state
->replace
= replace
;
3243 subreq
= get_fnum_from_path_send(
3244 state
, ev
, cli
, fname_src
, DELETE_ACCESS
);
3245 if (tevent_req_nomem(subreq
, req
)) {
3246 return tevent_req_post(req
, ev
);
3248 tevent_req_set_callback(subreq
, cli_smb2_rename_opened
, req
);
3252 static void cli_smb2_rename_opened(struct tevent_req
*subreq
)
3254 struct tevent_req
*req
= tevent_req_callback_data(
3255 subreq
, struct tevent_req
);
3256 struct cli_smb2_rename_state
*state
= tevent_req_data(
3257 req
, struct cli_smb2_rename_state
);
3260 status
= get_fnum_from_path_recv(subreq
, &state
->fnum
);
3261 TALLOC_FREE(subreq
);
3262 if (tevent_req_nterror(req
, status
)) {
3266 subreq
= cli_smb2_rename_fnum_send(
3273 if (tevent_req_nomem(subreq
, req
)) {
3276 tevent_req_set_callback(subreq
, cli_smb2_rename_renamed
, req
);
3279 static void cli_smb2_rename_renamed(struct tevent_req
*subreq
)
3281 struct tevent_req
*req
= tevent_req_callback_data(
3282 subreq
, struct tevent_req
);
3283 struct cli_smb2_rename_state
*state
= tevent_req_data(
3284 req
, struct cli_smb2_rename_state
);
3286 state
->rename_status
= cli_smb2_rename_fnum_recv(subreq
);
3287 TALLOC_FREE(subreq
);
3289 subreq
= cli_smb2_close_fnum_send(
3290 state
, state
->ev
, state
->cli
, state
->fnum
);
3291 if (tevent_req_nomem(subreq
, req
)) {
3294 tevent_req_set_callback(subreq
, cli_smb2_rename_closed
, req
);
3297 static void cli_smb2_rename_closed(struct tevent_req
*subreq
)
3299 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
3300 tevent_req_simple_finish_ntstatus(subreq
, status
);
3303 NTSTATUS
cli_smb2_rename_recv(struct tevent_req
*req
)
3305 struct cli_smb2_rename_state
*state
= tevent_req_data(
3306 req
, struct cli_smb2_rename_state
);
3307 NTSTATUS status
= NT_STATUS_OK
;
3309 if (!tevent_req_is_nterror(req
, &status
)) {
3310 status
= state
->rename_status
;
3312 tevent_req_received(req
);
3316 /***************************************************************
3317 Wrapper that allows SMB2 to set an EA on a fnum.
3319 ***************************************************************/
3321 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
3323 const char *ea_name
,
3328 DATA_BLOB inbuf
= data_blob_null
;
3330 char *ea_name_ascii
= NULL
;
3332 TALLOC_CTX
*frame
= talloc_stackframe();
3334 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3336 * Can't use sync call while an async call is in flight
3338 status
= NT_STATUS_INVALID_PARAMETER
;
3342 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3343 status
= NT_STATUS_INVALID_PARAMETER
;
3347 /* Marshall the SMB2 EA data. */
3348 if (ea_len
> 0xFFFF) {
3349 status
= NT_STATUS_INVALID_PARAMETER
;
3353 if (!push_ascii_talloc(frame
,
3357 status
= NT_STATUS_INVALID_PARAMETER
;
3361 if (namelen
< 2 || namelen
> 0xFF) {
3362 status
= NT_STATUS_INVALID_PARAMETER
;
3366 bloblen
= 8 + ea_len
+ namelen
;
3367 /* Round up to a 4 byte boundary. */
3368 bloblen
= ((bloblen
+ 3)&~3);
3370 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
3371 if (inbuf
.data
== NULL
) {
3372 status
= NT_STATUS_NO_MEMORY
;
3375 /* namelen doesn't include the NULL byte. */
3376 SCVAL(inbuf
.data
, 5, namelen
- 1);
3377 SSVAL(inbuf
.data
, 6, ea_len
);
3378 memcpy(inbuf
.data
+ 8, ea_name_ascii
, namelen
);
3379 memcpy(inbuf
.data
+ 8 + namelen
, ea_val
, ea_len
);
3381 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3382 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3384 status
= cli_smb2_set_info_fnum(
3387 1, /* in_info_type */
3388 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
3389 &inbuf
, /* in_input_buffer */
3390 0); /* in_additional_info */
3394 cli
->raw_status
= status
;
3400 /***************************************************************
3401 Wrapper that allows SMB2 to set an EA on a pathname.
3403 ***************************************************************/
3405 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
3407 const char *ea_name
,
3412 uint16_t fnum
= 0xffff;
3414 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3416 * Can't use sync call while an async call is in flight
3418 status
= NT_STATUS_INVALID_PARAMETER
;
3422 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3423 status
= NT_STATUS_INVALID_PARAMETER
;
3427 status
= get_fnum_from_path(cli
,
3432 if (!NT_STATUS_IS_OK(status
)) {
3436 status
= cli_set_ea_fnum(cli
,
3441 if (!NT_STATUS_IS_OK(status
)) {
3447 if (fnum
!= 0xffff) {
3448 cli_smb2_close_fnum(cli
, fnum
);
3451 cli
->raw_status
= status
;
3456 /***************************************************************
3457 Wrapper that allows SMB2 to get an EA list on a pathname.
3459 ***************************************************************/
3461 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
3465 struct ea_struct
**pea_array
)
3468 uint16_t fnum
= 0xffff;
3469 DATA_BLOB outbuf
= data_blob_null
;
3470 struct ea_list
*ea_list
= NULL
;
3471 struct ea_list
*eal
= NULL
;
3472 size_t ea_count
= 0;
3473 TALLOC_CTX
*frame
= talloc_stackframe();
3478 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3480 * Can't use sync call while an async call is in flight
3482 status
= NT_STATUS_INVALID_PARAMETER
;
3486 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3487 status
= NT_STATUS_INVALID_PARAMETER
;
3491 status
= get_fnum_from_path(cli
,
3496 if (!NT_STATUS_IS_OK(status
)) {
3500 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3501 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3503 status
= cli_smb2_query_info_fnum(
3506 1, /* in_info_type */
3507 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
3508 0xFFFF, /* in_max_output_length */
3509 NULL
, /* in_input_buffer */
3510 0, /* in_additional_info */
3515 if (!NT_STATUS_IS_OK(status
)) {
3519 /* Parse the reply. */
3520 ea_list
= read_nttrans_ea_list(ctx
,
3521 (const char *)outbuf
.data
,
3523 if (ea_list
== NULL
) {
3524 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3528 /* Convert to an array. */
3529 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
3534 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
3535 if (*pea_array
== NULL
) {
3536 status
= NT_STATUS_NO_MEMORY
;
3540 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
3541 (*pea_array
)[ea_count
++] = eal
->ea
;
3543 *pnum_eas
= ea_count
;
3548 if (fnum
!= 0xffff) {
3549 cli_smb2_close_fnum(cli
, fnum
);
3552 cli
->raw_status
= status
;
3558 /***************************************************************
3559 Wrapper that allows SMB2 to get user quota.
3561 ***************************************************************/
3563 NTSTATUS
cli_smb2_get_user_quota(struct cli_state
*cli
,
3565 SMB_NTQUOTA_STRUCT
*pqt
)
3568 DATA_BLOB inbuf
= data_blob_null
;
3569 DATA_BLOB info_blob
= data_blob_null
;
3570 DATA_BLOB outbuf
= data_blob_null
;
3571 TALLOC_CTX
*frame
= talloc_stackframe();
3573 unsigned int offset
;
3574 struct smb2_query_quota_info query
= {0};
3575 struct file_get_quota_info info
= {0};
3576 enum ndr_err_code err
;
3577 struct ndr_push
*ndr_push
= NULL
;
3579 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3581 * Can't use sync call while an async call is in flight
3583 status
= NT_STATUS_INVALID_PARAMETER
;
3587 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3588 status
= NT_STATUS_INVALID_PARAMETER
;
3592 sid_len
= ndr_size_dom_sid(&pqt
->sid
, 0);
3594 query
.return_single
= 1;
3596 info
.next_entry_offset
= 0;
3597 info
.sid_length
= sid_len
;
3598 info
.sid
= pqt
->sid
;
3600 err
= ndr_push_struct_blob(
3604 (ndr_push_flags_fn_t
)ndr_push_file_get_quota_info
);
3606 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3607 status
= NT_STATUS_INTERNAL_ERROR
;
3611 query
.sid_list_length
= info_blob
.length
;
3612 ndr_push
= ndr_push_init_ctx(frame
);
3614 status
= NT_STATUS_NO_MEMORY
;
3618 err
= ndr_push_smb2_query_quota_info(ndr_push
,
3619 NDR_SCALARS
| NDR_BUFFERS
,
3622 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3623 status
= NT_STATUS_INTERNAL_ERROR
;
3627 err
= ndr_push_array_uint8(ndr_push
, NDR_SCALARS
, info_blob
.data
,
3630 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3631 status
= NT_STATUS_INTERNAL_ERROR
;
3634 inbuf
.data
= ndr_push
->data
;
3635 inbuf
.length
= ndr_push
->offset
;
3637 status
= cli_smb2_query_info_fnum(
3640 4, /* in_info_type */
3641 0, /* in_file_info_class */
3642 0xFFFF, /* in_max_output_length */
3643 &inbuf
, /* in_input_buffer */
3644 0, /* in_additional_info */
3649 if (!NT_STATUS_IS_OK(status
)) {
3653 if (!parse_user_quota_record(outbuf
.data
, outbuf
.length
, &offset
,
3655 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3656 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3660 cli
->raw_status
= status
;
3666 /***************************************************************
3667 Wrapper that allows SMB2 to list user quota.
3669 ***************************************************************/
3671 NTSTATUS
cli_smb2_list_user_quota_step(struct cli_state
*cli
,
3672 TALLOC_CTX
*mem_ctx
,
3674 SMB_NTQUOTA_LIST
**pqt_list
,
3678 DATA_BLOB inbuf
= data_blob_null
;
3679 DATA_BLOB outbuf
= data_blob_null
;
3680 TALLOC_CTX
*frame
= talloc_stackframe();
3681 struct smb2_query_quota_info info
= {0};
3682 enum ndr_err_code err
;
3684 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3686 * Can't use sync call while an async call is in flight
3688 status
= NT_STATUS_INVALID_PARAMETER
;
3692 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3693 status
= NT_STATUS_INVALID_PARAMETER
;
3697 info
.restart_scan
= first
? 1 : 0;
3699 err
= ndr_push_struct_blob(
3703 (ndr_push_flags_fn_t
)ndr_push_smb2_query_quota_info
);
3705 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3706 status
= NT_STATUS_INTERNAL_ERROR
;
3710 status
= cli_smb2_query_info_fnum(
3713 4, /* in_info_type */
3714 0, /* in_file_info_class */
3715 0xFFFF, /* in_max_output_length */
3716 &inbuf
, /* in_input_buffer */
3717 0, /* in_additional_info */
3723 * safeguard against panic from calling parse_user_quota_list with
3726 if (NT_STATUS_IS_OK(status
) && outbuf
.length
== 0) {
3727 status
= NT_STATUS_NO_MORE_ENTRIES
;
3730 if (!NT_STATUS_IS_OK(status
)) {
3734 status
= parse_user_quota_list(outbuf
.data
, outbuf
.length
, mem_ctx
,
3738 cli
->raw_status
= status
;
3744 /***************************************************************
3745 Wrapper that allows SMB2 to get file system quota.
3747 ***************************************************************/
3749 NTSTATUS
cli_smb2_get_fs_quota_info(struct cli_state
*cli
,
3751 SMB_NTQUOTA_STRUCT
*pqt
)
3754 DATA_BLOB outbuf
= data_blob_null
;
3755 TALLOC_CTX
*frame
= talloc_stackframe();
3757 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3759 * Can't use sync call while an async call is in flight
3761 status
= NT_STATUS_INVALID_PARAMETER
;
3765 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3766 status
= NT_STATUS_INVALID_PARAMETER
;
3770 status
= cli_smb2_query_info_fnum(
3773 2, /* in_info_type */
3774 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
3775 0xFFFF, /* in_max_output_length */
3776 NULL
, /* in_input_buffer */
3777 0, /* in_additional_info */
3782 if (!NT_STATUS_IS_OK(status
)) {
3786 status
= parse_fs_quota_buffer(outbuf
.data
, outbuf
.length
, pqt
);
3789 cli
->raw_status
= status
;
3795 /***************************************************************
3796 Wrapper that allows SMB2 to set user quota.
3798 ***************************************************************/
3800 NTSTATUS
cli_smb2_set_user_quota(struct cli_state
*cli
,
3802 SMB_NTQUOTA_LIST
*qtl
)
3805 DATA_BLOB inbuf
= data_blob_null
;
3806 TALLOC_CTX
*frame
= talloc_stackframe();
3808 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3810 * Can't use sync call while an async call is in flight
3812 status
= NT_STATUS_INVALID_PARAMETER
;
3816 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3817 status
= NT_STATUS_INVALID_PARAMETER
;
3821 status
= build_user_quota_buffer(qtl
, 0, talloc_tos(), &inbuf
, NULL
);
3822 if (!NT_STATUS_IS_OK(status
)) {
3826 status
= cli_smb2_set_info_fnum(
3829 4, /* in_info_type */
3830 0, /* in_file_info_class */
3831 &inbuf
, /* in_input_buffer */
3832 0); /* in_additional_info */
3835 cli
->raw_status
= status
;
3842 NTSTATUS
cli_smb2_set_fs_quota_info(struct cli_state
*cli
,
3844 SMB_NTQUOTA_STRUCT
*pqt
)
3847 DATA_BLOB inbuf
= data_blob_null
;
3848 TALLOC_CTX
*frame
= talloc_stackframe();
3850 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3852 * Can't use sync call while an async call is in flight
3854 status
= NT_STATUS_INVALID_PARAMETER
;
3858 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3859 status
= NT_STATUS_INVALID_PARAMETER
;
3863 status
= build_fs_quota_buffer(talloc_tos(), pqt
, &inbuf
, 0);
3864 if (!NT_STATUS_IS_OK(status
)) {
3868 status
= cli_smb2_set_info_fnum(
3871 2, /* in_info_type */
3872 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
3873 &inbuf
, /* in_input_buffer */
3874 0); /* in_additional_info */
3876 cli
->raw_status
= status
;
3882 struct cli_smb2_read_state
{
3883 struct tevent_context
*ev
;
3884 struct cli_state
*cli
;
3885 struct smb2_hnd
*ph
;
3886 uint64_t start_offset
;
3892 static void cli_smb2_read_done(struct tevent_req
*subreq
);
3894 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
3895 struct tevent_context
*ev
,
3896 struct cli_state
*cli
,
3902 struct tevent_req
*req
, *subreq
;
3903 struct cli_smb2_read_state
*state
;
3905 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
3911 state
->start_offset
= (uint64_t)offset
;
3912 state
->size
= (uint32_t)size
;
3913 state
->received
= 0;
3916 status
= map_fnum_to_smb2_handle(cli
,
3919 if (tevent_req_nterror(req
, status
)) {
3920 return tevent_req_post(req
, ev
);
3923 subreq
= smb2cli_read_send(state
,
3926 state
->cli
->timeout
,
3927 state
->cli
->smb2
.session
,
3928 state
->cli
->smb2
.tcon
,
3930 state
->start_offset
,
3931 state
->ph
->fid_persistent
,
3932 state
->ph
->fid_volatile
,
3933 0, /* minimum_count */
3934 0); /* remaining_bytes */
3936 if (tevent_req_nomem(subreq
, req
)) {
3937 return tevent_req_post(req
, ev
);
3939 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
3943 static void cli_smb2_read_done(struct tevent_req
*subreq
)
3945 struct tevent_req
*req
= tevent_req_callback_data(
3946 subreq
, struct tevent_req
);
3947 struct cli_smb2_read_state
*state
= tevent_req_data(
3948 req
, struct cli_smb2_read_state
);
3951 status
= smb2cli_read_recv(subreq
, state
,
3952 &state
->buf
, &state
->received
);
3953 if (tevent_req_nterror(req
, status
)) {
3957 if (state
->received
> state
->size
) {
3958 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3962 tevent_req_done(req
);
3965 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
3970 struct cli_smb2_read_state
*state
= tevent_req_data(
3971 req
, struct cli_smb2_read_state
);
3973 if (tevent_req_is_nterror(req
, &status
)) {
3974 state
->cli
->raw_status
= status
;
3978 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3979 * better make sure that you copy it away before you talloc_free(req).
3980 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3982 *received
= (ssize_t
)state
->received
;
3983 *rcvbuf
= state
->buf
;
3984 state
->cli
->raw_status
= NT_STATUS_OK
;
3985 return NT_STATUS_OK
;
3988 struct cli_smb2_write_state
{
3989 struct tevent_context
*ev
;
3990 struct cli_state
*cli
;
3991 struct smb2_hnd
*ph
;
3999 static void cli_smb2_write_written(struct tevent_req
*req
);
4001 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
4002 struct tevent_context
*ev
,
4003 struct cli_state
*cli
,
4011 struct tevent_req
*req
, *subreq
= NULL
;
4012 struct cli_smb2_write_state
*state
= NULL
;
4014 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
4020 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4021 state
->flags
= (uint32_t)mode
;
4023 state
->offset
= (uint64_t)offset
;
4024 state
->size
= (uint32_t)size
;
4027 status
= map_fnum_to_smb2_handle(cli
,
4030 if (tevent_req_nterror(req
, status
)) {
4031 return tevent_req_post(req
, ev
);
4034 subreq
= smb2cli_write_send(state
,
4037 state
->cli
->timeout
,
4038 state
->cli
->smb2
.session
,
4039 state
->cli
->smb2
.tcon
,
4042 state
->ph
->fid_persistent
,
4043 state
->ph
->fid_volatile
,
4044 0, /* remaining_bytes */
4045 state
->flags
, /* flags */
4048 if (tevent_req_nomem(subreq
, req
)) {
4049 return tevent_req_post(req
, ev
);
4051 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
4055 static void cli_smb2_write_written(struct tevent_req
*subreq
)
4057 struct tevent_req
*req
= tevent_req_callback_data(
4058 subreq
, struct tevent_req
);
4059 struct cli_smb2_write_state
*state
= tevent_req_data(
4060 req
, struct cli_smb2_write_state
);
4064 status
= smb2cli_write_recv(subreq
, &written
);
4065 TALLOC_FREE(subreq
);
4066 if (tevent_req_nterror(req
, status
)) {
4070 state
->written
= written
;
4072 tevent_req_done(req
);
4075 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
4078 struct cli_smb2_write_state
*state
= tevent_req_data(
4079 req
, struct cli_smb2_write_state
);
4082 if (tevent_req_is_nterror(req
, &status
)) {
4083 state
->cli
->raw_status
= status
;
4084 tevent_req_received(req
);
4088 if (pwritten
!= NULL
) {
4089 *pwritten
= (size_t)state
->written
;
4091 state
->cli
->raw_status
= NT_STATUS_OK
;
4092 tevent_req_received(req
);
4093 return NT_STATUS_OK
;
4096 /***************************************************************
4097 Wrapper that allows SMB2 async write using an fnum.
4098 This is mostly cut-and-paste from Volker's code inside
4099 source3/libsmb/clireadwrite.c, adapted for SMB2.
4101 Done this way so I can reuse all the logic inside cli_push()
4103 ***************************************************************/
4105 struct cli_smb2_writeall_state
{
4106 struct tevent_context
*ev
;
4107 struct cli_state
*cli
;
4108 struct smb2_hnd
*ph
;
4116 static void cli_smb2_writeall_written(struct tevent_req
*req
);
4118 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
4119 struct tevent_context
*ev
,
4120 struct cli_state
*cli
,
4128 struct tevent_req
*req
, *subreq
= NULL
;
4129 struct cli_smb2_writeall_state
*state
= NULL
;
4134 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
4140 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4141 state
->flags
= (uint32_t)mode
;
4143 state
->offset
= (uint64_t)offset
;
4144 state
->size
= (uint32_t)size
;
4147 status
= map_fnum_to_smb2_handle(cli
,
4150 if (tevent_req_nterror(req
, status
)) {
4151 return tevent_req_post(req
, ev
);
4154 to_write
= state
->size
;
4155 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
4156 to_write
= MIN(max_size
, to_write
);
4157 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
4159 to_write
= MIN(max_size
, to_write
);
4162 subreq
= smb2cli_write_send(state
,
4165 state
->cli
->timeout
,
4166 state
->cli
->smb2
.session
,
4167 state
->cli
->smb2
.tcon
,
4170 state
->ph
->fid_persistent
,
4171 state
->ph
->fid_volatile
,
4172 0, /* remaining_bytes */
4173 state
->flags
, /* flags */
4174 state
->buf
+ state
->written
);
4176 if (tevent_req_nomem(subreq
, req
)) {
4177 return tevent_req_post(req
, ev
);
4179 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
4183 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
4185 struct tevent_req
*req
= tevent_req_callback_data(
4186 subreq
, struct tevent_req
);
4187 struct cli_smb2_writeall_state
*state
= tevent_req_data(
4188 req
, struct cli_smb2_writeall_state
);
4190 uint32_t written
, to_write
;
4194 status
= smb2cli_write_recv(subreq
, &written
);
4195 TALLOC_FREE(subreq
);
4196 if (tevent_req_nterror(req
, status
)) {
4200 state
->written
+= written
;
4202 if (state
->written
> state
->size
) {
4203 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4207 to_write
= state
->size
- state
->written
;
4209 if (to_write
== 0) {
4210 tevent_req_done(req
);
4214 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
4215 to_write
= MIN(max_size
, to_write
);
4216 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
4218 to_write
= MIN(max_size
, to_write
);
4221 subreq
= smb2cli_write_send(state
,
4224 state
->cli
->timeout
,
4225 state
->cli
->smb2
.session
,
4226 state
->cli
->smb2
.tcon
,
4228 state
->offset
+ state
->written
,
4229 state
->ph
->fid_persistent
,
4230 state
->ph
->fid_volatile
,
4231 0, /* remaining_bytes */
4232 state
->flags
, /* flags */
4233 state
->buf
+ state
->written
);
4235 if (tevent_req_nomem(subreq
, req
)) {
4238 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
4241 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
4244 struct cli_smb2_writeall_state
*state
= tevent_req_data(
4245 req
, struct cli_smb2_writeall_state
);
4248 if (tevent_req_is_nterror(req
, &status
)) {
4249 state
->cli
->raw_status
= status
;
4252 if (pwritten
!= NULL
) {
4253 *pwritten
= (size_t)state
->written
;
4255 state
->cli
->raw_status
= NT_STATUS_OK
;
4256 return NT_STATUS_OK
;
4259 struct cli_smb2_splice_state
{
4260 struct tevent_context
*ev
;
4261 struct cli_state
*cli
;
4262 struct smb2_hnd
*src_ph
;
4263 struct smb2_hnd
*dst_ph
;
4264 int (*splice_cb
)(off_t n
, void *priv
);
4271 struct req_resume_key_rsp resume_rsp
;
4272 struct srv_copychunk_copy cc_copy
;
4275 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
4276 struct tevent_req
*req
);
4278 static void cli_splice_copychunk_done(struct tevent_req
*subreq
)
4280 struct tevent_req
*req
= tevent_req_callback_data(
4281 subreq
, struct tevent_req
);
4282 struct cli_smb2_splice_state
*state
=
4283 tevent_req_data(req
,
4284 struct cli_smb2_splice_state
);
4285 struct smbXcli_conn
*conn
= state
->cli
->conn
;
4286 DATA_BLOB out_input_buffer
= data_blob_null
;
4287 DATA_BLOB out_output_buffer
= data_blob_null
;
4288 struct srv_copychunk_rsp cc_copy_rsp
;
4289 enum ndr_err_code ndr_ret
;
4292 status
= smb2cli_ioctl_recv(subreq
, state
,
4294 &out_output_buffer
);
4295 TALLOC_FREE(subreq
);
4296 if ((!NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
) ||
4297 state
->resized
) && tevent_req_nterror(req
, status
)) {
4301 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
, state
, &cc_copy_rsp
,
4302 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
4303 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4304 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4305 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4309 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
4310 uint32_t max_chunks
= MIN(cc_copy_rsp
.chunks_written
,
4311 cc_copy_rsp
.total_bytes_written
/ cc_copy_rsp
.chunk_bytes_written
);
4312 if ((cc_copy_rsp
.chunk_bytes_written
> smb2cli_conn_cc_chunk_len(conn
) ||
4313 max_chunks
> smb2cli_conn_cc_max_chunks(conn
)) &&
4314 tevent_req_nterror(req
, status
)) {
4318 state
->resized
= true;
4319 smb2cli_conn_set_cc_chunk_len(conn
, cc_copy_rsp
.chunk_bytes_written
);
4320 smb2cli_conn_set_cc_max_chunks(conn
, max_chunks
);
4322 if ((state
->src_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
4323 (state
->dst_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
4324 (state
->written
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
)) {
4325 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
4328 state
->src_offset
+= cc_copy_rsp
.total_bytes_written
;
4329 state
->dst_offset
+= cc_copy_rsp
.total_bytes_written
;
4330 state
->written
+= cc_copy_rsp
.total_bytes_written
;
4331 if (!state
->splice_cb(state
->written
, state
->priv
)) {
4332 tevent_req_nterror(req
, NT_STATUS_CANCELLED
);
4337 cli_splice_copychunk_send(state
, req
);
4340 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
4341 struct tevent_req
*req
)
4343 struct tevent_req
*subreq
;
4344 enum ndr_err_code ndr_ret
;
4345 struct smbXcli_conn
*conn
= state
->cli
->conn
;
4346 struct srv_copychunk_copy
*cc_copy
= &state
->cc_copy
;
4347 off_t src_offset
= state
->src_offset
;
4348 off_t dst_offset
= state
->dst_offset
;
4349 uint32_t req_len
= MIN(smb2cli_conn_cc_chunk_len(conn
) * smb2cli_conn_cc_max_chunks(conn
),
4350 state
->size
- state
->written
);
4351 DATA_BLOB in_input_buffer
= data_blob_null
;
4352 DATA_BLOB in_output_buffer
= data_blob_null
;
4354 if (state
->size
- state
->written
== 0) {
4355 tevent_req_done(req
);
4359 cc_copy
->chunk_count
= 0;
4361 cc_copy
->chunks
[cc_copy
->chunk_count
].source_off
= src_offset
;
4362 cc_copy
->chunks
[cc_copy
->chunk_count
].target_off
= dst_offset
;
4363 cc_copy
->chunks
[cc_copy
->chunk_count
].length
= MIN(req_len
,
4364 smb2cli_conn_cc_chunk_len(conn
));
4365 if (req_len
< cc_copy
->chunks
[cc_copy
->chunk_count
].length
) {
4366 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
4369 req_len
-= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4370 if ((src_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
) ||
4371 (dst_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
)) {
4372 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
4375 src_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4376 dst_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4377 cc_copy
->chunk_count
++;
4380 ndr_ret
= ndr_push_struct_blob(&in_input_buffer
, state
, cc_copy
,
4381 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
4382 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4383 DEBUG(0, ("failed to marshall copy chunk req\n"));
4384 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
4388 subreq
= smb2cli_ioctl_send(state
, state
->ev
, state
->cli
->conn
,
4389 state
->cli
->timeout
,
4390 state
->cli
->smb2
.session
,
4391 state
->cli
->smb2
.tcon
,
4392 state
->dst_ph
->fid_persistent
, /* in_fid_persistent */
4393 state
->dst_ph
->fid_volatile
, /* in_fid_volatile */
4394 FSCTL_SRV_COPYCHUNK_WRITE
,
4395 0, /* in_max_input_length */
4397 12, /* in_max_output_length */
4399 SMB2_IOCTL_FLAG_IS_FSCTL
);
4400 if (tevent_req_nomem(subreq
, req
)) {
4403 tevent_req_set_callback(subreq
,
4404 cli_splice_copychunk_done
,
4408 static void cli_splice_key_done(struct tevent_req
*subreq
)
4410 struct tevent_req
*req
= tevent_req_callback_data(
4411 subreq
, struct tevent_req
);
4412 struct cli_smb2_splice_state
*state
=
4413 tevent_req_data(req
,
4414 struct cli_smb2_splice_state
);
4415 enum ndr_err_code ndr_ret
;
4418 DATA_BLOB out_input_buffer
= data_blob_null
;
4419 DATA_BLOB out_output_buffer
= data_blob_null
;
4421 status
= smb2cli_ioctl_recv(subreq
, state
,
4423 &out_output_buffer
);
4424 TALLOC_FREE(subreq
);
4425 if (tevent_req_nterror(req
, status
)) {
4429 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
,
4430 state
, &state
->resume_rsp
,
4431 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
4432 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4433 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4434 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4438 memcpy(&state
->cc_copy
.source_key
,
4439 &state
->resume_rsp
.resume_key
,
4440 sizeof state
->resume_rsp
.resume_key
);
4442 cli_splice_copychunk_send(state
, req
);
4445 struct tevent_req
*cli_smb2_splice_send(TALLOC_CTX
*mem_ctx
,
4446 struct tevent_context
*ev
,
4447 struct cli_state
*cli
,
4448 uint16_t src_fnum
, uint16_t dst_fnum
,
4449 off_t size
, off_t src_offset
, off_t dst_offset
,
4450 int (*splice_cb
)(off_t n
, void *priv
),
4453 struct tevent_req
*req
;
4454 struct tevent_req
*subreq
;
4455 struct cli_smb2_splice_state
*state
;
4457 DATA_BLOB in_input_buffer
= data_blob_null
;
4458 DATA_BLOB in_output_buffer
= data_blob_null
;
4460 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_splice_state
);
4466 state
->splice_cb
= splice_cb
;
4470 state
->src_offset
= src_offset
;
4471 state
->dst_offset
= dst_offset
;
4472 state
->cc_copy
.chunks
= talloc_array(state
,
4473 struct srv_copychunk
,
4474 smb2cli_conn_cc_max_chunks(cli
->conn
));
4475 if (state
->cc_copy
.chunks
== NULL
) {
4479 status
= map_fnum_to_smb2_handle(cli
, src_fnum
, &state
->src_ph
);
4480 if (tevent_req_nterror(req
, status
))
4481 return tevent_req_post(req
, ev
);
4483 status
= map_fnum_to_smb2_handle(cli
, dst_fnum
, &state
->dst_ph
);
4484 if (tevent_req_nterror(req
, status
))
4485 return tevent_req_post(req
, ev
);
4487 subreq
= smb2cli_ioctl_send(state
, ev
, cli
->conn
,
4491 state
->src_ph
->fid_persistent
, /* in_fid_persistent */
4492 state
->src_ph
->fid_volatile
, /* in_fid_volatile */
4493 FSCTL_SRV_REQUEST_RESUME_KEY
,
4494 0, /* in_max_input_length */
4496 32, /* in_max_output_length */
4498 SMB2_IOCTL_FLAG_IS_FSCTL
);
4499 if (tevent_req_nomem(subreq
, req
)) {
4502 tevent_req_set_callback(subreq
,
4503 cli_splice_key_done
,
4509 NTSTATUS
cli_smb2_splice_recv(struct tevent_req
*req
, off_t
*written
)
4511 struct cli_smb2_splice_state
*state
= tevent_req_data(
4512 req
, struct cli_smb2_splice_state
);
4515 if (tevent_req_is_nterror(req
, &status
)) {
4516 state
->cli
->raw_status
= status
;
4517 tevent_req_received(req
);
4520 if (written
!= NULL
) {
4521 *written
= state
->written
;
4523 state
->cli
->raw_status
= NT_STATUS_OK
;
4524 tevent_req_received(req
);
4525 return NT_STATUS_OK
;
4528 /***************************************************************
4529 SMB2 enum shadow copy data.
4530 ***************************************************************/
4532 struct cli_smb2_shadow_copy_data_fnum_state
{
4533 struct cli_state
*cli
;
4535 struct smb2_hnd
*ph
;
4536 DATA_BLOB out_input_buffer
;
4537 DATA_BLOB out_output_buffer
;
4540 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
);
4542 static struct tevent_req
*cli_smb2_shadow_copy_data_fnum_send(
4543 TALLOC_CTX
*mem_ctx
,
4544 struct tevent_context
*ev
,
4545 struct cli_state
*cli
,
4549 struct tevent_req
*req
, *subreq
;
4550 struct cli_smb2_shadow_copy_data_fnum_state
*state
;
4553 req
= tevent_req_create(mem_ctx
, &state
,
4554 struct cli_smb2_shadow_copy_data_fnum_state
);
4559 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
4560 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
4561 return tevent_req_post(req
, ev
);
4567 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
4568 if (tevent_req_nterror(req
, status
)) {
4569 return tevent_req_post(req
, ev
);
4573 * TODO. Under SMB2 we should send a zero max_output_length
4574 * ioctl to get the required size, then send another ioctl
4575 * to get the data, but the current SMB1 implementation just
4576 * does one roundtrip with a 64K buffer size. Do the same
4580 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
4581 state
->cli
->timeout
,
4582 state
->cli
->smb2
.session
,
4583 state
->cli
->smb2
.tcon
,
4584 state
->ph
->fid_persistent
, /* in_fid_persistent */
4585 state
->ph
->fid_volatile
, /* in_fid_volatile */
4586 FSCTL_GET_SHADOW_COPY_DATA
,
4587 0, /* in_max_input_length */
4588 NULL
, /* in_input_buffer */
4590 CLI_BUFFER_SIZE
: 16, /* in_max_output_length */
4591 NULL
, /* in_output_buffer */
4592 SMB2_IOCTL_FLAG_IS_FSCTL
);
4594 if (tevent_req_nomem(subreq
, req
)) {
4595 return tevent_req_post(req
, ev
);
4597 tevent_req_set_callback(subreq
,
4598 cli_smb2_shadow_copy_data_fnum_done
,
4604 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
)
4606 struct tevent_req
*req
= tevent_req_callback_data(
4607 subreq
, struct tevent_req
);
4608 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
4609 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
4612 status
= smb2cli_ioctl_recv(subreq
, state
,
4613 &state
->out_input_buffer
,
4614 &state
->out_output_buffer
);
4615 tevent_req_simple_finish_ntstatus(subreq
, status
);
4618 static NTSTATUS
cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req
*req
,
4619 TALLOC_CTX
*mem_ctx
,
4624 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
4625 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
4626 char **names
= NULL
;
4627 uint32_t num_names
= 0;
4628 uint32_t num_names_returned
= 0;
4629 uint32_t dlength
= 0;
4631 uint8_t *endp
= NULL
;
4634 if (tevent_req_is_nterror(req
, &status
)) {
4638 if (state
->out_output_buffer
.length
< 16) {
4639 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4642 num_names
= IVAL(state
->out_output_buffer
.data
, 0);
4643 num_names_returned
= IVAL(state
->out_output_buffer
.data
, 4);
4644 dlength
= IVAL(state
->out_output_buffer
.data
, 8);
4646 if (num_names
> 0x7FFFFFFF) {
4647 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4650 if (get_names
== false) {
4651 *pnum_names
= (int)num_names
;
4652 return NT_STATUS_OK
;
4654 if (num_names
!= num_names_returned
) {
4655 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4657 if (dlength
+ 12 < 12) {
4658 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4661 * NB. The below is an allowable return if there are
4662 * more snapshots than the buffer size we told the
4663 * server we can receive. We currently don't support
4666 if (dlength
+ 12 > state
->out_output_buffer
.length
) {
4667 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4669 if (state
->out_output_buffer
.length
+
4670 (2 * sizeof(SHADOW_COPY_LABEL
)) <
4671 state
->out_output_buffer
.length
) {
4672 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4675 names
= talloc_array(mem_ctx
, char *, num_names_returned
);
4676 if (names
== NULL
) {
4677 return NT_STATUS_NO_MEMORY
;
4680 endp
= state
->out_output_buffer
.data
+
4681 state
->out_output_buffer
.length
;
4683 for (i
=0; i
<num_names_returned
; i
++) {
4686 size_t converted_size
;
4688 src
= state
->out_output_buffer
.data
+ 12 +
4689 (i
* 2 * sizeof(SHADOW_COPY_LABEL
));
4691 if (src
+ (2 * sizeof(SHADOW_COPY_LABEL
)) > endp
) {
4692 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4694 ret
= convert_string_talloc(
4695 names
, CH_UTF16LE
, CH_UNIX
,
4696 src
, 2 * sizeof(SHADOW_COPY_LABEL
),
4697 &names
[i
], &converted_size
);
4700 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4703 *pnum_names
= num_names
;
4705 return NT_STATUS_OK
;
4708 NTSTATUS
cli_smb2_shadow_copy_data(TALLOC_CTX
*mem_ctx
,
4709 struct cli_state
*cli
,
4715 TALLOC_CTX
*frame
= talloc_stackframe();
4716 struct tevent_context
*ev
;
4717 struct tevent_req
*req
;
4718 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
4720 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4722 * Can't use sync call while an async call is in flight
4724 status
= NT_STATUS_INVALID_PARAMETER
;
4727 ev
= samba_tevent_context_init(frame
);
4731 req
= cli_smb2_shadow_copy_data_fnum_send(frame
,
4739 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4742 status
= cli_smb2_shadow_copy_data_fnum_recv(req
,
4748 cli
->raw_status
= status
;
4754 /***************************************************************
4755 Wrapper that allows SMB2 to truncate a file.
4757 ***************************************************************/
4759 NTSTATUS
cli_smb2_ftruncate(struct cli_state
*cli
,
4764 uint8_t buf
[8] = {0};
4765 DATA_BLOB inbuf
= { .data
= buf
, .length
= sizeof(buf
) };
4766 TALLOC_CTX
*frame
= talloc_stackframe();
4768 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4770 * Can't use sync call while an async call is in flight
4772 status
= NT_STATUS_INVALID_PARAMETER
;
4776 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
4777 status
= NT_STATUS_INVALID_PARAMETER
;
4781 SBVAL(buf
, 0, newsize
);
4783 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4784 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4786 status
= cli_smb2_set_info_fnum(
4789 1, /* in_info_type */
4790 SMB_FILE_END_OF_FILE_INFORMATION
-1000, /* in_file_info_class */
4791 &inbuf
, /* in_input_buffer */
4796 cli
->raw_status
= status
;
4802 struct cli_smb2_notify_state
{
4803 struct tevent_req
*subreq
;
4804 struct notify_change
*changes
;
4808 static void cli_smb2_notify_done(struct tevent_req
*subreq
);
4809 static bool cli_smb2_notify_cancel(struct tevent_req
*req
);
4811 struct tevent_req
*cli_smb2_notify_send(
4812 TALLOC_CTX
*mem_ctx
,
4813 struct tevent_context
*ev
,
4814 struct cli_state
*cli
,
4816 uint32_t buffer_size
,
4817 uint32_t completion_filter
,
4820 struct tevent_req
*req
= NULL
;
4821 struct cli_smb2_notify_state
*state
= NULL
;
4822 struct smb2_hnd
*ph
= NULL
;
4825 req
= tevent_req_create(mem_ctx
, &state
,
4826 struct cli_smb2_notify_state
);
4831 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
4832 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
4833 return tevent_req_post(req
, ev
);
4836 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
4837 if (tevent_req_nterror(req
, status
)) {
4838 return tevent_req_post(req
, ev
);
4841 state
->subreq
= smb2cli_notify_send(
4853 if (tevent_req_nomem(state
->subreq
, req
)) {
4854 return tevent_req_post(req
, ev
);
4856 tevent_req_set_callback(state
->subreq
, cli_smb2_notify_done
, req
);
4857 tevent_req_set_cancel_fn(req
, cli_smb2_notify_cancel
);
4861 static bool cli_smb2_notify_cancel(struct tevent_req
*req
)
4863 struct cli_smb2_notify_state
*state
= tevent_req_data(
4864 req
, struct cli_smb2_notify_state
);
4867 ok
= tevent_req_cancel(state
->subreq
);
4871 static void cli_smb2_notify_done(struct tevent_req
*subreq
)
4873 struct tevent_req
*req
= tevent_req_callback_data(
4874 subreq
, struct tevent_req
);
4875 struct cli_smb2_notify_state
*state
= tevent_req_data(
4876 req
, struct cli_smb2_notify_state
);
4882 status
= smb2cli_notify_recv(subreq
, state
, &base
, &len
);
4883 TALLOC_FREE(subreq
);
4885 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
4886 tevent_req_done(req
);
4889 if (tevent_req_nterror(req
, status
)) {
4895 while (len
- ofs
>= 12) {
4896 struct notify_change
*tmp
;
4897 struct notify_change
*c
;
4898 uint32_t next_ofs
= IVAL(base
, ofs
);
4899 uint32_t file_name_length
= IVAL(base
, ofs
+8);
4903 tmp
= talloc_realloc(
4906 struct notify_change
,
4907 state
->num_changes
+ 1);
4908 if (tevent_req_nomem(tmp
, req
)) {
4911 state
->changes
= tmp
;
4912 c
= &state
->changes
[state
->num_changes
];
4913 state
->num_changes
+= 1;
4915 if (smb_buffer_oob(len
, ofs
, next_ofs
) ||
4916 smb_buffer_oob(len
, ofs
+12, file_name_length
)) {
4918 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4922 c
->action
= IVAL(base
, ofs
+4);
4924 ok
= convert_string_talloc(
4934 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4938 if (next_ofs
== 0) {
4944 tevent_req_done(req
);
4947 NTSTATUS
cli_smb2_notify_recv(struct tevent_req
*req
,
4948 TALLOC_CTX
*mem_ctx
,
4949 struct notify_change
**pchanges
,
4950 uint32_t *pnum_changes
)
4952 struct cli_smb2_notify_state
*state
= tevent_req_data(
4953 req
, struct cli_smb2_notify_state
);
4956 if (tevent_req_is_nterror(req
, &status
)) {
4959 *pchanges
= talloc_move(mem_ctx
, &state
->changes
);
4960 *pnum_changes
= state
->num_changes
;
4961 return NT_STATUS_OK
;
4964 NTSTATUS
cli_smb2_notify(struct cli_state
*cli
, uint16_t fnum
,
4965 uint32_t buffer_size
, uint32_t completion_filter
,
4966 bool recursive
, TALLOC_CTX
*mem_ctx
,
4967 struct notify_change
**pchanges
,
4968 uint32_t *pnum_changes
)
4970 TALLOC_CTX
*frame
= talloc_stackframe();
4971 struct tevent_context
*ev
;
4972 struct tevent_req
*req
;
4973 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
4975 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4977 * Can't use sync call while an async call is in flight
4979 status
= NT_STATUS_INVALID_PARAMETER
;
4982 ev
= samba_tevent_context_init(frame
);
4986 req
= cli_smb2_notify_send(
4997 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
5000 status
= cli_smb2_notify_recv(req
, mem_ctx
, pchanges
, pnum_changes
);
5006 struct cli_smb2_set_reparse_point_fnum_state
{
5007 struct cli_state
*cli
;
5009 struct smb2_hnd
*ph
;
5010 DATA_BLOB input_buffer
;
5013 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req
*subreq
);
5015 struct tevent_req
*cli_smb2_set_reparse_point_fnum_send(
5016 TALLOC_CTX
*mem_ctx
,
5017 struct tevent_context
*ev
,
5018 struct cli_state
*cli
,
5022 struct tevent_req
*req
, *subreq
;
5023 struct cli_smb2_set_reparse_point_fnum_state
*state
= NULL
;
5026 req
= tevent_req_create(mem_ctx
, &state
,
5027 struct cli_smb2_set_reparse_point_fnum_state
);
5032 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
5033 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
5034 return tevent_req_post(req
, ev
);
5040 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
5041 if (tevent_req_nterror(req
, status
)) {
5042 return tevent_req_post(req
, ev
);
5045 state
->input_buffer
= data_blob_talloc(state
,
5048 if (state
->input_buffer
.data
== NULL
) {
5049 tevent_req_nterror(req
, NT_STATUS_NO_MEMORY
);
5050 return tevent_req_post(req
, ev
);
5053 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
5054 state
->cli
->timeout
,
5055 state
->cli
->smb2
.session
,
5056 state
->cli
->smb2
.tcon
,
5057 state
->ph
->fid_persistent
, /* in_fid_persistent */
5058 state
->ph
->fid_volatile
, /* in_fid_volatile */
5059 FSCTL_SET_REPARSE_POINT
,
5060 0, /* in_max_input_length */
5061 &state
->input_buffer
,
5064 SMB2_IOCTL_FLAG_IS_FSCTL
);
5066 if (tevent_req_nomem(subreq
, req
)) {
5067 return tevent_req_post(req
, ev
);
5069 tevent_req_set_callback(subreq
,
5070 cli_smb2_set_reparse_point_fnum_done
,
5076 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req
*subreq
)
5078 struct tevent_req
*req
= tevent_req_callback_data(
5079 subreq
, struct tevent_req
);
5080 struct cli_smb2_set_reparse_point_fnum_state
*state
= tevent_req_data(
5081 req
, struct cli_smb2_set_reparse_point_fnum_state
);
5084 status
= smb2cli_ioctl_recv(subreq
, state
,
5087 TALLOC_FREE(subreq
);
5088 if (tevent_req_nterror(req
, status
)) {
5091 tevent_req_done(req
);
5094 NTSTATUS
cli_smb2_set_reparse_point_fnum_recv(struct tevent_req
*req
)
5096 return tevent_req_simple_recv_ntstatus(req
);
5099 struct cli_smb2_get_reparse_point_fnum_state
{
5100 struct cli_state
*cli
;
5102 struct smb2_hnd
*ph
;
5103 DATA_BLOB output_buffer
;
5106 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req
*subreq
);
5108 struct tevent_req
*cli_smb2_get_reparse_point_fnum_send(
5109 TALLOC_CTX
*mem_ctx
,
5110 struct tevent_context
*ev
,
5111 struct cli_state
*cli
,
5114 struct tevent_req
*req
, *subreq
;
5115 struct cli_smb2_get_reparse_point_fnum_state
*state
= NULL
;
5118 req
= tevent_req_create(mem_ctx
, &state
,
5119 struct cli_smb2_get_reparse_point_fnum_state
);
5124 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
5125 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
5126 return tevent_req_post(req
, ev
);
5132 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
5133 if (tevent_req_nterror(req
, status
)) {
5134 return tevent_req_post(req
, ev
);
5137 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
5138 state
->cli
->timeout
,
5139 state
->cli
->smb2
.session
,
5140 state
->cli
->smb2
.tcon
,
5141 state
->ph
->fid_persistent
, /* in_fid_persistent */
5142 state
->ph
->fid_volatile
, /* in_fid_volatile */
5143 FSCTL_GET_REPARSE_POINT
,
5144 0, /* in_max_input_length */
5148 SMB2_IOCTL_FLAG_IS_FSCTL
);
5150 if (tevent_req_nomem(subreq
, req
)) {
5151 return tevent_req_post(req
, ev
);
5153 tevent_req_set_callback(subreq
,
5154 cli_smb2_get_reparse_point_fnum_done
,
5160 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req
*subreq
)
5162 struct tevent_req
*req
= tevent_req_callback_data(
5163 subreq
, struct tevent_req
);
5164 struct cli_smb2_get_reparse_point_fnum_state
*state
= tevent_req_data(
5165 req
, struct cli_smb2_get_reparse_point_fnum_state
);
5166 struct cli_state
*cli
= state
->cli
;
5169 status
= smb2cli_ioctl_recv(subreq
, state
,
5171 &state
->output_buffer
);
5172 TALLOC_FREE(subreq
);
5173 if (tevent_req_nterror(req
, status
)) {
5174 cli
->raw_status
= status
;
5177 tevent_req_done(req
);
5180 NTSTATUS
cli_smb2_get_reparse_point_fnum_recv(struct tevent_req
*req
,
5181 TALLOC_CTX
*mem_ctx
,
5184 struct cli_smb2_get_reparse_point_fnum_state
*state
= tevent_req_data(
5185 req
, struct cli_smb2_get_reparse_point_fnum_state
);
5187 if (tevent_req_is_nterror(req
, &state
->cli
->raw_status
)) {
5188 NTSTATUS status
= state
->cli
->raw_status
;
5189 tevent_req_received(req
);
5192 *output
= data_blob_dup_talloc(mem_ctx
, state
->output_buffer
);
5193 if (output
->data
== NULL
) {
5194 tevent_req_received(req
);
5195 return NT_STATUS_NO_MEMORY
;
5197 tevent_req_received(req
);
5198 return NT_STATUS_OK
;