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 smb_create_returns cr
;
163 struct tevent_req
*subreq
;
166 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
);
167 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
);
169 struct tevent_req
*cli_smb2_create_fnum_send(TALLOC_CTX
*mem_ctx
,
170 struct tevent_context
*ev
,
171 struct cli_state
*cli
,
173 uint32_t create_flags
,
174 uint32_t desired_access
,
175 uint32_t file_attributes
,
176 uint32_t share_access
,
177 uint32_t create_disposition
,
178 uint32_t create_options
)
180 struct tevent_req
*req
, *subreq
;
181 struct cli_smb2_create_fnum_state
*state
;
182 size_t fname_len
= 0;
183 const char *startp
= NULL
;
184 const char *endp
= NULL
;
185 time_t tstamp
= (time_t)0;
186 struct smb2_create_blobs
*cblobs
= NULL
;
188 req
= tevent_req_create(mem_ctx
, &state
,
189 struct cli_smb2_create_fnum_state
);
195 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
196 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
197 return tevent_req_post(req
, ev
);
200 if (cli
->backup_intent
) {
201 create_options
|= FILE_OPEN_FOR_BACKUP_INTENT
;
204 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
205 fname_len
= strlen(fname
);
206 if (clistr_is_previous_version_path(fname
, &startp
, &endp
, &tstamp
)) {
207 size_t len_before_gmt
= startp
- fname
;
208 size_t len_after_gmt
= fname
+ fname_len
- endp
;
213 char *new_fname
= talloc_array(state
, char,
214 len_before_gmt
+ len_after_gmt
+ 1);
216 if (tevent_req_nomem(new_fname
, req
)) {
217 return tevent_req_post(req
, ev
);
220 memcpy(new_fname
, fname
, len_before_gmt
);
221 memcpy(new_fname
+ len_before_gmt
, endp
, len_after_gmt
+ 1);
223 fname_len
= len_before_gmt
+ len_after_gmt
;
225 unix_to_nt_time(&ntt
, tstamp
);
226 twrp_blob
= data_blob_const((const void *)&ntt
, 8);
228 cblobs
= talloc_zero(state
, struct smb2_create_blobs
);
229 if (tevent_req_nomem(cblobs
, req
)) {
230 return tevent_req_post(req
, ev
);
233 status
= smb2_create_blob_add(state
, cblobs
,
234 SMB2_CREATE_TAG_TWRP
, twrp_blob
);
235 if (!NT_STATUS_IS_OK(status
)) {
236 tevent_req_nterror(req
, status
);
237 return tevent_req_post(req
, ev
);
241 /* SMB2 is pickier about pathnames. Ensure it doesn't
243 if (*fname
== '\\') {
248 /* Or end in a '\' */
249 if (fname_len
> 0 && fname
[fname_len
-1] == '\\') {
250 char *new_fname
= talloc_strdup(state
, fname
);
251 if (tevent_req_nomem(new_fname
, req
)) {
252 return tevent_req_post(req
, ev
);
254 new_fname
[fname_len
-1] = '\0';
258 subreq
= smb2cli_create_send(state
, ev
,
264 flags_to_smb2_oplock(create_flags
),
265 SMB2_IMPERSONATION_IMPERSONATION
,
272 if (tevent_req_nomem(subreq
, req
)) {
273 return tevent_req_post(req
, ev
);
275 tevent_req_set_callback(subreq
, cli_smb2_create_fnum_done
, req
);
277 state
->subreq
= subreq
;
278 tevent_req_set_cancel_fn(req
, cli_smb2_create_fnum_cancel
);
283 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
)
285 struct tevent_req
*req
= tevent_req_callback_data(
286 subreq
, struct tevent_req
);
287 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
288 req
, struct cli_smb2_create_fnum_state
);
292 status
= smb2cli_create_recv(subreq
, &h
.fid_persistent
,
293 &h
.fid_volatile
, &state
->cr
, NULL
, NULL
);
295 if (tevent_req_nterror(req
, status
)) {
299 status
= map_smb2_handle_to_fnum(state
->cli
, &h
, &state
->fnum
);
300 if (tevent_req_nterror(req
, status
)) {
303 tevent_req_done(req
);
306 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
)
308 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
309 req
, struct cli_smb2_create_fnum_state
);
310 return tevent_req_cancel(state
->subreq
);
313 NTSTATUS
cli_smb2_create_fnum_recv(struct tevent_req
*req
, uint16_t *pfnum
,
314 struct smb_create_returns
*cr
)
316 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
317 req
, struct cli_smb2_create_fnum_state
);
320 if (tevent_req_is_nterror(req
, &status
)) {
321 state
->cli
->raw_status
= status
;
325 *pfnum
= state
->fnum
;
330 state
->cli
->raw_status
= NT_STATUS_OK
;
334 NTSTATUS
cli_smb2_create_fnum(struct cli_state
*cli
,
336 uint32_t create_flags
,
337 uint32_t desired_access
,
338 uint32_t file_attributes
,
339 uint32_t share_access
,
340 uint32_t create_disposition
,
341 uint32_t create_options
,
343 struct smb_create_returns
*cr
)
345 TALLOC_CTX
*frame
= talloc_stackframe();
346 struct tevent_context
*ev
;
347 struct tevent_req
*req
;
348 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
350 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
352 * Can't use sync call while an async call is in flight
354 status
= NT_STATUS_INVALID_PARAMETER
;
357 ev
= samba_tevent_context_init(frame
);
361 req
= cli_smb2_create_fnum_send(frame
, ev
, cli
, fname
, create_flags
,
362 desired_access
, file_attributes
,
363 share_access
, create_disposition
,
368 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
371 status
= cli_smb2_create_fnum_recv(req
, pfid
, cr
);
377 /***************************************************************
378 Small wrapper that allows SMB2 close to use a uint16_t fnum.
379 ***************************************************************/
381 struct cli_smb2_close_fnum_state
{
382 struct cli_state
*cli
;
387 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
);
389 struct tevent_req
*cli_smb2_close_fnum_send(TALLOC_CTX
*mem_ctx
,
390 struct tevent_context
*ev
,
391 struct cli_state
*cli
,
394 struct tevent_req
*req
, *subreq
;
395 struct cli_smb2_close_fnum_state
*state
;
398 req
= tevent_req_create(mem_ctx
, &state
,
399 struct cli_smb2_close_fnum_state
);
406 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
407 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
408 return tevent_req_post(req
, ev
);
411 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
412 if (tevent_req_nterror(req
, status
)) {
413 return tevent_req_post(req
, ev
);
416 subreq
= smb2cli_close_send(state
, ev
, cli
->conn
, cli
->timeout
,
417 cli
->smb2
.session
, cli
->smb2
.tcon
,
418 0, state
->ph
->fid_persistent
,
419 state
->ph
->fid_volatile
);
420 if (tevent_req_nomem(subreq
, req
)) {
421 return tevent_req_post(req
, ev
);
423 tevent_req_set_callback(subreq
, cli_smb2_close_fnum_done
, req
);
427 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
)
429 struct tevent_req
*req
= tevent_req_callback_data(
430 subreq
, struct tevent_req
);
431 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
432 req
, struct cli_smb2_close_fnum_state
);
435 status
= smb2cli_close_recv(subreq
);
436 if (tevent_req_nterror(req
, status
)) {
440 /* Delete the fnum -> handle mapping. */
441 status
= delete_smb2_handle_mapping(state
->cli
, &state
->ph
,
443 if (tevent_req_nterror(req
, status
)) {
446 tevent_req_done(req
);
449 NTSTATUS
cli_smb2_close_fnum_recv(struct tevent_req
*req
)
451 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
452 req
, struct cli_smb2_close_fnum_state
);
453 NTSTATUS status
= NT_STATUS_OK
;
455 if (tevent_req_is_nterror(req
, &status
)) {
456 state
->cli
->raw_status
= status
;
458 tevent_req_received(req
);
462 NTSTATUS
cli_smb2_close_fnum(struct cli_state
*cli
, uint16_t fnum
)
464 TALLOC_CTX
*frame
= talloc_stackframe();
465 struct tevent_context
*ev
;
466 struct tevent_req
*req
;
467 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
469 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
471 * Can't use sync call while an async call is in flight
473 status
= NT_STATUS_INVALID_PARAMETER
;
476 ev
= samba_tevent_context_init(frame
);
480 req
= cli_smb2_close_fnum_send(frame
, ev
, cli
, fnum
);
484 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
487 status
= cli_smb2_close_fnum_recv(req
);
493 struct cli_smb2_delete_on_close_state
{
494 struct cli_state
*cli
;
501 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
);
503 struct tevent_req
*cli_smb2_delete_on_close_send(TALLOC_CTX
*mem_ctx
,
504 struct tevent_context
*ev
,
505 struct cli_state
*cli
,
509 struct tevent_req
*req
= NULL
;
510 struct cli_smb2_delete_on_close_state
*state
= NULL
;
511 struct tevent_req
*subreq
= NULL
;
512 uint8_t in_info_type
;
513 uint8_t in_file_info_class
;
516 req
= tevent_req_create(mem_ctx
, &state
,
517 struct cli_smb2_delete_on_close_state
);
524 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
525 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
526 return tevent_req_post(req
, ev
);
529 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
530 if (tevent_req_nterror(req
, status
)) {
531 return tevent_req_post(req
, ev
);
535 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
536 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
539 in_file_info_class
= SMB_FILE_DISPOSITION_INFORMATION
- 1000;
540 /* Setup data array. */
541 SCVAL(&state
->data
[0], 0, flag
? 1 : 0);
542 state
->inbuf
.data
= &state
->data
[0];
543 state
->inbuf
.length
= 1;
545 subreq
= smb2cli_set_info_send(state
, ev
,
552 &state
->inbuf
, /* in_input_buffer */
553 0, /* in_additional_info */
554 state
->ph
->fid_persistent
,
555 state
->ph
->fid_volatile
);
556 if (tevent_req_nomem(subreq
, req
)) {
557 return tevent_req_post(req
, ev
);
559 tevent_req_set_callback(subreq
,
560 cli_smb2_delete_on_close_done
,
565 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
)
567 NTSTATUS status
= smb2cli_set_info_recv(subreq
);
568 tevent_req_simple_finish_ntstatus(subreq
, status
);
571 NTSTATUS
cli_smb2_delete_on_close_recv(struct tevent_req
*req
)
573 struct cli_smb2_delete_on_close_state
*state
=
575 struct cli_smb2_delete_on_close_state
);
578 if (tevent_req_is_nterror(req
, &status
)) {
579 state
->cli
->raw_status
= status
;
580 tevent_req_received(req
);
584 state
->cli
->raw_status
= NT_STATUS_OK
;
585 tevent_req_received(req
);
589 NTSTATUS
cli_smb2_delete_on_close(struct cli_state
*cli
, uint16_t fnum
, bool flag
)
591 TALLOC_CTX
*frame
= talloc_stackframe();
592 struct tevent_context
*ev
;
593 struct tevent_req
*req
;
594 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
596 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
598 * Can't use sync call while an async call is in flight
600 status
= NT_STATUS_INVALID_PARAMETER
;
603 ev
= samba_tevent_context_init(frame
);
607 req
= cli_smb2_delete_on_close_send(frame
, ev
, cli
, fnum
, flag
);
611 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
614 status
= cli_smb2_delete_on_close_recv(req
);
620 /***************************************************************
621 Small wrapper that allows SMB2 to create a directory
623 ***************************************************************/
625 NTSTATUS
cli_smb2_mkdir(struct cli_state
*cli
, const char *dname
)
630 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
632 * Can't use sync call while an async call is in flight
634 return NT_STATUS_INVALID_PARAMETER
;
637 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
638 return NT_STATUS_INVALID_PARAMETER
;
641 status
= cli_smb2_create_fnum(cli
,
643 0, /* create_flags */
644 FILE_READ_ATTRIBUTES
, /* desired_access */
645 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
646 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
647 FILE_CREATE
, /* create_disposition */
648 FILE_DIRECTORY_FILE
, /* create_options */
652 if (!NT_STATUS_IS_OK(status
)) {
655 return cli_smb2_close_fnum(cli
, fnum
);
658 /***************************************************************
659 Small wrapper that allows SMB2 to delete a directory
661 ***************************************************************/
663 NTSTATUS
cli_smb2_rmdir(struct cli_state
*cli
, const char *dname
)
668 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
670 * Can't use sync call while an async call is in flight
672 return NT_STATUS_INVALID_PARAMETER
;
675 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
676 return NT_STATUS_INVALID_PARAMETER
;
679 status
= cli_smb2_create_fnum(cli
,
681 0, /* create_flags */
682 DELETE_ACCESS
, /* desired_access */
683 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
684 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
685 FILE_OPEN
, /* create_disposition */
686 FILE_DIRECTORY_FILE
, /* create_options */
690 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
692 * Naive option to match our SMB1 code. Assume the
693 * symlink path that tripped us up was the last
694 * component and try again. Eventually we will have to
695 * deal with the returned path unprocessed component. JRA.
697 status
= cli_smb2_create_fnum(cli
,
699 0, /* create_flags */
700 DELETE_ACCESS
, /* desired_access */
701 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
702 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
703 FILE_OPEN
, /* create_disposition */
705 FILE_DELETE_ON_CLOSE
|
706 FILE_OPEN_REPARSE_POINT
, /* create_options */
711 if (!NT_STATUS_IS_OK(status
)) {
715 status
= cli_smb2_delete_on_close(cli
, fnum
, true);
716 if (!NT_STATUS_IS_OK(status
)) {
717 cli_smb2_close_fnum(cli
, fnum
);
721 return cli_smb2_close_fnum(cli
, fnum
);
724 /***************************************************************
725 Small wrapper that allows SMB2 to unlink a pathname.
727 ***************************************************************/
729 NTSTATUS
cli_smb2_unlink(struct cli_state
*cli
, const char *fname
)
734 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
736 * Can't use sync call while an async call is in flight
738 return NT_STATUS_INVALID_PARAMETER
;
741 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
742 return NT_STATUS_INVALID_PARAMETER
;
745 status
= cli_smb2_create_fnum(cli
,
747 0, /* create_flags */
748 DELETE_ACCESS
, /* desired_access */
749 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
750 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
751 FILE_OPEN
, /* create_disposition */
752 FILE_DELETE_ON_CLOSE
, /* create_options */
756 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
758 * Naive option to match our SMB1 code. Assume the
759 * symlink path that tripped us up was the last
760 * component and try again. Eventually we will have to
761 * deal with the returned path unprocessed component. JRA.
763 status
= cli_smb2_create_fnum(cli
,
765 0, /* create_flags */
766 DELETE_ACCESS
, /* desired_access */
767 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
768 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
769 FILE_OPEN
, /* create_disposition */
770 FILE_DELETE_ON_CLOSE
|
771 FILE_OPEN_REPARSE_POINT
, /* create_options */
776 if (!NT_STATUS_IS_OK(status
)) {
779 return cli_smb2_close_fnum(cli
, fnum
);
782 /***************************************************************
783 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
784 ***************************************************************/
786 static NTSTATUS
parse_finfo_id_both_directory_info(uint8_t *dir_data
,
787 uint32_t dir_data_length
,
788 struct file_info
*finfo
,
789 uint32_t *next_offset
)
795 if (dir_data_length
< 4) {
796 return NT_STATUS_INFO_LENGTH_MISMATCH
;
799 *next_offset
= IVAL(dir_data
, 0);
801 if (*next_offset
> dir_data_length
) {
802 return NT_STATUS_INFO_LENGTH_MISMATCH
;
805 if (*next_offset
!= 0) {
806 /* Ensure we only read what in this record. */
807 dir_data_length
= *next_offset
;
810 if (dir_data_length
< 105) {
811 return NT_STATUS_INFO_LENGTH_MISMATCH
;
814 finfo
->btime_ts
= interpret_long_date((const char *)dir_data
+ 8);
815 finfo
->atime_ts
= interpret_long_date((const char *)dir_data
+ 16);
816 finfo
->mtime_ts
= interpret_long_date((const char *)dir_data
+ 24);
817 finfo
->ctime_ts
= interpret_long_date((const char *)dir_data
+ 32);
818 finfo
->size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 40, 0);
819 finfo
->mode
= CVAL(dir_data
+ 56, 0);
820 namelen
= IVAL(dir_data
+ 60,0);
821 if (namelen
> (dir_data_length
- 104)) {
822 return NT_STATUS_INFO_LENGTH_MISMATCH
;
824 slen
= CVAL(dir_data
+ 68, 0);
826 return NT_STATUS_INFO_LENGTH_MISMATCH
;
828 ret
= pull_string_talloc(finfo
,
830 FLAGS2_UNICODE_STRINGS
,
835 if (ret
== (size_t)-1) {
836 /* Bad conversion. */
837 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
840 ret
= pull_string_talloc(finfo
,
842 FLAGS2_UNICODE_STRINGS
,
847 if (ret
== (size_t)-1) {
848 /* Bad conversion. */
849 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
854 /*******************************************************************
855 Given a filename - get its directory name
856 ********************************************************************/
858 static bool windows_parent_dirname(TALLOC_CTX
*mem_ctx
,
866 p
= strrchr_m(dir
, '\\'); /* Find final '\\', if any */
869 if (!(*parent
= talloc_strdup(mem_ctx
, "\\"))) {
880 if (!(*parent
= (char *)talloc_memdup(mem_ctx
, dir
, len
+1))) {
883 (*parent
)[len
] = '\0';
891 /***************************************************************
892 Wrapper that allows SMB2 to list a directory.
894 ***************************************************************/
896 NTSTATUS
cli_smb2_list(struct cli_state
*cli
,
897 const char *pathname
,
899 NTSTATUS (*fn
)(const char *,
906 uint16_t fnum
= 0xffff;
907 char *parent_dir
= NULL
;
908 const char *mask
= NULL
;
909 struct smb2_hnd
*ph
= NULL
;
910 bool processed_file
= false;
911 TALLOC_CTX
*frame
= talloc_stackframe();
912 TALLOC_CTX
*subframe
= NULL
;
915 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
917 * Can't use sync call while an async call is in flight
919 status
= NT_STATUS_INVALID_PARAMETER
;
923 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
924 status
= NT_STATUS_INVALID_PARAMETER
;
928 /* Get the directory name. */
929 if (!windows_parent_dirname(frame
,
933 status
= NT_STATUS_NO_MEMORY
;
937 mask_has_wild
= ms_has_wild(mask
);
939 status
= cli_smb2_create_fnum(cli
,
941 0, /* create_flags */
942 SEC_DIR_LIST
|SEC_DIR_READ_ATTRIBUTE
,/* desired_access */
943 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
944 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
945 FILE_OPEN
, /* create_disposition */
946 FILE_DIRECTORY_FILE
, /* create_options */
950 if (!NT_STATUS_IS_OK(status
)) {
954 status
= map_fnum_to_smb2_handle(cli
,
957 if (!NT_STATUS_IS_OK(status
)) {
962 uint8_t *dir_data
= NULL
;
963 uint32_t dir_data_length
= 0;
964 uint32_t next_offset
= 0;
965 subframe
= talloc_stackframe();
967 status
= smb2cli_query_directory(cli
->conn
,
971 SMB2_FIND_ID_BOTH_DIRECTORY_INFO
,
982 if (!NT_STATUS_IS_OK(status
)) {
983 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
990 struct file_info
*finfo
= talloc_zero(subframe
,
994 status
= NT_STATUS_NO_MEMORY
;
998 status
= parse_finfo_id_both_directory_info(dir_data
,
1003 if (!NT_STATUS_IS_OK(status
)) {
1007 if (dir_check_ftype((uint32_t)finfo
->mode
,
1008 (uint32_t)attribute
)) {
1010 * Only process if attributes match.
1011 * On SMB1 server does this, so on
1012 * SMB2 we need to emulate in the
1015 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1017 processed_file
= true;
1019 status
= fn(cli
->dfs_mountpoint
,
1024 if (!NT_STATUS_IS_OK(status
)) {
1031 /* Move to next entry. */
1033 dir_data
+= next_offset
;
1034 dir_data_length
-= next_offset
;
1036 } while (next_offset
!= 0);
1038 TALLOC_FREE(subframe
);
1040 if (!mask_has_wild
) {
1042 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1043 * when handed a non-wildcard path. Do it
1044 * for the server (with a non-wildcard path
1045 * there should only ever be one file returned.
1047 status
= STATUS_NO_MORE_FILES
;
1051 } while (NT_STATUS_IS_OK(status
));
1053 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
1054 status
= NT_STATUS_OK
;
1057 if (NT_STATUS_IS_OK(status
) && !processed_file
) {
1059 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1060 * if no files match. Emulate this in the client.
1062 status
= NT_STATUS_NO_SUCH_FILE
;
1067 if (fnum
!= 0xffff) {
1068 cli_smb2_close_fnum(cli
, fnum
);
1071 cli
->raw_status
= status
;
1073 TALLOC_FREE(subframe
);
1078 /***************************************************************
1079 Wrapper that allows SMB2 to query a path info (basic level).
1081 ***************************************************************/
1083 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
1085 SMB_STRUCT_STAT
*sbuf
,
1086 uint32_t *attributes
)
1089 struct smb_create_returns cr
;
1090 uint16_t fnum
= 0xffff;
1091 size_t namelen
= strlen(name
);
1093 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1095 * Can't use sync call while an async call is in flight
1097 return NT_STATUS_INVALID_PARAMETER
;
1100 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1101 return NT_STATUS_INVALID_PARAMETER
;
1104 /* SMB2 is pickier about pathnames. Ensure it doesn't
1106 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1107 char *modname
= talloc_strdup(talloc_tos(), name
);
1108 modname
[namelen
-1] = '\0';
1112 /* This is commonly used as a 'cd'. Try qpathinfo on
1113 a directory handle first. */
1115 status
= cli_smb2_create_fnum(cli
,
1117 0, /* create_flags */
1118 FILE_READ_ATTRIBUTES
, /* desired_access */
1119 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1120 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1121 FILE_OPEN
, /* create_disposition */
1122 FILE_DIRECTORY_FILE
, /* create_options */
1126 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
1127 /* Maybe a file ? */
1128 status
= cli_smb2_create_fnum(cli
,
1130 0, /* create_flags */
1131 FILE_READ_ATTRIBUTES
, /* desired_access */
1132 0, /* file attributes */
1133 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1134 FILE_OPEN
, /* create_disposition */
1135 0, /* create_options */
1140 if (!NT_STATUS_IS_OK(status
)) {
1144 status
= cli_smb2_close_fnum(cli
, fnum
);
1148 sbuf
->st_ex_atime
= nt_time_to_unix_timespec(cr
.last_access_time
);
1149 sbuf
->st_ex_mtime
= nt_time_to_unix_timespec(cr
.last_write_time
);
1150 sbuf
->st_ex_ctime
= nt_time_to_unix_timespec(cr
.change_time
);
1151 sbuf
->st_ex_size
= cr
.end_of_file
;
1152 *attributes
= cr
.file_attributes
;
1157 /***************************************************************
1158 Wrapper that allows SMB2 to check if a path is a directory.
1160 ***************************************************************/
1162 NTSTATUS
cli_smb2_chkpath(struct cli_state
*cli
,
1166 uint16_t fnum
= 0xffff;
1168 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1170 * Can't use sync call while an async call is in flight
1172 return NT_STATUS_INVALID_PARAMETER
;
1175 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1176 return NT_STATUS_INVALID_PARAMETER
;
1179 /* Ensure this is a directory. */
1180 status
= cli_smb2_create_fnum(cli
,
1182 0, /* create_flags */
1183 FILE_READ_ATTRIBUTES
, /* desired_access */
1184 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1185 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1186 FILE_OPEN
, /* create_disposition */
1187 FILE_DIRECTORY_FILE
, /* create_options */
1191 if (!NT_STATUS_IS_OK(status
)) {
1195 return cli_smb2_close_fnum(cli
, fnum
);
1198 /***************************************************************
1199 Helper function for pathname operations.
1200 ***************************************************************/
1202 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
1204 uint32_t desired_access
,
1208 size_t namelen
= strlen(name
);
1209 TALLOC_CTX
*frame
= talloc_stackframe();
1210 uint32_t create_options
= 0;
1212 /* SMB2 is pickier about pathnames. Ensure it doesn't
1214 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1215 char *modname
= talloc_strdup(frame
, name
);
1216 if (modname
== NULL
) {
1217 status
= NT_STATUS_NO_MEMORY
;
1220 modname
[namelen
-1] = '\0';
1224 /* Try to open a file handle first. */
1225 status
= cli_smb2_create_fnum(cli
,
1227 0, /* create_flags */
1229 0, /* file attributes */
1230 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1231 FILE_OPEN
, /* create_disposition */
1236 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
1238 * Naive option to match our SMB1 code. Assume the
1239 * symlink path that tripped us up was the last
1240 * component and try again. Eventually we will have to
1241 * deal with the returned path unprocessed component. JRA.
1243 create_options
|= FILE_OPEN_REPARSE_POINT
;
1244 status
= cli_smb2_create_fnum(cli
,
1246 0, /* create_flags */
1248 0, /* file attributes */
1249 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1250 FILE_OPEN
, /* create_disposition */
1256 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
1257 create_options
|= FILE_DIRECTORY_FILE
;
1258 status
= cli_smb2_create_fnum(cli
,
1260 0, /* create_flags */
1262 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1263 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1264 FILE_OPEN
, /* create_disposition */
1265 FILE_DIRECTORY_FILE
, /* create_options */
1276 /***************************************************************
1277 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1279 ***************************************************************/
1281 NTSTATUS
cli_smb2_qpathinfo_alt_name(struct cli_state
*cli
,
1286 DATA_BLOB outbuf
= data_blob_null
;
1287 uint16_t fnum
= 0xffff;
1288 struct smb2_hnd
*ph
= NULL
;
1289 uint32_t altnamelen
= 0;
1290 TALLOC_CTX
*frame
= talloc_stackframe();
1292 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1294 * Can't use sync call while an async call is in flight
1296 status
= NT_STATUS_INVALID_PARAMETER
;
1300 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1301 status
= NT_STATUS_INVALID_PARAMETER
;
1305 status
= get_fnum_from_path(cli
,
1307 FILE_READ_ATTRIBUTES
,
1310 if (!NT_STATUS_IS_OK(status
)) {
1314 status
= map_fnum_to_smb2_handle(cli
,
1317 if (!NT_STATUS_IS_OK(status
)) {
1321 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1322 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1324 status
= smb2cli_query_info(cli
->conn
,
1328 1, /* in_info_type */
1329 (SMB_FILE_ALTERNATE_NAME_INFORMATION
- 1000), /* in_file_info_class */
1330 0xFFFF, /* in_max_output_length */
1331 NULL
, /* in_input_buffer */
1332 0, /* in_additional_info */
1339 if (!NT_STATUS_IS_OK(status
)) {
1343 /* Parse the reply. */
1344 if (outbuf
.length
< 4) {
1345 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1349 altnamelen
= IVAL(outbuf
.data
, 0);
1350 if (altnamelen
> outbuf
.length
- 4) {
1351 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1355 if (altnamelen
> 0) {
1357 char *short_name
= NULL
;
1358 ret
= pull_string_talloc(frame
,
1360 FLAGS2_UNICODE_STRINGS
,
1365 if (ret
== (size_t)-1) {
1366 /* Bad conversion. */
1367 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1371 fstrcpy(alt_name
, short_name
);
1376 status
= NT_STATUS_OK
;
1380 if (fnum
!= 0xffff) {
1381 cli_smb2_close_fnum(cli
, fnum
);
1384 cli
->raw_status
= status
;
1391 /***************************************************************
1392 Wrapper that allows SMB2 to query a fnum info (basic level).
1394 ***************************************************************/
1396 NTSTATUS
cli_smb2_qfileinfo_basic(struct cli_state
*cli
,
1400 struct timespec
*create_time
,
1401 struct timespec
*access_time
,
1402 struct timespec
*write_time
,
1403 struct timespec
*change_time
,
1407 DATA_BLOB outbuf
= data_blob_null
;
1408 struct smb2_hnd
*ph
= NULL
;
1409 TALLOC_CTX
*frame
= talloc_stackframe();
1411 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1413 * Can't use sync call while an async call is in flight
1415 status
= NT_STATUS_INVALID_PARAMETER
;
1419 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1420 status
= NT_STATUS_INVALID_PARAMETER
;
1424 status
= map_fnum_to_smb2_handle(cli
,
1427 if (!NT_STATUS_IS_OK(status
)) {
1431 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1432 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1434 status
= smb2cli_query_info(cli
->conn
,
1438 1, /* in_info_type */
1439 (SMB_FILE_ALL_INFORMATION
- 1000), /* in_file_info_class */
1440 0xFFFF, /* in_max_output_length */
1441 NULL
, /* in_input_buffer */
1442 0, /* in_additional_info */
1448 if (!NT_STATUS_IS_OK(status
)) {
1452 /* Parse the reply. */
1453 if (outbuf
.length
< 0x60) {
1454 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1459 *create_time
= interpret_long_date((const char *)outbuf
.data
+ 0x0);
1462 *access_time
= interpret_long_date((const char *)outbuf
.data
+ 0x8);
1465 *write_time
= interpret_long_date((const char *)outbuf
.data
+ 0x10);
1468 *change_time
= interpret_long_date((const char *)outbuf
.data
+ 0x18);
1471 uint32_t attr
= IVAL(outbuf
.data
, 0x20);
1472 *mode
= (uint16_t)attr
;
1475 uint64_t file_size
= BVAL(outbuf
.data
, 0x30);
1476 *size
= (off_t
)file_size
;
1479 uint64_t file_index
= BVAL(outbuf
.data
, 0x40);
1480 *ino
= (SMB_INO_T
)file_index
;
1485 cli
->raw_status
= status
;
1491 /***************************************************************
1492 Wrapper that allows SMB2 to query an fnum.
1493 Implement on top of cli_smb2_qfileinfo_basic().
1495 ***************************************************************/
1497 NTSTATUS
cli_smb2_getattrE(struct cli_state
*cli
,
1501 time_t *change_time
,
1502 time_t *access_time
,
1505 struct timespec access_time_ts
;
1506 struct timespec write_time_ts
;
1507 struct timespec change_time_ts
;
1508 NTSTATUS status
= cli_smb2_qfileinfo_basic(cli
,
1518 cli
->raw_status
= status
;
1520 if (!NT_STATUS_IS_OK(status
)) {
1525 *change_time
= change_time_ts
.tv_sec
;
1528 *access_time
= access_time_ts
.tv_sec
;
1531 *write_time
= write_time_ts
.tv_sec
;
1533 return NT_STATUS_OK
;
1536 /***************************************************************
1537 Wrapper that allows SMB2 to get pathname attributes.
1539 ***************************************************************/
1541 NTSTATUS
cli_smb2_getatr(struct cli_state
*cli
,
1548 uint16_t fnum
= 0xffff;
1549 struct smb2_hnd
*ph
= NULL
;
1550 TALLOC_CTX
*frame
= talloc_stackframe();
1552 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1554 * Can't use sync call while an async call is in flight
1556 status
= NT_STATUS_INVALID_PARAMETER
;
1560 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1561 status
= NT_STATUS_INVALID_PARAMETER
;
1565 status
= get_fnum_from_path(cli
,
1567 FILE_READ_ATTRIBUTES
,
1570 if (!NT_STATUS_IS_OK(status
)) {
1574 status
= map_fnum_to_smb2_handle(cli
,
1577 if (!NT_STATUS_IS_OK(status
)) {
1580 status
= cli_smb2_getattrE(cli
,
1587 if (!NT_STATUS_IS_OK(status
)) {
1593 if (fnum
!= 0xffff) {
1594 cli_smb2_close_fnum(cli
, fnum
);
1597 cli
->raw_status
= status
;
1603 /***************************************************************
1604 Wrapper that allows SMB2 to query a pathname info (basic level).
1605 Implement on top of cli_smb2_qfileinfo_basic().
1607 ***************************************************************/
1609 NTSTATUS
cli_smb2_qpathinfo2(struct cli_state
*cli
,
1611 struct timespec
*create_time
,
1612 struct timespec
*access_time
,
1613 struct timespec
*write_time
,
1614 struct timespec
*change_time
,
1620 struct smb2_hnd
*ph
= NULL
;
1621 uint16_t fnum
= 0xffff;
1622 TALLOC_CTX
*frame
= talloc_stackframe();
1624 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1626 * Can't use sync call while an async call is in flight
1628 status
= NT_STATUS_INVALID_PARAMETER
;
1632 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1633 status
= NT_STATUS_INVALID_PARAMETER
;
1637 status
= get_fnum_from_path(cli
,
1639 FILE_READ_ATTRIBUTES
,
1642 if (!NT_STATUS_IS_OK(status
)) {
1646 status
= map_fnum_to_smb2_handle(cli
,
1649 if (!NT_STATUS_IS_OK(status
)) {
1653 status
= cli_smb2_qfileinfo_basic(cli
,
1665 if (fnum
!= 0xffff) {
1666 cli_smb2_close_fnum(cli
, fnum
);
1669 cli
->raw_status
= status
;
1675 /***************************************************************
1676 Wrapper that allows SMB2 to query pathname streams.
1678 ***************************************************************/
1680 NTSTATUS
cli_smb2_qpathinfo_streams(struct cli_state
*cli
,
1682 TALLOC_CTX
*mem_ctx
,
1683 unsigned int *pnum_streams
,
1684 struct stream_struct
**pstreams
)
1687 struct smb2_hnd
*ph
= NULL
;
1688 uint16_t fnum
= 0xffff;
1689 DATA_BLOB outbuf
= data_blob_null
;
1690 TALLOC_CTX
*frame
= talloc_stackframe();
1692 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1694 * Can't use sync call while an async call is in flight
1696 status
= NT_STATUS_INVALID_PARAMETER
;
1700 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1701 status
= NT_STATUS_INVALID_PARAMETER
;
1705 status
= get_fnum_from_path(cli
,
1707 FILE_READ_ATTRIBUTES
,
1710 if (!NT_STATUS_IS_OK(status
)) {
1714 status
= map_fnum_to_smb2_handle(cli
,
1717 if (!NT_STATUS_IS_OK(status
)) {
1721 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1722 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1724 status
= smb2cli_query_info(cli
->conn
,
1728 1, /* in_info_type */
1729 (SMB_FILE_STREAM_INFORMATION
- 1000), /* in_file_info_class */
1730 0xFFFF, /* in_max_output_length */
1731 NULL
, /* in_input_buffer */
1732 0, /* in_additional_info */
1739 if (!NT_STATUS_IS_OK(status
)) {
1743 /* Parse the reply. */
1744 if (!parse_streams_blob(mem_ctx
,
1749 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1755 if (fnum
!= 0xffff) {
1756 cli_smb2_close_fnum(cli
, fnum
);
1759 cli
->raw_status
= status
;
1765 /***************************************************************
1766 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
1769 ***************************************************************/
1771 NTSTATUS
cli_smb2_setpathinfo(struct cli_state
*cli
,
1773 uint8_t in_info_type
,
1774 uint8_t in_file_info_class
,
1775 const DATA_BLOB
*p_in_data
)
1778 uint16_t fnum
= 0xffff;
1779 struct smb2_hnd
*ph
= NULL
;
1780 TALLOC_CTX
*frame
= talloc_stackframe();
1782 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1784 * Can't use sync call while an async call is in flight
1786 status
= NT_STATUS_INVALID_PARAMETER
;
1790 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1791 status
= NT_STATUS_INVALID_PARAMETER
;
1795 status
= get_fnum_from_path(cli
,
1797 FILE_WRITE_ATTRIBUTES
,
1800 if (!NT_STATUS_IS_OK(status
)) {
1804 status
= map_fnum_to_smb2_handle(cli
,
1807 if (!NT_STATUS_IS_OK(status
)) {
1811 status
= smb2cli_set_info(cli
->conn
,
1817 p_in_data
, /* in_input_buffer */
1818 0, /* in_additional_info */
1823 if (fnum
!= 0xffff) {
1824 cli_smb2_close_fnum(cli
, fnum
);
1827 cli
->raw_status
= status
;
1834 /***************************************************************
1835 Wrapper that allows SMB2 to set pathname attributes.
1837 ***************************************************************/
1839 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
1844 uint8_t inbuf_store
[40];
1845 DATA_BLOB inbuf
= data_blob_null
;
1847 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1848 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1850 inbuf
.data
= inbuf_store
;
1851 inbuf
.length
= sizeof(inbuf_store
);
1852 data_blob_clear(&inbuf
);
1855 * SMB1 uses attr == 0 to clear all attributes
1856 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
1857 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
1858 * request attribute change.
1860 * SMB2 uses exactly the reverse. Unfortunately as the
1861 * cli_setatr() ABI is exposed inside libsmbclient,
1862 * we must make the SMB2 cli_smb2_setatr() call
1863 * export the same ABI as the SMB1 cli_setatr()
1864 * which calls it. This means reversing the sense
1865 * of the requested attr argument if it's zero
1866 * or FILE_ATTRIBUTE_NORMAL.
1868 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
1872 attr
= FILE_ATTRIBUTE_NORMAL
;
1873 } else if (attr
== FILE_ATTRIBUTE_NORMAL
) {
1877 SSVAL(inbuf
.data
, 32, attr
);
1879 put_long_date((char *)inbuf
.data
+ 16,mtime
);
1881 /* Set all the other times to -1. */
1882 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1883 SBVAL(inbuf
.data
, 8, 0xFFFFFFFFFFFFFFFFLL
);
1884 SBVAL(inbuf
.data
, 24, 0xFFFFFFFFFFFFFFFFLL
);
1886 return cli_smb2_setpathinfo(cli
,
1888 1, /* in_info_type */
1889 /* in_file_info_class */
1890 SMB_FILE_BASIC_INFORMATION
- 1000,
1895 /***************************************************************
1896 Wrapper that allows SMB2 to set file handle times.
1898 ***************************************************************/
1900 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
1907 struct smb2_hnd
*ph
= NULL
;
1908 uint8_t inbuf_store
[40];
1909 DATA_BLOB inbuf
= data_blob_null
;
1911 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1913 * Can't use sync call while an async call is in flight
1915 return NT_STATUS_INVALID_PARAMETER
;
1918 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1919 return NT_STATUS_INVALID_PARAMETER
;
1922 status
= map_fnum_to_smb2_handle(cli
,
1925 if (!NT_STATUS_IS_OK(status
)) {
1929 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1930 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1932 inbuf
.data
= inbuf_store
;
1933 inbuf
.length
= sizeof(inbuf_store
);
1934 data_blob_clear(&inbuf
);
1936 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1937 if (change_time
!= 0) {
1938 put_long_date((char *)inbuf
.data
+ 24, change_time
);
1940 if (access_time
!= 0) {
1941 put_long_date((char *)inbuf
.data
+ 8, access_time
);
1943 if (write_time
!= 0) {
1944 put_long_date((char *)inbuf
.data
+ 16, write_time
);
1947 cli
->raw_status
= smb2cli_set_info(cli
->conn
,
1951 1, /* in_info_type */
1952 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1953 &inbuf
, /* in_input_buffer */
1954 0, /* in_additional_info */
1958 return cli
->raw_status
;
1961 /***************************************************************
1962 Wrapper that allows SMB2 to query disk attributes (size).
1964 ***************************************************************/
1966 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, const char *path
,
1967 uint64_t *bsize
, uint64_t *total
, uint64_t *avail
)
1970 uint16_t fnum
= 0xffff;
1971 DATA_BLOB outbuf
= data_blob_null
;
1972 struct smb2_hnd
*ph
= NULL
;
1973 uint32_t sectors_per_unit
= 0;
1974 uint32_t bytes_per_sector
= 0;
1975 uint64_t total_size
= 0;
1976 uint64_t size_free
= 0;
1977 TALLOC_CTX
*frame
= talloc_stackframe();
1979 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1981 * Can't use sync call while an async call is in flight
1983 status
= NT_STATUS_INVALID_PARAMETER
;
1987 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1988 status
= NT_STATUS_INVALID_PARAMETER
;
1992 /* First open the top level directory. */
1993 status
= cli_smb2_create_fnum(cli
,
1995 0, /* create_flags */
1996 FILE_READ_ATTRIBUTES
, /* desired_access */
1997 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1998 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1999 FILE_OPEN
, /* create_disposition */
2000 FILE_DIRECTORY_FILE
, /* create_options */
2004 if (!NT_STATUS_IS_OK(status
)) {
2008 status
= map_fnum_to_smb2_handle(cli
,
2011 if (!NT_STATUS_IS_OK(status
)) {
2015 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2016 level 3 (SMB_FS_SIZE_INFORMATION). */
2018 status
= smb2cli_query_info(cli
->conn
,
2022 2, /* in_info_type */
2023 3, /* in_file_info_class */
2024 0xFFFF, /* in_max_output_length */
2025 NULL
, /* in_input_buffer */
2026 0, /* in_additional_info */
2032 if (!NT_STATUS_IS_OK(status
)) {
2036 /* Parse the reply. */
2037 if (outbuf
.length
!= 24) {
2038 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2042 total_size
= BVAL(outbuf
.data
, 0);
2043 size_free
= BVAL(outbuf
.data
, 8);
2044 sectors_per_unit
= IVAL(outbuf
.data
, 16);
2045 bytes_per_sector
= IVAL(outbuf
.data
, 20);
2048 *bsize
= (uint64_t)sectors_per_unit
* (uint64_t)bytes_per_sector
;
2051 *total
= total_size
;
2057 status
= NT_STATUS_OK
;
2061 if (fnum
!= 0xffff) {
2062 cli_smb2_close_fnum(cli
, fnum
);
2065 cli
->raw_status
= status
;
2071 /***************************************************************
2072 Wrapper that allows SMB2 to query file system sizes.
2074 ***************************************************************/
2076 NTSTATUS
cli_smb2_get_fs_full_size_info(struct cli_state
*cli
,
2077 uint64_t *total_allocation_units
,
2078 uint64_t *caller_allocation_units
,
2079 uint64_t *actual_allocation_units
,
2080 uint64_t *sectors_per_allocation_unit
,
2081 uint64_t *bytes_per_sector
)
2084 uint16_t fnum
= 0xffff;
2085 DATA_BLOB outbuf
= data_blob_null
;
2086 struct smb2_hnd
*ph
= NULL
;
2087 TALLOC_CTX
*frame
= talloc_stackframe();
2089 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2091 * Can't use sync call while an async call is in flight
2093 status
= NT_STATUS_INVALID_PARAMETER
;
2097 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2098 status
= NT_STATUS_INVALID_PARAMETER
;
2102 /* First open the top level directory. */
2104 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2105 FILE_READ_ATTRIBUTES
, /* desired_access */
2106 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2107 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2108 FILE_SHARE_DELETE
, /* share_access */
2109 FILE_OPEN
, /* create_disposition */
2110 FILE_DIRECTORY_FILE
, /* create_options */
2114 if (!NT_STATUS_IS_OK(status
)) {
2118 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
2119 if (!NT_STATUS_IS_OK(status
)) {
2123 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2124 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2126 status
= smb2cli_query_info(cli
->conn
,
2130 SMB2_GETINFO_FS
, /* in_info_type */
2131 /* in_file_info_class */
2132 SMB_FS_FULL_SIZE_INFORMATION
- 1000,
2133 0xFFFF, /* in_max_output_length */
2134 NULL
, /* in_input_buffer */
2135 0, /* in_additional_info */
2141 if (!NT_STATUS_IS_OK(status
)) {
2145 if (outbuf
.length
< 32) {
2146 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2150 *total_allocation_units
= BIG_UINT(outbuf
.data
, 0);
2151 *caller_allocation_units
= BIG_UINT(outbuf
.data
, 8);
2152 *actual_allocation_units
= BIG_UINT(outbuf
.data
, 16);
2153 *sectors_per_allocation_unit
= (uint64_t)IVAL(outbuf
.data
, 24);
2154 *bytes_per_sector
= (uint64_t)IVAL(outbuf
.data
, 28);
2158 if (fnum
!= 0xffff) {
2159 cli_smb2_close_fnum(cli
, fnum
);
2162 cli
->raw_status
= status
;
2168 /***************************************************************
2169 Wrapper that allows SMB2 to query file system attributes.
2171 ***************************************************************/
2173 NTSTATUS
cli_smb2_get_fs_attr_info(struct cli_state
*cli
, uint32_t *fs_attr
)
2176 uint16_t fnum
= 0xffff;
2177 DATA_BLOB outbuf
= data_blob_null
;
2178 struct smb2_hnd
*ph
= NULL
;
2179 TALLOC_CTX
*frame
= talloc_stackframe();
2181 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2183 * Can't use sync call while an async call is in flight
2185 status
= NT_STATUS_INVALID_PARAMETER
;
2189 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2190 status
= NT_STATUS_INVALID_PARAMETER
;
2194 /* First open the top level directory. */
2196 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2197 FILE_READ_ATTRIBUTES
, /* desired_access */
2198 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2199 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2200 FILE_SHARE_DELETE
, /* share_access */
2201 FILE_OPEN
, /* create_disposition */
2202 FILE_DIRECTORY_FILE
, /* create_options */
2206 if (!NT_STATUS_IS_OK(status
)) {
2210 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
2211 if (!NT_STATUS_IS_OK(status
)) {
2215 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
2216 cli
->smb2
.tcon
, 2, /* in_info_type */
2217 5, /* in_file_info_class */
2218 0xFFFF, /* in_max_output_length */
2219 NULL
, /* in_input_buffer */
2220 0, /* in_additional_info */
2222 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
2224 if (!NT_STATUS_IS_OK(status
)) {
2228 if (outbuf
.length
< 12) {
2229 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2233 *fs_attr
= IVAL(outbuf
.data
, 0);
2237 if (fnum
!= 0xffff) {
2238 cli_smb2_close_fnum(cli
, fnum
);
2241 cli
->raw_status
= status
;
2247 /***************************************************************
2248 Wrapper that allows SMB2 to query file system volume info.
2250 ***************************************************************/
2252 NTSTATUS
cli_smb2_get_fs_volume_info(struct cli_state
*cli
,
2253 TALLOC_CTX
*mem_ctx
,
2254 char **_volume_name
,
2255 uint32_t *pserial_number
,
2259 uint16_t fnum
= 0xffff;
2260 DATA_BLOB outbuf
= data_blob_null
;
2261 struct smb2_hnd
*ph
= NULL
;
2263 char *volume_name
= NULL
;
2264 TALLOC_CTX
*frame
= talloc_stackframe();
2266 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2268 * Can't use sync call while an async call is in flight
2270 status
= NT_STATUS_INVALID_PARAMETER
;
2274 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2275 status
= NT_STATUS_INVALID_PARAMETER
;
2279 /* First open the top level directory. */
2281 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2282 FILE_READ_ATTRIBUTES
, /* desired_access */
2283 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2284 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2285 FILE_SHARE_DELETE
, /* share_access */
2286 FILE_OPEN
, /* create_disposition */
2287 FILE_DIRECTORY_FILE
, /* create_options */
2291 if (!NT_STATUS_IS_OK(status
)) {
2295 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
2296 if (!NT_STATUS_IS_OK(status
)) {
2300 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2301 level 1 (SMB_FS_VOLUME_INFORMATION). */
2303 status
= smb2cli_query_info(cli
->conn
,
2307 SMB2_GETINFO_FS
, /* in_info_type */
2308 /* in_file_info_class */
2309 SMB_FS_VOLUME_INFORMATION
- 1000,
2310 0xFFFF, /* in_max_output_length */
2311 NULL
, /* in_input_buffer */
2312 0, /* in_additional_info */
2318 if (!NT_STATUS_IS_OK(status
)) {
2322 if (outbuf
.length
< 24) {
2323 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2329 ts
= interpret_long_date((char *)outbuf
.data
);
2332 if (pserial_number
) {
2333 *pserial_number
= IVAL(outbuf
.data
,8);
2335 nlen
= IVAL(outbuf
.data
,12);
2336 if (nlen
+ 18 < 18) {
2338 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2342 * The next check is safe as we know outbuf.length >= 24
2345 if (nlen
> (outbuf
.length
- 18)) {
2346 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2350 clistr_pull_talloc(mem_ctx
,
2351 (const char *)outbuf
.data
,
2357 if (volume_name
== NULL
) {
2358 status
= map_nt_error_from_unix(errno
);
2362 *_volume_name
= volume_name
;
2366 if (fnum
!= 0xffff) {
2367 cli_smb2_close_fnum(cli
, fnum
);
2370 cli
->raw_status
= status
;
2377 /***************************************************************
2378 Wrapper that allows SMB2 to query a security descriptor.
2380 ***************************************************************/
2382 NTSTATUS
cli_smb2_query_security_descriptor(struct cli_state
*cli
,
2385 TALLOC_CTX
*mem_ctx
,
2386 struct security_descriptor
**ppsd
)
2389 DATA_BLOB outbuf
= data_blob_null
;
2390 struct smb2_hnd
*ph
= NULL
;
2391 struct security_descriptor
*lsd
= NULL
;
2392 TALLOC_CTX
*frame
= talloc_stackframe();
2394 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2396 * Can't use sync call while an async call is in flight
2398 status
= NT_STATUS_INVALID_PARAMETER
;
2402 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2403 status
= NT_STATUS_INVALID_PARAMETER
;
2407 status
= map_fnum_to_smb2_handle(cli
,
2410 if (!NT_STATUS_IS_OK(status
)) {
2414 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2416 status
= smb2cli_query_info(cli
->conn
,
2420 3, /* in_info_type */
2421 0, /* in_file_info_class */
2422 0xFFFF, /* in_max_output_length */
2423 NULL
, /* in_input_buffer */
2424 sec_info
, /* in_additional_info */
2431 if (!NT_STATUS_IS_OK(status
)) {
2435 /* Parse the reply. */
2436 status
= unmarshall_sec_desc(mem_ctx
,
2441 if (!NT_STATUS_IS_OK(status
)) {
2453 cli
->raw_status
= status
;
2459 /***************************************************************
2460 Wrapper that allows SMB2 to set a security descriptor.
2462 ***************************************************************/
2464 NTSTATUS
cli_smb2_set_security_descriptor(struct cli_state
*cli
,
2467 const struct security_descriptor
*sd
)
2470 DATA_BLOB inbuf
= data_blob_null
;
2471 struct smb2_hnd
*ph
= NULL
;
2472 TALLOC_CTX
*frame
= talloc_stackframe();
2474 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2476 * Can't use sync call while an async call is in flight
2478 status
= NT_STATUS_INVALID_PARAMETER
;
2482 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2483 status
= NT_STATUS_INVALID_PARAMETER
;
2487 status
= map_fnum_to_smb2_handle(cli
,
2490 if (!NT_STATUS_IS_OK(status
)) {
2494 status
= marshall_sec_desc(frame
,
2499 if (!NT_STATUS_IS_OK(status
)) {
2503 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2505 status
= smb2cli_set_info(cli
->conn
,
2509 3, /* in_info_type */
2510 0, /* in_file_info_class */
2511 &inbuf
, /* in_input_buffer */
2512 sec_info
, /* in_additional_info */
2518 cli
->raw_status
= status
;
2524 /***************************************************************
2525 Wrapper that allows SMB2 to rename a file.
2527 ***************************************************************/
2529 NTSTATUS
cli_smb2_rename(struct cli_state
*cli
,
2530 const char *fname_src
,
2531 const char *fname_dst
,
2535 DATA_BLOB inbuf
= data_blob_null
;
2536 uint16_t fnum
= 0xffff;
2537 struct smb2_hnd
*ph
= NULL
;
2538 smb_ucs2_t
*converted_str
= NULL
;
2539 size_t converted_size_bytes
= 0;
2541 TALLOC_CTX
*frame
= talloc_stackframe();
2543 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2545 * Can't use sync call while an async call is in flight
2547 status
= NT_STATUS_INVALID_PARAMETER
;
2551 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2552 status
= NT_STATUS_INVALID_PARAMETER
;
2556 status
= get_fnum_from_path(cli
,
2561 if (!NT_STATUS_IS_OK(status
)) {
2565 status
= map_fnum_to_smb2_handle(cli
,
2568 if (!NT_STATUS_IS_OK(status
)) {
2572 /* SMB2 is pickier about pathnames. Ensure it doesn't
2574 if (*fname_dst
== '\\') {
2578 /* SMB2 is pickier about pathnames. Ensure it doesn't
2580 namelen
= strlen(fname_dst
);
2581 if (namelen
> 0 && fname_dst
[namelen
-1] == '\\') {
2582 char *modname
= talloc_strdup(frame
, fname_dst
);
2583 modname
[namelen
-1] = '\0';
2584 fname_dst
= modname
;
2587 if (!push_ucs2_talloc(frame
,
2590 &converted_size_bytes
)) {
2591 status
= NT_STATUS_INVALID_PARAMETER
;
2595 /* W2K8 insists the dest name is not null
2596 terminated. Remove the last 2 zero bytes
2597 and reduce the name length. */
2599 if (converted_size_bytes
< 2) {
2600 status
= NT_STATUS_INVALID_PARAMETER
;
2603 converted_size_bytes
-= 2;
2605 inbuf
= data_blob_talloc_zero(frame
,
2606 20 + converted_size_bytes
);
2607 if (inbuf
.data
== NULL
) {
2608 status
= NT_STATUS_NO_MEMORY
;
2613 SCVAL(inbuf
.data
, 0, 1);
2616 SIVAL(inbuf
.data
, 16, converted_size_bytes
);
2617 memcpy(inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
2619 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2620 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2622 status
= smb2cli_set_info(cli
->conn
,
2626 1, /* in_info_type */
2627 SMB_FILE_RENAME_INFORMATION
- 1000, /* in_file_info_class */
2628 &inbuf
, /* in_input_buffer */
2629 0, /* in_additional_info */
2635 if (fnum
!= 0xffff) {
2636 cli_smb2_close_fnum(cli
, fnum
);
2639 cli
->raw_status
= status
;
2645 /***************************************************************
2646 Wrapper that allows SMB2 to set an EA on a fnum.
2648 ***************************************************************/
2650 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
2652 const char *ea_name
,
2657 DATA_BLOB inbuf
= data_blob_null
;
2659 char *ea_name_ascii
= NULL
;
2661 struct smb2_hnd
*ph
= NULL
;
2662 TALLOC_CTX
*frame
= talloc_stackframe();
2664 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2666 * Can't use sync call while an async call is in flight
2668 status
= NT_STATUS_INVALID_PARAMETER
;
2672 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2673 status
= NT_STATUS_INVALID_PARAMETER
;
2677 status
= map_fnum_to_smb2_handle(cli
,
2680 if (!NT_STATUS_IS_OK(status
)) {
2684 /* Marshall the SMB2 EA data. */
2685 if (ea_len
> 0xFFFF) {
2686 status
= NT_STATUS_INVALID_PARAMETER
;
2690 if (!push_ascii_talloc(frame
,
2694 status
= NT_STATUS_INVALID_PARAMETER
;
2698 if (namelen
< 2 || namelen
> 0xFF) {
2699 status
= NT_STATUS_INVALID_PARAMETER
;
2703 bloblen
= 8 + ea_len
+ namelen
;
2704 /* Round up to a 4 byte boundary. */
2705 bloblen
= ((bloblen
+ 3)&~3);
2707 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
2708 if (inbuf
.data
== NULL
) {
2709 status
= NT_STATUS_NO_MEMORY
;
2712 /* namelen doesn't include the NULL byte. */
2713 SCVAL(inbuf
.data
, 5, namelen
- 1);
2714 SSVAL(inbuf
.data
, 6, ea_len
);
2715 memcpy(inbuf
.data
+ 8, ea_name_ascii
, namelen
);
2716 memcpy(inbuf
.data
+ 8 + namelen
, ea_val
, ea_len
);
2718 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2719 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2721 status
= smb2cli_set_info(cli
->conn
,
2725 1, /* in_info_type */
2726 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
2727 &inbuf
, /* in_input_buffer */
2728 0, /* in_additional_info */
2734 cli
->raw_status
= status
;
2740 /***************************************************************
2741 Wrapper that allows SMB2 to set an EA on a pathname.
2743 ***************************************************************/
2745 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
2747 const char *ea_name
,
2752 uint16_t fnum
= 0xffff;
2754 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2756 * Can't use sync call while an async call is in flight
2758 status
= NT_STATUS_INVALID_PARAMETER
;
2762 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2763 status
= NT_STATUS_INVALID_PARAMETER
;
2767 status
= get_fnum_from_path(cli
,
2772 if (!NT_STATUS_IS_OK(status
)) {
2776 status
= cli_set_ea_fnum(cli
,
2781 if (!NT_STATUS_IS_OK(status
)) {
2787 if (fnum
!= 0xffff) {
2788 cli_smb2_close_fnum(cli
, fnum
);
2791 cli
->raw_status
= status
;
2796 /***************************************************************
2797 Wrapper that allows SMB2 to get an EA list on a pathname.
2799 ***************************************************************/
2801 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
2805 struct ea_struct
**pea_array
)
2808 uint16_t fnum
= 0xffff;
2809 DATA_BLOB outbuf
= data_blob_null
;
2810 struct smb2_hnd
*ph
= NULL
;
2811 struct ea_list
*ea_list
= NULL
;
2812 struct ea_list
*eal
= NULL
;
2813 size_t ea_count
= 0;
2814 TALLOC_CTX
*frame
= talloc_stackframe();
2819 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2821 * Can't use sync call while an async call is in flight
2823 status
= NT_STATUS_INVALID_PARAMETER
;
2827 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2828 status
= NT_STATUS_INVALID_PARAMETER
;
2832 status
= get_fnum_from_path(cli
,
2837 if (!NT_STATUS_IS_OK(status
)) {
2841 status
= map_fnum_to_smb2_handle(cli
,
2844 if (!NT_STATUS_IS_OK(status
)) {
2848 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2849 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2851 status
= smb2cli_query_info(cli
->conn
,
2855 1, /* in_info_type */
2856 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
2857 0xFFFF, /* in_max_output_length */
2858 NULL
, /* in_input_buffer */
2859 0, /* in_additional_info */
2866 if (!NT_STATUS_IS_OK(status
)) {
2870 /* Parse the reply. */
2871 ea_list
= read_nttrans_ea_list(ctx
,
2872 (const char *)outbuf
.data
,
2874 if (ea_list
== NULL
) {
2875 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2879 /* Convert to an array. */
2880 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2885 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
2886 if (*pea_array
== NULL
) {
2887 status
= NT_STATUS_NO_MEMORY
;
2891 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2892 (*pea_array
)[ea_count
++] = eal
->ea
;
2894 *pnum_eas
= ea_count
;
2899 if (fnum
!= 0xffff) {
2900 cli_smb2_close_fnum(cli
, fnum
);
2903 cli
->raw_status
= status
;
2909 /***************************************************************
2910 Wrapper that allows SMB2 to get user quota.
2912 ***************************************************************/
2914 NTSTATUS
cli_smb2_get_user_quota(struct cli_state
*cli
,
2916 SMB_NTQUOTA_STRUCT
*pqt
)
2919 DATA_BLOB inbuf
= data_blob_null
;
2920 DATA_BLOB info_blob
= data_blob_null
;
2921 DATA_BLOB outbuf
= data_blob_null
;
2922 struct smb2_hnd
*ph
= NULL
;
2923 TALLOC_CTX
*frame
= talloc_stackframe();
2925 unsigned int offset
;
2926 struct smb2_query_quota_info query
= {0};
2927 struct file_get_quota_info info
= {0};
2928 enum ndr_err_code err
;
2929 struct ndr_push
*ndr_push
= NULL
;
2931 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2933 * Can't use sync call while an async call is in flight
2935 status
= NT_STATUS_INVALID_PARAMETER
;
2939 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2940 status
= NT_STATUS_INVALID_PARAMETER
;
2944 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
2945 if (!NT_STATUS_IS_OK(status
)) {
2949 sid_len
= ndr_size_dom_sid(&pqt
->sid
, 0);
2951 query
.return_single
= 1;
2953 info
.next_entry_offset
= 0;
2954 info
.sid_length
= sid_len
;
2955 info
.sid
= pqt
->sid
;
2957 err
= ndr_push_struct_blob(
2961 (ndr_push_flags_fn_t
)ndr_push_file_get_quota_info
);
2963 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
2964 status
= NT_STATUS_INTERNAL_ERROR
;
2968 query
.sid_list_length
= info_blob
.length
;
2969 ndr_push
= ndr_push_init_ctx(frame
);
2971 status
= NT_STATUS_NO_MEMORY
;
2975 err
= ndr_push_smb2_query_quota_info(ndr_push
,
2976 NDR_SCALARS
| NDR_BUFFERS
,
2979 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
2980 status
= NT_STATUS_INTERNAL_ERROR
;
2984 err
= ndr_push_array_uint8(ndr_push
, NDR_SCALARS
, info_blob
.data
,
2987 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
2988 status
= NT_STATUS_INTERNAL_ERROR
;
2991 inbuf
.data
= ndr_push
->data
;
2992 inbuf
.length
= ndr_push
->offset
;
2994 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
2995 cli
->smb2
.tcon
, 4, /* in_info_type */
2996 0, /* in_file_info_class */
2997 0xFFFF, /* in_max_output_length */
2998 &inbuf
, /* in_input_buffer */
2999 0, /* in_additional_info */
3001 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
3004 if (!NT_STATUS_IS_OK(status
)) {
3008 if (!parse_user_quota_record(outbuf
.data
, outbuf
.length
, &offset
,
3010 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3011 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3015 cli
->raw_status
= status
;
3021 /***************************************************************
3022 Wrapper that allows SMB2 to list user quota.
3024 ***************************************************************/
3026 NTSTATUS
cli_smb2_list_user_quota_step(struct cli_state
*cli
,
3027 TALLOC_CTX
*mem_ctx
,
3029 SMB_NTQUOTA_LIST
**pqt_list
,
3033 DATA_BLOB inbuf
= data_blob_null
;
3034 DATA_BLOB outbuf
= data_blob_null
;
3035 struct smb2_hnd
*ph
= NULL
;
3036 TALLOC_CTX
*frame
= talloc_stackframe();
3037 struct smb2_query_quota_info info
= {0};
3038 enum ndr_err_code err
;
3040 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3042 * Can't use sync call while an async call is in flight
3044 status
= NT_STATUS_INVALID_PARAMETER
;
3048 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3049 status
= NT_STATUS_INVALID_PARAMETER
;
3053 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
3054 if (!NT_STATUS_IS_OK(status
)) {
3059 info
.restart_scan
= first
? 1 : 0;
3061 err
= ndr_push_struct_blob(
3065 (ndr_push_flags_fn_t
)ndr_push_smb2_query_quota_info
);
3067 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3068 status
= NT_STATUS_INTERNAL_ERROR
;
3072 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
3073 cli
->smb2
.tcon
, 4, /* in_info_type */
3074 0, /* in_file_info_class */
3075 0xFFFF, /* in_max_output_length */
3076 &inbuf
, /* in_input_buffer */
3077 0, /* in_additional_info */
3079 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
3083 * safeguard against panic from calling parse_user_quota_list with
3086 if (NT_STATUS_IS_OK(status
) && outbuf
.length
== 0) {
3087 status
= NT_STATUS_NO_MORE_ENTRIES
;
3090 if (!NT_STATUS_IS_OK(status
)) {
3094 status
= parse_user_quota_list(outbuf
.data
, outbuf
.length
, mem_ctx
,
3098 cli
->raw_status
= status
;
3104 /***************************************************************
3105 Wrapper that allows SMB2 to get file system quota.
3107 ***************************************************************/
3109 NTSTATUS
cli_smb2_get_fs_quota_info(struct cli_state
*cli
,
3111 SMB_NTQUOTA_STRUCT
*pqt
)
3114 DATA_BLOB outbuf
= data_blob_null
;
3115 struct smb2_hnd
*ph
= NULL
;
3116 TALLOC_CTX
*frame
= talloc_stackframe();
3118 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3120 * Can't use sync call while an async call is in flight
3122 status
= NT_STATUS_INVALID_PARAMETER
;
3126 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3127 status
= NT_STATUS_INVALID_PARAMETER
;
3131 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
3132 if (!NT_STATUS_IS_OK(status
)) {
3136 status
= smb2cli_query_info(
3137 cli
->conn
, cli
->timeout
, cli
->smb2
.session
, cli
->smb2
.tcon
,
3138 2, /* in_info_type */
3139 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
3140 0xFFFF, /* in_max_output_length */
3141 NULL
, /* in_input_buffer */
3142 0, /* in_additional_info */
3144 ph
->fid_persistent
, ph
->fid_volatile
, frame
, &outbuf
);
3146 if (!NT_STATUS_IS_OK(status
)) {
3150 status
= parse_fs_quota_buffer(outbuf
.data
, outbuf
.length
, pqt
);
3153 cli
->raw_status
= status
;
3159 /***************************************************************
3160 Wrapper that allows SMB2 to set user quota.
3162 ***************************************************************/
3164 NTSTATUS
cli_smb2_set_user_quota(struct cli_state
*cli
,
3166 SMB_NTQUOTA_LIST
*qtl
)
3169 DATA_BLOB inbuf
= data_blob_null
;
3170 struct smb2_hnd
*ph
= NULL
;
3171 TALLOC_CTX
*frame
= talloc_stackframe();
3173 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3175 * Can't use sync call while an async call is in flight
3177 status
= NT_STATUS_INVALID_PARAMETER
;
3181 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3182 status
= NT_STATUS_INVALID_PARAMETER
;
3186 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
3187 if (!NT_STATUS_IS_OK(status
)) {
3191 status
= build_user_quota_buffer(qtl
, 0, talloc_tos(), &inbuf
, NULL
);
3192 if (!NT_STATUS_IS_OK(status
)) {
3196 status
= smb2cli_set_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
3197 cli
->smb2
.tcon
, 4, /* in_info_type */
3198 0, /* in_file_info_class */
3199 &inbuf
, /* in_input_buffer */
3200 0, /* in_additional_info */
3201 ph
->fid_persistent
, ph
->fid_volatile
);
3204 cli
->raw_status
= status
;
3211 NTSTATUS
cli_smb2_set_fs_quota_info(struct cli_state
*cli
,
3213 SMB_NTQUOTA_STRUCT
*pqt
)
3216 DATA_BLOB inbuf
= data_blob_null
;
3217 struct smb2_hnd
*ph
= NULL
;
3218 TALLOC_CTX
*frame
= talloc_stackframe();
3220 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3222 * Can't use sync call while an async call is in flight
3224 status
= NT_STATUS_INVALID_PARAMETER
;
3228 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3229 status
= NT_STATUS_INVALID_PARAMETER
;
3233 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
3234 if (!NT_STATUS_IS_OK(status
)) {
3238 status
= build_fs_quota_buffer(talloc_tos(), pqt
, &inbuf
, 0);
3239 if (!NT_STATUS_IS_OK(status
)) {
3243 status
= smb2cli_set_info(
3244 cli
->conn
, cli
->timeout
, cli
->smb2
.session
, cli
->smb2
.tcon
,
3245 2, /* in_info_type */
3246 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
3247 &inbuf
, /* in_input_buffer */
3248 0, /* in_additional_info */
3249 ph
->fid_persistent
, ph
->fid_volatile
);
3251 cli
->raw_status
= status
;
3257 struct cli_smb2_read_state
{
3258 struct tevent_context
*ev
;
3259 struct cli_state
*cli
;
3260 struct smb2_hnd
*ph
;
3261 uint64_t start_offset
;
3267 static void cli_smb2_read_done(struct tevent_req
*subreq
);
3269 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
3270 struct tevent_context
*ev
,
3271 struct cli_state
*cli
,
3277 struct tevent_req
*req
, *subreq
;
3278 struct cli_smb2_read_state
*state
;
3280 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
3286 state
->start_offset
= (uint64_t)offset
;
3287 state
->size
= (uint32_t)size
;
3288 state
->received
= 0;
3291 status
= map_fnum_to_smb2_handle(cli
,
3294 if (tevent_req_nterror(req
, status
)) {
3295 return tevent_req_post(req
, ev
);
3298 subreq
= smb2cli_read_send(state
,
3301 state
->cli
->timeout
,
3302 state
->cli
->smb2
.session
,
3303 state
->cli
->smb2
.tcon
,
3305 state
->start_offset
,
3306 state
->ph
->fid_persistent
,
3307 state
->ph
->fid_volatile
,
3308 0, /* minimum_count */
3309 0); /* remaining_bytes */
3311 if (tevent_req_nomem(subreq
, req
)) {
3312 return tevent_req_post(req
, ev
);
3314 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
3318 static void cli_smb2_read_done(struct tevent_req
*subreq
)
3320 struct tevent_req
*req
= tevent_req_callback_data(
3321 subreq
, struct tevent_req
);
3322 struct cli_smb2_read_state
*state
= tevent_req_data(
3323 req
, struct cli_smb2_read_state
);
3326 status
= smb2cli_read_recv(subreq
, state
,
3327 &state
->buf
, &state
->received
);
3328 if (tevent_req_nterror(req
, status
)) {
3332 if (state
->received
> state
->size
) {
3333 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3337 tevent_req_done(req
);
3340 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
3345 struct cli_smb2_read_state
*state
= tevent_req_data(
3346 req
, struct cli_smb2_read_state
);
3348 if (tevent_req_is_nterror(req
, &status
)) {
3349 state
->cli
->raw_status
= status
;
3353 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3354 * better make sure that you copy it away before you talloc_free(req).
3355 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3357 *received
= (ssize_t
)state
->received
;
3358 *rcvbuf
= state
->buf
;
3359 state
->cli
->raw_status
= NT_STATUS_OK
;
3360 return NT_STATUS_OK
;
3363 struct cli_smb2_write_state
{
3364 struct tevent_context
*ev
;
3365 struct cli_state
*cli
;
3366 struct smb2_hnd
*ph
;
3374 static void cli_smb2_write_written(struct tevent_req
*req
);
3376 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
3377 struct tevent_context
*ev
,
3378 struct cli_state
*cli
,
3386 struct tevent_req
*req
, *subreq
= NULL
;
3387 struct cli_smb2_write_state
*state
= NULL
;
3389 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
3395 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3396 state
->flags
= (uint32_t)mode
;
3398 state
->offset
= (uint64_t)offset
;
3399 state
->size
= (uint32_t)size
;
3402 status
= map_fnum_to_smb2_handle(cli
,
3405 if (tevent_req_nterror(req
, status
)) {
3406 return tevent_req_post(req
, ev
);
3409 subreq
= smb2cli_write_send(state
,
3412 state
->cli
->timeout
,
3413 state
->cli
->smb2
.session
,
3414 state
->cli
->smb2
.tcon
,
3417 state
->ph
->fid_persistent
,
3418 state
->ph
->fid_volatile
,
3419 0, /* remaining_bytes */
3420 state
->flags
, /* flags */
3423 if (tevent_req_nomem(subreq
, req
)) {
3424 return tevent_req_post(req
, ev
);
3426 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
3430 static void cli_smb2_write_written(struct tevent_req
*subreq
)
3432 struct tevent_req
*req
= tevent_req_callback_data(
3433 subreq
, struct tevent_req
);
3434 struct cli_smb2_write_state
*state
= tevent_req_data(
3435 req
, struct cli_smb2_write_state
);
3439 status
= smb2cli_write_recv(subreq
, &written
);
3440 TALLOC_FREE(subreq
);
3441 if (tevent_req_nterror(req
, status
)) {
3445 state
->written
= written
;
3447 tevent_req_done(req
);
3450 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
3453 struct cli_smb2_write_state
*state
= tevent_req_data(
3454 req
, struct cli_smb2_write_state
);
3457 if (tevent_req_is_nterror(req
, &status
)) {
3458 state
->cli
->raw_status
= status
;
3459 tevent_req_received(req
);
3463 if (pwritten
!= NULL
) {
3464 *pwritten
= (size_t)state
->written
;
3466 state
->cli
->raw_status
= NT_STATUS_OK
;
3467 tevent_req_received(req
);
3468 return NT_STATUS_OK
;
3471 /***************************************************************
3472 Wrapper that allows SMB2 async write using an fnum.
3473 This is mostly cut-and-paste from Volker's code inside
3474 source3/libsmb/clireadwrite.c, adapted for SMB2.
3476 Done this way so I can reuse all the logic inside cli_push()
3478 ***************************************************************/
3480 struct cli_smb2_writeall_state
{
3481 struct tevent_context
*ev
;
3482 struct cli_state
*cli
;
3483 struct smb2_hnd
*ph
;
3491 static void cli_smb2_writeall_written(struct tevent_req
*req
);
3493 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
3494 struct tevent_context
*ev
,
3495 struct cli_state
*cli
,
3503 struct tevent_req
*req
, *subreq
= NULL
;
3504 struct cli_smb2_writeall_state
*state
= NULL
;
3509 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
3515 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3516 state
->flags
= (uint32_t)mode
;
3518 state
->offset
= (uint64_t)offset
;
3519 state
->size
= (uint32_t)size
;
3522 status
= map_fnum_to_smb2_handle(cli
,
3525 if (tevent_req_nterror(req
, status
)) {
3526 return tevent_req_post(req
, ev
);
3529 to_write
= state
->size
;
3530 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
3531 to_write
= MIN(max_size
, to_write
);
3532 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
3534 to_write
= MIN(max_size
, to_write
);
3537 subreq
= smb2cli_write_send(state
,
3540 state
->cli
->timeout
,
3541 state
->cli
->smb2
.session
,
3542 state
->cli
->smb2
.tcon
,
3545 state
->ph
->fid_persistent
,
3546 state
->ph
->fid_volatile
,
3547 0, /* remaining_bytes */
3548 state
->flags
, /* flags */
3549 state
->buf
+ state
->written
);
3551 if (tevent_req_nomem(subreq
, req
)) {
3552 return tevent_req_post(req
, ev
);
3554 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
3558 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
3560 struct tevent_req
*req
= tevent_req_callback_data(
3561 subreq
, struct tevent_req
);
3562 struct cli_smb2_writeall_state
*state
= tevent_req_data(
3563 req
, struct cli_smb2_writeall_state
);
3565 uint32_t written
, to_write
;
3569 status
= smb2cli_write_recv(subreq
, &written
);
3570 TALLOC_FREE(subreq
);
3571 if (tevent_req_nterror(req
, status
)) {
3575 state
->written
+= written
;
3577 if (state
->written
> state
->size
) {
3578 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3582 to_write
= state
->size
- state
->written
;
3584 if (to_write
== 0) {
3585 tevent_req_done(req
);
3589 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
3590 to_write
= MIN(max_size
, to_write
);
3591 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
3593 to_write
= MIN(max_size
, to_write
);
3596 subreq
= smb2cli_write_send(state
,
3599 state
->cli
->timeout
,
3600 state
->cli
->smb2
.session
,
3601 state
->cli
->smb2
.tcon
,
3603 state
->offset
+ state
->written
,
3604 state
->ph
->fid_persistent
,
3605 state
->ph
->fid_volatile
,
3606 0, /* remaining_bytes */
3607 state
->flags
, /* flags */
3608 state
->buf
+ state
->written
);
3610 if (tevent_req_nomem(subreq
, req
)) {
3613 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
3616 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
3619 struct cli_smb2_writeall_state
*state
= tevent_req_data(
3620 req
, struct cli_smb2_writeall_state
);
3623 if (tevent_req_is_nterror(req
, &status
)) {
3624 state
->cli
->raw_status
= status
;
3627 if (pwritten
!= NULL
) {
3628 *pwritten
= (size_t)state
->written
;
3630 state
->cli
->raw_status
= NT_STATUS_OK
;
3631 return NT_STATUS_OK
;
3634 struct cli_smb2_splice_state
{
3635 struct tevent_context
*ev
;
3636 struct cli_state
*cli
;
3637 struct smb2_hnd
*src_ph
;
3638 struct smb2_hnd
*dst_ph
;
3639 int (*splice_cb
)(off_t n
, void *priv
);
3646 struct req_resume_key_rsp resume_rsp
;
3647 struct srv_copychunk_copy cc_copy
;
3650 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
3651 struct tevent_req
*req
);
3653 static void cli_splice_copychunk_done(struct tevent_req
*subreq
)
3655 struct tevent_req
*req
= tevent_req_callback_data(
3656 subreq
, struct tevent_req
);
3657 struct cli_smb2_splice_state
*state
=
3658 tevent_req_data(req
,
3659 struct cli_smb2_splice_state
);
3660 struct smbXcli_conn
*conn
= state
->cli
->conn
;
3661 DATA_BLOB out_input_buffer
= data_blob_null
;
3662 DATA_BLOB out_output_buffer
= data_blob_null
;
3663 struct srv_copychunk_rsp cc_copy_rsp
;
3664 enum ndr_err_code ndr_ret
;
3667 status
= smb2cli_ioctl_recv(subreq
, state
,
3669 &out_output_buffer
);
3670 TALLOC_FREE(subreq
);
3671 if ((!NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
) ||
3672 state
->resized
) && tevent_req_nterror(req
, status
)) {
3676 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
, state
, &cc_copy_rsp
,
3677 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
3678 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
3679 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3680 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3684 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
3685 uint32_t max_chunks
= MIN(cc_copy_rsp
.chunks_written
,
3686 cc_copy_rsp
.total_bytes_written
/ cc_copy_rsp
.chunk_bytes_written
);
3687 if ((cc_copy_rsp
.chunk_bytes_written
> smb2cli_conn_cc_chunk_len(conn
) ||
3688 max_chunks
> smb2cli_conn_cc_max_chunks(conn
)) &&
3689 tevent_req_nterror(req
, status
)) {
3693 state
->resized
= true;
3694 smb2cli_conn_set_cc_chunk_len(conn
, cc_copy_rsp
.chunk_bytes_written
);
3695 smb2cli_conn_set_cc_max_chunks(conn
, max_chunks
);
3697 if ((state
->src_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
3698 (state
->dst_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
3699 (state
->written
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
)) {
3700 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
3703 state
->src_offset
+= cc_copy_rsp
.total_bytes_written
;
3704 state
->dst_offset
+= cc_copy_rsp
.total_bytes_written
;
3705 state
->written
+= cc_copy_rsp
.total_bytes_written
;
3706 if (!state
->splice_cb(state
->written
, state
->priv
)) {
3707 tevent_req_nterror(req
, NT_STATUS_CANCELLED
);
3712 cli_splice_copychunk_send(state
, req
);
3715 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
3716 struct tevent_req
*req
)
3718 struct tevent_req
*subreq
;
3719 enum ndr_err_code ndr_ret
;
3720 struct smbXcli_conn
*conn
= state
->cli
->conn
;
3721 struct srv_copychunk_copy
*cc_copy
= &state
->cc_copy
;
3722 off_t src_offset
= state
->src_offset
;
3723 off_t dst_offset
= state
->dst_offset
;
3724 uint32_t req_len
= MIN(smb2cli_conn_cc_chunk_len(conn
) * smb2cli_conn_cc_max_chunks(conn
),
3725 state
->size
- state
->written
);
3726 DATA_BLOB in_input_buffer
= data_blob_null
;
3727 DATA_BLOB in_output_buffer
= data_blob_null
;
3729 if (state
->size
- state
->written
== 0) {
3730 tevent_req_done(req
);
3734 cc_copy
->chunk_count
= 0;
3736 cc_copy
->chunks
[cc_copy
->chunk_count
].source_off
= src_offset
;
3737 cc_copy
->chunks
[cc_copy
->chunk_count
].target_off
= dst_offset
;
3738 cc_copy
->chunks
[cc_copy
->chunk_count
].length
= MIN(req_len
,
3739 smb2cli_conn_cc_chunk_len(conn
));
3740 if (req_len
< cc_copy
->chunks
[cc_copy
->chunk_count
].length
) {
3741 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
3744 req_len
-= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
3745 if ((src_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
) ||
3746 (dst_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
)) {
3747 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
3750 src_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
3751 dst_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
3752 cc_copy
->chunk_count
++;
3755 ndr_ret
= ndr_push_struct_blob(&in_input_buffer
, state
, cc_copy
,
3756 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
3757 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
3758 DEBUG(0, ("failed to marshall copy chunk req\n"));
3759 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
3763 subreq
= smb2cli_ioctl_send(state
, state
->ev
, state
->cli
->conn
,
3764 state
->cli
->timeout
,
3765 state
->cli
->smb2
.session
,
3766 state
->cli
->smb2
.tcon
,
3767 state
->dst_ph
->fid_persistent
, /* in_fid_persistent */
3768 state
->dst_ph
->fid_volatile
, /* in_fid_volatile */
3769 FSCTL_SRV_COPYCHUNK_WRITE
,
3770 0, /* in_max_input_length */
3772 12, /* in_max_output_length */
3774 SMB2_IOCTL_FLAG_IS_FSCTL
);
3775 if (tevent_req_nomem(subreq
, req
)) {
3778 tevent_req_set_callback(subreq
,
3779 cli_splice_copychunk_done
,
3783 static void cli_splice_key_done(struct tevent_req
*subreq
)
3785 struct tevent_req
*req
= tevent_req_callback_data(
3786 subreq
, struct tevent_req
);
3787 struct cli_smb2_splice_state
*state
=
3788 tevent_req_data(req
,
3789 struct cli_smb2_splice_state
);
3790 enum ndr_err_code ndr_ret
;
3793 DATA_BLOB out_input_buffer
= data_blob_null
;
3794 DATA_BLOB out_output_buffer
= data_blob_null
;
3796 status
= smb2cli_ioctl_recv(subreq
, state
,
3798 &out_output_buffer
);
3799 TALLOC_FREE(subreq
);
3800 if (tevent_req_nterror(req
, status
)) {
3804 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
,
3805 state
, &state
->resume_rsp
,
3806 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
3807 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
3808 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3809 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3813 memcpy(&state
->cc_copy
.source_key
,
3814 &state
->resume_rsp
.resume_key
,
3815 sizeof state
->resume_rsp
.resume_key
);
3817 cli_splice_copychunk_send(state
, req
);
3820 struct tevent_req
*cli_smb2_splice_send(TALLOC_CTX
*mem_ctx
,
3821 struct tevent_context
*ev
,
3822 struct cli_state
*cli
,
3823 uint16_t src_fnum
, uint16_t dst_fnum
,
3824 off_t size
, off_t src_offset
, off_t dst_offset
,
3825 int (*splice_cb
)(off_t n
, void *priv
),
3828 struct tevent_req
*req
;
3829 struct tevent_req
*subreq
;
3830 struct cli_smb2_splice_state
*state
;
3832 DATA_BLOB in_input_buffer
= data_blob_null
;
3833 DATA_BLOB in_output_buffer
= data_blob_null
;
3835 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_splice_state
);
3841 state
->splice_cb
= splice_cb
;
3845 state
->src_offset
= src_offset
;
3846 state
->dst_offset
= dst_offset
;
3847 state
->cc_copy
.chunks
= talloc_array(state
,
3848 struct srv_copychunk
,
3849 smb2cli_conn_cc_max_chunks(cli
->conn
));
3850 if (state
->cc_copy
.chunks
== NULL
) {
3854 status
= map_fnum_to_smb2_handle(cli
, src_fnum
, &state
->src_ph
);
3855 if (tevent_req_nterror(req
, status
))
3856 return tevent_req_post(req
, ev
);
3858 status
= map_fnum_to_smb2_handle(cli
, dst_fnum
, &state
->dst_ph
);
3859 if (tevent_req_nterror(req
, status
))
3860 return tevent_req_post(req
, ev
);
3862 subreq
= smb2cli_ioctl_send(state
, ev
, cli
->conn
,
3866 state
->src_ph
->fid_persistent
, /* in_fid_persistent */
3867 state
->src_ph
->fid_volatile
, /* in_fid_volatile */
3868 FSCTL_SRV_REQUEST_RESUME_KEY
,
3869 0, /* in_max_input_length */
3871 32, /* in_max_output_length */
3873 SMB2_IOCTL_FLAG_IS_FSCTL
);
3874 if (tevent_req_nomem(subreq
, req
)) {
3877 tevent_req_set_callback(subreq
,
3878 cli_splice_key_done
,
3884 NTSTATUS
cli_smb2_splice_recv(struct tevent_req
*req
, off_t
*written
)
3886 struct cli_smb2_splice_state
*state
= tevent_req_data(
3887 req
, struct cli_smb2_splice_state
);
3890 if (tevent_req_is_nterror(req
, &status
)) {
3891 state
->cli
->raw_status
= status
;
3892 tevent_req_received(req
);
3895 if (written
!= NULL
) {
3896 *written
= state
->written
;
3898 state
->cli
->raw_status
= NT_STATUS_OK
;
3899 tevent_req_received(req
);
3900 return NT_STATUS_OK
;
3903 /***************************************************************
3904 SMB2 enum shadow copy data.
3905 ***************************************************************/
3907 struct cli_smb2_shadow_copy_data_fnum_state
{
3908 struct cli_state
*cli
;
3910 struct smb2_hnd
*ph
;
3911 DATA_BLOB out_input_buffer
;
3912 DATA_BLOB out_output_buffer
;
3915 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
);
3917 static struct tevent_req
*cli_smb2_shadow_copy_data_fnum_send(
3918 TALLOC_CTX
*mem_ctx
,
3919 struct tevent_context
*ev
,
3920 struct cli_state
*cli
,
3924 struct tevent_req
*req
, *subreq
;
3925 struct cli_smb2_shadow_copy_data_fnum_state
*state
;
3928 req
= tevent_req_create(mem_ctx
, &state
,
3929 struct cli_smb2_shadow_copy_data_fnum_state
);
3934 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3935 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3936 return tevent_req_post(req
, ev
);
3942 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
3943 if (tevent_req_nterror(req
, status
)) {
3944 return tevent_req_post(req
, ev
);
3948 * TODO. Under SMB2 we should send a zero max_output_length
3949 * ioctl to get the required size, then send another ioctl
3950 * to get the data, but the current SMB1 implementation just
3951 * does one roundtrip with a 64K buffer size. Do the same
3955 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
3956 state
->cli
->timeout
,
3957 state
->cli
->smb2
.session
,
3958 state
->cli
->smb2
.tcon
,
3959 state
->ph
->fid_persistent
, /* in_fid_persistent */
3960 state
->ph
->fid_volatile
, /* in_fid_volatile */
3961 FSCTL_GET_SHADOW_COPY_DATA
,
3962 0, /* in_max_input_length */
3963 NULL
, /* in_input_buffer */
3965 CLI_BUFFER_SIZE
: 16, /* in_max_output_length */
3966 NULL
, /* in_output_buffer */
3967 SMB2_IOCTL_FLAG_IS_FSCTL
);
3969 if (tevent_req_nomem(subreq
, req
)) {
3970 return tevent_req_post(req
, ev
);
3972 tevent_req_set_callback(subreq
,
3973 cli_smb2_shadow_copy_data_fnum_done
,
3979 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
)
3981 struct tevent_req
*req
= tevent_req_callback_data(
3982 subreq
, struct tevent_req
);
3983 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
3984 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
3987 status
= smb2cli_ioctl_recv(subreq
, state
,
3988 &state
->out_input_buffer
,
3989 &state
->out_output_buffer
);
3990 TALLOC_FREE(subreq
);
3991 if (tevent_req_nterror(req
, status
)) {
3994 tevent_req_done(req
);
3997 static NTSTATUS
cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req
*req
,
3998 TALLOC_CTX
*mem_ctx
,
4003 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
4004 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
4005 char **names
= NULL
;
4006 uint32_t num_names
= 0;
4007 uint32_t num_names_returned
= 0;
4008 uint32_t dlength
= 0;
4010 uint8_t *endp
= NULL
;
4013 if (tevent_req_is_nterror(req
, &status
)) {
4017 if (state
->out_output_buffer
.length
< 16) {
4018 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4021 num_names
= IVAL(state
->out_output_buffer
.data
, 0);
4022 num_names_returned
= IVAL(state
->out_output_buffer
.data
, 4);
4023 dlength
= IVAL(state
->out_output_buffer
.data
, 8);
4025 if (num_names
> 0x7FFFFFFF) {
4026 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4029 if (get_names
== false) {
4030 *pnum_names
= (int)num_names
;
4031 return NT_STATUS_OK
;
4033 if (num_names
!= num_names_returned
) {
4034 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4036 if (dlength
+ 12 < 12) {
4037 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4040 * NB. The below is an allowable return if there are
4041 * more snapshots than the buffer size we told the
4042 * server we can receive. We currently don't support
4045 if (dlength
+ 12 > state
->out_output_buffer
.length
) {
4046 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4048 if (state
->out_output_buffer
.length
+
4049 (2 * sizeof(SHADOW_COPY_LABEL
)) <
4050 state
->out_output_buffer
.length
) {
4051 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4054 names
= talloc_array(mem_ctx
, char *, num_names_returned
);
4055 if (names
== NULL
) {
4056 return NT_STATUS_NO_MEMORY
;
4059 endp
= state
->out_output_buffer
.data
+
4060 state
->out_output_buffer
.length
;
4062 for (i
=0; i
<num_names_returned
; i
++) {
4065 size_t converted_size
;
4067 src
= state
->out_output_buffer
.data
+ 12 +
4068 (i
* 2 * sizeof(SHADOW_COPY_LABEL
));
4070 if (src
+ (2 * sizeof(SHADOW_COPY_LABEL
)) > endp
) {
4071 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4073 ret
= convert_string_talloc(
4074 names
, CH_UTF16LE
, CH_UNIX
,
4075 src
, 2 * sizeof(SHADOW_COPY_LABEL
),
4076 &names
[i
], &converted_size
);
4079 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4082 *pnum_names
= num_names
;
4084 return NT_STATUS_OK
;
4087 NTSTATUS
cli_smb2_shadow_copy_data(TALLOC_CTX
*mem_ctx
,
4088 struct cli_state
*cli
,
4094 TALLOC_CTX
*frame
= talloc_stackframe();
4095 struct tevent_context
*ev
;
4096 struct tevent_req
*req
;
4097 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
4099 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4101 * Can't use sync call while an async call is in flight
4103 status
= NT_STATUS_INVALID_PARAMETER
;
4106 ev
= samba_tevent_context_init(frame
);
4110 req
= cli_smb2_shadow_copy_data_fnum_send(frame
,
4118 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4121 status
= cli_smb2_shadow_copy_data_fnum_recv(req
,
4127 cli
->raw_status
= status
;
4133 /***************************************************************
4134 Wrapper that allows SMB2 to truncate a file.
4136 ***************************************************************/
4138 NTSTATUS
cli_smb2_ftruncate(struct cli_state
*cli
,
4143 DATA_BLOB inbuf
= data_blob_null
;
4144 struct smb2_hnd
*ph
= NULL
;
4145 TALLOC_CTX
*frame
= talloc_stackframe();
4147 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4149 * Can't use sync call while an async call is in flight
4151 status
= NT_STATUS_INVALID_PARAMETER
;
4155 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
4156 status
= NT_STATUS_INVALID_PARAMETER
;
4160 status
= map_fnum_to_smb2_handle(cli
,
4163 if (!NT_STATUS_IS_OK(status
)) {
4167 inbuf
= data_blob_talloc_zero(frame
, 8);
4168 if (inbuf
.data
== NULL
) {
4169 status
= NT_STATUS_NO_MEMORY
;
4173 SBVAL(inbuf
.data
, 0, newsize
);
4175 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4176 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4178 status
= smb2cli_set_info(cli
->conn
,
4182 1, /* in_info_type */
4183 /* in_file_info_class */
4184 SMB_FILE_END_OF_FILE_INFORMATION
- 1000,
4185 &inbuf
, /* in_input_buffer */
4186 0, /* in_additional_info */
4192 cli
->raw_status
= status
;
4198 NTSTATUS
cli_smb2_notify(struct cli_state
*cli
, uint16_t fnum
,
4199 uint32_t buffer_size
, uint32_t completion_filter
,
4200 bool recursive
, TALLOC_CTX
*mem_ctx
,
4201 struct notify_change
**pchanges
,
4202 uint32_t *pnum_changes
)
4205 struct smb2_hnd
*ph
= NULL
;
4206 TALLOC_CTX
*frame
= talloc_stackframe();
4209 struct notify_change
*changes
= NULL
;
4210 size_t num_changes
= 0;
4212 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4214 * Can't use sync call while an async call is in flight
4216 status
= NT_STATUS_INVALID_PARAMETER
;
4220 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
4221 status
= NT_STATUS_INVALID_PARAMETER
;
4225 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
4226 if (!NT_STATUS_IS_OK(status
)) {
4230 status
= smb2cli_notify(cli
->conn
, cli
->timeout
,
4231 cli
->smb2
.session
, cli
->smb2
.tcon
,
4233 ph
->fid_persistent
, ph
->fid_volatile
,
4234 completion_filter
, recursive
,
4235 frame
, &base
, &len
);
4237 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
4239 status
= NT_STATUS_OK
;
4242 if (!NT_STATUS_IS_OK(status
)) {
4248 while (len
- ofs
>= 12) {
4249 struct notify_change
*tmp
;
4250 struct notify_change
*c
;
4251 uint32_t next_ofs
= IVAL(base
, ofs
);
4252 uint32_t file_name_length
= IVAL(base
, ofs
+8);
4256 tmp
= talloc_realloc(frame
, changes
, struct notify_change
,
4259 status
= NT_STATUS_NO_MEMORY
;
4263 c
= &changes
[num_changes
];
4266 if (smb_buffer_oob(len
, ofs
, next_ofs
) ||
4267 smb_buffer_oob(len
, ofs
+12, file_name_length
)) {
4268 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
4272 c
->action
= IVAL(base
, ofs
+4);
4274 ok
= convert_string_talloc(changes
, CH_UTF16LE
, CH_UNIX
,
4275 base
+ ofs
+ 12, file_name_length
,
4276 &c
->name
, &namelen
);
4278 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
4282 if (next_ofs
== 0) {
4288 *pchanges
= talloc_move(mem_ctx
, &changes
);
4289 *pnum_changes
= num_changes
;
4290 status
= NT_STATUS_OK
;
4293 cli
->raw_status
= status
;
4299 struct cli_smb2_set_reparse_point_fnum_state
{
4300 struct cli_state
*cli
;
4302 struct smb2_hnd
*ph
;
4303 DATA_BLOB input_buffer
;
4306 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req
*subreq
);
4308 struct tevent_req
*cli_smb2_set_reparse_point_fnum_send(
4309 TALLOC_CTX
*mem_ctx
,
4310 struct tevent_context
*ev
,
4311 struct cli_state
*cli
,
4315 struct tevent_req
*req
, *subreq
;
4316 struct cli_smb2_set_reparse_point_fnum_state
*state
= NULL
;
4319 req
= tevent_req_create(mem_ctx
, &state
,
4320 struct cli_smb2_set_reparse_point_fnum_state
);
4325 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
4326 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
4327 return tevent_req_post(req
, ev
);
4333 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
4334 if (tevent_req_nterror(req
, status
)) {
4335 return tevent_req_post(req
, ev
);
4338 state
->input_buffer
= data_blob_talloc(state
,
4341 if (state
->input_buffer
.data
== NULL
) {
4342 tevent_req_nterror(req
, NT_STATUS_NO_MEMORY
);
4343 return tevent_req_post(req
, ev
);
4346 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
4347 state
->cli
->timeout
,
4348 state
->cli
->smb2
.session
,
4349 state
->cli
->smb2
.tcon
,
4350 state
->ph
->fid_persistent
, /* in_fid_persistent */
4351 state
->ph
->fid_volatile
, /* in_fid_volatile */
4352 FSCTL_SET_REPARSE_POINT
,
4353 0, /* in_max_input_length */
4354 &state
->input_buffer
,
4357 SMB2_IOCTL_FLAG_IS_FSCTL
);
4359 if (tevent_req_nomem(subreq
, req
)) {
4360 return tevent_req_post(req
, ev
);
4362 tevent_req_set_callback(subreq
,
4363 cli_smb2_set_reparse_point_fnum_done
,
4369 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req
*subreq
)
4371 struct tevent_req
*req
= tevent_req_callback_data(
4372 subreq
, struct tevent_req
);
4373 struct cli_smb2_set_reparse_point_fnum_state
*state
= tevent_req_data(
4374 req
, struct cli_smb2_set_reparse_point_fnum_state
);
4377 status
= smb2cli_ioctl_recv(subreq
, state
,
4380 TALLOC_FREE(subreq
);
4381 if (tevent_req_nterror(req
, status
)) {
4384 tevent_req_done(req
);
4387 NTSTATUS
cli_smb2_set_reparse_point_fnum_recv(struct tevent_req
*req
)
4389 return tevent_req_simple_recv_ntstatus(req
);
4392 struct cli_smb2_get_reparse_point_fnum_state
{
4393 struct cli_state
*cli
;
4395 struct smb2_hnd
*ph
;
4396 DATA_BLOB output_buffer
;
4399 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req
*subreq
);
4401 struct tevent_req
*cli_smb2_get_reparse_point_fnum_send(
4402 TALLOC_CTX
*mem_ctx
,
4403 struct tevent_context
*ev
,
4404 struct cli_state
*cli
,
4407 struct tevent_req
*req
, *subreq
;
4408 struct cli_smb2_set_reparse_point_fnum_state
*state
= NULL
;
4411 req
= tevent_req_create(mem_ctx
, &state
,
4412 struct cli_smb2_get_reparse_point_fnum_state
);
4417 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
4418 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
4419 return tevent_req_post(req
, ev
);
4425 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
4426 if (tevent_req_nterror(req
, status
)) {
4427 return tevent_req_post(req
, ev
);
4430 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
4431 state
->cli
->timeout
,
4432 state
->cli
->smb2
.session
,
4433 state
->cli
->smb2
.tcon
,
4434 state
->ph
->fid_persistent
, /* in_fid_persistent */
4435 state
->ph
->fid_volatile
, /* in_fid_volatile */
4436 FSCTL_GET_REPARSE_POINT
,
4437 0, /* in_max_input_length */
4441 SMB2_IOCTL_FLAG_IS_FSCTL
);
4443 if (tevent_req_nomem(subreq
, req
)) {
4444 return tevent_req_post(req
, ev
);
4446 tevent_req_set_callback(subreq
,
4447 cli_smb2_get_reparse_point_fnum_done
,
4453 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req
*subreq
)
4455 struct tevent_req
*req
= tevent_req_callback_data(
4456 subreq
, struct tevent_req
);
4457 struct cli_smb2_get_reparse_point_fnum_state
*state
= tevent_req_data(
4458 req
, struct cli_smb2_get_reparse_point_fnum_state
);
4461 status
= smb2cli_ioctl_recv(subreq
, state
,
4463 &state
->output_buffer
);
4464 TALLOC_FREE(subreq
);
4465 if (tevent_req_nterror(req
, status
)) {
4466 state
->cli
->raw_status
= status
;
4469 tevent_req_done(req
);
4472 NTSTATUS
cli_smb2_get_reparse_point_fnum_recv(struct tevent_req
*req
,
4473 TALLOC_CTX
*mem_ctx
,
4476 struct cli_smb2_get_reparse_point_fnum_state
*state
= tevent_req_data(
4477 req
, struct cli_smb2_get_reparse_point_fnum_state
);
4479 if (tevent_req_is_nterror(req
, &state
->cli
->raw_status
)) {
4480 tevent_req_received(req
);
4481 return state
->cli
->raw_status
;
4483 *output
= data_blob_dup_talloc(mem_ctx
, state
->output_buffer
);
4484 if (output
->data
== NULL
) {
4485 tevent_req_received(req
);
4486 return NT_STATUS_NO_MEMORY
;
4488 tevent_req_received(req
);
4489 return NT_STATUS_OK
;