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"
47 uint64_t fid_persistent
;
48 uint64_t fid_volatile
;
52 * Handle mapping code.
55 /***************************************************************
56 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
57 Ensures handle is owned by cli struct.
58 ***************************************************************/
60 static NTSTATUS
map_smb2_handle_to_fnum(struct cli_state
*cli
,
61 const struct smb2_hnd
*ph
, /* In */
62 uint16_t *pfnum
) /* Out */
65 struct idr_context
*idp
= cli
->smb2
.open_handles
;
66 struct smb2_hnd
*owned_h
= talloc_memdup(cli
,
68 sizeof(struct smb2_hnd
));
70 if (owned_h
== NULL
) {
71 return NT_STATUS_NO_MEMORY
;
76 cli
->smb2
.open_handles
= idr_init(cli
);
77 if (cli
->smb2
.open_handles
== NULL
) {
79 return NT_STATUS_NO_MEMORY
;
81 idp
= cli
->smb2
.open_handles
;
84 ret
= idr_get_new_above(idp
, owned_h
, 1, 0xFFFE);
87 return NT_STATUS_NO_MEMORY
;
90 *pfnum
= (uint16_t)ret
;
94 /***************************************************************
95 Return the smb2_hnd pointer associated with the given fnum.
96 ***************************************************************/
98 static NTSTATUS
map_fnum_to_smb2_handle(struct cli_state
*cli
,
99 uint16_t fnum
, /* In */
100 struct smb2_hnd
**pph
) /* Out */
102 struct idr_context
*idp
= cli
->smb2
.open_handles
;
105 return NT_STATUS_INVALID_PARAMETER
;
107 *pph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
109 return NT_STATUS_INVALID_HANDLE
;
114 /***************************************************************
115 Delete the fnum to smb2_hnd mapping. Zeros out handle on
117 ***************************************************************/
119 static NTSTATUS
delete_smb2_handle_mapping(struct cli_state
*cli
,
120 struct smb2_hnd
**pph
, /* In */
121 uint16_t fnum
) /* In */
123 struct idr_context
*idp
= cli
->smb2
.open_handles
;
127 return NT_STATUS_INVALID_PARAMETER
;
130 ph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
132 return NT_STATUS_INVALID_PARAMETER
;
134 idr_remove(idp
, fnum
);
139 /***************************************************************
141 ***************************************************************/
143 static uint8_t flags_to_smb2_oplock(uint32_t create_flags
)
145 if (create_flags
& REQUEST_BATCH_OPLOCK
) {
146 return SMB2_OPLOCK_LEVEL_BATCH
;
147 } else if (create_flags
& REQUEST_OPLOCK
) {
148 return SMB2_OPLOCK_LEVEL_EXCLUSIVE
;
151 /* create_flags doesn't do a level2 request. */
152 return SMB2_OPLOCK_LEVEL_NONE
;
155 /***************************************************************
156 Small wrapper that allows SMB2 create to return a uint16_t fnum.
157 ***************************************************************/
159 struct cli_smb2_create_fnum_state
{
160 struct cli_state
*cli
;
161 struct smb2_create_blobs in_cblobs
;
162 struct smb2_create_blobs out_cblobs
;
163 struct smb_create_returns cr
;
165 struct tevent_req
*subreq
;
168 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
);
169 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
);
171 struct tevent_req
*cli_smb2_create_fnum_send(
173 struct tevent_context
*ev
,
174 struct cli_state
*cli
,
176 uint32_t create_flags
,
177 uint32_t impersonation_level
,
178 uint32_t desired_access
,
179 uint32_t file_attributes
,
180 uint32_t share_access
,
181 uint32_t create_disposition
,
182 uint32_t create_options
,
183 const struct smb2_create_blobs
*in_cblobs
)
185 struct tevent_req
*req
, *subreq
;
186 struct cli_smb2_create_fnum_state
*state
;
187 size_t fname_len
= 0;
188 const char *startp
= NULL
;
189 const char *endp
= NULL
;
190 time_t tstamp
= (time_t)0;
193 req
= tevent_req_create(mem_ctx
, &state
,
194 struct cli_smb2_create_fnum_state
);
200 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
201 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
202 return tevent_req_post(req
, ev
);
205 if (cli
->backup_intent
) {
206 create_options
|= FILE_OPEN_FOR_BACKUP_INTENT
;
209 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
210 fname_len
= strlen(fname
);
211 if (clistr_is_previous_version_path(fname
, &startp
, &endp
, &tstamp
)) {
212 size_t len_before_gmt
= startp
- fname
;
213 size_t len_after_gmt
= fname
+ fname_len
- endp
;
217 char *new_fname
= talloc_array(state
, char,
218 len_before_gmt
+ len_after_gmt
+ 1);
220 if (tevent_req_nomem(new_fname
, req
)) {
221 return tevent_req_post(req
, ev
);
224 memcpy(new_fname
, fname
, len_before_gmt
);
225 memcpy(new_fname
+ len_before_gmt
, endp
, len_after_gmt
+ 1);
227 fname_len
= len_before_gmt
+ len_after_gmt
;
229 unix_to_nt_time(&ntt
, tstamp
);
230 twrp_blob
= data_blob_const((const void *)&ntt
, 8);
232 status
= smb2_create_blob_add(
235 SMB2_CREATE_TAG_TWRP
,
237 if (!NT_STATUS_IS_OK(status
)) {
238 tevent_req_nterror(req
, status
);
239 return tevent_req_post(req
, ev
);
243 if (in_cblobs
!= NULL
) {
245 for (i
=0; i
<in_cblobs
->num_blobs
; i
++) {
246 struct smb2_create_blob
*b
= &in_cblobs
->blobs
[i
];
247 status
= smb2_create_blob_add(
248 state
, &state
->in_cblobs
, b
->tag
, b
->data
);
249 if (!NT_STATUS_IS_OK(status
)) {
250 tevent_req_nterror(req
, status
);
251 return tevent_req_post(req
, ev
);
256 /* SMB2 is pickier about pathnames. Ensure it doesn't
258 if (*fname
== '\\') {
263 /* Or end in a '\' */
264 if (fname_len
> 0 && fname
[fname_len
-1] == '\\') {
265 char *new_fname
= talloc_strdup(state
, fname
);
266 if (tevent_req_nomem(new_fname
, req
)) {
267 return tevent_req_post(req
, ev
);
269 new_fname
[fname_len
-1] = '\0';
273 subreq
= smb2cli_create_send(state
, ev
,
279 flags_to_smb2_oplock(create_flags
),
287 if (tevent_req_nomem(subreq
, req
)) {
288 return tevent_req_post(req
, ev
);
290 tevent_req_set_callback(subreq
, cli_smb2_create_fnum_done
, req
);
292 state
->subreq
= subreq
;
293 tevent_req_set_cancel_fn(req
, cli_smb2_create_fnum_cancel
);
298 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
)
300 struct tevent_req
*req
= tevent_req_callback_data(
301 subreq
, struct tevent_req
);
302 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
303 req
, struct cli_smb2_create_fnum_state
);
307 status
= smb2cli_create_recv(
310 &h
.fid_volatile
, &state
->cr
,
314 if (tevent_req_nterror(req
, status
)) {
318 status
= map_smb2_handle_to_fnum(state
->cli
, &h
, &state
->fnum
);
319 if (tevent_req_nterror(req
, status
)) {
322 tevent_req_done(req
);
325 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
)
327 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
328 req
, struct cli_smb2_create_fnum_state
);
329 return tevent_req_cancel(state
->subreq
);
332 NTSTATUS
cli_smb2_create_fnum_recv(
333 struct tevent_req
*req
,
335 struct smb_create_returns
*cr
,
337 struct smb2_create_blobs
*out_cblobs
)
339 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
340 req
, struct cli_smb2_create_fnum_state
);
343 if (tevent_req_is_nterror(req
, &status
)) {
344 state
->cli
->raw_status
= status
;
348 *pfnum
= state
->fnum
;
353 if (out_cblobs
!= NULL
) {
354 *out_cblobs
= (struct smb2_create_blobs
) {
355 .num_blobs
= state
->out_cblobs
.num_blobs
,
356 .blobs
= talloc_move(
357 mem_ctx
, &state
->out_cblobs
.blobs
),
360 state
->cli
->raw_status
= NT_STATUS_OK
;
364 NTSTATUS
cli_smb2_create_fnum(
365 struct cli_state
*cli
,
367 uint32_t create_flags
,
368 uint32_t impersonation_level
,
369 uint32_t desired_access
,
370 uint32_t file_attributes
,
371 uint32_t share_access
,
372 uint32_t create_disposition
,
373 uint32_t create_options
,
374 const struct smb2_create_blobs
*in_cblobs
,
376 struct smb_create_returns
*cr
,
378 struct smb2_create_blobs
*out_cblobs
)
380 TALLOC_CTX
*frame
= talloc_stackframe();
381 struct tevent_context
*ev
;
382 struct tevent_req
*req
;
383 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
385 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
387 * Can't use sync call while an async call is in flight
389 status
= NT_STATUS_INVALID_PARAMETER
;
392 ev
= samba_tevent_context_init(frame
);
396 req
= cli_smb2_create_fnum_send(
412 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
415 status
= cli_smb2_create_fnum_recv(req
, pfid
, cr
, mem_ctx
, out_cblobs
);
421 /***************************************************************
422 Small wrapper that allows SMB2 close to use a uint16_t fnum.
423 ***************************************************************/
425 struct cli_smb2_close_fnum_state
{
426 struct cli_state
*cli
;
431 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
);
433 struct tevent_req
*cli_smb2_close_fnum_send(TALLOC_CTX
*mem_ctx
,
434 struct tevent_context
*ev
,
435 struct cli_state
*cli
,
438 struct tevent_req
*req
, *subreq
;
439 struct cli_smb2_close_fnum_state
*state
;
442 req
= tevent_req_create(mem_ctx
, &state
,
443 struct cli_smb2_close_fnum_state
);
450 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
451 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
452 return tevent_req_post(req
, ev
);
455 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
456 if (tevent_req_nterror(req
, status
)) {
457 return tevent_req_post(req
, ev
);
460 subreq
= smb2cli_close_send(state
, ev
, cli
->conn
, cli
->timeout
,
461 cli
->smb2
.session
, cli
->smb2
.tcon
,
462 0, state
->ph
->fid_persistent
,
463 state
->ph
->fid_volatile
);
464 if (tevent_req_nomem(subreq
, req
)) {
465 return tevent_req_post(req
, ev
);
467 tevent_req_set_callback(subreq
, cli_smb2_close_fnum_done
, req
);
471 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
)
473 struct tevent_req
*req
= tevent_req_callback_data(
474 subreq
, struct tevent_req
);
475 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
476 req
, struct cli_smb2_close_fnum_state
);
479 status
= smb2cli_close_recv(subreq
);
480 if (tevent_req_nterror(req
, status
)) {
484 /* Delete the fnum -> handle mapping. */
485 status
= delete_smb2_handle_mapping(state
->cli
, &state
->ph
,
487 if (tevent_req_nterror(req
, status
)) {
490 tevent_req_done(req
);
493 NTSTATUS
cli_smb2_close_fnum_recv(struct tevent_req
*req
)
495 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
496 req
, struct cli_smb2_close_fnum_state
);
497 NTSTATUS status
= NT_STATUS_OK
;
499 if (tevent_req_is_nterror(req
, &status
)) {
500 state
->cli
->raw_status
= status
;
502 tevent_req_received(req
);
506 NTSTATUS
cli_smb2_close_fnum(struct cli_state
*cli
, uint16_t fnum
)
508 TALLOC_CTX
*frame
= talloc_stackframe();
509 struct tevent_context
*ev
;
510 struct tevent_req
*req
;
511 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
513 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
515 * Can't use sync call while an async call is in flight
517 status
= NT_STATUS_INVALID_PARAMETER
;
520 ev
= samba_tevent_context_init(frame
);
524 req
= cli_smb2_close_fnum_send(frame
, ev
, cli
, fnum
);
528 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
531 status
= cli_smb2_close_fnum_recv(req
);
537 struct cli_smb2_delete_on_close_state
{
538 struct cli_state
*cli
;
545 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
);
547 struct tevent_req
*cli_smb2_delete_on_close_send(TALLOC_CTX
*mem_ctx
,
548 struct tevent_context
*ev
,
549 struct cli_state
*cli
,
553 struct tevent_req
*req
= NULL
;
554 struct cli_smb2_delete_on_close_state
*state
= NULL
;
555 struct tevent_req
*subreq
= NULL
;
556 uint8_t in_info_type
;
557 uint8_t in_file_info_class
;
560 req
= tevent_req_create(mem_ctx
, &state
,
561 struct cli_smb2_delete_on_close_state
);
568 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
569 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
570 return tevent_req_post(req
, ev
);
573 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
574 if (tevent_req_nterror(req
, status
)) {
575 return tevent_req_post(req
, ev
);
579 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
580 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
583 in_file_info_class
= SMB_FILE_DISPOSITION_INFORMATION
- 1000;
584 /* Setup data array. */
585 SCVAL(&state
->data
[0], 0, flag
? 1 : 0);
586 state
->inbuf
.data
= &state
->data
[0];
587 state
->inbuf
.length
= 1;
589 subreq
= smb2cli_set_info_send(state
, ev
,
596 &state
->inbuf
, /* in_input_buffer */
597 0, /* in_additional_info */
598 state
->ph
->fid_persistent
,
599 state
->ph
->fid_volatile
);
600 if (tevent_req_nomem(subreq
, req
)) {
601 return tevent_req_post(req
, ev
);
603 tevent_req_set_callback(subreq
,
604 cli_smb2_delete_on_close_done
,
609 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
)
611 NTSTATUS status
= smb2cli_set_info_recv(subreq
);
612 tevent_req_simple_finish_ntstatus(subreq
, status
);
615 NTSTATUS
cli_smb2_delete_on_close_recv(struct tevent_req
*req
)
617 struct cli_smb2_delete_on_close_state
*state
=
619 struct cli_smb2_delete_on_close_state
);
622 if (tevent_req_is_nterror(req
, &status
)) {
623 state
->cli
->raw_status
= status
;
624 tevent_req_received(req
);
628 state
->cli
->raw_status
= NT_STATUS_OK
;
629 tevent_req_received(req
);
633 NTSTATUS
cli_smb2_delete_on_close(struct cli_state
*cli
, uint16_t fnum
, bool flag
)
635 TALLOC_CTX
*frame
= talloc_stackframe();
636 struct tevent_context
*ev
;
637 struct tevent_req
*req
;
638 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
640 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
642 * Can't use sync call while an async call is in flight
644 status
= NT_STATUS_INVALID_PARAMETER
;
647 ev
= samba_tevent_context_init(frame
);
651 req
= cli_smb2_delete_on_close_send(frame
, ev
, cli
, fnum
, flag
);
655 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
658 status
= cli_smb2_delete_on_close_recv(req
);
664 /***************************************************************
665 Small wrapper that allows SMB2 to create a directory
667 ***************************************************************/
669 NTSTATUS
cli_smb2_mkdir(struct cli_state
*cli
, const char *dname
)
674 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
676 * Can't use sync call while an async call is in flight
678 return NT_STATUS_INVALID_PARAMETER
;
681 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
682 return NT_STATUS_INVALID_PARAMETER
;
685 status
= cli_smb2_create_fnum(cli
,
687 0, /* create_flags */
688 SMB2_IMPERSONATION_IMPERSONATION
,
689 FILE_READ_ATTRIBUTES
, /* desired_access */
690 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
691 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
692 FILE_CREATE
, /* create_disposition */
693 FILE_DIRECTORY_FILE
, /* create_options */
700 if (!NT_STATUS_IS_OK(status
)) {
703 return cli_smb2_close_fnum(cli
, fnum
);
706 struct cli_smb2_rmdir_state
{
707 struct tevent_context
*ev
;
708 struct cli_state
*cli
;
710 const struct smb2_create_blobs
*in_cblobs
;
715 static void cli_smb2_rmdir_opened1(struct tevent_req
*subreq
);
716 static void cli_smb2_rmdir_opened2(struct tevent_req
*subreq
);
717 static void cli_smb2_rmdir_disp_set(struct tevent_req
*subreq
);
718 static void cli_smb2_rmdir_closed(struct tevent_req
*subreq
);
720 struct tevent_req
*cli_smb2_rmdir_send(
722 struct tevent_context
*ev
,
723 struct cli_state
*cli
,
725 const struct smb2_create_blobs
*in_cblobs
)
727 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
728 struct cli_smb2_rmdir_state
*state
= NULL
;
730 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_rmdir_state
);
736 state
->dname
= dname
;
737 state
->in_cblobs
= in_cblobs
;
739 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
740 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
741 return tevent_req_post(req
, ev
);
744 subreq
= cli_smb2_create_fnum_send(
749 0, /* create_flags */
750 SMB2_IMPERSONATION_IMPERSONATION
,
751 DELETE_ACCESS
, /* desired_access */
752 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
753 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
754 FILE_OPEN
, /* create_disposition */
755 FILE_DIRECTORY_FILE
, /* create_options */
756 state
->in_cblobs
); /* in_cblobs */
757 if (tevent_req_nomem(subreq
, req
)) {
758 return tevent_req_post(req
, ev
);
760 tevent_req_set_callback(subreq
, cli_smb2_rmdir_opened1
, req
);
764 static void cli_smb2_rmdir_opened1(struct tevent_req
*subreq
)
766 struct tevent_req
*req
= tevent_req_callback_data(
767 subreq
, struct tevent_req
);
768 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
769 req
, struct cli_smb2_rmdir_state
);
772 status
= cli_smb2_create_fnum_recv(
773 subreq
, &state
->fnum
, NULL
, NULL
, NULL
);
776 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
778 * Naive option to match our SMB1 code. Assume the
779 * symlink path that tripped us up was the last
780 * component and try again. Eventually we will have to
781 * deal with the returned path unprocessed component. JRA.
783 subreq
= cli_smb2_create_fnum_send(
788 0, /* create_flags */
789 SMB2_IMPERSONATION_IMPERSONATION
,
790 DELETE_ACCESS
, /* desired_access */
791 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
792 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
793 FILE_OPEN
, /* create_disposition */
795 FILE_DELETE_ON_CLOSE
|
796 FILE_OPEN_REPARSE_POINT
, /* create_options */
797 state
->in_cblobs
); /* in_cblobs */
798 if (tevent_req_nomem(subreq
, req
)) {
801 tevent_req_set_callback(subreq
, cli_smb2_rmdir_opened2
, req
);
805 if (tevent_req_nterror(req
, status
)) {
809 subreq
= cli_smb2_delete_on_close_send(
810 state
, state
->ev
, state
->cli
, state
->fnum
, true);
811 if (tevent_req_nomem(subreq
, req
)) {
814 tevent_req_set_callback(subreq
, cli_smb2_rmdir_disp_set
, req
);
817 static void cli_smb2_rmdir_opened2(struct tevent_req
*subreq
)
819 struct tevent_req
*req
= tevent_req_callback_data(
820 subreq
, struct tevent_req
);
821 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
822 req
, struct cli_smb2_rmdir_state
);
825 status
= cli_smb2_create_fnum_recv(
826 subreq
, &state
->fnum
, NULL
, NULL
, NULL
);
828 if (tevent_req_nterror(req
, status
)) {
832 subreq
= cli_smb2_delete_on_close_send(
833 state
, state
->ev
, state
->cli
, state
->fnum
, true);
834 if (tevent_req_nomem(subreq
, req
)) {
837 tevent_req_set_callback(subreq
, cli_smb2_rmdir_disp_set
, req
);
840 static void cli_smb2_rmdir_disp_set(struct tevent_req
*subreq
)
842 struct tevent_req
*req
= tevent_req_callback_data(
843 subreq
, struct tevent_req
);
844 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
845 req
, struct cli_smb2_rmdir_state
);
847 state
->status
= cli_smb2_delete_on_close_recv(subreq
);
851 * Close the fd even if the set_disp failed
854 subreq
= cli_smb2_close_fnum_send(
855 state
, state
->ev
, state
->cli
, state
->fnum
);
856 if (tevent_req_nomem(subreq
, req
)) {
859 tevent_req_set_callback(subreq
, cli_smb2_rmdir_closed
, req
);
862 static void cli_smb2_rmdir_closed(struct tevent_req
*subreq
)
864 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
865 tevent_req_simple_finish_ntstatus(subreq
, status
);
868 NTSTATUS
cli_smb2_rmdir_recv(struct tevent_req
*req
)
870 struct cli_smb2_rmdir_state
*state
= tevent_req_data(
871 req
, struct cli_smb2_rmdir_state
);
874 if (tevent_req_is_nterror(req
, &status
)) {
877 return state
->status
;
880 NTSTATUS
cli_smb2_rmdir(
881 struct cli_state
*cli
,
883 const struct smb2_create_blobs
*in_cblobs
)
885 TALLOC_CTX
*frame
= talloc_stackframe();
886 struct tevent_context
*ev
;
887 struct tevent_req
*req
;
888 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
891 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
893 * Can't use sync call while an async call is in flight
895 status
= NT_STATUS_INVALID_PARAMETER
;
898 ev
= samba_tevent_context_init(frame
);
902 req
= cli_smb2_rmdir_send(frame
, ev
, cli
, dname
, in_cblobs
);
906 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
910 status
= cli_smb2_rmdir_recv(req
);
912 cli
->raw_status
= status
;
917 /***************************************************************
918 Small wrapper that allows SMB2 to unlink a pathname.
920 ***************************************************************/
922 struct cli_smb2_unlink_state
{
923 struct tevent_context
*ev
;
924 struct cli_state
*cli
;
926 const struct smb2_create_blobs
*in_cblobs
;
929 static void cli_smb2_unlink_opened1(struct tevent_req
*subreq
);
930 static void cli_smb2_unlink_opened2(struct tevent_req
*subreq
);
931 static void cli_smb2_unlink_closed(struct tevent_req
*subreq
);
933 struct tevent_req
*cli_smb2_unlink_send(
935 struct tevent_context
*ev
,
936 struct cli_state
*cli
,
938 const struct smb2_create_blobs
*in_cblobs
)
940 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
941 struct cli_smb2_unlink_state
*state
= NULL
;
943 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_unlink_state
);
949 state
->fname
= fname
;
950 state
->in_cblobs
= in_cblobs
;
952 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
953 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
954 return tevent_req_post(req
, ev
);
957 subreq
= cli_smb2_create_fnum_send(
959 state
->ev
, /* tevent_context */
960 state
->cli
, /* cli_struct */
961 state
->fname
, /* filename */
962 0, /* create_flags */
963 SMB2_IMPERSONATION_IMPERSONATION
,
964 DELETE_ACCESS
, /* desired_access */
965 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
968 FILE_SHARE_DELETE
, /* share_access */
969 FILE_OPEN
, /* create_disposition */
970 FILE_DELETE_ON_CLOSE
, /* create_options */
971 state
->in_cblobs
); /* in_cblobs */
972 if (tevent_req_nomem(subreq
, req
)) {
973 return tevent_req_post(req
, ev
);
975 tevent_req_set_callback(subreq
, cli_smb2_unlink_opened1
, req
);
979 static void cli_smb2_unlink_opened1(struct tevent_req
*subreq
)
981 struct tevent_req
*req
= tevent_req_callback_data(
982 subreq
, struct tevent_req
);
983 struct cli_smb2_unlink_state
*state
= tevent_req_data(
984 req
, struct cli_smb2_unlink_state
);
988 status
= cli_smb2_create_fnum_recv(subreq
, &fnum
, NULL
, NULL
, NULL
);
991 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
993 * Naive option to match our SMB1 code. Assume the
994 * symlink path that tripped us up was the last
995 * component and try again. Eventually we will have to
996 * deal with the returned path unprocessed component. JRA.
998 subreq
= cli_smb2_create_fnum_send(
1000 state
->ev
, /* tevent_context */
1001 state
->cli
, /* cli_struct */
1002 state
->fname
, /* filename */
1003 0, /* create_flags */
1004 SMB2_IMPERSONATION_IMPERSONATION
,
1005 DELETE_ACCESS
, /* desired_access */
1006 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
1009 FILE_SHARE_DELETE
, /* share_access */
1010 FILE_OPEN
, /* create_disposition */
1011 FILE_DELETE_ON_CLOSE
|
1012 FILE_OPEN_REPARSE_POINT
, /* create_options */
1013 state
->in_cblobs
); /* in_cblobs */
1014 if (tevent_req_nomem(subreq
, req
)) {
1017 tevent_req_set_callback(subreq
, cli_smb2_unlink_opened2
, req
);
1021 if (tevent_req_nterror(req
, status
)) {
1025 subreq
= cli_smb2_close_fnum_send(state
, state
->ev
, state
->cli
, fnum
);
1026 if (tevent_req_nomem(subreq
, req
)) {
1029 tevent_req_set_callback(subreq
, cli_smb2_unlink_closed
, req
);
1032 static void cli_smb2_unlink_opened2(struct tevent_req
*subreq
)
1034 struct tevent_req
*req
= tevent_req_callback_data(
1035 subreq
, struct tevent_req
);
1036 struct cli_smb2_unlink_state
*state
= tevent_req_data(
1037 req
, struct cli_smb2_unlink_state
);
1041 status
= cli_smb2_create_fnum_recv(subreq
, &fnum
, NULL
, NULL
, NULL
);
1042 TALLOC_FREE(subreq
);
1043 if (tevent_req_nterror(req
, status
)) {
1047 subreq
= cli_smb2_close_fnum_send(state
, state
->ev
, state
->cli
, fnum
);
1048 if (tevent_req_nomem(subreq
, req
)) {
1051 tevent_req_set_callback(subreq
, cli_smb2_unlink_closed
, req
);
1054 static void cli_smb2_unlink_closed(struct tevent_req
*subreq
)
1056 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
1057 tevent_req_simple_finish_ntstatus(subreq
, status
);
1060 NTSTATUS
cli_smb2_unlink_recv(struct tevent_req
*req
)
1062 return tevent_req_simple_recv_ntstatus(req
);
1065 NTSTATUS
cli_smb2_unlink(
1066 struct cli_state
*cli
,
1068 const struct smb2_create_blobs
*in_cblobs
)
1070 TALLOC_CTX
*frame
= talloc_stackframe();
1071 struct tevent_context
*ev
;
1072 struct tevent_req
*req
;
1073 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1076 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1078 * Can't use sync call while an async call is in flight
1080 status
= NT_STATUS_INVALID_PARAMETER
;
1083 ev
= samba_tevent_context_init(frame
);
1087 req
= cli_smb2_unlink_send(frame
, ev
, cli
, fname
, in_cblobs
);
1091 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
1095 status
= cli_smb2_unlink_recv(req
);
1097 cli
->raw_status
= status
;
1102 /***************************************************************
1103 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1104 ***************************************************************/
1106 static NTSTATUS
parse_finfo_id_both_directory_info(uint8_t *dir_data
,
1107 uint32_t dir_data_length
,
1108 struct file_info
*finfo
,
1109 uint32_t *next_offset
)
1115 if (dir_data_length
< 4) {
1116 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1119 *next_offset
= IVAL(dir_data
, 0);
1121 if (*next_offset
> dir_data_length
) {
1122 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1125 if (*next_offset
!= 0) {
1126 /* Ensure we only read what in this record. */
1127 dir_data_length
= *next_offset
;
1130 if (dir_data_length
< 105) {
1131 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1134 finfo
->btime_ts
= interpret_long_date((const char *)dir_data
+ 8);
1135 finfo
->atime_ts
= interpret_long_date((const char *)dir_data
+ 16);
1136 finfo
->mtime_ts
= interpret_long_date((const char *)dir_data
+ 24);
1137 finfo
->ctime_ts
= interpret_long_date((const char *)dir_data
+ 32);
1138 finfo
->size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 40, 0);
1139 finfo
->allocated_size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 48, 0);
1140 finfo
->mode
= CVAL(dir_data
+ 56, 0);
1141 finfo
->ino
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 96, 0);
1142 namelen
= IVAL(dir_data
+ 60,0);
1143 if (namelen
> (dir_data_length
- 104)) {
1144 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1146 slen
= CVAL(dir_data
+ 68, 0);
1148 return NT_STATUS_INFO_LENGTH_MISMATCH
;
1150 ret
= pull_string_talloc(finfo
,
1152 FLAGS2_UNICODE_STRINGS
,
1157 if (ret
== (size_t)-1) {
1158 /* Bad conversion. */
1159 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1162 ret
= pull_string_talloc(finfo
,
1164 FLAGS2_UNICODE_STRINGS
,
1169 if (ret
== (size_t)-1) {
1170 /* Bad conversion. */
1171 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1173 return NT_STATUS_OK
;
1176 /*******************************************************************
1177 Given a filename - get its directory name
1178 ********************************************************************/
1180 static bool windows_parent_dirname(TALLOC_CTX
*mem_ctx
,
1188 p
= strrchr_m(dir
, '\\'); /* Find final '\\', if any */
1191 if (!(*parent
= talloc_strdup(mem_ctx
, "\\"))) {
1202 if (!(*parent
= (char *)talloc_memdup(mem_ctx
, dir
, len
+1))) {
1205 (*parent
)[len
] = '\0';
1213 /***************************************************************
1214 Wrapper that allows SMB2 to list a directory.
1216 ***************************************************************/
1218 NTSTATUS
cli_smb2_list(struct cli_state
*cli
,
1219 const char *pathname
,
1221 NTSTATUS (*fn
)(const char *,
1228 uint16_t fnum
= 0xffff;
1229 char *parent_dir
= NULL
;
1230 const char *mask
= NULL
;
1231 struct smb2_hnd
*ph
= NULL
;
1232 bool processed_file
= false;
1233 TALLOC_CTX
*frame
= talloc_stackframe();
1234 TALLOC_CTX
*subframe
= NULL
;
1237 uint32_t max_avail_len
;
1240 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1242 * Can't use sync call while an async call is in flight
1244 status
= NT_STATUS_INVALID_PARAMETER
;
1248 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1249 status
= NT_STATUS_INVALID_PARAMETER
;
1253 /* Get the directory name. */
1254 if (!windows_parent_dirname(frame
,
1258 status
= NT_STATUS_NO_MEMORY
;
1262 mask_has_wild
= ms_has_wild(mask
);
1264 status
= cli_smb2_create_fnum(cli
,
1266 0, /* create_flags */
1267 SMB2_IMPERSONATION_IMPERSONATION
,
1268 SEC_DIR_LIST
|SEC_DIR_READ_ATTRIBUTE
,/* desired_access */
1269 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1270 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
1271 FILE_OPEN
, /* create_disposition */
1272 FILE_DIRECTORY_FILE
, /* create_options */
1279 if (!NT_STATUS_IS_OK(status
)) {
1283 status
= map_fnum_to_smb2_handle(cli
,
1286 if (!NT_STATUS_IS_OK(status
)) {
1291 * ideally, use the max transaction size, but don't send a request
1292 * bigger than we have credits available for
1294 max_trans
= smb2cli_conn_max_trans_size(cli
->conn
);
1295 ok
= smb2cli_conn_req_possible(cli
->conn
, &max_avail_len
);
1297 max_trans
= MIN(max_trans
, max_avail_len
);
1301 uint8_t *dir_data
= NULL
;
1302 uint32_t dir_data_length
= 0;
1303 uint32_t next_offset
= 0;
1304 subframe
= talloc_stackframe();
1306 status
= smb2cli_query_directory(cli
->conn
,
1310 SMB2_FIND_ID_BOTH_DIRECTORY_INFO
,
1321 if (!NT_STATUS_IS_OK(status
)) {
1322 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
1329 struct file_info
*finfo
= talloc_zero(subframe
,
1332 if (finfo
== NULL
) {
1333 status
= NT_STATUS_NO_MEMORY
;
1337 status
= parse_finfo_id_both_directory_info(dir_data
,
1342 if (!NT_STATUS_IS_OK(status
)) {
1346 if (dir_check_ftype((uint32_t)finfo
->mode
,
1347 (uint32_t)attribute
)) {
1349 * Only process if attributes match.
1350 * On SMB1 server does this, so on
1351 * SMB2 we need to emulate in the
1354 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1356 processed_file
= true;
1358 status
= fn(cli
->dfs_mountpoint
,
1363 if (!NT_STATUS_IS_OK(status
)) {
1370 /* Move to next entry. */
1372 dir_data
+= next_offset
;
1373 dir_data_length
-= next_offset
;
1375 } while (next_offset
!= 0);
1377 TALLOC_FREE(subframe
);
1379 if (!mask_has_wild
) {
1381 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1382 * when handed a non-wildcard path. Do it
1383 * for the server (with a non-wildcard path
1384 * there should only ever be one file returned.
1386 status
= STATUS_NO_MORE_FILES
;
1390 } while (NT_STATUS_IS_OK(status
));
1392 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
1393 status
= NT_STATUS_OK
;
1396 if (NT_STATUS_IS_OK(status
) && !processed_file
) {
1398 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1399 * if no files match. Emulate this in the client.
1401 status
= NT_STATUS_NO_SUCH_FILE
;
1406 if (fnum
!= 0xffff) {
1407 cli_smb2_close_fnum(cli
, fnum
);
1410 cli
->raw_status
= status
;
1412 TALLOC_FREE(subframe
);
1417 /***************************************************************
1418 Wrapper that allows SMB2 to query a path info (basic level).
1420 ***************************************************************/
1422 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
1424 SMB_STRUCT_STAT
*sbuf
,
1425 uint32_t *attributes
)
1428 struct smb_create_returns cr
;
1429 uint16_t fnum
= 0xffff;
1430 size_t namelen
= strlen(name
);
1432 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1434 * Can't use sync call while an async call is in flight
1436 return NT_STATUS_INVALID_PARAMETER
;
1439 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1440 return NT_STATUS_INVALID_PARAMETER
;
1443 /* SMB2 is pickier about pathnames. Ensure it doesn't
1445 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1446 char *modname
= talloc_strdup(talloc_tos(), name
);
1447 modname
[namelen
-1] = '\0';
1451 /* This is commonly used as a 'cd'. Try qpathinfo on
1452 a directory handle first. */
1454 status
= cli_smb2_create_fnum(cli
,
1456 0, /* create_flags */
1457 SMB2_IMPERSONATION_IMPERSONATION
,
1458 FILE_READ_ATTRIBUTES
, /* desired_access */
1459 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1460 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1461 FILE_OPEN
, /* create_disposition */
1462 FILE_DIRECTORY_FILE
, /* create_options */
1469 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
1470 /* Maybe a file ? */
1471 status
= cli_smb2_create_fnum(cli
,
1473 0, /* create_flags */
1474 SMB2_IMPERSONATION_IMPERSONATION
,
1475 FILE_READ_ATTRIBUTES
, /* desired_access */
1476 0, /* file attributes */
1477 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1478 FILE_OPEN
, /* create_disposition */
1479 0, /* create_options */
1487 if (!NT_STATUS_IS_OK(status
)) {
1491 status
= cli_smb2_close_fnum(cli
, fnum
);
1495 sbuf
->st_ex_atime
= nt_time_to_unix_timespec(cr
.last_access_time
);
1496 sbuf
->st_ex_mtime
= nt_time_to_unix_timespec(cr
.last_write_time
);
1497 sbuf
->st_ex_ctime
= nt_time_to_unix_timespec(cr
.change_time
);
1498 sbuf
->st_ex_size
= cr
.end_of_file
;
1499 *attributes
= cr
.file_attributes
;
1504 /***************************************************************
1505 Wrapper that allows SMB2 to check if a path is a directory.
1507 ***************************************************************/
1509 NTSTATUS
cli_smb2_chkpath(struct cli_state
*cli
,
1513 uint16_t fnum
= 0xffff;
1515 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1517 * Can't use sync call while an async call is in flight
1519 return NT_STATUS_INVALID_PARAMETER
;
1522 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1523 return NT_STATUS_INVALID_PARAMETER
;
1526 /* Ensure this is a directory. */
1527 status
= cli_smb2_create_fnum(cli
,
1529 0, /* create_flags */
1530 SMB2_IMPERSONATION_IMPERSONATION
,
1531 FILE_READ_ATTRIBUTES
, /* desired_access */
1532 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1533 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1534 FILE_OPEN
, /* create_disposition */
1535 FILE_DIRECTORY_FILE
, /* create_options */
1542 if (!NT_STATUS_IS_OK(status
)) {
1546 return cli_smb2_close_fnum(cli
, fnum
);
1549 struct cli_smb2_query_info_fnum_state
{
1553 static void cli_smb2_query_info_fnum_done(struct tevent_req
*subreq
);
1555 struct tevent_req
*cli_smb2_query_info_fnum_send(
1556 TALLOC_CTX
*mem_ctx
,
1557 struct tevent_context
*ev
,
1558 struct cli_state
*cli
,
1560 uint8_t in_info_type
,
1561 uint8_t in_info_class
,
1562 uint32_t in_max_output_length
,
1563 const DATA_BLOB
*in_input_buffer
,
1564 uint32_t in_additional_info
,
1567 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1568 struct cli_smb2_query_info_fnum_state
*state
= NULL
;
1569 struct smb2_hnd
*ph
= NULL
;
1572 req
= tevent_req_create(
1573 mem_ctx
, &state
, struct cli_smb2_query_info_fnum_state
);
1578 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
1579 if (tevent_req_nterror(req
, status
)) {
1580 return tevent_req_post(req
, ev
);
1583 subreq
= smb2cli_query_info_send(
1592 in_max_output_length
,
1598 if (tevent_req_nomem(subreq
, req
)) {
1599 return tevent_req_post(req
, ev
);
1601 tevent_req_set_callback(subreq
, cli_smb2_query_info_fnum_done
, req
);
1605 static void cli_smb2_query_info_fnum_done(struct tevent_req
*subreq
)
1607 struct tevent_req
*req
= tevent_req_callback_data(
1608 subreq
, struct tevent_req
);
1609 struct cli_smb2_query_info_fnum_state
*state
= tevent_req_data(
1610 req
, struct cli_smb2_query_info_fnum_state
);
1614 status
= smb2cli_query_info_recv(subreq
, state
, &outbuf
);
1615 TALLOC_FREE(subreq
);
1616 if (tevent_req_nterror(req
, status
)) {
1621 * We have to dup the memory here because outbuf.data is not
1622 * returned as a talloc object by smb2cli_query_info_recv.
1623 * It's a pointer into the received buffer.
1625 state
->outbuf
= data_blob_dup_talloc(state
, outbuf
);
1627 if ((outbuf
.length
!= 0) &&
1628 tevent_req_nomem(state
->outbuf
.data
, req
)) {
1631 tevent_req_done(req
);
1634 NTSTATUS
cli_smb2_query_info_fnum_recv(
1635 struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
, DATA_BLOB
*outbuf
)
1637 struct cli_smb2_query_info_fnum_state
*state
= tevent_req_data(
1638 req
, struct cli_smb2_query_info_fnum_state
);
1641 if (tevent_req_is_nterror(req
, &status
)) {
1644 *outbuf
= (DATA_BLOB
) {
1645 .data
= talloc_move(mem_ctx
, &state
->outbuf
.data
),
1646 .length
= state
->outbuf
.length
,
1648 return NT_STATUS_OK
;
1651 NTSTATUS
cli_smb2_query_info_fnum(
1652 struct cli_state
*cli
,
1654 uint8_t in_info_type
,
1655 uint8_t in_info_class
,
1656 uint32_t in_max_output_length
,
1657 const DATA_BLOB
*in_input_buffer
,
1658 uint32_t in_additional_info
,
1660 TALLOC_CTX
*mem_ctx
,
1663 TALLOC_CTX
*frame
= talloc_stackframe();
1664 struct tevent_context
*ev
= NULL
;
1665 struct tevent_req
*req
= NULL
;
1666 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1669 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1671 * Can't use sync call while an async call is in flight
1673 status
= NT_STATUS_INVALID_PARAMETER
;
1676 ev
= samba_tevent_context_init(frame
);
1680 req
= cli_smb2_query_info_fnum_send(
1687 in_max_output_length
,
1694 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
1698 status
= cli_smb2_query_info_fnum_recv(req
, mem_ctx
, outbuf
);
1704 /***************************************************************
1705 Helper function for pathname operations.
1706 ***************************************************************/
1708 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
1710 uint32_t desired_access
,
1714 size_t namelen
= strlen(name
);
1715 TALLOC_CTX
*frame
= talloc_stackframe();
1716 uint32_t create_options
= 0;
1718 /* SMB2 is pickier about pathnames. Ensure it doesn't
1720 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1721 char *modname
= talloc_strdup(frame
, name
);
1722 if (modname
== NULL
) {
1723 status
= NT_STATUS_NO_MEMORY
;
1726 modname
[namelen
-1] = '\0';
1730 /* Try to open a file handle first. */
1731 status
= cli_smb2_create_fnum(cli
,
1733 0, /* create_flags */
1734 SMB2_IMPERSONATION_IMPERSONATION
,
1736 0, /* file attributes */
1737 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1738 FILE_OPEN
, /* create_disposition */
1746 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
1748 * Naive option to match our SMB1 code. Assume the
1749 * symlink path that tripped us up was the last
1750 * component and try again. Eventually we will have to
1751 * deal with the returned path unprocessed component. JRA.
1753 create_options
|= FILE_OPEN_REPARSE_POINT
;
1754 status
= cli_smb2_create_fnum(cli
,
1756 0, /* create_flags */
1757 SMB2_IMPERSONATION_IMPERSONATION
,
1759 0, /* file attributes */
1760 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1761 FILE_OPEN
, /* create_disposition */
1770 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
1771 create_options
|= FILE_DIRECTORY_FILE
;
1772 status
= cli_smb2_create_fnum(cli
,
1774 0, /* create_flags */
1775 SMB2_IMPERSONATION_IMPERSONATION
,
1777 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1778 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1779 FILE_OPEN
, /* create_disposition */
1780 FILE_DIRECTORY_FILE
, /* create_options */
1794 /***************************************************************
1795 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1797 ***************************************************************/
1799 NTSTATUS
cli_smb2_qpathinfo_alt_name(struct cli_state
*cli
,
1804 DATA_BLOB outbuf
= data_blob_null
;
1805 uint16_t fnum
= 0xffff;
1806 struct smb2_hnd
*ph
= NULL
;
1807 uint32_t altnamelen
= 0;
1808 TALLOC_CTX
*frame
= talloc_stackframe();
1810 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1812 * Can't use sync call while an async call is in flight
1814 status
= NT_STATUS_INVALID_PARAMETER
;
1818 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1819 status
= NT_STATUS_INVALID_PARAMETER
;
1823 status
= get_fnum_from_path(cli
,
1825 FILE_READ_ATTRIBUTES
,
1828 if (!NT_STATUS_IS_OK(status
)) {
1832 status
= map_fnum_to_smb2_handle(cli
,
1835 if (!NT_STATUS_IS_OK(status
)) {
1839 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1840 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1842 status
= smb2cli_query_info(cli
->conn
,
1846 1, /* in_info_type */
1847 (SMB_FILE_ALTERNATE_NAME_INFORMATION
- 1000), /* in_file_info_class */
1848 0xFFFF, /* in_max_output_length */
1849 NULL
, /* in_input_buffer */
1850 0, /* in_additional_info */
1857 if (!NT_STATUS_IS_OK(status
)) {
1861 /* Parse the reply. */
1862 if (outbuf
.length
< 4) {
1863 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1867 altnamelen
= IVAL(outbuf
.data
, 0);
1868 if (altnamelen
> outbuf
.length
- 4) {
1869 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1873 if (altnamelen
> 0) {
1875 char *short_name
= NULL
;
1876 ret
= pull_string_talloc(frame
,
1878 FLAGS2_UNICODE_STRINGS
,
1883 if (ret
== (size_t)-1) {
1884 /* Bad conversion. */
1885 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1889 fstrcpy(alt_name
, short_name
);
1894 status
= NT_STATUS_OK
;
1898 if (fnum
!= 0xffff) {
1899 cli_smb2_close_fnum(cli
, fnum
);
1902 cli
->raw_status
= status
;
1909 /***************************************************************
1910 Wrapper that allows SMB2 to query a fnum info (basic level).
1912 ***************************************************************/
1914 NTSTATUS
cli_smb2_qfileinfo_basic(struct cli_state
*cli
,
1918 struct timespec
*create_time
,
1919 struct timespec
*access_time
,
1920 struct timespec
*write_time
,
1921 struct timespec
*change_time
,
1925 DATA_BLOB outbuf
= data_blob_null
;
1926 struct smb2_hnd
*ph
= NULL
;
1927 TALLOC_CTX
*frame
= talloc_stackframe();
1929 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1931 * Can't use sync call while an async call is in flight
1933 status
= NT_STATUS_INVALID_PARAMETER
;
1937 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1938 status
= NT_STATUS_INVALID_PARAMETER
;
1942 status
= map_fnum_to_smb2_handle(cli
,
1945 if (!NT_STATUS_IS_OK(status
)) {
1949 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1950 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1952 status
= smb2cli_query_info(cli
->conn
,
1956 1, /* in_info_type */
1957 (SMB_FILE_ALL_INFORMATION
- 1000), /* in_file_info_class */
1958 0xFFFF, /* in_max_output_length */
1959 NULL
, /* in_input_buffer */
1960 0, /* in_additional_info */
1966 if (!NT_STATUS_IS_OK(status
)) {
1970 /* Parse the reply. */
1971 if (outbuf
.length
< 0x60) {
1972 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1977 *create_time
= interpret_long_date((const char *)outbuf
.data
+ 0x0);
1980 *access_time
= interpret_long_date((const char *)outbuf
.data
+ 0x8);
1983 *write_time
= interpret_long_date((const char *)outbuf
.data
+ 0x10);
1986 *change_time
= interpret_long_date((const char *)outbuf
.data
+ 0x18);
1989 uint32_t attr
= IVAL(outbuf
.data
, 0x20);
1990 *mode
= (uint16_t)attr
;
1993 uint64_t file_size
= BVAL(outbuf
.data
, 0x30);
1994 *size
= (off_t
)file_size
;
1997 uint64_t file_index
= BVAL(outbuf
.data
, 0x40);
1998 *ino
= (SMB_INO_T
)file_index
;
2003 cli
->raw_status
= status
;
2009 /***************************************************************
2010 Wrapper that allows SMB2 to query an fnum.
2011 Implement on top of cli_smb2_qfileinfo_basic().
2013 ***************************************************************/
2015 NTSTATUS
cli_smb2_getattrE(struct cli_state
*cli
,
2019 time_t *change_time
,
2020 time_t *access_time
,
2023 struct timespec access_time_ts
;
2024 struct timespec write_time_ts
;
2025 struct timespec change_time_ts
;
2026 NTSTATUS status
= cli_smb2_qfileinfo_basic(cli
,
2036 cli
->raw_status
= status
;
2038 if (!NT_STATUS_IS_OK(status
)) {
2043 *change_time
= change_time_ts
.tv_sec
;
2046 *access_time
= access_time_ts
.tv_sec
;
2049 *write_time
= write_time_ts
.tv_sec
;
2051 return NT_STATUS_OK
;
2054 /***************************************************************
2055 Wrapper that allows SMB2 to get pathname attributes.
2057 ***************************************************************/
2059 NTSTATUS
cli_smb2_getatr(struct cli_state
*cli
,
2066 uint16_t fnum
= 0xffff;
2067 struct smb2_hnd
*ph
= NULL
;
2068 TALLOC_CTX
*frame
= talloc_stackframe();
2070 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2072 * Can't use sync call while an async call is in flight
2074 status
= NT_STATUS_INVALID_PARAMETER
;
2078 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2079 status
= NT_STATUS_INVALID_PARAMETER
;
2083 status
= get_fnum_from_path(cli
,
2085 FILE_READ_ATTRIBUTES
,
2088 if (!NT_STATUS_IS_OK(status
)) {
2092 status
= map_fnum_to_smb2_handle(cli
,
2095 if (!NT_STATUS_IS_OK(status
)) {
2098 status
= cli_smb2_getattrE(cli
,
2105 if (!NT_STATUS_IS_OK(status
)) {
2111 if (fnum
!= 0xffff) {
2112 cli_smb2_close_fnum(cli
, fnum
);
2115 cli
->raw_status
= status
;
2121 /***************************************************************
2122 Wrapper that allows SMB2 to query a pathname info (basic level).
2123 Implement on top of cli_smb2_qfileinfo_basic().
2125 ***************************************************************/
2127 NTSTATUS
cli_smb2_qpathinfo2(struct cli_state
*cli
,
2129 struct timespec
*create_time
,
2130 struct timespec
*access_time
,
2131 struct timespec
*write_time
,
2132 struct timespec
*change_time
,
2138 struct smb2_hnd
*ph
= NULL
;
2139 uint16_t fnum
= 0xffff;
2140 TALLOC_CTX
*frame
= talloc_stackframe();
2142 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2144 * Can't use sync call while an async call is in flight
2146 status
= NT_STATUS_INVALID_PARAMETER
;
2150 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2151 status
= NT_STATUS_INVALID_PARAMETER
;
2155 status
= get_fnum_from_path(cli
,
2157 FILE_READ_ATTRIBUTES
,
2160 if (!NT_STATUS_IS_OK(status
)) {
2164 status
= map_fnum_to_smb2_handle(cli
,
2167 if (!NT_STATUS_IS_OK(status
)) {
2171 status
= cli_smb2_qfileinfo_basic(cli
,
2183 if (fnum
!= 0xffff) {
2184 cli_smb2_close_fnum(cli
, fnum
);
2187 cli
->raw_status
= status
;
2193 /***************************************************************
2194 Wrapper that allows SMB2 to query pathname streams.
2196 ***************************************************************/
2198 NTSTATUS
cli_smb2_qpathinfo_streams(struct cli_state
*cli
,
2200 TALLOC_CTX
*mem_ctx
,
2201 unsigned int *pnum_streams
,
2202 struct stream_struct
**pstreams
)
2205 struct smb2_hnd
*ph
= NULL
;
2206 uint16_t fnum
= 0xffff;
2207 DATA_BLOB outbuf
= data_blob_null
;
2208 TALLOC_CTX
*frame
= talloc_stackframe();
2210 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2212 * Can't use sync call while an async call is in flight
2214 status
= NT_STATUS_INVALID_PARAMETER
;
2218 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2219 status
= NT_STATUS_INVALID_PARAMETER
;
2223 status
= get_fnum_from_path(cli
,
2225 FILE_READ_ATTRIBUTES
,
2228 if (!NT_STATUS_IS_OK(status
)) {
2232 status
= map_fnum_to_smb2_handle(cli
,
2235 if (!NT_STATUS_IS_OK(status
)) {
2239 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2240 level 22 (SMB2_FILE_STREAM_INFORMATION). */
2242 status
= smb2cli_query_info(cli
->conn
,
2246 1, /* in_info_type */
2247 (SMB_FILE_STREAM_INFORMATION
- 1000), /* in_file_info_class */
2248 0xFFFF, /* in_max_output_length */
2249 NULL
, /* in_input_buffer */
2250 0, /* in_additional_info */
2257 if (!NT_STATUS_IS_OK(status
)) {
2261 /* Parse the reply. */
2262 if (!parse_streams_blob(mem_ctx
,
2267 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2273 if (fnum
!= 0xffff) {
2274 cli_smb2_close_fnum(cli
, fnum
);
2277 cli
->raw_status
= status
;
2283 /***************************************************************
2284 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2287 ***************************************************************/
2289 NTSTATUS
cli_smb2_setpathinfo(struct cli_state
*cli
,
2291 uint8_t in_info_type
,
2292 uint8_t in_file_info_class
,
2293 const DATA_BLOB
*p_in_data
)
2296 uint16_t fnum
= 0xffff;
2297 struct smb2_hnd
*ph
= NULL
;
2298 TALLOC_CTX
*frame
= talloc_stackframe();
2300 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2302 * Can't use sync call while an async call is in flight
2304 status
= NT_STATUS_INVALID_PARAMETER
;
2308 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2309 status
= NT_STATUS_INVALID_PARAMETER
;
2313 status
= get_fnum_from_path(cli
,
2315 FILE_WRITE_ATTRIBUTES
,
2318 if (!NT_STATUS_IS_OK(status
)) {
2322 status
= map_fnum_to_smb2_handle(cli
,
2325 if (!NT_STATUS_IS_OK(status
)) {
2329 status
= smb2cli_set_info(cli
->conn
,
2335 p_in_data
, /* in_input_buffer */
2336 0, /* in_additional_info */
2341 if (fnum
!= 0xffff) {
2342 cli_smb2_close_fnum(cli
, fnum
);
2345 cli
->raw_status
= status
;
2352 /***************************************************************
2353 Wrapper that allows SMB2 to set pathname attributes.
2355 ***************************************************************/
2357 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
2362 uint8_t inbuf_store
[40];
2363 DATA_BLOB inbuf
= data_blob_null
;
2365 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2366 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2368 inbuf
.data
= inbuf_store
;
2369 inbuf
.length
= sizeof(inbuf_store
);
2370 data_blob_clear(&inbuf
);
2373 * SMB1 uses attr == 0 to clear all attributes
2374 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2375 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2376 * request attribute change.
2378 * SMB2 uses exactly the reverse. Unfortunately as the
2379 * cli_setatr() ABI is exposed inside libsmbclient,
2380 * we must make the SMB2 cli_smb2_setatr() call
2381 * export the same ABI as the SMB1 cli_setatr()
2382 * which calls it. This means reversing the sense
2383 * of the requested attr argument if it's zero
2384 * or FILE_ATTRIBUTE_NORMAL.
2386 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2390 attr
= FILE_ATTRIBUTE_NORMAL
;
2391 } else if (attr
== FILE_ATTRIBUTE_NORMAL
) {
2395 SSVAL(inbuf
.data
, 32, attr
);
2397 put_long_date((char *)inbuf
.data
+ 16,mtime
);
2399 /* Set all the other times to -1. */
2400 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
2401 SBVAL(inbuf
.data
, 8, 0xFFFFFFFFFFFFFFFFLL
);
2402 SBVAL(inbuf
.data
, 24, 0xFFFFFFFFFFFFFFFFLL
);
2404 return cli_smb2_setpathinfo(cli
,
2406 1, /* in_info_type */
2407 /* in_file_info_class */
2408 SMB_FILE_BASIC_INFORMATION
- 1000,
2413 /***************************************************************
2414 Wrapper that allows SMB2 to set file handle times.
2416 ***************************************************************/
2418 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
2425 struct smb2_hnd
*ph
= NULL
;
2426 uint8_t inbuf_store
[40];
2427 DATA_BLOB inbuf
= data_blob_null
;
2429 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2431 * Can't use sync call while an async call is in flight
2433 return NT_STATUS_INVALID_PARAMETER
;
2436 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2437 return NT_STATUS_INVALID_PARAMETER
;
2440 status
= map_fnum_to_smb2_handle(cli
,
2443 if (!NT_STATUS_IS_OK(status
)) {
2447 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2448 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2450 inbuf
.data
= inbuf_store
;
2451 inbuf
.length
= sizeof(inbuf_store
);
2452 data_blob_clear(&inbuf
);
2454 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
2455 if (change_time
!= 0) {
2456 put_long_date((char *)inbuf
.data
+ 24, change_time
);
2458 if (access_time
!= 0) {
2459 put_long_date((char *)inbuf
.data
+ 8, access_time
);
2461 if (write_time
!= 0) {
2462 put_long_date((char *)inbuf
.data
+ 16, write_time
);
2465 cli
->raw_status
= smb2cli_set_info(cli
->conn
,
2469 1, /* in_info_type */
2470 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
2471 &inbuf
, /* in_input_buffer */
2472 0, /* in_additional_info */
2476 return cli
->raw_status
;
2479 /***************************************************************
2480 Wrapper that allows SMB2 to query disk attributes (size).
2482 ***************************************************************/
2484 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, const char *path
,
2485 uint64_t *bsize
, uint64_t *total
, uint64_t *avail
)
2488 uint16_t fnum
= 0xffff;
2489 DATA_BLOB outbuf
= data_blob_null
;
2490 struct smb2_hnd
*ph
= NULL
;
2491 uint32_t sectors_per_unit
= 0;
2492 uint32_t bytes_per_sector
= 0;
2493 uint64_t total_size
= 0;
2494 uint64_t size_free
= 0;
2495 TALLOC_CTX
*frame
= talloc_stackframe();
2497 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2499 * Can't use sync call while an async call is in flight
2501 status
= NT_STATUS_INVALID_PARAMETER
;
2505 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2506 status
= NT_STATUS_INVALID_PARAMETER
;
2510 /* First open the top level directory. */
2511 status
= cli_smb2_create_fnum(cli
,
2513 0, /* create_flags */
2514 SMB2_IMPERSONATION_IMPERSONATION
,
2515 FILE_READ_ATTRIBUTES
, /* desired_access */
2516 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2517 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
2518 FILE_OPEN
, /* create_disposition */
2519 FILE_DIRECTORY_FILE
, /* create_options */
2526 if (!NT_STATUS_IS_OK(status
)) {
2530 status
= map_fnum_to_smb2_handle(cli
,
2533 if (!NT_STATUS_IS_OK(status
)) {
2537 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2538 level 3 (SMB_FS_SIZE_INFORMATION). */
2540 status
= smb2cli_query_info(cli
->conn
,
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 */
2554 if (!NT_STATUS_IS_OK(status
)) {
2558 /* Parse the reply. */
2559 if (outbuf
.length
!= 24) {
2560 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2564 total_size
= BVAL(outbuf
.data
, 0);
2565 size_free
= BVAL(outbuf
.data
, 8);
2566 sectors_per_unit
= IVAL(outbuf
.data
, 16);
2567 bytes_per_sector
= IVAL(outbuf
.data
, 20);
2570 *bsize
= (uint64_t)sectors_per_unit
* (uint64_t)bytes_per_sector
;
2573 *total
= total_size
;
2579 status
= NT_STATUS_OK
;
2583 if (fnum
!= 0xffff) {
2584 cli_smb2_close_fnum(cli
, fnum
);
2587 cli
->raw_status
= status
;
2593 /***************************************************************
2594 Wrapper that allows SMB2 to query file system sizes.
2596 ***************************************************************/
2598 NTSTATUS
cli_smb2_get_fs_full_size_info(struct cli_state
*cli
,
2599 uint64_t *total_allocation_units
,
2600 uint64_t *caller_allocation_units
,
2601 uint64_t *actual_allocation_units
,
2602 uint64_t *sectors_per_allocation_unit
,
2603 uint64_t *bytes_per_sector
)
2606 uint16_t fnum
= 0xffff;
2607 DATA_BLOB outbuf
= data_blob_null
;
2608 struct smb2_hnd
*ph
= NULL
;
2609 TALLOC_CTX
*frame
= talloc_stackframe();
2611 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2613 * Can't use sync call while an async call is in flight
2615 status
= NT_STATUS_INVALID_PARAMETER
;
2619 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2620 status
= NT_STATUS_INVALID_PARAMETER
;
2624 /* First open the top level directory. */
2626 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2627 SMB2_IMPERSONATION_IMPERSONATION
,
2628 FILE_READ_ATTRIBUTES
, /* desired_access */
2629 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2630 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2631 FILE_SHARE_DELETE
, /* share_access */
2632 FILE_OPEN
, /* create_disposition */
2633 FILE_DIRECTORY_FILE
, /* create_options */
2640 if (!NT_STATUS_IS_OK(status
)) {
2644 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
2645 if (!NT_STATUS_IS_OK(status
)) {
2649 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2650 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2652 status
= smb2cli_query_info(cli
->conn
,
2656 SMB2_GETINFO_FS
, /* in_info_type */
2657 /* in_file_info_class */
2658 SMB_FS_FULL_SIZE_INFORMATION
- 1000,
2659 0xFFFF, /* in_max_output_length */
2660 NULL
, /* in_input_buffer */
2661 0, /* in_additional_info */
2667 if (!NT_STATUS_IS_OK(status
)) {
2671 if (outbuf
.length
< 32) {
2672 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2676 *total_allocation_units
= BIG_UINT(outbuf
.data
, 0);
2677 *caller_allocation_units
= BIG_UINT(outbuf
.data
, 8);
2678 *actual_allocation_units
= BIG_UINT(outbuf
.data
, 16);
2679 *sectors_per_allocation_unit
= (uint64_t)IVAL(outbuf
.data
, 24);
2680 *bytes_per_sector
= (uint64_t)IVAL(outbuf
.data
, 28);
2684 if (fnum
!= 0xffff) {
2685 cli_smb2_close_fnum(cli
, fnum
);
2688 cli
->raw_status
= status
;
2694 /***************************************************************
2695 Wrapper that allows SMB2 to query file system attributes.
2697 ***************************************************************/
2699 NTSTATUS
cli_smb2_get_fs_attr_info(struct cli_state
*cli
, uint32_t *fs_attr
)
2702 uint16_t fnum
= 0xffff;
2703 DATA_BLOB outbuf
= data_blob_null
;
2704 struct smb2_hnd
*ph
= NULL
;
2705 TALLOC_CTX
*frame
= talloc_stackframe();
2707 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2709 * Can't use sync call while an async call is in flight
2711 status
= NT_STATUS_INVALID_PARAMETER
;
2715 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2716 status
= NT_STATUS_INVALID_PARAMETER
;
2720 /* First open the top level directory. */
2722 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2723 SMB2_IMPERSONATION_IMPERSONATION
,
2724 FILE_READ_ATTRIBUTES
, /* desired_access */
2725 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2726 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2727 FILE_SHARE_DELETE
, /* share_access */
2728 FILE_OPEN
, /* create_disposition */
2729 FILE_DIRECTORY_FILE
, /* create_options */
2736 if (!NT_STATUS_IS_OK(status
)) {
2740 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
2741 if (!NT_STATUS_IS_OK(status
)) {
2745 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
2746 cli
->smb2
.tcon
, 2, /* in_info_type */
2747 5, /* in_file_info_class */
2748 0xFFFF, /* in_max_output_length */
2749 NULL
, /* in_input_buffer */
2750 0, /* in_additional_info */
2752 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
2754 if (!NT_STATUS_IS_OK(status
)) {
2758 if (outbuf
.length
< 12) {
2759 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2763 *fs_attr
= IVAL(outbuf
.data
, 0);
2767 if (fnum
!= 0xffff) {
2768 cli_smb2_close_fnum(cli
, fnum
);
2771 cli
->raw_status
= status
;
2777 /***************************************************************
2778 Wrapper that allows SMB2 to query file system volume info.
2780 ***************************************************************/
2782 NTSTATUS
cli_smb2_get_fs_volume_info(struct cli_state
*cli
,
2783 TALLOC_CTX
*mem_ctx
,
2784 char **_volume_name
,
2785 uint32_t *pserial_number
,
2789 uint16_t fnum
= 0xffff;
2790 DATA_BLOB outbuf
= data_blob_null
;
2791 struct smb2_hnd
*ph
= NULL
;
2793 char *volume_name
= NULL
;
2794 TALLOC_CTX
*frame
= talloc_stackframe();
2796 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2798 * Can't use sync call while an async call is in flight
2800 status
= NT_STATUS_INVALID_PARAMETER
;
2804 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2805 status
= NT_STATUS_INVALID_PARAMETER
;
2809 /* First open the top level directory. */
2811 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2812 SMB2_IMPERSONATION_IMPERSONATION
,
2813 FILE_READ_ATTRIBUTES
, /* desired_access */
2814 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2815 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2816 FILE_SHARE_DELETE
, /* share_access */
2817 FILE_OPEN
, /* create_disposition */
2818 FILE_DIRECTORY_FILE
, /* create_options */
2825 if (!NT_STATUS_IS_OK(status
)) {
2829 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
2830 if (!NT_STATUS_IS_OK(status
)) {
2834 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2835 level 1 (SMB_FS_VOLUME_INFORMATION). */
2837 status
= smb2cli_query_info(cli
->conn
,
2841 SMB2_GETINFO_FS
, /* in_info_type */
2842 /* in_file_info_class */
2843 SMB_FS_VOLUME_INFORMATION
- 1000,
2844 0xFFFF, /* in_max_output_length */
2845 NULL
, /* in_input_buffer */
2846 0, /* in_additional_info */
2852 if (!NT_STATUS_IS_OK(status
)) {
2856 if (outbuf
.length
< 24) {
2857 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2863 ts
= interpret_long_date((char *)outbuf
.data
);
2866 if (pserial_number
) {
2867 *pserial_number
= IVAL(outbuf
.data
,8);
2869 nlen
= IVAL(outbuf
.data
,12);
2870 if (nlen
+ 18 < 18) {
2872 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2876 * The next check is safe as we know outbuf.length >= 24
2879 if (nlen
> (outbuf
.length
- 18)) {
2880 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2884 clistr_pull_talloc(mem_ctx
,
2885 (const char *)outbuf
.data
,
2891 if (volume_name
== NULL
) {
2892 status
= map_nt_error_from_unix(errno
);
2896 *_volume_name
= volume_name
;
2900 if (fnum
!= 0xffff) {
2901 cli_smb2_close_fnum(cli
, fnum
);
2904 cli
->raw_status
= status
;
2911 /***************************************************************
2912 Wrapper that allows SMB2 to query a security descriptor.
2914 ***************************************************************/
2916 NTSTATUS
cli_smb2_query_security_descriptor(struct cli_state
*cli
,
2919 TALLOC_CTX
*mem_ctx
,
2920 struct security_descriptor
**ppsd
)
2923 DATA_BLOB outbuf
= data_blob_null
;
2924 struct smb2_hnd
*ph
= NULL
;
2925 struct security_descriptor
*lsd
= NULL
;
2926 TALLOC_CTX
*frame
= talloc_stackframe();
2928 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2930 * Can't use sync call while an async call is in flight
2932 status
= NT_STATUS_INVALID_PARAMETER
;
2936 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2937 status
= NT_STATUS_INVALID_PARAMETER
;
2941 status
= map_fnum_to_smb2_handle(cli
,
2944 if (!NT_STATUS_IS_OK(status
)) {
2948 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2950 status
= smb2cli_query_info(cli
->conn
,
2954 3, /* in_info_type */
2955 0, /* in_file_info_class */
2956 0xFFFF, /* in_max_output_length */
2957 NULL
, /* in_input_buffer */
2958 sec_info
, /* in_additional_info */
2965 if (!NT_STATUS_IS_OK(status
)) {
2969 /* Parse the reply. */
2970 status
= unmarshall_sec_desc(mem_ctx
,
2975 if (!NT_STATUS_IS_OK(status
)) {
2987 cli
->raw_status
= status
;
2993 /***************************************************************
2994 Wrapper that allows SMB2 to set a security descriptor.
2996 ***************************************************************/
2998 NTSTATUS
cli_smb2_set_security_descriptor(struct cli_state
*cli
,
3001 const struct security_descriptor
*sd
)
3004 DATA_BLOB inbuf
= data_blob_null
;
3005 struct smb2_hnd
*ph
= NULL
;
3006 TALLOC_CTX
*frame
= talloc_stackframe();
3008 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3010 * Can't use sync call while an async call is in flight
3012 status
= NT_STATUS_INVALID_PARAMETER
;
3016 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3017 status
= NT_STATUS_INVALID_PARAMETER
;
3021 status
= map_fnum_to_smb2_handle(cli
,
3024 if (!NT_STATUS_IS_OK(status
)) {
3028 status
= marshall_sec_desc(frame
,
3033 if (!NT_STATUS_IS_OK(status
)) {
3037 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
3039 status
= smb2cli_set_info(cli
->conn
,
3043 3, /* in_info_type */
3044 0, /* in_file_info_class */
3045 &inbuf
, /* in_input_buffer */
3046 sec_info
, /* in_additional_info */
3052 cli
->raw_status
= status
;
3058 /***************************************************************
3059 Wrapper that allows SMB2 to query a security descriptor.
3062 ***************************************************************/
3064 struct cli_smb2_mxac_state
{
3065 struct tevent_context
*ev
;
3066 struct cli_state
*cli
;
3068 struct smb2_create_blobs in_cblobs
;
3074 static void cli_smb2_mxac_opened(struct tevent_req
*subreq
);
3075 static void cli_smb2_mxac_closed(struct tevent_req
*subreq
);
3077 struct tevent_req
*cli_smb2_query_mxac_send(TALLOC_CTX
*mem_ctx
,
3078 struct tevent_context
*ev
,
3079 struct cli_state
*cli
,
3082 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
3083 struct cli_smb2_mxac_state
*state
= NULL
;
3086 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_mxac_state
);
3090 *state
= (struct cli_smb2_mxac_state
) {
3093 state
->fname
= fname
,
3096 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3097 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3098 return tevent_req_post(req
, ev
);
3101 status
= smb2_create_blob_add(state
,
3103 SMB2_CREATE_TAG_MXAC
,
3104 data_blob(NULL
, 0));
3105 if (tevent_req_nterror(req
, status
)) {
3106 return tevent_req_post(req
, ev
);
3109 subreq
= cli_smb2_create_fnum_send(
3114 0, /* create_flags */
3115 SMB2_IMPERSONATION_IMPERSONATION
,
3116 FILE_READ_ATTRIBUTES
,
3117 0, /* file attributes */
3118 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
3120 0, /* create_options */
3122 if (tevent_req_nomem(subreq
, req
)) {
3123 return tevent_req_post(req
, ev
);
3125 tevent_req_set_callback(subreq
, cli_smb2_mxac_opened
, req
);
3129 static void cli_smb2_mxac_opened(struct tevent_req
*subreq
)
3131 struct tevent_req
*req
= tevent_req_callback_data(
3132 subreq
, struct tevent_req
);
3133 struct cli_smb2_mxac_state
*state
= tevent_req_data(
3134 req
, struct cli_smb2_mxac_state
);
3135 struct smb2_create_blobs out_cblobs
= {0};
3136 struct smb2_create_blob
*mxac_blob
= NULL
;
3139 status
= cli_smb2_create_fnum_recv(
3140 subreq
, &state
->fnum
, NULL
, state
, &out_cblobs
);
3141 TALLOC_FREE(subreq
);
3143 if (tevent_req_nterror(req
, status
)) {
3147 mxac_blob
= smb2_create_blob_find(&out_cblobs
, SMB2_CREATE_TAG_MXAC
);
3148 if (mxac_blob
== NULL
) {
3149 state
->status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3152 if (mxac_blob
->data
.length
!= 8) {
3153 state
->status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3157 state
->status
= NT_STATUS(IVAL(mxac_blob
->data
.data
, 0));
3158 state
->mxac
= IVAL(mxac_blob
->data
.data
, 4);
3161 subreq
= cli_smb2_close_fnum_send(
3162 state
, state
->ev
, state
->cli
, state
->fnum
);
3163 if (tevent_req_nomem(subreq
, req
)) {
3166 tevent_req_set_callback(subreq
, cli_smb2_mxac_closed
, req
);
3171 static void cli_smb2_mxac_closed(struct tevent_req
*subreq
)
3173 struct tevent_req
*req
= tevent_req_callback_data(
3174 subreq
, struct tevent_req
);
3177 status
= cli_smb2_close_fnum_recv(subreq
);
3178 if (tevent_req_nterror(req
, status
)) {
3182 tevent_req_done(req
);
3185 NTSTATUS
cli_smb2_query_mxac_recv(struct tevent_req
*req
, uint32_t *mxac
)
3187 struct cli_smb2_mxac_state
*state
= tevent_req_data(
3188 req
, struct cli_smb2_mxac_state
);
3191 if (tevent_req_is_nterror(req
, &status
)) {
3195 if (!NT_STATUS_IS_OK(state
->status
)) {
3196 return state
->status
;
3199 *mxac
= state
->mxac
;
3200 return NT_STATUS_OK
;
3203 NTSTATUS
cli_smb2_query_mxac(struct cli_state
*cli
,
3207 TALLOC_CTX
*frame
= talloc_stackframe();
3208 struct tevent_context
*ev
= NULL
;
3209 struct tevent_req
*req
= NULL
;
3210 NTSTATUS status
= NT_STATUS_INTERNAL_ERROR
;
3213 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3215 * Can't use sync call while an async call is in flight
3217 status
= NT_STATUS_INVALID_PARAMETER
;
3221 ev
= samba_tevent_context_init(frame
);
3225 req
= cli_smb2_query_mxac_send(frame
, ev
, cli
, fname
);
3229 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
3233 status
= cli_smb2_query_mxac_recv(req
, _mxac
);
3236 cli
->raw_status
= status
;
3241 /***************************************************************
3242 Wrapper that allows SMB2 to rename a file.
3244 ***************************************************************/
3246 NTSTATUS
cli_smb2_rename(struct cli_state
*cli
,
3247 const char *fname_src
,
3248 const char *fname_dst
,
3252 DATA_BLOB inbuf
= data_blob_null
;
3253 uint16_t fnum
= 0xffff;
3254 struct smb2_hnd
*ph
= NULL
;
3255 smb_ucs2_t
*converted_str
= NULL
;
3256 size_t converted_size_bytes
= 0;
3258 TALLOC_CTX
*frame
= talloc_stackframe();
3260 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3262 * Can't use sync call while an async call is in flight
3264 status
= NT_STATUS_INVALID_PARAMETER
;
3268 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3269 status
= NT_STATUS_INVALID_PARAMETER
;
3273 status
= get_fnum_from_path(cli
,
3278 if (!NT_STATUS_IS_OK(status
)) {
3282 status
= map_fnum_to_smb2_handle(cli
,
3285 if (!NT_STATUS_IS_OK(status
)) {
3289 /* SMB2 is pickier about pathnames. Ensure it doesn't
3291 if (*fname_dst
== '\\') {
3295 /* SMB2 is pickier about pathnames. Ensure it doesn't
3297 namelen
= strlen(fname_dst
);
3298 if (namelen
> 0 && fname_dst
[namelen
-1] == '\\') {
3299 char *modname
= talloc_strdup(frame
, fname_dst
);
3300 modname
[namelen
-1] = '\0';
3301 fname_dst
= modname
;
3304 if (!push_ucs2_talloc(frame
,
3307 &converted_size_bytes
)) {
3308 status
= NT_STATUS_INVALID_PARAMETER
;
3312 /* W2K8 insists the dest name is not null
3313 terminated. Remove the last 2 zero bytes
3314 and reduce the name length. */
3316 if (converted_size_bytes
< 2) {
3317 status
= NT_STATUS_INVALID_PARAMETER
;
3320 converted_size_bytes
-= 2;
3322 inbuf
= data_blob_talloc_zero(frame
,
3323 20 + converted_size_bytes
);
3324 if (inbuf
.data
== NULL
) {
3325 status
= NT_STATUS_NO_MEMORY
;
3330 SCVAL(inbuf
.data
, 0, 1);
3333 SIVAL(inbuf
.data
, 16, converted_size_bytes
);
3334 memcpy(inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
3336 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3337 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3339 status
= smb2cli_set_info(cli
->conn
,
3343 1, /* in_info_type */
3344 SMB_FILE_RENAME_INFORMATION
- 1000, /* in_file_info_class */
3345 &inbuf
, /* in_input_buffer */
3346 0, /* in_additional_info */
3352 if (fnum
!= 0xffff) {
3353 cli_smb2_close_fnum(cli
, fnum
);
3356 cli
->raw_status
= status
;
3362 /***************************************************************
3363 Wrapper that allows SMB2 to set an EA on a fnum.
3365 ***************************************************************/
3367 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
3369 const char *ea_name
,
3374 DATA_BLOB inbuf
= data_blob_null
;
3376 char *ea_name_ascii
= NULL
;
3378 struct smb2_hnd
*ph
= NULL
;
3379 TALLOC_CTX
*frame
= talloc_stackframe();
3381 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3383 * Can't use sync call while an async call is in flight
3385 status
= NT_STATUS_INVALID_PARAMETER
;
3389 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3390 status
= NT_STATUS_INVALID_PARAMETER
;
3394 status
= map_fnum_to_smb2_handle(cli
,
3397 if (!NT_STATUS_IS_OK(status
)) {
3401 /* Marshall the SMB2 EA data. */
3402 if (ea_len
> 0xFFFF) {
3403 status
= NT_STATUS_INVALID_PARAMETER
;
3407 if (!push_ascii_talloc(frame
,
3411 status
= NT_STATUS_INVALID_PARAMETER
;
3415 if (namelen
< 2 || namelen
> 0xFF) {
3416 status
= NT_STATUS_INVALID_PARAMETER
;
3420 bloblen
= 8 + ea_len
+ namelen
;
3421 /* Round up to a 4 byte boundary. */
3422 bloblen
= ((bloblen
+ 3)&~3);
3424 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
3425 if (inbuf
.data
== NULL
) {
3426 status
= NT_STATUS_NO_MEMORY
;
3429 /* namelen doesn't include the NULL byte. */
3430 SCVAL(inbuf
.data
, 5, namelen
- 1);
3431 SSVAL(inbuf
.data
, 6, ea_len
);
3432 memcpy(inbuf
.data
+ 8, ea_name_ascii
, namelen
);
3433 memcpy(inbuf
.data
+ 8 + namelen
, ea_val
, ea_len
);
3435 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3436 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3438 status
= smb2cli_set_info(cli
->conn
,
3442 1, /* in_info_type */
3443 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
3444 &inbuf
, /* in_input_buffer */
3445 0, /* in_additional_info */
3451 cli
->raw_status
= status
;
3457 /***************************************************************
3458 Wrapper that allows SMB2 to set an EA on a pathname.
3460 ***************************************************************/
3462 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
3464 const char *ea_name
,
3469 uint16_t fnum
= 0xffff;
3471 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3473 * Can't use sync call while an async call is in flight
3475 status
= NT_STATUS_INVALID_PARAMETER
;
3479 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3480 status
= NT_STATUS_INVALID_PARAMETER
;
3484 status
= get_fnum_from_path(cli
,
3489 if (!NT_STATUS_IS_OK(status
)) {
3493 status
= cli_set_ea_fnum(cli
,
3498 if (!NT_STATUS_IS_OK(status
)) {
3504 if (fnum
!= 0xffff) {
3505 cli_smb2_close_fnum(cli
, fnum
);
3508 cli
->raw_status
= status
;
3513 /***************************************************************
3514 Wrapper that allows SMB2 to get an EA list on a pathname.
3516 ***************************************************************/
3518 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
3522 struct ea_struct
**pea_array
)
3525 uint16_t fnum
= 0xffff;
3526 DATA_BLOB outbuf
= data_blob_null
;
3527 struct smb2_hnd
*ph
= NULL
;
3528 struct ea_list
*ea_list
= NULL
;
3529 struct ea_list
*eal
= NULL
;
3530 size_t ea_count
= 0;
3531 TALLOC_CTX
*frame
= talloc_stackframe();
3536 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3538 * Can't use sync call while an async call is in flight
3540 status
= NT_STATUS_INVALID_PARAMETER
;
3544 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3545 status
= NT_STATUS_INVALID_PARAMETER
;
3549 status
= get_fnum_from_path(cli
,
3554 if (!NT_STATUS_IS_OK(status
)) {
3558 status
= map_fnum_to_smb2_handle(cli
,
3561 if (!NT_STATUS_IS_OK(status
)) {
3565 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3566 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3568 status
= smb2cli_query_info(cli
->conn
,
3572 1, /* in_info_type */
3573 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
3574 0xFFFF, /* in_max_output_length */
3575 NULL
, /* in_input_buffer */
3576 0, /* in_additional_info */
3583 if (!NT_STATUS_IS_OK(status
)) {
3587 /* Parse the reply. */
3588 ea_list
= read_nttrans_ea_list(ctx
,
3589 (const char *)outbuf
.data
,
3591 if (ea_list
== NULL
) {
3592 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3596 /* Convert to an array. */
3597 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
3602 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
3603 if (*pea_array
== NULL
) {
3604 status
= NT_STATUS_NO_MEMORY
;
3608 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
3609 (*pea_array
)[ea_count
++] = eal
->ea
;
3611 *pnum_eas
= ea_count
;
3616 if (fnum
!= 0xffff) {
3617 cli_smb2_close_fnum(cli
, fnum
);
3620 cli
->raw_status
= status
;
3626 /***************************************************************
3627 Wrapper that allows SMB2 to get user quota.
3629 ***************************************************************/
3631 NTSTATUS
cli_smb2_get_user_quota(struct cli_state
*cli
,
3633 SMB_NTQUOTA_STRUCT
*pqt
)
3636 DATA_BLOB inbuf
= data_blob_null
;
3637 DATA_BLOB info_blob
= data_blob_null
;
3638 DATA_BLOB outbuf
= data_blob_null
;
3639 struct smb2_hnd
*ph
= NULL
;
3640 TALLOC_CTX
*frame
= talloc_stackframe();
3642 unsigned int offset
;
3643 struct smb2_query_quota_info query
= {0};
3644 struct file_get_quota_info info
= {0};
3645 enum ndr_err_code err
;
3646 struct ndr_push
*ndr_push
= NULL
;
3648 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3650 * Can't use sync call while an async call is in flight
3652 status
= NT_STATUS_INVALID_PARAMETER
;
3656 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3657 status
= NT_STATUS_INVALID_PARAMETER
;
3661 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
3662 if (!NT_STATUS_IS_OK(status
)) {
3666 sid_len
= ndr_size_dom_sid(&pqt
->sid
, 0);
3668 query
.return_single
= 1;
3670 info
.next_entry_offset
= 0;
3671 info
.sid_length
= sid_len
;
3672 info
.sid
= pqt
->sid
;
3674 err
= ndr_push_struct_blob(
3678 (ndr_push_flags_fn_t
)ndr_push_file_get_quota_info
);
3680 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3681 status
= NT_STATUS_INTERNAL_ERROR
;
3685 query
.sid_list_length
= info_blob
.length
;
3686 ndr_push
= ndr_push_init_ctx(frame
);
3688 status
= NT_STATUS_NO_MEMORY
;
3692 err
= ndr_push_smb2_query_quota_info(ndr_push
,
3693 NDR_SCALARS
| NDR_BUFFERS
,
3696 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3697 status
= NT_STATUS_INTERNAL_ERROR
;
3701 err
= ndr_push_array_uint8(ndr_push
, NDR_SCALARS
, info_blob
.data
,
3704 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3705 status
= NT_STATUS_INTERNAL_ERROR
;
3708 inbuf
.data
= ndr_push
->data
;
3709 inbuf
.length
= ndr_push
->offset
;
3711 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
3712 cli
->smb2
.tcon
, 4, /* in_info_type */
3713 0, /* in_file_info_class */
3714 0xFFFF, /* in_max_output_length */
3715 &inbuf
, /* in_input_buffer */
3716 0, /* in_additional_info */
3718 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
3721 if (!NT_STATUS_IS_OK(status
)) {
3725 if (!parse_user_quota_record(outbuf
.data
, outbuf
.length
, &offset
,
3727 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3728 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3732 cli
->raw_status
= status
;
3738 /***************************************************************
3739 Wrapper that allows SMB2 to list user quota.
3741 ***************************************************************/
3743 NTSTATUS
cli_smb2_list_user_quota_step(struct cli_state
*cli
,
3744 TALLOC_CTX
*mem_ctx
,
3746 SMB_NTQUOTA_LIST
**pqt_list
,
3750 DATA_BLOB inbuf
= data_blob_null
;
3751 DATA_BLOB outbuf
= data_blob_null
;
3752 struct smb2_hnd
*ph
= NULL
;
3753 TALLOC_CTX
*frame
= talloc_stackframe();
3754 struct smb2_query_quota_info info
= {0};
3755 enum ndr_err_code err
;
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
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
3771 if (!NT_STATUS_IS_OK(status
)) {
3776 info
.restart_scan
= first
? 1 : 0;
3778 err
= ndr_push_struct_blob(
3782 (ndr_push_flags_fn_t
)ndr_push_smb2_query_quota_info
);
3784 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3785 status
= NT_STATUS_INTERNAL_ERROR
;
3789 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
3790 cli
->smb2
.tcon
, 4, /* in_info_type */
3791 0, /* in_file_info_class */
3792 0xFFFF, /* in_max_output_length */
3793 &inbuf
, /* in_input_buffer */
3794 0, /* in_additional_info */
3796 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
3800 * safeguard against panic from calling parse_user_quota_list with
3803 if (NT_STATUS_IS_OK(status
) && outbuf
.length
== 0) {
3804 status
= NT_STATUS_NO_MORE_ENTRIES
;
3807 if (!NT_STATUS_IS_OK(status
)) {
3811 status
= parse_user_quota_list(outbuf
.data
, outbuf
.length
, mem_ctx
,
3815 cli
->raw_status
= status
;
3821 /***************************************************************
3822 Wrapper that allows SMB2 to get file system quota.
3824 ***************************************************************/
3826 NTSTATUS
cli_smb2_get_fs_quota_info(struct cli_state
*cli
,
3828 SMB_NTQUOTA_STRUCT
*pqt
)
3831 DATA_BLOB outbuf
= data_blob_null
;
3832 struct smb2_hnd
*ph
= NULL
;
3833 TALLOC_CTX
*frame
= talloc_stackframe();
3835 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3837 * Can't use sync call while an async call is in flight
3839 status
= NT_STATUS_INVALID_PARAMETER
;
3843 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3844 status
= NT_STATUS_INVALID_PARAMETER
;
3848 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
3849 if (!NT_STATUS_IS_OK(status
)) {
3853 status
= smb2cli_query_info(
3854 cli
->conn
, cli
->timeout
, cli
->smb2
.session
, cli
->smb2
.tcon
,
3855 2, /* in_info_type */
3856 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
3857 0xFFFF, /* in_max_output_length */
3858 NULL
, /* in_input_buffer */
3859 0, /* in_additional_info */
3861 ph
->fid_persistent
, ph
->fid_volatile
, frame
, &outbuf
);
3863 if (!NT_STATUS_IS_OK(status
)) {
3867 status
= parse_fs_quota_buffer(outbuf
.data
, outbuf
.length
, pqt
);
3870 cli
->raw_status
= status
;
3876 /***************************************************************
3877 Wrapper that allows SMB2 to set user quota.
3879 ***************************************************************/
3881 NTSTATUS
cli_smb2_set_user_quota(struct cli_state
*cli
,
3883 SMB_NTQUOTA_LIST
*qtl
)
3886 DATA_BLOB inbuf
= data_blob_null
;
3887 struct smb2_hnd
*ph
= NULL
;
3888 TALLOC_CTX
*frame
= talloc_stackframe();
3890 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3892 * Can't use sync call while an async call is in flight
3894 status
= NT_STATUS_INVALID_PARAMETER
;
3898 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3899 status
= NT_STATUS_INVALID_PARAMETER
;
3903 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
3904 if (!NT_STATUS_IS_OK(status
)) {
3908 status
= build_user_quota_buffer(qtl
, 0, talloc_tos(), &inbuf
, NULL
);
3909 if (!NT_STATUS_IS_OK(status
)) {
3913 status
= smb2cli_set_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
3914 cli
->smb2
.tcon
, 4, /* in_info_type */
3915 0, /* in_file_info_class */
3916 &inbuf
, /* in_input_buffer */
3917 0, /* in_additional_info */
3918 ph
->fid_persistent
, ph
->fid_volatile
);
3921 cli
->raw_status
= status
;
3928 NTSTATUS
cli_smb2_set_fs_quota_info(struct cli_state
*cli
,
3930 SMB_NTQUOTA_STRUCT
*pqt
)
3933 DATA_BLOB inbuf
= data_blob_null
;
3934 struct smb2_hnd
*ph
= NULL
;
3935 TALLOC_CTX
*frame
= talloc_stackframe();
3937 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3939 * Can't use sync call while an async call is in flight
3941 status
= NT_STATUS_INVALID_PARAMETER
;
3945 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3946 status
= NT_STATUS_INVALID_PARAMETER
;
3950 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
3951 if (!NT_STATUS_IS_OK(status
)) {
3955 status
= build_fs_quota_buffer(talloc_tos(), pqt
, &inbuf
, 0);
3956 if (!NT_STATUS_IS_OK(status
)) {
3960 status
= smb2cli_set_info(
3961 cli
->conn
, cli
->timeout
, cli
->smb2
.session
, cli
->smb2
.tcon
,
3962 2, /* in_info_type */
3963 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
3964 &inbuf
, /* in_input_buffer */
3965 0, /* in_additional_info */
3966 ph
->fid_persistent
, ph
->fid_volatile
);
3968 cli
->raw_status
= status
;
3974 struct cli_smb2_read_state
{
3975 struct tevent_context
*ev
;
3976 struct cli_state
*cli
;
3977 struct smb2_hnd
*ph
;
3978 uint64_t start_offset
;
3984 static void cli_smb2_read_done(struct tevent_req
*subreq
);
3986 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
3987 struct tevent_context
*ev
,
3988 struct cli_state
*cli
,
3994 struct tevent_req
*req
, *subreq
;
3995 struct cli_smb2_read_state
*state
;
3997 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
4003 state
->start_offset
= (uint64_t)offset
;
4004 state
->size
= (uint32_t)size
;
4005 state
->received
= 0;
4008 status
= map_fnum_to_smb2_handle(cli
,
4011 if (tevent_req_nterror(req
, status
)) {
4012 return tevent_req_post(req
, ev
);
4015 subreq
= smb2cli_read_send(state
,
4018 state
->cli
->timeout
,
4019 state
->cli
->smb2
.session
,
4020 state
->cli
->smb2
.tcon
,
4022 state
->start_offset
,
4023 state
->ph
->fid_persistent
,
4024 state
->ph
->fid_volatile
,
4025 0, /* minimum_count */
4026 0); /* remaining_bytes */
4028 if (tevent_req_nomem(subreq
, req
)) {
4029 return tevent_req_post(req
, ev
);
4031 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
4035 static void cli_smb2_read_done(struct tevent_req
*subreq
)
4037 struct tevent_req
*req
= tevent_req_callback_data(
4038 subreq
, struct tevent_req
);
4039 struct cli_smb2_read_state
*state
= tevent_req_data(
4040 req
, struct cli_smb2_read_state
);
4043 status
= smb2cli_read_recv(subreq
, state
,
4044 &state
->buf
, &state
->received
);
4045 if (tevent_req_nterror(req
, status
)) {
4049 if (state
->received
> state
->size
) {
4050 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4054 tevent_req_done(req
);
4057 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
4062 struct cli_smb2_read_state
*state
= tevent_req_data(
4063 req
, struct cli_smb2_read_state
);
4065 if (tevent_req_is_nterror(req
, &status
)) {
4066 state
->cli
->raw_status
= status
;
4070 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
4071 * better make sure that you copy it away before you talloc_free(req).
4072 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
4074 *received
= (ssize_t
)state
->received
;
4075 *rcvbuf
= state
->buf
;
4076 state
->cli
->raw_status
= NT_STATUS_OK
;
4077 return NT_STATUS_OK
;
4080 struct cli_smb2_write_state
{
4081 struct tevent_context
*ev
;
4082 struct cli_state
*cli
;
4083 struct smb2_hnd
*ph
;
4091 static void cli_smb2_write_written(struct tevent_req
*req
);
4093 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
4094 struct tevent_context
*ev
,
4095 struct cli_state
*cli
,
4103 struct tevent_req
*req
, *subreq
= NULL
;
4104 struct cli_smb2_write_state
*state
= NULL
;
4106 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
4112 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4113 state
->flags
= (uint32_t)mode
;
4115 state
->offset
= (uint64_t)offset
;
4116 state
->size
= (uint32_t)size
;
4119 status
= map_fnum_to_smb2_handle(cli
,
4122 if (tevent_req_nterror(req
, status
)) {
4123 return tevent_req_post(req
, ev
);
4126 subreq
= smb2cli_write_send(state
,
4129 state
->cli
->timeout
,
4130 state
->cli
->smb2
.session
,
4131 state
->cli
->smb2
.tcon
,
4134 state
->ph
->fid_persistent
,
4135 state
->ph
->fid_volatile
,
4136 0, /* remaining_bytes */
4137 state
->flags
, /* flags */
4140 if (tevent_req_nomem(subreq
, req
)) {
4141 return tevent_req_post(req
, ev
);
4143 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
4147 static void cli_smb2_write_written(struct tevent_req
*subreq
)
4149 struct tevent_req
*req
= tevent_req_callback_data(
4150 subreq
, struct tevent_req
);
4151 struct cli_smb2_write_state
*state
= tevent_req_data(
4152 req
, struct cli_smb2_write_state
);
4156 status
= smb2cli_write_recv(subreq
, &written
);
4157 TALLOC_FREE(subreq
);
4158 if (tevent_req_nterror(req
, status
)) {
4162 state
->written
= written
;
4164 tevent_req_done(req
);
4167 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
4170 struct cli_smb2_write_state
*state
= tevent_req_data(
4171 req
, struct cli_smb2_write_state
);
4174 if (tevent_req_is_nterror(req
, &status
)) {
4175 state
->cli
->raw_status
= status
;
4176 tevent_req_received(req
);
4180 if (pwritten
!= NULL
) {
4181 *pwritten
= (size_t)state
->written
;
4183 state
->cli
->raw_status
= NT_STATUS_OK
;
4184 tevent_req_received(req
);
4185 return NT_STATUS_OK
;
4188 /***************************************************************
4189 Wrapper that allows SMB2 async write using an fnum.
4190 This is mostly cut-and-paste from Volker's code inside
4191 source3/libsmb/clireadwrite.c, adapted for SMB2.
4193 Done this way so I can reuse all the logic inside cli_push()
4195 ***************************************************************/
4197 struct cli_smb2_writeall_state
{
4198 struct tevent_context
*ev
;
4199 struct cli_state
*cli
;
4200 struct smb2_hnd
*ph
;
4208 static void cli_smb2_writeall_written(struct tevent_req
*req
);
4210 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
4211 struct tevent_context
*ev
,
4212 struct cli_state
*cli
,
4220 struct tevent_req
*req
, *subreq
= NULL
;
4221 struct cli_smb2_writeall_state
*state
= NULL
;
4226 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
4232 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4233 state
->flags
= (uint32_t)mode
;
4235 state
->offset
= (uint64_t)offset
;
4236 state
->size
= (uint32_t)size
;
4239 status
= map_fnum_to_smb2_handle(cli
,
4242 if (tevent_req_nterror(req
, status
)) {
4243 return tevent_req_post(req
, ev
);
4246 to_write
= state
->size
;
4247 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
4248 to_write
= MIN(max_size
, to_write
);
4249 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
4251 to_write
= MIN(max_size
, to_write
);
4254 subreq
= smb2cli_write_send(state
,
4257 state
->cli
->timeout
,
4258 state
->cli
->smb2
.session
,
4259 state
->cli
->smb2
.tcon
,
4262 state
->ph
->fid_persistent
,
4263 state
->ph
->fid_volatile
,
4264 0, /* remaining_bytes */
4265 state
->flags
, /* flags */
4266 state
->buf
+ state
->written
);
4268 if (tevent_req_nomem(subreq
, req
)) {
4269 return tevent_req_post(req
, ev
);
4271 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
4275 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
4277 struct tevent_req
*req
= tevent_req_callback_data(
4278 subreq
, struct tevent_req
);
4279 struct cli_smb2_writeall_state
*state
= tevent_req_data(
4280 req
, struct cli_smb2_writeall_state
);
4282 uint32_t written
, to_write
;
4286 status
= smb2cli_write_recv(subreq
, &written
);
4287 TALLOC_FREE(subreq
);
4288 if (tevent_req_nterror(req
, status
)) {
4292 state
->written
+= written
;
4294 if (state
->written
> state
->size
) {
4295 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4299 to_write
= state
->size
- state
->written
;
4301 if (to_write
== 0) {
4302 tevent_req_done(req
);
4306 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
4307 to_write
= MIN(max_size
, to_write
);
4308 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
4310 to_write
= MIN(max_size
, to_write
);
4313 subreq
= smb2cli_write_send(state
,
4316 state
->cli
->timeout
,
4317 state
->cli
->smb2
.session
,
4318 state
->cli
->smb2
.tcon
,
4320 state
->offset
+ state
->written
,
4321 state
->ph
->fid_persistent
,
4322 state
->ph
->fid_volatile
,
4323 0, /* remaining_bytes */
4324 state
->flags
, /* flags */
4325 state
->buf
+ state
->written
);
4327 if (tevent_req_nomem(subreq
, req
)) {
4330 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
4333 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
4336 struct cli_smb2_writeall_state
*state
= tevent_req_data(
4337 req
, struct cli_smb2_writeall_state
);
4340 if (tevent_req_is_nterror(req
, &status
)) {
4341 state
->cli
->raw_status
= status
;
4344 if (pwritten
!= NULL
) {
4345 *pwritten
= (size_t)state
->written
;
4347 state
->cli
->raw_status
= NT_STATUS_OK
;
4348 return NT_STATUS_OK
;
4351 struct cli_smb2_splice_state
{
4352 struct tevent_context
*ev
;
4353 struct cli_state
*cli
;
4354 struct smb2_hnd
*src_ph
;
4355 struct smb2_hnd
*dst_ph
;
4356 int (*splice_cb
)(off_t n
, void *priv
);
4363 struct req_resume_key_rsp resume_rsp
;
4364 struct srv_copychunk_copy cc_copy
;
4367 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
4368 struct tevent_req
*req
);
4370 static void cli_splice_copychunk_done(struct tevent_req
*subreq
)
4372 struct tevent_req
*req
= tevent_req_callback_data(
4373 subreq
, struct tevent_req
);
4374 struct cli_smb2_splice_state
*state
=
4375 tevent_req_data(req
,
4376 struct cli_smb2_splice_state
);
4377 struct smbXcli_conn
*conn
= state
->cli
->conn
;
4378 DATA_BLOB out_input_buffer
= data_blob_null
;
4379 DATA_BLOB out_output_buffer
= data_blob_null
;
4380 struct srv_copychunk_rsp cc_copy_rsp
;
4381 enum ndr_err_code ndr_ret
;
4384 status
= smb2cli_ioctl_recv(subreq
, state
,
4386 &out_output_buffer
);
4387 TALLOC_FREE(subreq
);
4388 if ((!NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
) ||
4389 state
->resized
) && tevent_req_nterror(req
, status
)) {
4393 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
, state
, &cc_copy_rsp
,
4394 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
4395 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4396 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4397 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4401 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
4402 uint32_t max_chunks
= MIN(cc_copy_rsp
.chunks_written
,
4403 cc_copy_rsp
.total_bytes_written
/ cc_copy_rsp
.chunk_bytes_written
);
4404 if ((cc_copy_rsp
.chunk_bytes_written
> smb2cli_conn_cc_chunk_len(conn
) ||
4405 max_chunks
> smb2cli_conn_cc_max_chunks(conn
)) &&
4406 tevent_req_nterror(req
, status
)) {
4410 state
->resized
= true;
4411 smb2cli_conn_set_cc_chunk_len(conn
, cc_copy_rsp
.chunk_bytes_written
);
4412 smb2cli_conn_set_cc_max_chunks(conn
, max_chunks
);
4414 if ((state
->src_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
4415 (state
->dst_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
4416 (state
->written
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
)) {
4417 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
4420 state
->src_offset
+= cc_copy_rsp
.total_bytes_written
;
4421 state
->dst_offset
+= cc_copy_rsp
.total_bytes_written
;
4422 state
->written
+= cc_copy_rsp
.total_bytes_written
;
4423 if (!state
->splice_cb(state
->written
, state
->priv
)) {
4424 tevent_req_nterror(req
, NT_STATUS_CANCELLED
);
4429 cli_splice_copychunk_send(state
, req
);
4432 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
4433 struct tevent_req
*req
)
4435 struct tevent_req
*subreq
;
4436 enum ndr_err_code ndr_ret
;
4437 struct smbXcli_conn
*conn
= state
->cli
->conn
;
4438 struct srv_copychunk_copy
*cc_copy
= &state
->cc_copy
;
4439 off_t src_offset
= state
->src_offset
;
4440 off_t dst_offset
= state
->dst_offset
;
4441 uint32_t req_len
= MIN(smb2cli_conn_cc_chunk_len(conn
) * smb2cli_conn_cc_max_chunks(conn
),
4442 state
->size
- state
->written
);
4443 DATA_BLOB in_input_buffer
= data_blob_null
;
4444 DATA_BLOB in_output_buffer
= data_blob_null
;
4446 if (state
->size
- state
->written
== 0) {
4447 tevent_req_done(req
);
4451 cc_copy
->chunk_count
= 0;
4453 cc_copy
->chunks
[cc_copy
->chunk_count
].source_off
= src_offset
;
4454 cc_copy
->chunks
[cc_copy
->chunk_count
].target_off
= dst_offset
;
4455 cc_copy
->chunks
[cc_copy
->chunk_count
].length
= MIN(req_len
,
4456 smb2cli_conn_cc_chunk_len(conn
));
4457 if (req_len
< cc_copy
->chunks
[cc_copy
->chunk_count
].length
) {
4458 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
4461 req_len
-= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4462 if ((src_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
) ||
4463 (dst_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
)) {
4464 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
4467 src_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4468 dst_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
4469 cc_copy
->chunk_count
++;
4472 ndr_ret
= ndr_push_struct_blob(&in_input_buffer
, state
, cc_copy
,
4473 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
4474 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4475 DEBUG(0, ("failed to marshall copy chunk req\n"));
4476 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
4480 subreq
= smb2cli_ioctl_send(state
, state
->ev
, state
->cli
->conn
,
4481 state
->cli
->timeout
,
4482 state
->cli
->smb2
.session
,
4483 state
->cli
->smb2
.tcon
,
4484 state
->dst_ph
->fid_persistent
, /* in_fid_persistent */
4485 state
->dst_ph
->fid_volatile
, /* in_fid_volatile */
4486 FSCTL_SRV_COPYCHUNK_WRITE
,
4487 0, /* in_max_input_length */
4489 12, /* in_max_output_length */
4491 SMB2_IOCTL_FLAG_IS_FSCTL
);
4492 if (tevent_req_nomem(subreq
, req
)) {
4495 tevent_req_set_callback(subreq
,
4496 cli_splice_copychunk_done
,
4500 static void cli_splice_key_done(struct tevent_req
*subreq
)
4502 struct tevent_req
*req
= tevent_req_callback_data(
4503 subreq
, struct tevent_req
);
4504 struct cli_smb2_splice_state
*state
=
4505 tevent_req_data(req
,
4506 struct cli_smb2_splice_state
);
4507 enum ndr_err_code ndr_ret
;
4510 DATA_BLOB out_input_buffer
= data_blob_null
;
4511 DATA_BLOB out_output_buffer
= data_blob_null
;
4513 status
= smb2cli_ioctl_recv(subreq
, state
,
4515 &out_output_buffer
);
4516 TALLOC_FREE(subreq
);
4517 if (tevent_req_nterror(req
, status
)) {
4521 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
,
4522 state
, &state
->resume_rsp
,
4523 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
4524 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
4525 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4526 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4530 memcpy(&state
->cc_copy
.source_key
,
4531 &state
->resume_rsp
.resume_key
,
4532 sizeof state
->resume_rsp
.resume_key
);
4534 cli_splice_copychunk_send(state
, req
);
4537 struct tevent_req
*cli_smb2_splice_send(TALLOC_CTX
*mem_ctx
,
4538 struct tevent_context
*ev
,
4539 struct cli_state
*cli
,
4540 uint16_t src_fnum
, uint16_t dst_fnum
,
4541 off_t size
, off_t src_offset
, off_t dst_offset
,
4542 int (*splice_cb
)(off_t n
, void *priv
),
4545 struct tevent_req
*req
;
4546 struct tevent_req
*subreq
;
4547 struct cli_smb2_splice_state
*state
;
4549 DATA_BLOB in_input_buffer
= data_blob_null
;
4550 DATA_BLOB in_output_buffer
= data_blob_null
;
4552 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_splice_state
);
4558 state
->splice_cb
= splice_cb
;
4562 state
->src_offset
= src_offset
;
4563 state
->dst_offset
= dst_offset
;
4564 state
->cc_copy
.chunks
= talloc_array(state
,
4565 struct srv_copychunk
,
4566 smb2cli_conn_cc_max_chunks(cli
->conn
));
4567 if (state
->cc_copy
.chunks
== NULL
) {
4571 status
= map_fnum_to_smb2_handle(cli
, src_fnum
, &state
->src_ph
);
4572 if (tevent_req_nterror(req
, status
))
4573 return tevent_req_post(req
, ev
);
4575 status
= map_fnum_to_smb2_handle(cli
, dst_fnum
, &state
->dst_ph
);
4576 if (tevent_req_nterror(req
, status
))
4577 return tevent_req_post(req
, ev
);
4579 subreq
= smb2cli_ioctl_send(state
, ev
, cli
->conn
,
4583 state
->src_ph
->fid_persistent
, /* in_fid_persistent */
4584 state
->src_ph
->fid_volatile
, /* in_fid_volatile */
4585 FSCTL_SRV_REQUEST_RESUME_KEY
,
4586 0, /* in_max_input_length */
4588 32, /* in_max_output_length */
4590 SMB2_IOCTL_FLAG_IS_FSCTL
);
4591 if (tevent_req_nomem(subreq
, req
)) {
4594 tevent_req_set_callback(subreq
,
4595 cli_splice_key_done
,
4601 NTSTATUS
cli_smb2_splice_recv(struct tevent_req
*req
, off_t
*written
)
4603 struct cli_smb2_splice_state
*state
= tevent_req_data(
4604 req
, struct cli_smb2_splice_state
);
4607 if (tevent_req_is_nterror(req
, &status
)) {
4608 state
->cli
->raw_status
= status
;
4609 tevent_req_received(req
);
4612 if (written
!= NULL
) {
4613 *written
= state
->written
;
4615 state
->cli
->raw_status
= NT_STATUS_OK
;
4616 tevent_req_received(req
);
4617 return NT_STATUS_OK
;
4620 /***************************************************************
4621 SMB2 enum shadow copy data.
4622 ***************************************************************/
4624 struct cli_smb2_shadow_copy_data_fnum_state
{
4625 struct cli_state
*cli
;
4627 struct smb2_hnd
*ph
;
4628 DATA_BLOB out_input_buffer
;
4629 DATA_BLOB out_output_buffer
;
4632 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
);
4634 static struct tevent_req
*cli_smb2_shadow_copy_data_fnum_send(
4635 TALLOC_CTX
*mem_ctx
,
4636 struct tevent_context
*ev
,
4637 struct cli_state
*cli
,
4641 struct tevent_req
*req
, *subreq
;
4642 struct cli_smb2_shadow_copy_data_fnum_state
*state
;
4645 req
= tevent_req_create(mem_ctx
, &state
,
4646 struct cli_smb2_shadow_copy_data_fnum_state
);
4651 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
4652 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
4653 return tevent_req_post(req
, ev
);
4659 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
4660 if (tevent_req_nterror(req
, status
)) {
4661 return tevent_req_post(req
, ev
);
4665 * TODO. Under SMB2 we should send a zero max_output_length
4666 * ioctl to get the required size, then send another ioctl
4667 * to get the data, but the current SMB1 implementation just
4668 * does one roundtrip with a 64K buffer size. Do the same
4672 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
4673 state
->cli
->timeout
,
4674 state
->cli
->smb2
.session
,
4675 state
->cli
->smb2
.tcon
,
4676 state
->ph
->fid_persistent
, /* in_fid_persistent */
4677 state
->ph
->fid_volatile
, /* in_fid_volatile */
4678 FSCTL_GET_SHADOW_COPY_DATA
,
4679 0, /* in_max_input_length */
4680 NULL
, /* in_input_buffer */
4682 CLI_BUFFER_SIZE
: 16, /* in_max_output_length */
4683 NULL
, /* in_output_buffer */
4684 SMB2_IOCTL_FLAG_IS_FSCTL
);
4686 if (tevent_req_nomem(subreq
, req
)) {
4687 return tevent_req_post(req
, ev
);
4689 tevent_req_set_callback(subreq
,
4690 cli_smb2_shadow_copy_data_fnum_done
,
4696 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
)
4698 struct tevent_req
*req
= tevent_req_callback_data(
4699 subreq
, struct tevent_req
);
4700 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
4701 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
4704 status
= smb2cli_ioctl_recv(subreq
, state
,
4705 &state
->out_input_buffer
,
4706 &state
->out_output_buffer
);
4707 tevent_req_simple_finish_ntstatus(subreq
, status
);
4710 static NTSTATUS
cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req
*req
,
4711 TALLOC_CTX
*mem_ctx
,
4716 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
4717 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
4718 char **names
= NULL
;
4719 uint32_t num_names
= 0;
4720 uint32_t num_names_returned
= 0;
4721 uint32_t dlength
= 0;
4723 uint8_t *endp
= NULL
;
4726 if (tevent_req_is_nterror(req
, &status
)) {
4730 if (state
->out_output_buffer
.length
< 16) {
4731 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4734 num_names
= IVAL(state
->out_output_buffer
.data
, 0);
4735 num_names_returned
= IVAL(state
->out_output_buffer
.data
, 4);
4736 dlength
= IVAL(state
->out_output_buffer
.data
, 8);
4738 if (num_names
> 0x7FFFFFFF) {
4739 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4742 if (get_names
== false) {
4743 *pnum_names
= (int)num_names
;
4744 return NT_STATUS_OK
;
4746 if (num_names
!= num_names_returned
) {
4747 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4749 if (dlength
+ 12 < 12) {
4750 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4753 * NB. The below is an allowable return if there are
4754 * more snapshots than the buffer size we told the
4755 * server we can receive. We currently don't support
4758 if (dlength
+ 12 > state
->out_output_buffer
.length
) {
4759 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4761 if (state
->out_output_buffer
.length
+
4762 (2 * sizeof(SHADOW_COPY_LABEL
)) <
4763 state
->out_output_buffer
.length
) {
4764 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4767 names
= talloc_array(mem_ctx
, char *, num_names_returned
);
4768 if (names
== NULL
) {
4769 return NT_STATUS_NO_MEMORY
;
4772 endp
= state
->out_output_buffer
.data
+
4773 state
->out_output_buffer
.length
;
4775 for (i
=0; i
<num_names_returned
; i
++) {
4778 size_t converted_size
;
4780 src
= state
->out_output_buffer
.data
+ 12 +
4781 (i
* 2 * sizeof(SHADOW_COPY_LABEL
));
4783 if (src
+ (2 * sizeof(SHADOW_COPY_LABEL
)) > endp
) {
4784 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4786 ret
= convert_string_talloc(
4787 names
, CH_UTF16LE
, CH_UNIX
,
4788 src
, 2 * sizeof(SHADOW_COPY_LABEL
),
4789 &names
[i
], &converted_size
);
4792 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4795 *pnum_names
= num_names
;
4797 return NT_STATUS_OK
;
4800 NTSTATUS
cli_smb2_shadow_copy_data(TALLOC_CTX
*mem_ctx
,
4801 struct cli_state
*cli
,
4807 TALLOC_CTX
*frame
= talloc_stackframe();
4808 struct tevent_context
*ev
;
4809 struct tevent_req
*req
;
4810 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
4812 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4814 * Can't use sync call while an async call is in flight
4816 status
= NT_STATUS_INVALID_PARAMETER
;
4819 ev
= samba_tevent_context_init(frame
);
4823 req
= cli_smb2_shadow_copy_data_fnum_send(frame
,
4831 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4834 status
= cli_smb2_shadow_copy_data_fnum_recv(req
,
4840 cli
->raw_status
= status
;
4846 /***************************************************************
4847 Wrapper that allows SMB2 to truncate a file.
4849 ***************************************************************/
4851 NTSTATUS
cli_smb2_ftruncate(struct cli_state
*cli
,
4856 DATA_BLOB inbuf
= data_blob_null
;
4857 struct smb2_hnd
*ph
= NULL
;
4858 TALLOC_CTX
*frame
= talloc_stackframe();
4860 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4862 * Can't use sync call while an async call is in flight
4864 status
= NT_STATUS_INVALID_PARAMETER
;
4868 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
4869 status
= NT_STATUS_INVALID_PARAMETER
;
4873 status
= map_fnum_to_smb2_handle(cli
,
4876 if (!NT_STATUS_IS_OK(status
)) {
4880 inbuf
= data_blob_talloc_zero(frame
, 8);
4881 if (inbuf
.data
== NULL
) {
4882 status
= NT_STATUS_NO_MEMORY
;
4886 SBVAL(inbuf
.data
, 0, newsize
);
4888 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4889 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4891 status
= smb2cli_set_info(cli
->conn
,
4895 1, /* in_info_type */
4896 /* in_file_info_class */
4897 SMB_FILE_END_OF_FILE_INFORMATION
- 1000,
4898 &inbuf
, /* in_input_buffer */
4899 0, /* in_additional_info */
4905 cli
->raw_status
= status
;
4911 struct cli_smb2_notify_state
{
4912 struct tevent_req
*subreq
;
4913 struct notify_change
*changes
;
4917 static void cli_smb2_notify_done(struct tevent_req
*subreq
);
4918 static bool cli_smb2_notify_cancel(struct tevent_req
*req
);
4920 struct tevent_req
*cli_smb2_notify_send(
4921 TALLOC_CTX
*mem_ctx
,
4922 struct tevent_context
*ev
,
4923 struct cli_state
*cli
,
4925 uint32_t buffer_size
,
4926 uint32_t completion_filter
,
4929 struct tevent_req
*req
= NULL
;
4930 struct cli_smb2_notify_state
*state
= NULL
;
4931 struct smb2_hnd
*ph
= NULL
;
4934 req
= tevent_req_create(mem_ctx
, &state
,
4935 struct cli_smb2_notify_state
);
4940 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
4941 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
4942 return tevent_req_post(req
, ev
);
4945 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
4946 if (tevent_req_nterror(req
, status
)) {
4947 return tevent_req_post(req
, ev
);
4950 state
->subreq
= smb2cli_notify_send(
4962 if (tevent_req_nomem(state
->subreq
, req
)) {
4963 return tevent_req_post(req
, ev
);
4965 tevent_req_set_callback(state
->subreq
, cli_smb2_notify_done
, req
);
4966 tevent_req_set_cancel_fn(req
, cli_smb2_notify_cancel
);
4970 static bool cli_smb2_notify_cancel(struct tevent_req
*req
)
4972 struct cli_smb2_notify_state
*state
= tevent_req_data(
4973 req
, struct cli_smb2_notify_state
);
4976 ok
= tevent_req_cancel(state
->subreq
);
4980 static void cli_smb2_notify_done(struct tevent_req
*subreq
)
4982 struct tevent_req
*req
= tevent_req_callback_data(
4983 subreq
, struct tevent_req
);
4984 struct cli_smb2_notify_state
*state
= tevent_req_data(
4985 req
, struct cli_smb2_notify_state
);
4991 status
= smb2cli_notify_recv(subreq
, state
, &base
, &len
);
4992 TALLOC_FREE(subreq
);
4994 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
4995 tevent_req_done(req
);
4998 if (tevent_req_nterror(req
, status
)) {
5004 while (len
- ofs
>= 12) {
5005 struct notify_change
*tmp
;
5006 struct notify_change
*c
;
5007 uint32_t next_ofs
= IVAL(base
, ofs
);
5008 uint32_t file_name_length
= IVAL(base
, ofs
+8);
5012 tmp
= talloc_realloc(
5015 struct notify_change
,
5016 state
->num_changes
+ 1);
5017 if (tevent_req_nomem(tmp
, req
)) {
5020 state
->changes
= tmp
;
5021 c
= &state
->changes
[state
->num_changes
];
5022 state
->num_changes
+= 1;
5024 if (smb_buffer_oob(len
, ofs
, next_ofs
) ||
5025 smb_buffer_oob(len
, ofs
+12, file_name_length
)) {
5027 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
5031 c
->action
= IVAL(base
, ofs
+4);
5033 ok
= convert_string_talloc(
5043 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
5047 if (next_ofs
== 0) {
5053 tevent_req_done(req
);
5056 NTSTATUS
cli_smb2_notify_recv(struct tevent_req
*req
,
5057 TALLOC_CTX
*mem_ctx
,
5058 struct notify_change
**pchanges
,
5059 uint32_t *pnum_changes
)
5061 struct cli_smb2_notify_state
*state
= tevent_req_data(
5062 req
, struct cli_smb2_notify_state
);
5065 if (tevent_req_is_nterror(req
, &status
)) {
5068 *pchanges
= talloc_move(mem_ctx
, &state
->changes
);
5069 *pnum_changes
= state
->num_changes
;
5070 return NT_STATUS_OK
;
5073 NTSTATUS
cli_smb2_notify(struct cli_state
*cli
, uint16_t fnum
,
5074 uint32_t buffer_size
, uint32_t completion_filter
,
5075 bool recursive
, TALLOC_CTX
*mem_ctx
,
5076 struct notify_change
**pchanges
,
5077 uint32_t *pnum_changes
)
5079 TALLOC_CTX
*frame
= talloc_stackframe();
5080 struct tevent_context
*ev
;
5081 struct tevent_req
*req
;
5082 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
5084 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
5086 * Can't use sync call while an async call is in flight
5088 status
= NT_STATUS_INVALID_PARAMETER
;
5091 ev
= samba_tevent_context_init(frame
);
5095 req
= cli_smb2_notify_send(
5106 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
5109 status
= cli_smb2_notify_recv(req
, mem_ctx
, pchanges
, pnum_changes
);
5115 struct cli_smb2_set_reparse_point_fnum_state
{
5116 struct cli_state
*cli
;
5118 struct smb2_hnd
*ph
;
5119 DATA_BLOB input_buffer
;
5122 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req
*subreq
);
5124 struct tevent_req
*cli_smb2_set_reparse_point_fnum_send(
5125 TALLOC_CTX
*mem_ctx
,
5126 struct tevent_context
*ev
,
5127 struct cli_state
*cli
,
5131 struct tevent_req
*req
, *subreq
;
5132 struct cli_smb2_set_reparse_point_fnum_state
*state
= NULL
;
5135 req
= tevent_req_create(mem_ctx
, &state
,
5136 struct cli_smb2_set_reparse_point_fnum_state
);
5141 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
5142 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
5143 return tevent_req_post(req
, ev
);
5149 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
5150 if (tevent_req_nterror(req
, status
)) {
5151 return tevent_req_post(req
, ev
);
5154 state
->input_buffer
= data_blob_talloc(state
,
5157 if (state
->input_buffer
.data
== NULL
) {
5158 tevent_req_nterror(req
, NT_STATUS_NO_MEMORY
);
5159 return tevent_req_post(req
, ev
);
5162 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
5163 state
->cli
->timeout
,
5164 state
->cli
->smb2
.session
,
5165 state
->cli
->smb2
.tcon
,
5166 state
->ph
->fid_persistent
, /* in_fid_persistent */
5167 state
->ph
->fid_volatile
, /* in_fid_volatile */
5168 FSCTL_SET_REPARSE_POINT
,
5169 0, /* in_max_input_length */
5170 &state
->input_buffer
,
5173 SMB2_IOCTL_FLAG_IS_FSCTL
);
5175 if (tevent_req_nomem(subreq
, req
)) {
5176 return tevent_req_post(req
, ev
);
5178 tevent_req_set_callback(subreq
,
5179 cli_smb2_set_reparse_point_fnum_done
,
5185 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req
*subreq
)
5187 struct tevent_req
*req
= tevent_req_callback_data(
5188 subreq
, struct tevent_req
);
5189 struct cli_smb2_set_reparse_point_fnum_state
*state
= tevent_req_data(
5190 req
, struct cli_smb2_set_reparse_point_fnum_state
);
5193 status
= smb2cli_ioctl_recv(subreq
, state
,
5196 TALLOC_FREE(subreq
);
5197 if (tevent_req_nterror(req
, status
)) {
5200 tevent_req_done(req
);
5203 NTSTATUS
cli_smb2_set_reparse_point_fnum_recv(struct tevent_req
*req
)
5205 return tevent_req_simple_recv_ntstatus(req
);
5208 struct cli_smb2_get_reparse_point_fnum_state
{
5209 struct cli_state
*cli
;
5211 struct smb2_hnd
*ph
;
5212 DATA_BLOB output_buffer
;
5215 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req
*subreq
);
5217 struct tevent_req
*cli_smb2_get_reparse_point_fnum_send(
5218 TALLOC_CTX
*mem_ctx
,
5219 struct tevent_context
*ev
,
5220 struct cli_state
*cli
,
5223 struct tevent_req
*req
, *subreq
;
5224 struct cli_smb2_set_reparse_point_fnum_state
*state
= NULL
;
5227 req
= tevent_req_create(mem_ctx
, &state
,
5228 struct cli_smb2_get_reparse_point_fnum_state
);
5233 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
5234 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
5235 return tevent_req_post(req
, ev
);
5241 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
5242 if (tevent_req_nterror(req
, status
)) {
5243 return tevent_req_post(req
, ev
);
5246 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
5247 state
->cli
->timeout
,
5248 state
->cli
->smb2
.session
,
5249 state
->cli
->smb2
.tcon
,
5250 state
->ph
->fid_persistent
, /* in_fid_persistent */
5251 state
->ph
->fid_volatile
, /* in_fid_volatile */
5252 FSCTL_GET_REPARSE_POINT
,
5253 0, /* in_max_input_length */
5257 SMB2_IOCTL_FLAG_IS_FSCTL
);
5259 if (tevent_req_nomem(subreq
, req
)) {
5260 return tevent_req_post(req
, ev
);
5262 tevent_req_set_callback(subreq
,
5263 cli_smb2_get_reparse_point_fnum_done
,
5269 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req
*subreq
)
5271 struct tevent_req
*req
= tevent_req_callback_data(
5272 subreq
, struct tevent_req
);
5273 struct cli_smb2_get_reparse_point_fnum_state
*state
= tevent_req_data(
5274 req
, struct cli_smb2_get_reparse_point_fnum_state
);
5277 status
= smb2cli_ioctl_recv(subreq
, state
,
5279 &state
->output_buffer
);
5280 TALLOC_FREE(subreq
);
5281 if (tevent_req_nterror(req
, status
)) {
5282 state
->cli
->raw_status
= status
;
5285 tevent_req_done(req
);
5288 NTSTATUS
cli_smb2_get_reparse_point_fnum_recv(struct tevent_req
*req
,
5289 TALLOC_CTX
*mem_ctx
,
5292 struct cli_smb2_get_reparse_point_fnum_state
*state
= tevent_req_data(
5293 req
, struct cli_smb2_get_reparse_point_fnum_state
);
5295 if (tevent_req_is_nterror(req
, &state
->cli
->raw_status
)) {
5296 tevent_req_received(req
);
5297 return state
->cli
->raw_status
;
5299 *output
= data_blob_dup_talloc(mem_ctx
, state
->output_buffer
);
5300 if (output
->data
== NULL
) {
5301 tevent_req_received(req
);
5302 return NT_STATUS_NO_MEMORY
;
5304 tevent_req_received(req
);
5305 return NT_STATUS_OK
;