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"
46 uint64_t fid_persistent
;
47 uint64_t fid_volatile
;
51 * Handle mapping code.
54 /***************************************************************
55 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
56 Ensures handle is owned by cli struct.
57 ***************************************************************/
59 static NTSTATUS
map_smb2_handle_to_fnum(struct cli_state
*cli
,
60 const struct smb2_hnd
*ph
, /* In */
61 uint16_t *pfnum
) /* Out */
64 struct idr_context
*idp
= cli
->smb2
.open_handles
;
65 struct smb2_hnd
*owned_h
= talloc_memdup(cli
,
67 sizeof(struct smb2_hnd
));
69 if (owned_h
== NULL
) {
70 return NT_STATUS_NO_MEMORY
;
75 cli
->smb2
.open_handles
= idr_init(cli
);
76 if (cli
->smb2
.open_handles
== NULL
) {
78 return NT_STATUS_NO_MEMORY
;
80 idp
= cli
->smb2
.open_handles
;
83 ret
= idr_get_new_above(idp
, owned_h
, 1, 0xFFFE);
86 return NT_STATUS_NO_MEMORY
;
89 *pfnum
= (uint16_t)ret
;
93 /***************************************************************
94 Return the smb2_hnd pointer associated with the given fnum.
95 ***************************************************************/
97 static NTSTATUS
map_fnum_to_smb2_handle(struct cli_state
*cli
,
98 uint16_t fnum
, /* In */
99 struct smb2_hnd
**pph
) /* Out */
101 struct idr_context
*idp
= cli
->smb2
.open_handles
;
104 return NT_STATUS_INVALID_PARAMETER
;
106 *pph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
108 return NT_STATUS_INVALID_HANDLE
;
113 /***************************************************************
114 Delete the fnum to smb2_hnd mapping. Zeros out handle on
116 ***************************************************************/
118 static NTSTATUS
delete_smb2_handle_mapping(struct cli_state
*cli
,
119 struct smb2_hnd
**pph
, /* In */
120 uint16_t fnum
) /* In */
122 struct idr_context
*idp
= cli
->smb2
.open_handles
;
126 return NT_STATUS_INVALID_PARAMETER
;
129 ph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
131 return NT_STATUS_INVALID_PARAMETER
;
133 idr_remove(idp
, fnum
);
138 /***************************************************************
140 ***************************************************************/
142 static uint8_t flags_to_smb2_oplock(uint32_t create_flags
)
144 if (create_flags
& REQUEST_BATCH_OPLOCK
) {
145 return SMB2_OPLOCK_LEVEL_BATCH
;
146 } else if (create_flags
& REQUEST_OPLOCK
) {
147 return SMB2_OPLOCK_LEVEL_EXCLUSIVE
;
150 /* create_flags doesn't do a level2 request. */
151 return SMB2_OPLOCK_LEVEL_NONE
;
154 /***************************************************************
155 Small wrapper that allows SMB2 create to return a uint16_t fnum.
156 ***************************************************************/
158 struct cli_smb2_create_fnum_state
{
159 struct cli_state
*cli
;
160 struct smb_create_returns cr
;
162 struct tevent_req
*subreq
;
165 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
);
166 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
);
168 struct tevent_req
*cli_smb2_create_fnum_send(TALLOC_CTX
*mem_ctx
,
169 struct tevent_context
*ev
,
170 struct cli_state
*cli
,
172 uint32_t create_flags
,
173 uint32_t desired_access
,
174 uint32_t file_attributes
,
175 uint32_t share_access
,
176 uint32_t create_disposition
,
177 uint32_t create_options
)
179 struct tevent_req
*req
, *subreq
;
180 struct cli_smb2_create_fnum_state
*state
;
181 size_t fname_len
= 0;
182 const char *startp
= NULL
;
183 const char *endp
= NULL
;
184 time_t tstamp
= (time_t)0;
185 struct smb2_create_blobs
*cblobs
= NULL
;
187 req
= tevent_req_create(mem_ctx
, &state
,
188 struct cli_smb2_create_fnum_state
);
194 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
195 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
196 return tevent_req_post(req
, ev
);
199 if (cli
->backup_intent
) {
200 create_options
|= FILE_OPEN_FOR_BACKUP_INTENT
;
203 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
204 fname_len
= strlen(fname
);
205 if (clistr_is_previous_version_path(fname
, &startp
, &endp
, &tstamp
)) {
206 size_t len_before_gmt
= startp
- fname
;
207 size_t len_after_gmt
= fname
+ fname_len
- endp
;
212 char *new_fname
= talloc_array(state
, char,
213 len_before_gmt
+ len_after_gmt
+ 1);
215 if (tevent_req_nomem(new_fname
, req
)) {
216 return tevent_req_post(req
, ev
);
219 memcpy(new_fname
, fname
, len_before_gmt
);
220 memcpy(new_fname
+ len_before_gmt
, endp
, len_after_gmt
+ 1);
222 fname_len
= len_before_gmt
+ len_after_gmt
;
224 unix_to_nt_time(&ntt
, tstamp
);
225 twrp_blob
= data_blob_const((const void *)&ntt
, 8);
227 cblobs
= talloc_zero(state
, struct smb2_create_blobs
);
228 if (tevent_req_nomem(cblobs
, req
)) {
229 return tevent_req_post(req
, ev
);
232 status
= smb2_create_blob_add(state
, cblobs
,
233 SMB2_CREATE_TAG_TWRP
, twrp_blob
);
234 if (!NT_STATUS_IS_OK(status
)) {
235 tevent_req_nterror(req
, status
);
236 return tevent_req_post(req
, ev
);
240 /* SMB2 is pickier about pathnames. Ensure it doesn't
242 if (*fname
== '\\') {
247 /* Or end in a '\' */
248 if (fname_len
> 0 && fname
[fname_len
-1] == '\\') {
249 char *new_fname
= talloc_strdup(state
, fname
);
250 if (tevent_req_nomem(new_fname
, req
)) {
251 return tevent_req_post(req
, ev
);
253 new_fname
[fname_len
-1] = '\0';
257 subreq
= smb2cli_create_send(state
, ev
,
263 flags_to_smb2_oplock(create_flags
),
264 SMB2_IMPERSONATION_IMPERSONATION
,
271 if (tevent_req_nomem(subreq
, req
)) {
272 return tevent_req_post(req
, ev
);
274 tevent_req_set_callback(subreq
, cli_smb2_create_fnum_done
, req
);
276 state
->subreq
= subreq
;
277 tevent_req_set_cancel_fn(req
, cli_smb2_create_fnum_cancel
);
282 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
)
284 struct tevent_req
*req
= tevent_req_callback_data(
285 subreq
, struct tevent_req
);
286 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
287 req
, struct cli_smb2_create_fnum_state
);
291 status
= smb2cli_create_recv(subreq
, &h
.fid_persistent
,
292 &h
.fid_volatile
, &state
->cr
, NULL
, NULL
);
294 if (tevent_req_nterror(req
, status
)) {
298 status
= map_smb2_handle_to_fnum(state
->cli
, &h
, &state
->fnum
);
299 if (tevent_req_nterror(req
, status
)) {
302 tevent_req_done(req
);
305 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
)
307 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
308 req
, struct cli_smb2_create_fnum_state
);
309 return tevent_req_cancel(state
->subreq
);
312 NTSTATUS
cli_smb2_create_fnum_recv(struct tevent_req
*req
, uint16_t *pfnum
,
313 struct smb_create_returns
*cr
)
315 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
316 req
, struct cli_smb2_create_fnum_state
);
319 if (tevent_req_is_nterror(req
, &status
)) {
320 state
->cli
->raw_status
= status
;
324 *pfnum
= state
->fnum
;
329 state
->cli
->raw_status
= NT_STATUS_OK
;
333 NTSTATUS
cli_smb2_create_fnum(struct cli_state
*cli
,
335 uint32_t create_flags
,
336 uint32_t desired_access
,
337 uint32_t file_attributes
,
338 uint32_t share_access
,
339 uint32_t create_disposition
,
340 uint32_t create_options
,
342 struct smb_create_returns
*cr
)
344 TALLOC_CTX
*frame
= talloc_stackframe();
345 struct tevent_context
*ev
;
346 struct tevent_req
*req
;
347 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
349 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
351 * Can't use sync call while an async call is in flight
353 status
= NT_STATUS_INVALID_PARAMETER
;
356 ev
= samba_tevent_context_init(frame
);
360 req
= cli_smb2_create_fnum_send(frame
, ev
, cli
, fname
, create_flags
,
361 desired_access
, file_attributes
,
362 share_access
, create_disposition
,
367 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
370 status
= cli_smb2_create_fnum_recv(req
, pfid
, cr
);
376 /***************************************************************
377 Small wrapper that allows SMB2 close to use a uint16_t fnum.
378 ***************************************************************/
380 struct cli_smb2_close_fnum_state
{
381 struct cli_state
*cli
;
386 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
);
388 struct tevent_req
*cli_smb2_close_fnum_send(TALLOC_CTX
*mem_ctx
,
389 struct tevent_context
*ev
,
390 struct cli_state
*cli
,
393 struct tevent_req
*req
, *subreq
;
394 struct cli_smb2_close_fnum_state
*state
;
397 req
= tevent_req_create(mem_ctx
, &state
,
398 struct cli_smb2_close_fnum_state
);
405 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
406 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
407 return tevent_req_post(req
, ev
);
410 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
411 if (tevent_req_nterror(req
, status
)) {
412 return tevent_req_post(req
, ev
);
415 subreq
= smb2cli_close_send(state
, ev
, cli
->conn
, cli
->timeout
,
416 cli
->smb2
.session
, cli
->smb2
.tcon
,
417 0, state
->ph
->fid_persistent
,
418 state
->ph
->fid_volatile
);
419 if (tevent_req_nomem(subreq
, req
)) {
420 return tevent_req_post(req
, ev
);
422 tevent_req_set_callback(subreq
, cli_smb2_close_fnum_done
, req
);
426 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
)
428 struct tevent_req
*req
= tevent_req_callback_data(
429 subreq
, struct tevent_req
);
430 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
431 req
, struct cli_smb2_close_fnum_state
);
434 status
= smb2cli_close_recv(subreq
);
435 if (tevent_req_nterror(req
, status
)) {
439 /* Delete the fnum -> handle mapping. */
440 status
= delete_smb2_handle_mapping(state
->cli
, &state
->ph
,
442 if (tevent_req_nterror(req
, status
)) {
445 tevent_req_done(req
);
448 NTSTATUS
cli_smb2_close_fnum_recv(struct tevent_req
*req
)
450 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
451 req
, struct cli_smb2_close_fnum_state
);
452 NTSTATUS status
= NT_STATUS_OK
;
454 if (tevent_req_is_nterror(req
, &status
)) {
455 state
->cli
->raw_status
= status
;
457 tevent_req_received(req
);
461 NTSTATUS
cli_smb2_close_fnum(struct cli_state
*cli
, uint16_t fnum
)
463 TALLOC_CTX
*frame
= talloc_stackframe();
464 struct tevent_context
*ev
;
465 struct tevent_req
*req
;
466 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
468 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
470 * Can't use sync call while an async call is in flight
472 status
= NT_STATUS_INVALID_PARAMETER
;
475 ev
= samba_tevent_context_init(frame
);
479 req
= cli_smb2_close_fnum_send(frame
, ev
, cli
, fnum
);
483 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
486 status
= cli_smb2_close_fnum_recv(req
);
492 struct cli_smb2_delete_on_close_state
{
493 struct cli_state
*cli
;
500 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
);
502 struct tevent_req
*cli_smb2_delete_on_close_send(TALLOC_CTX
*mem_ctx
,
503 struct tevent_context
*ev
,
504 struct cli_state
*cli
,
508 struct tevent_req
*req
= NULL
;
509 struct cli_smb2_delete_on_close_state
*state
= NULL
;
510 struct tevent_req
*subreq
= NULL
;
511 uint8_t in_info_type
;
512 uint8_t in_file_info_class
;
515 req
= tevent_req_create(mem_ctx
, &state
,
516 struct cli_smb2_delete_on_close_state
);
523 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
524 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
525 return tevent_req_post(req
, ev
);
528 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
529 if (tevent_req_nterror(req
, status
)) {
530 return tevent_req_post(req
, ev
);
534 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
535 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
538 in_file_info_class
= SMB_FILE_DISPOSITION_INFORMATION
- 1000;
539 /* Setup data array. */
540 SCVAL(&state
->data
[0], 0, flag
? 1 : 0);
541 state
->inbuf
.data
= &state
->data
[0];
542 state
->inbuf
.length
= 1;
544 subreq
= smb2cli_set_info_send(state
, ev
,
551 &state
->inbuf
, /* in_input_buffer */
552 0, /* in_additional_info */
553 state
->ph
->fid_persistent
,
554 state
->ph
->fid_volatile
);
555 if (tevent_req_nomem(subreq
, req
)) {
556 return tevent_req_post(req
, ev
);
558 tevent_req_set_callback(subreq
,
559 cli_smb2_delete_on_close_done
,
564 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
)
566 NTSTATUS status
= smb2cli_set_info_recv(subreq
);
567 tevent_req_simple_finish_ntstatus(subreq
, status
);
570 NTSTATUS
cli_smb2_delete_on_close_recv(struct tevent_req
*req
)
572 struct cli_smb2_delete_on_close_state
*state
=
574 struct cli_smb2_delete_on_close_state
);
577 if (tevent_req_is_nterror(req
, &status
)) {
578 state
->cli
->raw_status
= status
;
579 tevent_req_received(req
);
583 state
->cli
->raw_status
= NT_STATUS_OK
;
584 tevent_req_received(req
);
588 NTSTATUS
cli_smb2_delete_on_close(struct cli_state
*cli
, uint16_t fnum
, bool flag
)
590 TALLOC_CTX
*frame
= talloc_stackframe();
591 struct tevent_context
*ev
;
592 struct tevent_req
*req
;
593 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
595 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
597 * Can't use sync call while an async call is in flight
599 status
= NT_STATUS_INVALID_PARAMETER
;
602 ev
= samba_tevent_context_init(frame
);
606 req
= cli_smb2_delete_on_close_send(frame
, ev
, cli
, fnum
, flag
);
610 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
613 status
= cli_smb2_delete_on_close_recv(req
);
619 /***************************************************************
620 Small wrapper that allows SMB2 to create a directory
622 ***************************************************************/
624 NTSTATUS
cli_smb2_mkdir(struct cli_state
*cli
, const char *dname
)
629 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
631 * Can't use sync call while an async call is in flight
633 return NT_STATUS_INVALID_PARAMETER
;
636 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
637 return NT_STATUS_INVALID_PARAMETER
;
640 status
= cli_smb2_create_fnum(cli
,
642 0, /* create_flags */
643 FILE_READ_ATTRIBUTES
, /* desired_access */
644 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
645 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
646 FILE_CREATE
, /* create_disposition */
647 FILE_DIRECTORY_FILE
, /* create_options */
651 if (!NT_STATUS_IS_OK(status
)) {
654 return cli_smb2_close_fnum(cli
, fnum
);
657 /***************************************************************
658 Small wrapper that allows SMB2 to delete a directory
660 ***************************************************************/
662 NTSTATUS
cli_smb2_rmdir(struct cli_state
*cli
, const char *dname
)
667 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
669 * Can't use sync call while an async call is in flight
671 return NT_STATUS_INVALID_PARAMETER
;
674 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
675 return NT_STATUS_INVALID_PARAMETER
;
678 status
= cli_smb2_create_fnum(cli
,
680 0, /* create_flags */
681 DELETE_ACCESS
, /* desired_access */
682 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
683 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
684 FILE_OPEN
, /* create_disposition */
685 FILE_DIRECTORY_FILE
|FILE_DELETE_ON_CLOSE
, /* create_options */
689 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
691 * Naive option to match our SMB1 code. Assume the
692 * symlink path that tripped us up was the last
693 * component and try again. Eventually we will have to
694 * deal with the returned path unprocessed component. JRA.
696 status
= cli_smb2_create_fnum(cli
,
698 0, /* create_flags */
699 DELETE_ACCESS
, /* desired_access */
700 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
701 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
702 FILE_OPEN
, /* create_disposition */
704 FILE_DELETE_ON_CLOSE
|
705 FILE_OPEN_REPARSE_POINT
, /* create_options */
710 if (!NT_STATUS_IS_OK(status
)) {
713 return cli_smb2_close_fnum(cli
, fnum
);
716 /***************************************************************
717 Small wrapper that allows SMB2 to unlink a pathname.
719 ***************************************************************/
721 NTSTATUS
cli_smb2_unlink(struct cli_state
*cli
, const char *fname
)
726 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
728 * Can't use sync call while an async call is in flight
730 return NT_STATUS_INVALID_PARAMETER
;
733 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
734 return NT_STATUS_INVALID_PARAMETER
;
737 status
= cli_smb2_create_fnum(cli
,
739 0, /* create_flags */
740 DELETE_ACCESS
, /* desired_access */
741 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
742 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
743 FILE_OPEN
, /* create_disposition */
744 FILE_DELETE_ON_CLOSE
, /* create_options */
748 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
750 * Naive option to match our SMB1 code. Assume the
751 * symlink path that tripped us up was the last
752 * component and try again. Eventually we will have to
753 * deal with the returned path unprocessed component. JRA.
755 status
= cli_smb2_create_fnum(cli
,
757 0, /* create_flags */
758 DELETE_ACCESS
, /* desired_access */
759 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
760 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
761 FILE_OPEN
, /* create_disposition */
762 FILE_DELETE_ON_CLOSE
|
763 FILE_OPEN_REPARSE_POINT
, /* create_options */
768 if (!NT_STATUS_IS_OK(status
)) {
771 return cli_smb2_close_fnum(cli
, fnum
);
774 /***************************************************************
775 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
776 ***************************************************************/
778 static NTSTATUS
parse_finfo_id_both_directory_info(uint8_t *dir_data
,
779 uint32_t dir_data_length
,
780 struct file_info
*finfo
,
781 uint32_t *next_offset
)
787 if (dir_data_length
< 4) {
788 return NT_STATUS_INFO_LENGTH_MISMATCH
;
791 *next_offset
= IVAL(dir_data
, 0);
793 if (*next_offset
> dir_data_length
) {
794 return NT_STATUS_INFO_LENGTH_MISMATCH
;
797 if (*next_offset
!= 0) {
798 /* Ensure we only read what in this record. */
799 dir_data_length
= *next_offset
;
802 if (dir_data_length
< 105) {
803 return NT_STATUS_INFO_LENGTH_MISMATCH
;
806 finfo
->atime_ts
= interpret_long_date((const char *)dir_data
+ 16);
807 finfo
->mtime_ts
= interpret_long_date((const char *)dir_data
+ 24);
808 finfo
->ctime_ts
= interpret_long_date((const char *)dir_data
+ 32);
809 finfo
->size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 40, 0);
810 finfo
->mode
= CVAL(dir_data
+ 56, 0);
811 namelen
= IVAL(dir_data
+ 60,0);
812 if (namelen
> (dir_data_length
- 104)) {
813 return NT_STATUS_INFO_LENGTH_MISMATCH
;
815 slen
= CVAL(dir_data
+ 68, 0);
817 return NT_STATUS_INFO_LENGTH_MISMATCH
;
819 ret
= pull_string_talloc(finfo
,
821 FLAGS2_UNICODE_STRINGS
,
826 if (ret
== (size_t)-1) {
827 /* Bad conversion. */
828 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
831 ret
= pull_string_talloc(finfo
,
833 FLAGS2_UNICODE_STRINGS
,
838 if (ret
== (size_t)-1) {
839 /* Bad conversion. */
840 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
845 /*******************************************************************
846 Given a filename - get its directory name
847 ********************************************************************/
849 static bool windows_parent_dirname(TALLOC_CTX
*mem_ctx
,
857 p
= strrchr_m(dir
, '\\'); /* Find final '\\', if any */
860 if (!(*parent
= talloc_strdup(mem_ctx
, "\\"))) {
871 if (!(*parent
= (char *)talloc_memdup(mem_ctx
, dir
, len
+1))) {
874 (*parent
)[len
] = '\0';
882 /***************************************************************
883 Wrapper that allows SMB2 to list a directory.
885 ***************************************************************/
887 NTSTATUS
cli_smb2_list(struct cli_state
*cli
,
888 const char *pathname
,
890 NTSTATUS (*fn
)(const char *,
897 uint16_t fnum
= 0xffff;
898 char *parent_dir
= NULL
;
899 const char *mask
= NULL
;
900 struct smb2_hnd
*ph
= NULL
;
901 bool processed_file
= false;
902 TALLOC_CTX
*frame
= talloc_stackframe();
903 TALLOC_CTX
*subframe
= NULL
;
906 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
908 * Can't use sync call while an async call is in flight
910 status
= NT_STATUS_INVALID_PARAMETER
;
914 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
915 status
= NT_STATUS_INVALID_PARAMETER
;
919 /* Get the directory name. */
920 if (!windows_parent_dirname(frame
,
924 status
= NT_STATUS_NO_MEMORY
;
928 mask_has_wild
= ms_has_wild(mask
);
930 status
= cli_smb2_create_fnum(cli
,
932 0, /* create_flags */
933 SEC_DIR_LIST
|SEC_DIR_READ_ATTRIBUTE
,/* desired_access */
934 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
935 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
936 FILE_OPEN
, /* create_disposition */
937 FILE_DIRECTORY_FILE
, /* create_options */
941 if (!NT_STATUS_IS_OK(status
)) {
945 status
= map_fnum_to_smb2_handle(cli
,
948 if (!NT_STATUS_IS_OK(status
)) {
953 uint8_t *dir_data
= NULL
;
954 uint32_t dir_data_length
= 0;
955 uint32_t next_offset
= 0;
956 subframe
= talloc_stackframe();
958 status
= smb2cli_query_directory(cli
->conn
,
962 SMB2_FIND_ID_BOTH_DIRECTORY_INFO
,
973 if (!NT_STATUS_IS_OK(status
)) {
974 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
981 struct file_info
*finfo
= talloc_zero(subframe
,
985 status
= NT_STATUS_NO_MEMORY
;
989 status
= parse_finfo_id_both_directory_info(dir_data
,
994 if (!NT_STATUS_IS_OK(status
)) {
998 if (dir_check_ftype((uint32_t)finfo
->mode
,
999 (uint32_t)attribute
)) {
1001 * Only process if attributes match.
1002 * On SMB1 server does this, so on
1003 * SMB2 we need to emulate in the
1006 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1008 processed_file
= true;
1010 status
= fn(cli
->dfs_mountpoint
,
1015 if (!NT_STATUS_IS_OK(status
)) {
1022 /* Move to next entry. */
1024 dir_data
+= next_offset
;
1025 dir_data_length
-= next_offset
;
1027 } while (next_offset
!= 0);
1029 TALLOC_FREE(subframe
);
1031 if (!mask_has_wild
) {
1033 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1034 * when handed a non-wildcard path. Do it
1035 * for the server (with a non-wildcard path
1036 * there should only ever be one file returned.
1038 status
= STATUS_NO_MORE_FILES
;
1042 } while (NT_STATUS_IS_OK(status
));
1044 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
1045 status
= NT_STATUS_OK
;
1048 if (NT_STATUS_IS_OK(status
) && !processed_file
) {
1050 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1051 * if no files match. Emulate this in the client.
1053 status
= NT_STATUS_NO_SUCH_FILE
;
1058 if (fnum
!= 0xffff) {
1059 cli_smb2_close_fnum(cli
, fnum
);
1062 cli
->raw_status
= status
;
1064 TALLOC_FREE(subframe
);
1069 /***************************************************************
1070 Wrapper that allows SMB2 to query a path info (basic level).
1072 ***************************************************************/
1074 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
1076 SMB_STRUCT_STAT
*sbuf
,
1077 uint32_t *attributes
)
1080 struct smb_create_returns cr
;
1081 uint16_t fnum
= 0xffff;
1082 size_t namelen
= strlen(name
);
1084 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1086 * Can't use sync call while an async call is in flight
1088 return NT_STATUS_INVALID_PARAMETER
;
1091 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1092 return NT_STATUS_INVALID_PARAMETER
;
1095 /* SMB2 is pickier about pathnames. Ensure it doesn't
1097 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1098 char *modname
= talloc_strdup(talloc_tos(), name
);
1099 modname
[namelen
-1] = '\0';
1103 /* This is commonly used as a 'cd'. Try qpathinfo on
1104 a directory handle first. */
1106 status
= cli_smb2_create_fnum(cli
,
1108 0, /* create_flags */
1109 FILE_READ_ATTRIBUTES
, /* desired_access */
1110 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1111 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1112 FILE_OPEN
, /* create_disposition */
1113 FILE_DIRECTORY_FILE
, /* create_options */
1117 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
1118 /* Maybe a file ? */
1119 status
= cli_smb2_create_fnum(cli
,
1121 0, /* create_flags */
1122 FILE_READ_ATTRIBUTES
, /* desired_access */
1123 0, /* file attributes */
1124 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1125 FILE_OPEN
, /* create_disposition */
1126 0, /* create_options */
1131 if (!NT_STATUS_IS_OK(status
)) {
1135 status
= cli_smb2_close_fnum(cli
, fnum
);
1139 sbuf
->st_ex_atime
= nt_time_to_unix_timespec(cr
.last_access_time
);
1140 sbuf
->st_ex_mtime
= nt_time_to_unix_timespec(cr
.last_write_time
);
1141 sbuf
->st_ex_ctime
= nt_time_to_unix_timespec(cr
.change_time
);
1142 sbuf
->st_ex_size
= cr
.end_of_file
;
1143 *attributes
= cr
.file_attributes
;
1148 /***************************************************************
1149 Wrapper that allows SMB2 to check if a path is a directory.
1151 ***************************************************************/
1153 NTSTATUS
cli_smb2_chkpath(struct cli_state
*cli
,
1157 uint16_t fnum
= 0xffff;
1159 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1161 * Can't use sync call while an async call is in flight
1163 return NT_STATUS_INVALID_PARAMETER
;
1166 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1167 return NT_STATUS_INVALID_PARAMETER
;
1170 /* Ensure this is a directory. */
1171 status
= cli_smb2_create_fnum(cli
,
1173 0, /* create_flags */
1174 FILE_READ_ATTRIBUTES
, /* desired_access */
1175 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1176 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1177 FILE_OPEN
, /* create_disposition */
1178 FILE_DIRECTORY_FILE
, /* create_options */
1182 if (!NT_STATUS_IS_OK(status
)) {
1186 return cli_smb2_close_fnum(cli
, fnum
);
1189 /***************************************************************
1190 Helper function for pathname operations.
1191 ***************************************************************/
1193 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
1195 uint32_t desired_access
,
1199 size_t namelen
= strlen(name
);
1200 TALLOC_CTX
*frame
= talloc_stackframe();
1201 uint32_t create_options
= 0;
1203 /* SMB2 is pickier about pathnames. Ensure it doesn't
1205 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1206 char *modname
= talloc_strdup(frame
, name
);
1207 if (modname
== NULL
) {
1208 status
= NT_STATUS_NO_MEMORY
;
1211 modname
[namelen
-1] = '\0';
1215 /* Try to open a file handle first. */
1216 status
= cli_smb2_create_fnum(cli
,
1218 0, /* create_flags */
1220 0, /* file attributes */
1221 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1222 FILE_OPEN
, /* create_disposition */
1227 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
1229 * Naive option to match our SMB1 code. Assume the
1230 * symlink path that tripped us up was the last
1231 * component and try again. Eventually we will have to
1232 * deal with the returned path unprocessed component. JRA.
1234 create_options
|= FILE_OPEN_REPARSE_POINT
;
1235 status
= cli_smb2_create_fnum(cli
,
1237 0, /* create_flags */
1239 0, /* file attributes */
1240 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1241 FILE_OPEN
, /* create_disposition */
1247 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
1248 create_options
|= FILE_DIRECTORY_FILE
;
1249 status
= cli_smb2_create_fnum(cli
,
1251 0, /* create_flags */
1253 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1254 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1255 FILE_OPEN
, /* create_disposition */
1256 FILE_DIRECTORY_FILE
, /* create_options */
1267 /***************************************************************
1268 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1270 ***************************************************************/
1272 NTSTATUS
cli_smb2_qpathinfo_alt_name(struct cli_state
*cli
,
1277 DATA_BLOB outbuf
= data_blob_null
;
1278 uint16_t fnum
= 0xffff;
1279 struct smb2_hnd
*ph
= NULL
;
1280 uint32_t altnamelen
= 0;
1281 TALLOC_CTX
*frame
= talloc_stackframe();
1283 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1285 * Can't use sync call while an async call is in flight
1287 status
= NT_STATUS_INVALID_PARAMETER
;
1291 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1292 status
= NT_STATUS_INVALID_PARAMETER
;
1296 status
= get_fnum_from_path(cli
,
1298 FILE_READ_ATTRIBUTES
,
1301 if (!NT_STATUS_IS_OK(status
)) {
1305 status
= map_fnum_to_smb2_handle(cli
,
1308 if (!NT_STATUS_IS_OK(status
)) {
1312 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1313 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1315 status
= smb2cli_query_info(cli
->conn
,
1319 1, /* in_info_type */
1320 (SMB_FILE_ALTERNATE_NAME_INFORMATION
- 1000), /* in_file_info_class */
1321 0xFFFF, /* in_max_output_length */
1322 NULL
, /* in_input_buffer */
1323 0, /* in_additional_info */
1330 if (!NT_STATUS_IS_OK(status
)) {
1334 /* Parse the reply. */
1335 if (outbuf
.length
< 4) {
1336 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1340 altnamelen
= IVAL(outbuf
.data
, 0);
1341 if (altnamelen
> outbuf
.length
- 4) {
1342 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1346 if (altnamelen
> 0) {
1348 char *short_name
= NULL
;
1349 ret
= pull_string_talloc(frame
,
1351 FLAGS2_UNICODE_STRINGS
,
1356 if (ret
== (size_t)-1) {
1357 /* Bad conversion. */
1358 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1362 fstrcpy(alt_name
, short_name
);
1367 status
= NT_STATUS_OK
;
1371 if (fnum
!= 0xffff) {
1372 cli_smb2_close_fnum(cli
, fnum
);
1375 cli
->raw_status
= status
;
1382 /***************************************************************
1383 Wrapper that allows SMB2 to query a fnum info (basic level).
1385 ***************************************************************/
1387 NTSTATUS
cli_smb2_qfileinfo_basic(struct cli_state
*cli
,
1391 struct timespec
*create_time
,
1392 struct timespec
*access_time
,
1393 struct timespec
*write_time
,
1394 struct timespec
*change_time
,
1398 DATA_BLOB outbuf
= data_blob_null
;
1399 struct smb2_hnd
*ph
= NULL
;
1400 TALLOC_CTX
*frame
= talloc_stackframe();
1402 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1404 * Can't use sync call while an async call is in flight
1406 status
= NT_STATUS_INVALID_PARAMETER
;
1410 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1411 status
= NT_STATUS_INVALID_PARAMETER
;
1415 status
= map_fnum_to_smb2_handle(cli
,
1418 if (!NT_STATUS_IS_OK(status
)) {
1422 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1423 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1425 status
= smb2cli_query_info(cli
->conn
,
1429 1, /* in_info_type */
1430 (SMB_FILE_ALL_INFORMATION
- 1000), /* in_file_info_class */
1431 0xFFFF, /* in_max_output_length */
1432 NULL
, /* in_input_buffer */
1433 0, /* in_additional_info */
1439 if (!NT_STATUS_IS_OK(status
)) {
1443 /* Parse the reply. */
1444 if (outbuf
.length
< 0x60) {
1445 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1450 *create_time
= interpret_long_date((const char *)outbuf
.data
+ 0x0);
1453 *access_time
= interpret_long_date((const char *)outbuf
.data
+ 0x8);
1456 *write_time
= interpret_long_date((const char *)outbuf
.data
+ 0x10);
1459 *change_time
= interpret_long_date((const char *)outbuf
.data
+ 0x18);
1462 uint32_t attr
= IVAL(outbuf
.data
, 0x20);
1463 *mode
= (uint16_t)attr
;
1466 uint64_t file_size
= BVAL(outbuf
.data
, 0x30);
1467 *size
= (off_t
)file_size
;
1470 uint64_t file_index
= BVAL(outbuf
.data
, 0x40);
1471 *ino
= (SMB_INO_T
)file_index
;
1476 cli
->raw_status
= status
;
1482 /***************************************************************
1483 Wrapper that allows SMB2 to query an fnum.
1484 Implement on top of cli_smb2_qfileinfo_basic().
1486 ***************************************************************/
1488 NTSTATUS
cli_smb2_getattrE(struct cli_state
*cli
,
1492 time_t *change_time
,
1493 time_t *access_time
,
1496 struct timespec access_time_ts
;
1497 struct timespec write_time_ts
;
1498 struct timespec change_time_ts
;
1499 NTSTATUS status
= cli_smb2_qfileinfo_basic(cli
,
1509 cli
->raw_status
= status
;
1511 if (!NT_STATUS_IS_OK(status
)) {
1516 *change_time
= change_time_ts
.tv_sec
;
1519 *access_time
= access_time_ts
.tv_sec
;
1522 *write_time
= write_time_ts
.tv_sec
;
1524 return NT_STATUS_OK
;
1527 /***************************************************************
1528 Wrapper that allows SMB2 to get pathname attributes.
1530 ***************************************************************/
1532 NTSTATUS
cli_smb2_getatr(struct cli_state
*cli
,
1539 uint16_t fnum
= 0xffff;
1540 struct smb2_hnd
*ph
= NULL
;
1541 TALLOC_CTX
*frame
= talloc_stackframe();
1543 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1545 * Can't use sync call while an async call is in flight
1547 status
= NT_STATUS_INVALID_PARAMETER
;
1551 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1552 status
= NT_STATUS_INVALID_PARAMETER
;
1556 status
= get_fnum_from_path(cli
,
1558 FILE_READ_ATTRIBUTES
,
1561 if (!NT_STATUS_IS_OK(status
)) {
1565 status
= map_fnum_to_smb2_handle(cli
,
1568 if (!NT_STATUS_IS_OK(status
)) {
1571 status
= cli_smb2_getattrE(cli
,
1578 if (!NT_STATUS_IS_OK(status
)) {
1584 if (fnum
!= 0xffff) {
1585 cli_smb2_close_fnum(cli
, fnum
);
1588 cli
->raw_status
= status
;
1594 /***************************************************************
1595 Wrapper that allows SMB2 to query a pathname info (basic level).
1596 Implement on top of cli_smb2_qfileinfo_basic().
1598 ***************************************************************/
1600 NTSTATUS
cli_smb2_qpathinfo2(struct cli_state
*cli
,
1602 struct timespec
*create_time
,
1603 struct timespec
*access_time
,
1604 struct timespec
*write_time
,
1605 struct timespec
*change_time
,
1611 struct smb2_hnd
*ph
= NULL
;
1612 uint16_t fnum
= 0xffff;
1613 TALLOC_CTX
*frame
= talloc_stackframe();
1615 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1617 * Can't use sync call while an async call is in flight
1619 status
= NT_STATUS_INVALID_PARAMETER
;
1623 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1624 status
= NT_STATUS_INVALID_PARAMETER
;
1628 status
= get_fnum_from_path(cli
,
1630 FILE_READ_ATTRIBUTES
,
1633 if (!NT_STATUS_IS_OK(status
)) {
1637 status
= map_fnum_to_smb2_handle(cli
,
1640 if (!NT_STATUS_IS_OK(status
)) {
1644 status
= cli_smb2_qfileinfo_basic(cli
,
1656 if (fnum
!= 0xffff) {
1657 cli_smb2_close_fnum(cli
, fnum
);
1660 cli
->raw_status
= status
;
1666 /***************************************************************
1667 Wrapper that allows SMB2 to query pathname streams.
1669 ***************************************************************/
1671 NTSTATUS
cli_smb2_qpathinfo_streams(struct cli_state
*cli
,
1673 TALLOC_CTX
*mem_ctx
,
1674 unsigned int *pnum_streams
,
1675 struct stream_struct
**pstreams
)
1678 struct smb2_hnd
*ph
= NULL
;
1679 uint16_t fnum
= 0xffff;
1680 DATA_BLOB outbuf
= data_blob_null
;
1681 TALLOC_CTX
*frame
= talloc_stackframe();
1683 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1685 * Can't use sync call while an async call is in flight
1687 status
= NT_STATUS_INVALID_PARAMETER
;
1691 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1692 status
= NT_STATUS_INVALID_PARAMETER
;
1696 status
= get_fnum_from_path(cli
,
1698 FILE_READ_ATTRIBUTES
,
1701 if (!NT_STATUS_IS_OK(status
)) {
1705 status
= map_fnum_to_smb2_handle(cli
,
1708 if (!NT_STATUS_IS_OK(status
)) {
1712 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1713 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1715 status
= smb2cli_query_info(cli
->conn
,
1719 1, /* in_info_type */
1720 (SMB_FILE_STREAM_INFORMATION
- 1000), /* in_file_info_class */
1721 0xFFFF, /* in_max_output_length */
1722 NULL
, /* in_input_buffer */
1723 0, /* in_additional_info */
1730 if (!NT_STATUS_IS_OK(status
)) {
1734 /* Parse the reply. */
1735 if (!parse_streams_blob(mem_ctx
,
1740 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1746 if (fnum
!= 0xffff) {
1747 cli_smb2_close_fnum(cli
, fnum
);
1750 cli
->raw_status
= status
;
1756 /***************************************************************
1757 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
1760 ***************************************************************/
1762 NTSTATUS
cli_smb2_setpathinfo(struct cli_state
*cli
,
1764 uint8_t in_info_type
,
1765 uint8_t in_file_info_class
,
1766 const DATA_BLOB
*p_in_data
)
1769 uint16_t fnum
= 0xffff;
1770 struct smb2_hnd
*ph
= NULL
;
1771 TALLOC_CTX
*frame
= talloc_stackframe();
1773 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1775 * Can't use sync call while an async call is in flight
1777 status
= NT_STATUS_INVALID_PARAMETER
;
1781 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1782 status
= NT_STATUS_INVALID_PARAMETER
;
1786 status
= get_fnum_from_path(cli
,
1788 FILE_WRITE_ATTRIBUTES
,
1791 if (!NT_STATUS_IS_OK(status
)) {
1795 status
= map_fnum_to_smb2_handle(cli
,
1798 if (!NT_STATUS_IS_OK(status
)) {
1802 status
= smb2cli_set_info(cli
->conn
,
1808 p_in_data
, /* in_input_buffer */
1809 0, /* in_additional_info */
1814 if (fnum
!= 0xffff) {
1815 cli_smb2_close_fnum(cli
, fnum
);
1818 cli
->raw_status
= status
;
1825 /***************************************************************
1826 Wrapper that allows SMB2 to set pathname attributes.
1828 ***************************************************************/
1830 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
1835 uint8_t inbuf_store
[40];
1836 DATA_BLOB inbuf
= data_blob_null
;
1838 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1839 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1841 inbuf
.data
= inbuf_store
;
1842 inbuf
.length
= sizeof(inbuf_store
);
1843 data_blob_clear(&inbuf
);
1846 * SMB1 uses attr == 0 to clear all attributes
1847 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
1848 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
1849 * request attribute change.
1851 * SMB2 uses exactly the reverse. Unfortunately as the
1852 * cli_setatr() ABI is exposed inside libsmbclient,
1853 * we must make the SMB2 cli_smb2_setatr() call
1854 * export the same ABI as the SMB1 cli_setatr()
1855 * which calls it. This means reversing the sense
1856 * of the requested attr argument if it's zero
1857 * or FILE_ATTRIBUTE_NORMAL.
1859 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
1863 attr
= FILE_ATTRIBUTE_NORMAL
;
1864 } else if (attr
== FILE_ATTRIBUTE_NORMAL
) {
1868 SSVAL(inbuf
.data
, 32, attr
);
1870 put_long_date((char *)inbuf
.data
+ 16,mtime
);
1872 /* Set all the other times to -1. */
1873 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1874 SBVAL(inbuf
.data
, 8, 0xFFFFFFFFFFFFFFFFLL
);
1875 SBVAL(inbuf
.data
, 24, 0xFFFFFFFFFFFFFFFFLL
);
1877 return cli_smb2_setpathinfo(cli
,
1879 1, /* in_info_type */
1880 /* in_file_info_class */
1881 SMB_FILE_BASIC_INFORMATION
- 1000,
1886 /***************************************************************
1887 Wrapper that allows SMB2 to set file handle times.
1889 ***************************************************************/
1891 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
1898 struct smb2_hnd
*ph
= NULL
;
1899 uint8_t inbuf_store
[40];
1900 DATA_BLOB inbuf
= data_blob_null
;
1902 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1904 * Can't use sync call while an async call is in flight
1906 return NT_STATUS_INVALID_PARAMETER
;
1909 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1910 return NT_STATUS_INVALID_PARAMETER
;
1913 status
= map_fnum_to_smb2_handle(cli
,
1916 if (!NT_STATUS_IS_OK(status
)) {
1920 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1921 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1923 inbuf
.data
= inbuf_store
;
1924 inbuf
.length
= sizeof(inbuf_store
);
1925 data_blob_clear(&inbuf
);
1927 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1928 if (change_time
!= 0) {
1929 put_long_date((char *)inbuf
.data
+ 24, change_time
);
1931 if (access_time
!= 0) {
1932 put_long_date((char *)inbuf
.data
+ 8, access_time
);
1934 if (write_time
!= 0) {
1935 put_long_date((char *)inbuf
.data
+ 16, write_time
);
1938 cli
->raw_status
= smb2cli_set_info(cli
->conn
,
1942 1, /* in_info_type */
1943 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1944 &inbuf
, /* in_input_buffer */
1945 0, /* in_additional_info */
1949 return cli
->raw_status
;
1952 /***************************************************************
1953 Wrapper that allows SMB2 to query disk attributes (size).
1955 ***************************************************************/
1957 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, const char *path
,
1958 uint64_t *bsize
, uint64_t *total
, uint64_t *avail
)
1961 uint16_t fnum
= 0xffff;
1962 DATA_BLOB outbuf
= data_blob_null
;
1963 struct smb2_hnd
*ph
= NULL
;
1964 uint32_t sectors_per_unit
= 0;
1965 uint32_t bytes_per_sector
= 0;
1966 uint64_t total_size
= 0;
1967 uint64_t size_free
= 0;
1968 TALLOC_CTX
*frame
= talloc_stackframe();
1970 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1972 * Can't use sync call while an async call is in flight
1974 status
= NT_STATUS_INVALID_PARAMETER
;
1978 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1979 status
= NT_STATUS_INVALID_PARAMETER
;
1983 /* First open the top level directory. */
1984 status
= cli_smb2_create_fnum(cli
,
1986 0, /* create_flags */
1987 FILE_READ_ATTRIBUTES
, /* desired_access */
1988 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1989 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1990 FILE_OPEN
, /* create_disposition */
1991 FILE_DIRECTORY_FILE
, /* create_options */
1995 if (!NT_STATUS_IS_OK(status
)) {
1999 status
= map_fnum_to_smb2_handle(cli
,
2002 if (!NT_STATUS_IS_OK(status
)) {
2006 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2007 level 3 (SMB_FS_SIZE_INFORMATION). */
2009 status
= smb2cli_query_info(cli
->conn
,
2013 2, /* in_info_type */
2014 3, /* in_file_info_class */
2015 0xFFFF, /* in_max_output_length */
2016 NULL
, /* in_input_buffer */
2017 0, /* in_additional_info */
2023 if (!NT_STATUS_IS_OK(status
)) {
2027 /* Parse the reply. */
2028 if (outbuf
.length
!= 24) {
2029 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2033 total_size
= BVAL(outbuf
.data
, 0);
2034 size_free
= BVAL(outbuf
.data
, 8);
2035 sectors_per_unit
= IVAL(outbuf
.data
, 16);
2036 bytes_per_sector
= IVAL(outbuf
.data
, 20);
2039 *bsize
= (uint64_t)sectors_per_unit
* (uint64_t)bytes_per_sector
;
2042 *total
= total_size
;
2048 status
= NT_STATUS_OK
;
2052 if (fnum
!= 0xffff) {
2053 cli_smb2_close_fnum(cli
, fnum
);
2056 cli
->raw_status
= status
;
2062 /***************************************************************
2063 Wrapper that allows SMB2 to query file system sizes.
2065 ***************************************************************/
2067 NTSTATUS
cli_smb2_get_fs_full_size_info(struct cli_state
*cli
,
2068 uint64_t *total_allocation_units
,
2069 uint64_t *caller_allocation_units
,
2070 uint64_t *actual_allocation_units
,
2071 uint64_t *sectors_per_allocation_unit
,
2072 uint64_t *bytes_per_sector
)
2075 uint16_t fnum
= 0xffff;
2076 DATA_BLOB outbuf
= data_blob_null
;
2077 struct smb2_hnd
*ph
= NULL
;
2078 TALLOC_CTX
*frame
= talloc_stackframe();
2080 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2082 * Can't use sync call while an async call is in flight
2084 status
= NT_STATUS_INVALID_PARAMETER
;
2088 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2089 status
= NT_STATUS_INVALID_PARAMETER
;
2093 /* First open the top level directory. */
2095 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2096 FILE_READ_ATTRIBUTES
, /* desired_access */
2097 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2098 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2099 FILE_SHARE_DELETE
, /* share_access */
2100 FILE_OPEN
, /* create_disposition */
2101 FILE_DIRECTORY_FILE
, /* create_options */
2105 if (!NT_STATUS_IS_OK(status
)) {
2109 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
2110 if (!NT_STATUS_IS_OK(status
)) {
2114 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2115 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2117 status
= smb2cli_query_info(cli
->conn
,
2121 SMB2_GETINFO_FS
, /* in_info_type */
2122 /* in_file_info_class */
2123 SMB_FS_FULL_SIZE_INFORMATION
- 1000,
2124 0xFFFF, /* in_max_output_length */
2125 NULL
, /* in_input_buffer */
2126 0, /* in_additional_info */
2132 if (!NT_STATUS_IS_OK(status
)) {
2136 if (outbuf
.length
< 32) {
2137 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2141 *total_allocation_units
= BIG_UINT(outbuf
.data
, 0);
2142 *caller_allocation_units
= BIG_UINT(outbuf
.data
, 8);
2143 *actual_allocation_units
= BIG_UINT(outbuf
.data
, 16);
2144 *sectors_per_allocation_unit
= (uint64_t)IVAL(outbuf
.data
, 24);
2145 *bytes_per_sector
= (uint64_t)IVAL(outbuf
.data
, 28);
2149 if (fnum
!= 0xffff) {
2150 cli_smb2_close_fnum(cli
, fnum
);
2153 cli
->raw_status
= status
;
2159 /***************************************************************
2160 Wrapper that allows SMB2 to query file system attributes.
2162 ***************************************************************/
2164 NTSTATUS
cli_smb2_get_fs_attr_info(struct cli_state
*cli
, uint32_t *fs_attr
)
2167 uint16_t fnum
= 0xffff;
2168 DATA_BLOB outbuf
= data_blob_null
;
2169 struct smb2_hnd
*ph
= NULL
;
2170 TALLOC_CTX
*frame
= talloc_stackframe();
2172 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2174 * Can't use sync call while an async call is in flight
2176 status
= NT_STATUS_INVALID_PARAMETER
;
2180 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2181 status
= NT_STATUS_INVALID_PARAMETER
;
2185 /* First open the top level directory. */
2187 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2188 FILE_READ_ATTRIBUTES
, /* desired_access */
2189 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2190 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2191 FILE_SHARE_DELETE
, /* share_access */
2192 FILE_OPEN
, /* create_disposition */
2193 FILE_DIRECTORY_FILE
, /* create_options */
2197 if (!NT_STATUS_IS_OK(status
)) {
2201 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
2202 if (!NT_STATUS_IS_OK(status
)) {
2206 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
2207 cli
->smb2
.tcon
, 2, /* in_info_type */
2208 5, /* in_file_info_class */
2209 0xFFFF, /* in_max_output_length */
2210 NULL
, /* in_input_buffer */
2211 0, /* in_additional_info */
2213 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
2215 if (!NT_STATUS_IS_OK(status
)) {
2219 if (outbuf
.length
< 12) {
2220 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2224 *fs_attr
= IVAL(outbuf
.data
, 0);
2228 if (fnum
!= 0xffff) {
2229 cli_smb2_close_fnum(cli
, fnum
);
2232 cli
->raw_status
= status
;
2238 /***************************************************************
2239 Wrapper that allows SMB2 to query file system volume info.
2241 ***************************************************************/
2243 NTSTATUS
cli_smb2_get_fs_volume_info(struct cli_state
*cli
,
2244 TALLOC_CTX
*mem_ctx
,
2245 char **_volume_name
,
2246 uint32_t *pserial_number
,
2250 uint16_t fnum
= 0xffff;
2251 DATA_BLOB outbuf
= data_blob_null
;
2252 struct smb2_hnd
*ph
= NULL
;
2254 char *volume_name
= NULL
;
2255 TALLOC_CTX
*frame
= talloc_stackframe();
2257 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2259 * Can't use sync call while an async call is in flight
2261 status
= NT_STATUS_INVALID_PARAMETER
;
2265 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2266 status
= NT_STATUS_INVALID_PARAMETER
;
2270 /* First open the top level directory. */
2272 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2273 FILE_READ_ATTRIBUTES
, /* desired_access */
2274 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2275 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2276 FILE_SHARE_DELETE
, /* share_access */
2277 FILE_OPEN
, /* create_disposition */
2278 FILE_DIRECTORY_FILE
, /* create_options */
2282 if (!NT_STATUS_IS_OK(status
)) {
2286 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
2287 if (!NT_STATUS_IS_OK(status
)) {
2291 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2292 level 1 (SMB_FS_VOLUME_INFORMATION). */
2294 status
= smb2cli_query_info(cli
->conn
,
2298 SMB2_GETINFO_FS
, /* in_info_type */
2299 /* in_file_info_class */
2300 SMB_FS_VOLUME_INFORMATION
- 1000,
2301 0xFFFF, /* in_max_output_length */
2302 NULL
, /* in_input_buffer */
2303 0, /* in_additional_info */
2309 if (!NT_STATUS_IS_OK(status
)) {
2313 if (outbuf
.length
< 24) {
2314 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2320 ts
= interpret_long_date((char *)outbuf
.data
);
2323 if (pserial_number
) {
2324 *pserial_number
= IVAL(outbuf
.data
,8);
2326 nlen
= IVAL(outbuf
.data
,12);
2327 if (nlen
+ 18 < 18) {
2329 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2333 * The next check is safe as we know outbuf.length >= 24
2336 if (nlen
> (outbuf
.length
- 18)) {
2337 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2341 clistr_pull_talloc(mem_ctx
,
2342 (const char *)outbuf
.data
,
2348 if (volume_name
== NULL
) {
2349 status
= map_nt_error_from_unix(errno
);
2353 *_volume_name
= volume_name
;
2357 if (fnum
!= 0xffff) {
2358 cli_smb2_close_fnum(cli
, fnum
);
2361 cli
->raw_status
= status
;
2368 /***************************************************************
2369 Wrapper that allows SMB2 to query a security descriptor.
2371 ***************************************************************/
2373 NTSTATUS
cli_smb2_query_security_descriptor(struct cli_state
*cli
,
2376 TALLOC_CTX
*mem_ctx
,
2377 struct security_descriptor
**ppsd
)
2380 DATA_BLOB outbuf
= data_blob_null
;
2381 struct smb2_hnd
*ph
= NULL
;
2382 struct security_descriptor
*lsd
= NULL
;
2383 TALLOC_CTX
*frame
= talloc_stackframe();
2385 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2387 * Can't use sync call while an async call is in flight
2389 status
= NT_STATUS_INVALID_PARAMETER
;
2393 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2394 status
= NT_STATUS_INVALID_PARAMETER
;
2398 status
= map_fnum_to_smb2_handle(cli
,
2401 if (!NT_STATUS_IS_OK(status
)) {
2405 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2407 status
= smb2cli_query_info(cli
->conn
,
2411 3, /* in_info_type */
2412 0, /* in_file_info_class */
2413 0xFFFF, /* in_max_output_length */
2414 NULL
, /* in_input_buffer */
2415 sec_info
, /* in_additional_info */
2422 if (!NT_STATUS_IS_OK(status
)) {
2426 /* Parse the reply. */
2427 status
= unmarshall_sec_desc(mem_ctx
,
2432 if (!NT_STATUS_IS_OK(status
)) {
2444 cli
->raw_status
= status
;
2450 /***************************************************************
2451 Wrapper that allows SMB2 to set a security descriptor.
2453 ***************************************************************/
2455 NTSTATUS
cli_smb2_set_security_descriptor(struct cli_state
*cli
,
2458 const struct security_descriptor
*sd
)
2461 DATA_BLOB inbuf
= data_blob_null
;
2462 struct smb2_hnd
*ph
= NULL
;
2463 TALLOC_CTX
*frame
= talloc_stackframe();
2465 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2467 * Can't use sync call while an async call is in flight
2469 status
= NT_STATUS_INVALID_PARAMETER
;
2473 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2474 status
= NT_STATUS_INVALID_PARAMETER
;
2478 status
= map_fnum_to_smb2_handle(cli
,
2481 if (!NT_STATUS_IS_OK(status
)) {
2485 status
= marshall_sec_desc(frame
,
2490 if (!NT_STATUS_IS_OK(status
)) {
2494 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2496 status
= smb2cli_set_info(cli
->conn
,
2500 3, /* in_info_type */
2501 0, /* in_file_info_class */
2502 &inbuf
, /* in_input_buffer */
2503 sec_info
, /* in_additional_info */
2509 cli
->raw_status
= status
;
2515 /***************************************************************
2516 Wrapper that allows SMB2 to rename a file.
2518 ***************************************************************/
2520 NTSTATUS
cli_smb2_rename(struct cli_state
*cli
,
2521 const char *fname_src
,
2522 const char *fname_dst
,
2526 DATA_BLOB inbuf
= data_blob_null
;
2527 uint16_t fnum
= 0xffff;
2528 struct smb2_hnd
*ph
= NULL
;
2529 smb_ucs2_t
*converted_str
= NULL
;
2530 size_t converted_size_bytes
= 0;
2532 TALLOC_CTX
*frame
= talloc_stackframe();
2534 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2536 * Can't use sync call while an async call is in flight
2538 status
= NT_STATUS_INVALID_PARAMETER
;
2542 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2543 status
= NT_STATUS_INVALID_PARAMETER
;
2547 status
= get_fnum_from_path(cli
,
2552 if (!NT_STATUS_IS_OK(status
)) {
2556 status
= map_fnum_to_smb2_handle(cli
,
2559 if (!NT_STATUS_IS_OK(status
)) {
2563 /* SMB2 is pickier about pathnames. Ensure it doesn't
2565 if (*fname_dst
== '\\') {
2569 /* SMB2 is pickier about pathnames. Ensure it doesn't
2571 namelen
= strlen(fname_dst
);
2572 if (namelen
> 0 && fname_dst
[namelen
-1] == '\\') {
2573 char *modname
= talloc_strdup(frame
, fname_dst
);
2574 modname
[namelen
-1] = '\0';
2575 fname_dst
= modname
;
2578 if (!push_ucs2_talloc(frame
,
2581 &converted_size_bytes
)) {
2582 status
= NT_STATUS_INVALID_PARAMETER
;
2586 /* W2K8 insists the dest name is not null
2587 terminated. Remove the last 2 zero bytes
2588 and reduce the name length. */
2590 if (converted_size_bytes
< 2) {
2591 status
= NT_STATUS_INVALID_PARAMETER
;
2594 converted_size_bytes
-= 2;
2596 inbuf
= data_blob_talloc_zero(frame
,
2597 20 + converted_size_bytes
);
2598 if (inbuf
.data
== NULL
) {
2599 status
= NT_STATUS_NO_MEMORY
;
2604 SCVAL(inbuf
.data
, 0, 1);
2607 SIVAL(inbuf
.data
, 16, converted_size_bytes
);
2608 memcpy(inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
2610 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2611 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2613 status
= smb2cli_set_info(cli
->conn
,
2617 1, /* in_info_type */
2618 SMB_FILE_RENAME_INFORMATION
- 1000, /* in_file_info_class */
2619 &inbuf
, /* in_input_buffer */
2620 0, /* in_additional_info */
2626 if (fnum
!= 0xffff) {
2627 cli_smb2_close_fnum(cli
, fnum
);
2630 cli
->raw_status
= status
;
2636 /***************************************************************
2637 Wrapper that allows SMB2 to set an EA on a fnum.
2639 ***************************************************************/
2641 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
2643 const char *ea_name
,
2648 DATA_BLOB inbuf
= data_blob_null
;
2650 char *ea_name_ascii
= NULL
;
2652 struct smb2_hnd
*ph
= NULL
;
2653 TALLOC_CTX
*frame
= talloc_stackframe();
2655 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2657 * Can't use sync call while an async call is in flight
2659 status
= NT_STATUS_INVALID_PARAMETER
;
2663 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2664 status
= NT_STATUS_INVALID_PARAMETER
;
2668 status
= map_fnum_to_smb2_handle(cli
,
2671 if (!NT_STATUS_IS_OK(status
)) {
2675 /* Marshall the SMB2 EA data. */
2676 if (ea_len
> 0xFFFF) {
2677 status
= NT_STATUS_INVALID_PARAMETER
;
2681 if (!push_ascii_talloc(frame
,
2685 status
= NT_STATUS_INVALID_PARAMETER
;
2689 if (namelen
< 2 || namelen
> 0xFF) {
2690 status
= NT_STATUS_INVALID_PARAMETER
;
2694 bloblen
= 8 + ea_len
+ namelen
;
2695 /* Round up to a 4 byte boundary. */
2696 bloblen
= ((bloblen
+ 3)&~3);
2698 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
2699 if (inbuf
.data
== NULL
) {
2700 status
= NT_STATUS_NO_MEMORY
;
2703 /* namelen doesn't include the NULL byte. */
2704 SCVAL(inbuf
.data
, 5, namelen
- 1);
2705 SSVAL(inbuf
.data
, 6, ea_len
);
2706 memcpy(inbuf
.data
+ 8, ea_name_ascii
, namelen
);
2707 memcpy(inbuf
.data
+ 8 + namelen
, ea_val
, ea_len
);
2709 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2710 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2712 status
= smb2cli_set_info(cli
->conn
,
2716 1, /* in_info_type */
2717 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
2718 &inbuf
, /* in_input_buffer */
2719 0, /* in_additional_info */
2725 cli
->raw_status
= status
;
2731 /***************************************************************
2732 Wrapper that allows SMB2 to set an EA on a pathname.
2734 ***************************************************************/
2736 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
2738 const char *ea_name
,
2743 uint16_t fnum
= 0xffff;
2745 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2747 * Can't use sync call while an async call is in flight
2749 status
= NT_STATUS_INVALID_PARAMETER
;
2753 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2754 status
= NT_STATUS_INVALID_PARAMETER
;
2758 status
= get_fnum_from_path(cli
,
2763 if (!NT_STATUS_IS_OK(status
)) {
2767 status
= cli_set_ea_fnum(cli
,
2772 if (!NT_STATUS_IS_OK(status
)) {
2778 if (fnum
!= 0xffff) {
2779 cli_smb2_close_fnum(cli
, fnum
);
2782 cli
->raw_status
= status
;
2787 /***************************************************************
2788 Wrapper that allows SMB2 to get an EA list on a pathname.
2790 ***************************************************************/
2792 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
2796 struct ea_struct
**pea_array
)
2799 uint16_t fnum
= 0xffff;
2800 DATA_BLOB outbuf
= data_blob_null
;
2801 struct smb2_hnd
*ph
= NULL
;
2802 struct ea_list
*ea_list
= NULL
;
2803 struct ea_list
*eal
= NULL
;
2804 size_t ea_count
= 0;
2805 TALLOC_CTX
*frame
= talloc_stackframe();
2810 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2812 * Can't use sync call while an async call is in flight
2814 status
= NT_STATUS_INVALID_PARAMETER
;
2818 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2819 status
= NT_STATUS_INVALID_PARAMETER
;
2823 status
= get_fnum_from_path(cli
,
2828 if (!NT_STATUS_IS_OK(status
)) {
2832 status
= map_fnum_to_smb2_handle(cli
,
2835 if (!NT_STATUS_IS_OK(status
)) {
2839 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2840 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2842 status
= smb2cli_query_info(cli
->conn
,
2846 1, /* in_info_type */
2847 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
2848 0xFFFF, /* in_max_output_length */
2849 NULL
, /* in_input_buffer */
2850 0, /* in_additional_info */
2857 if (!NT_STATUS_IS_OK(status
)) {
2861 /* Parse the reply. */
2862 ea_list
= read_nttrans_ea_list(ctx
,
2863 (const char *)outbuf
.data
,
2865 if (ea_list
== NULL
) {
2866 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2870 /* Convert to an array. */
2871 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2876 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
2877 if (*pea_array
== NULL
) {
2878 status
= NT_STATUS_NO_MEMORY
;
2882 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2883 (*pea_array
)[ea_count
++] = eal
->ea
;
2885 *pnum_eas
= ea_count
;
2890 if (fnum
!= 0xffff) {
2891 cli_smb2_close_fnum(cli
, fnum
);
2894 cli
->raw_status
= status
;
2900 /***************************************************************
2901 Wrapper that allows SMB2 to get user quota.
2903 ***************************************************************/
2905 NTSTATUS
cli_smb2_get_user_quota(struct cli_state
*cli
,
2907 SMB_NTQUOTA_STRUCT
*pqt
)
2910 DATA_BLOB inbuf
= data_blob_null
;
2911 DATA_BLOB outbuf
= data_blob_null
;
2912 struct smb2_hnd
*ph
= NULL
;
2913 TALLOC_CTX
*frame
= talloc_stackframe();
2915 unsigned int offset
;
2918 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2920 * Can't use sync call while an async call is in flight
2922 status
= NT_STATUS_INVALID_PARAMETER
;
2926 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2927 status
= NT_STATUS_INVALID_PARAMETER
;
2931 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
2932 if (!NT_STATUS_IS_OK(status
)) {
2936 sid_len
= ndr_size_dom_sid(&pqt
->sid
, 0);
2938 inbuf
= data_blob_talloc_zero(frame
, 24 + sid_len
);
2939 if (inbuf
.data
== NULL
) {
2940 status
= NT_STATUS_NO_MEMORY
;
2946 SCVAL(buf
, 0, 1); /* ReturnSingle */
2947 SCVAL(buf
, 1, 0); /* RestartScan */
2948 SSVAL(buf
, 2, 0); /* Reserved */
2949 if (8 + sid_len
< 8) {
2950 status
= NT_STATUS_INVALID_PARAMETER
;
2953 SIVAL(buf
, 4, 8 + sid_len
); /* SidListLength */
2954 SIVAL(buf
, 8, 0); /* StartSidLength */
2955 SIVAL(buf
, 12, 0); /* StartSidOffset */
2956 SIVAL(buf
, 16, 0); /* NextEntryOffset */
2957 SIVAL(buf
, 20, sid_len
); /* SidLength */
2958 sid_linearize(buf
+ 24, sid_len
, &pqt
->sid
);
2960 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
2961 cli
->smb2
.tcon
, 4, /* in_info_type */
2962 0, /* in_file_info_class */
2963 0xFFFF, /* in_max_output_length */
2964 &inbuf
, /* in_input_buffer */
2965 0, /* in_additional_info */
2967 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
2970 if (!NT_STATUS_IS_OK(status
)) {
2974 if (!parse_user_quota_record(outbuf
.data
, outbuf
.length
, &offset
,
2976 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2977 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
2981 cli
->raw_status
= status
;
2987 /***************************************************************
2988 Wrapper that allows SMB2 to list user quota.
2990 ***************************************************************/
2992 NTSTATUS
cli_smb2_list_user_quota_step(struct cli_state
*cli
,
2993 TALLOC_CTX
*mem_ctx
,
2995 SMB_NTQUOTA_LIST
**pqt_list
,
2999 DATA_BLOB inbuf
= data_blob_null
;
3000 DATA_BLOB outbuf
= data_blob_null
;
3001 struct smb2_hnd
*ph
= NULL
;
3002 TALLOC_CTX
*frame
= talloc_stackframe();
3005 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3007 * Can't use sync call while an async call is in flight
3009 status
= NT_STATUS_INVALID_PARAMETER
;
3013 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3014 status
= NT_STATUS_INVALID_PARAMETER
;
3018 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
3019 if (!NT_STATUS_IS_OK(status
)) {
3023 inbuf
= data_blob_talloc_zero(frame
, 16);
3024 if (inbuf
.data
== NULL
) {
3025 status
= NT_STATUS_NO_MEMORY
;
3031 SCVAL(buf
, 0, 0); /* ReturnSingle */
3032 SCVAL(buf
, 1, first
? 1 : 0); /* RestartScan */
3033 SSVAL(buf
, 2, 0); /* Reserved */
3034 SIVAL(buf
, 4, 0); /* SidListLength */
3035 SIVAL(buf
, 8, 0); /* StartSidLength */
3036 SIVAL(buf
, 12, 0); /* StartSidOffset */
3038 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
3039 cli
->smb2
.tcon
, 4, /* in_info_type */
3040 0, /* in_file_info_class */
3041 0xFFFF, /* in_max_output_length */
3042 &inbuf
, /* in_input_buffer */
3043 0, /* in_additional_info */
3045 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
3048 if (!NT_STATUS_IS_OK(status
)) {
3052 status
= parse_user_quota_list(outbuf
.data
, outbuf
.length
, mem_ctx
,
3056 cli
->raw_status
= status
;
3062 /***************************************************************
3063 Wrapper that allows SMB2 to get file system quota.
3065 ***************************************************************/
3067 NTSTATUS
cli_smb2_get_fs_quota_info(struct cli_state
*cli
,
3069 SMB_NTQUOTA_STRUCT
*pqt
)
3072 DATA_BLOB outbuf
= data_blob_null
;
3073 struct smb2_hnd
*ph
= NULL
;
3074 TALLOC_CTX
*frame
= talloc_stackframe();
3076 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3078 * Can't use sync call while an async call is in flight
3080 status
= NT_STATUS_INVALID_PARAMETER
;
3084 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3085 status
= NT_STATUS_INVALID_PARAMETER
;
3089 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
3090 if (!NT_STATUS_IS_OK(status
)) {
3094 status
= smb2cli_query_info(
3095 cli
->conn
, cli
->timeout
, cli
->smb2
.session
, cli
->smb2
.tcon
,
3096 2, /* in_info_type */
3097 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
3098 0xFFFF, /* in_max_output_length */
3099 NULL
, /* in_input_buffer */
3100 0, /* in_additional_info */
3102 ph
->fid_persistent
, ph
->fid_volatile
, frame
, &outbuf
);
3104 if (!NT_STATUS_IS_OK(status
)) {
3108 status
= parse_fs_quota_buffer(outbuf
.data
, outbuf
.length
, pqt
);
3111 cli
->raw_status
= status
;
3117 /***************************************************************
3118 Wrapper that allows SMB2 to set user quota.
3120 ***************************************************************/
3122 NTSTATUS
cli_smb2_set_user_quota(struct cli_state
*cli
,
3124 SMB_NTQUOTA_LIST
*qtl
)
3127 DATA_BLOB inbuf
= data_blob_null
;
3128 struct smb2_hnd
*ph
= NULL
;
3129 TALLOC_CTX
*frame
= talloc_stackframe();
3131 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3133 * Can't use sync call while an async call is in flight
3135 status
= NT_STATUS_INVALID_PARAMETER
;
3139 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3140 status
= NT_STATUS_INVALID_PARAMETER
;
3144 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
3145 if (!NT_STATUS_IS_OK(status
)) {
3149 status
= build_user_quota_buffer(qtl
, 0, talloc_tos(), &inbuf
, NULL
);
3150 if (!NT_STATUS_IS_OK(status
)) {
3154 status
= smb2cli_set_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
3155 cli
->smb2
.tcon
, 4, /* in_info_type */
3156 0, /* in_file_info_class */
3157 &inbuf
, /* in_input_buffer */
3158 0, /* in_additional_info */
3159 ph
->fid_persistent
, ph
->fid_volatile
);
3162 cli
->raw_status
= status
;
3169 NTSTATUS
cli_smb2_set_fs_quota_info(struct cli_state
*cli
,
3171 SMB_NTQUOTA_STRUCT
*pqt
)
3174 DATA_BLOB inbuf
= data_blob_null
;
3175 struct smb2_hnd
*ph
= NULL
;
3176 TALLOC_CTX
*frame
= talloc_stackframe();
3178 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3180 * Can't use sync call while an async call is in flight
3182 status
= NT_STATUS_INVALID_PARAMETER
;
3186 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3187 status
= NT_STATUS_INVALID_PARAMETER
;
3191 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
3192 if (!NT_STATUS_IS_OK(status
)) {
3196 status
= build_fs_quota_buffer(talloc_tos(), pqt
, &inbuf
, 0);
3197 if (!NT_STATUS_IS_OK(status
)) {
3201 status
= smb2cli_set_info(
3202 cli
->conn
, cli
->timeout
, cli
->smb2
.session
, cli
->smb2
.tcon
,
3203 2, /* in_info_type */
3204 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
3205 &inbuf
, /* in_input_buffer */
3206 0, /* in_additional_info */
3207 ph
->fid_persistent
, ph
->fid_volatile
);
3209 cli
->raw_status
= status
;
3215 struct cli_smb2_read_state
{
3216 struct tevent_context
*ev
;
3217 struct cli_state
*cli
;
3218 struct smb2_hnd
*ph
;
3219 uint64_t start_offset
;
3225 static void cli_smb2_read_done(struct tevent_req
*subreq
);
3227 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
3228 struct tevent_context
*ev
,
3229 struct cli_state
*cli
,
3235 struct tevent_req
*req
, *subreq
;
3236 struct cli_smb2_read_state
*state
;
3238 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
3244 state
->start_offset
= (uint64_t)offset
;
3245 state
->size
= (uint32_t)size
;
3246 state
->received
= 0;
3249 status
= map_fnum_to_smb2_handle(cli
,
3252 if (tevent_req_nterror(req
, status
)) {
3253 return tevent_req_post(req
, ev
);
3256 subreq
= smb2cli_read_send(state
,
3259 state
->cli
->timeout
,
3260 state
->cli
->smb2
.session
,
3261 state
->cli
->smb2
.tcon
,
3263 state
->start_offset
,
3264 state
->ph
->fid_persistent
,
3265 state
->ph
->fid_volatile
,
3266 0, /* minimum_count */
3267 0); /* remaining_bytes */
3269 if (tevent_req_nomem(subreq
, req
)) {
3270 return tevent_req_post(req
, ev
);
3272 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
3276 static void cli_smb2_read_done(struct tevent_req
*subreq
)
3278 struct tevent_req
*req
= tevent_req_callback_data(
3279 subreq
, struct tevent_req
);
3280 struct cli_smb2_read_state
*state
= tevent_req_data(
3281 req
, struct cli_smb2_read_state
);
3284 status
= smb2cli_read_recv(subreq
, state
,
3285 &state
->buf
, &state
->received
);
3286 if (tevent_req_nterror(req
, status
)) {
3290 if (state
->received
> state
->size
) {
3291 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3295 tevent_req_done(req
);
3298 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
3303 struct cli_smb2_read_state
*state
= tevent_req_data(
3304 req
, struct cli_smb2_read_state
);
3306 if (tevent_req_is_nterror(req
, &status
)) {
3307 state
->cli
->raw_status
= status
;
3311 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3312 * better make sure that you copy it away before you talloc_free(req).
3313 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3315 *received
= (ssize_t
)state
->received
;
3316 *rcvbuf
= state
->buf
;
3317 state
->cli
->raw_status
= NT_STATUS_OK
;
3318 return NT_STATUS_OK
;
3321 struct cli_smb2_write_state
{
3322 struct tevent_context
*ev
;
3323 struct cli_state
*cli
;
3324 struct smb2_hnd
*ph
;
3332 static void cli_smb2_write_written(struct tevent_req
*req
);
3334 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
3335 struct tevent_context
*ev
,
3336 struct cli_state
*cli
,
3344 struct tevent_req
*req
, *subreq
= NULL
;
3345 struct cli_smb2_write_state
*state
= NULL
;
3347 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
3353 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3354 state
->flags
= (uint32_t)mode
;
3356 state
->offset
= (uint64_t)offset
;
3357 state
->size
= (uint32_t)size
;
3360 status
= map_fnum_to_smb2_handle(cli
,
3363 if (tevent_req_nterror(req
, status
)) {
3364 return tevent_req_post(req
, ev
);
3367 subreq
= smb2cli_write_send(state
,
3370 state
->cli
->timeout
,
3371 state
->cli
->smb2
.session
,
3372 state
->cli
->smb2
.tcon
,
3375 state
->ph
->fid_persistent
,
3376 state
->ph
->fid_volatile
,
3377 0, /* remaining_bytes */
3378 state
->flags
, /* flags */
3381 if (tevent_req_nomem(subreq
, req
)) {
3382 return tevent_req_post(req
, ev
);
3384 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
3388 static void cli_smb2_write_written(struct tevent_req
*subreq
)
3390 struct tevent_req
*req
= tevent_req_callback_data(
3391 subreq
, struct tevent_req
);
3392 struct cli_smb2_write_state
*state
= tevent_req_data(
3393 req
, struct cli_smb2_write_state
);
3397 status
= smb2cli_write_recv(subreq
, &written
);
3398 TALLOC_FREE(subreq
);
3399 if (tevent_req_nterror(req
, status
)) {
3403 state
->written
= written
;
3405 tevent_req_done(req
);
3408 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
3411 struct cli_smb2_write_state
*state
= tevent_req_data(
3412 req
, struct cli_smb2_write_state
);
3415 if (tevent_req_is_nterror(req
, &status
)) {
3416 state
->cli
->raw_status
= status
;
3417 tevent_req_received(req
);
3421 if (pwritten
!= NULL
) {
3422 *pwritten
= (size_t)state
->written
;
3424 state
->cli
->raw_status
= NT_STATUS_OK
;
3425 tevent_req_received(req
);
3426 return NT_STATUS_OK
;
3429 /***************************************************************
3430 Wrapper that allows SMB2 async write using an fnum.
3431 This is mostly cut-and-paste from Volker's code inside
3432 source3/libsmb/clireadwrite.c, adapted for SMB2.
3434 Done this way so I can reuse all the logic inside cli_push()
3436 ***************************************************************/
3438 struct cli_smb2_writeall_state
{
3439 struct tevent_context
*ev
;
3440 struct cli_state
*cli
;
3441 struct smb2_hnd
*ph
;
3449 static void cli_smb2_writeall_written(struct tevent_req
*req
);
3451 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
3452 struct tevent_context
*ev
,
3453 struct cli_state
*cli
,
3461 struct tevent_req
*req
, *subreq
= NULL
;
3462 struct cli_smb2_writeall_state
*state
= NULL
;
3467 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
3473 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3474 state
->flags
= (uint32_t)mode
;
3476 state
->offset
= (uint64_t)offset
;
3477 state
->size
= (uint32_t)size
;
3480 status
= map_fnum_to_smb2_handle(cli
,
3483 if (tevent_req_nterror(req
, status
)) {
3484 return tevent_req_post(req
, ev
);
3487 to_write
= state
->size
;
3488 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
3489 to_write
= MIN(max_size
, to_write
);
3490 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
3492 to_write
= MIN(max_size
, to_write
);
3495 subreq
= smb2cli_write_send(state
,
3498 state
->cli
->timeout
,
3499 state
->cli
->smb2
.session
,
3500 state
->cli
->smb2
.tcon
,
3503 state
->ph
->fid_persistent
,
3504 state
->ph
->fid_volatile
,
3505 0, /* remaining_bytes */
3506 state
->flags
, /* flags */
3507 state
->buf
+ state
->written
);
3509 if (tevent_req_nomem(subreq
, req
)) {
3510 return tevent_req_post(req
, ev
);
3512 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
3516 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
3518 struct tevent_req
*req
= tevent_req_callback_data(
3519 subreq
, struct tevent_req
);
3520 struct cli_smb2_writeall_state
*state
= tevent_req_data(
3521 req
, struct cli_smb2_writeall_state
);
3523 uint32_t written
, to_write
;
3527 status
= smb2cli_write_recv(subreq
, &written
);
3528 TALLOC_FREE(subreq
);
3529 if (tevent_req_nterror(req
, status
)) {
3533 state
->written
+= written
;
3535 if (state
->written
> state
->size
) {
3536 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3540 to_write
= state
->size
- state
->written
;
3542 if (to_write
== 0) {
3543 tevent_req_done(req
);
3547 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
3548 to_write
= MIN(max_size
, to_write
);
3549 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
3551 to_write
= MIN(max_size
, to_write
);
3554 subreq
= smb2cli_write_send(state
,
3557 state
->cli
->timeout
,
3558 state
->cli
->smb2
.session
,
3559 state
->cli
->smb2
.tcon
,
3561 state
->offset
+ state
->written
,
3562 state
->ph
->fid_persistent
,
3563 state
->ph
->fid_volatile
,
3564 0, /* remaining_bytes */
3565 state
->flags
, /* flags */
3566 state
->buf
+ state
->written
);
3568 if (tevent_req_nomem(subreq
, req
)) {
3571 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
3574 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
3577 struct cli_smb2_writeall_state
*state
= tevent_req_data(
3578 req
, struct cli_smb2_writeall_state
);
3581 if (tevent_req_is_nterror(req
, &status
)) {
3582 state
->cli
->raw_status
= status
;
3585 if (pwritten
!= NULL
) {
3586 *pwritten
= (size_t)state
->written
;
3588 state
->cli
->raw_status
= NT_STATUS_OK
;
3589 return NT_STATUS_OK
;
3592 struct cli_smb2_splice_state
{
3593 struct tevent_context
*ev
;
3594 struct cli_state
*cli
;
3595 struct smb2_hnd
*src_ph
;
3596 struct smb2_hnd
*dst_ph
;
3597 int (*splice_cb
)(off_t n
, void *priv
);
3604 struct req_resume_key_rsp resume_rsp
;
3605 struct srv_copychunk_copy cc_copy
;
3608 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
3609 struct tevent_req
*req
);
3611 static void cli_splice_copychunk_done(struct tevent_req
*subreq
)
3613 struct tevent_req
*req
= tevent_req_callback_data(
3614 subreq
, struct tevent_req
);
3615 struct cli_smb2_splice_state
*state
=
3616 tevent_req_data(req
,
3617 struct cli_smb2_splice_state
);
3618 struct smbXcli_conn
*conn
= state
->cli
->conn
;
3619 DATA_BLOB out_input_buffer
= data_blob_null
;
3620 DATA_BLOB out_output_buffer
= data_blob_null
;
3621 struct srv_copychunk_rsp cc_copy_rsp
;
3622 enum ndr_err_code ndr_ret
;
3625 status
= smb2cli_ioctl_recv(subreq
, state
,
3627 &out_output_buffer
);
3628 TALLOC_FREE(subreq
);
3629 if ((!NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
) ||
3630 state
->resized
) && tevent_req_nterror(req
, status
)) {
3634 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
, state
, &cc_copy_rsp
,
3635 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
3636 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
3637 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3638 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3642 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
3643 uint32_t max_chunks
= MIN(cc_copy_rsp
.chunks_written
,
3644 cc_copy_rsp
.total_bytes_written
/ cc_copy_rsp
.chunk_bytes_written
);
3645 if ((cc_copy_rsp
.chunk_bytes_written
> smb2cli_conn_cc_chunk_len(conn
) ||
3646 max_chunks
> smb2cli_conn_cc_max_chunks(conn
)) &&
3647 tevent_req_nterror(req
, status
)) {
3651 state
->resized
= true;
3652 smb2cli_conn_set_cc_chunk_len(conn
, cc_copy_rsp
.chunk_bytes_written
);
3653 smb2cli_conn_set_cc_max_chunks(conn
, max_chunks
);
3655 if ((state
->src_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
3656 (state
->dst_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
3657 (state
->written
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
)) {
3658 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
3661 state
->src_offset
+= cc_copy_rsp
.total_bytes_written
;
3662 state
->dst_offset
+= cc_copy_rsp
.total_bytes_written
;
3663 state
->written
+= cc_copy_rsp
.total_bytes_written
;
3664 if (!state
->splice_cb(state
->written
, state
->priv
)) {
3665 tevent_req_nterror(req
, NT_STATUS_CANCELLED
);
3670 cli_splice_copychunk_send(state
, req
);
3673 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
3674 struct tevent_req
*req
)
3676 struct tevent_req
*subreq
;
3677 enum ndr_err_code ndr_ret
;
3678 struct smbXcli_conn
*conn
= state
->cli
->conn
;
3679 struct srv_copychunk_copy
*cc_copy
= &state
->cc_copy
;
3680 off_t src_offset
= state
->src_offset
;
3681 off_t dst_offset
= state
->dst_offset
;
3682 uint32_t req_len
= MIN(smb2cli_conn_cc_chunk_len(conn
) * smb2cli_conn_cc_max_chunks(conn
),
3683 state
->size
- state
->written
);
3684 DATA_BLOB in_input_buffer
= data_blob_null
;
3685 DATA_BLOB in_output_buffer
= data_blob_null
;
3687 if (state
->size
- state
->written
== 0) {
3688 tevent_req_done(req
);
3692 cc_copy
->chunk_count
= 0;
3694 cc_copy
->chunks
[cc_copy
->chunk_count
].source_off
= src_offset
;
3695 cc_copy
->chunks
[cc_copy
->chunk_count
].target_off
= dst_offset
;
3696 cc_copy
->chunks
[cc_copy
->chunk_count
].length
= MIN(req_len
,
3697 smb2cli_conn_cc_chunk_len(conn
));
3698 if (req_len
< cc_copy
->chunks
[cc_copy
->chunk_count
].length
) {
3699 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
3702 req_len
-= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
3703 if ((src_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
) ||
3704 (dst_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
)) {
3705 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
3708 src_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
3709 dst_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
3710 cc_copy
->chunk_count
++;
3713 ndr_ret
= ndr_push_struct_blob(&in_input_buffer
, state
, cc_copy
,
3714 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
3715 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
3716 DEBUG(0, ("failed to marshall copy chunk req\n"));
3717 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
3721 subreq
= smb2cli_ioctl_send(state
, state
->ev
, state
->cli
->conn
,
3722 state
->cli
->timeout
,
3723 state
->cli
->smb2
.session
,
3724 state
->cli
->smb2
.tcon
,
3725 state
->dst_ph
->fid_persistent
, /* in_fid_persistent */
3726 state
->dst_ph
->fid_volatile
, /* in_fid_volatile */
3727 FSCTL_SRV_COPYCHUNK_WRITE
,
3728 0, /* in_max_input_length */
3730 12, /* in_max_output_length */
3732 SMB2_IOCTL_FLAG_IS_FSCTL
);
3733 if (tevent_req_nomem(subreq
, req
)) {
3736 tevent_req_set_callback(subreq
,
3737 cli_splice_copychunk_done
,
3741 static void cli_splice_key_done(struct tevent_req
*subreq
)
3743 struct tevent_req
*req
= tevent_req_callback_data(
3744 subreq
, struct tevent_req
);
3745 struct cli_smb2_splice_state
*state
=
3746 tevent_req_data(req
,
3747 struct cli_smb2_splice_state
);
3748 enum ndr_err_code ndr_ret
;
3751 DATA_BLOB out_input_buffer
= data_blob_null
;
3752 DATA_BLOB out_output_buffer
= data_blob_null
;
3754 status
= smb2cli_ioctl_recv(subreq
, state
,
3756 &out_output_buffer
);
3757 TALLOC_FREE(subreq
);
3758 if (tevent_req_nterror(req
, status
)) {
3762 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
,
3763 state
, &state
->resume_rsp
,
3764 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
3765 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
3766 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3767 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3771 memcpy(&state
->cc_copy
.source_key
,
3772 &state
->resume_rsp
.resume_key
,
3773 sizeof state
->resume_rsp
.resume_key
);
3775 cli_splice_copychunk_send(state
, req
);
3778 struct tevent_req
*cli_smb2_splice_send(TALLOC_CTX
*mem_ctx
,
3779 struct tevent_context
*ev
,
3780 struct cli_state
*cli
,
3781 uint16_t src_fnum
, uint16_t dst_fnum
,
3782 off_t size
, off_t src_offset
, off_t dst_offset
,
3783 int (*splice_cb
)(off_t n
, void *priv
),
3786 struct tevent_req
*req
;
3787 struct tevent_req
*subreq
;
3788 struct cli_smb2_splice_state
*state
;
3790 DATA_BLOB in_input_buffer
= data_blob_null
;
3791 DATA_BLOB in_output_buffer
= data_blob_null
;
3793 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_splice_state
);
3799 state
->splice_cb
= splice_cb
;
3803 state
->src_offset
= src_offset
;
3804 state
->dst_offset
= dst_offset
;
3805 state
->cc_copy
.chunks
= talloc_array(state
,
3806 struct srv_copychunk
,
3807 smb2cli_conn_cc_max_chunks(cli
->conn
));
3808 if (state
->cc_copy
.chunks
== NULL
) {
3812 status
= map_fnum_to_smb2_handle(cli
, src_fnum
, &state
->src_ph
);
3813 if (tevent_req_nterror(req
, status
))
3814 return tevent_req_post(req
, ev
);
3816 status
= map_fnum_to_smb2_handle(cli
, dst_fnum
, &state
->dst_ph
);
3817 if (tevent_req_nterror(req
, status
))
3818 return tevent_req_post(req
, ev
);
3820 subreq
= smb2cli_ioctl_send(state
, ev
, cli
->conn
,
3824 state
->src_ph
->fid_persistent
, /* in_fid_persistent */
3825 state
->src_ph
->fid_volatile
, /* in_fid_volatile */
3826 FSCTL_SRV_REQUEST_RESUME_KEY
,
3827 0, /* in_max_input_length */
3829 32, /* in_max_output_length */
3831 SMB2_IOCTL_FLAG_IS_FSCTL
);
3832 if (tevent_req_nomem(subreq
, req
)) {
3835 tevent_req_set_callback(subreq
,
3836 cli_splice_key_done
,
3842 NTSTATUS
cli_smb2_splice_recv(struct tevent_req
*req
, off_t
*written
)
3844 struct cli_smb2_splice_state
*state
= tevent_req_data(
3845 req
, struct cli_smb2_splice_state
);
3848 if (tevent_req_is_nterror(req
, &status
)) {
3849 state
->cli
->raw_status
= status
;
3850 tevent_req_received(req
);
3853 if (written
!= NULL
) {
3854 *written
= state
->written
;
3856 state
->cli
->raw_status
= NT_STATUS_OK
;
3857 tevent_req_received(req
);
3858 return NT_STATUS_OK
;
3861 /***************************************************************
3862 SMB2 enum shadow copy data.
3863 ***************************************************************/
3865 struct cli_smb2_shadow_copy_data_fnum_state
{
3866 struct cli_state
*cli
;
3868 struct smb2_hnd
*ph
;
3869 DATA_BLOB out_input_buffer
;
3870 DATA_BLOB out_output_buffer
;
3873 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
);
3875 static struct tevent_req
*cli_smb2_shadow_copy_data_fnum_send(
3876 TALLOC_CTX
*mem_ctx
,
3877 struct tevent_context
*ev
,
3878 struct cli_state
*cli
,
3882 struct tevent_req
*req
, *subreq
;
3883 struct cli_smb2_shadow_copy_data_fnum_state
*state
;
3886 req
= tevent_req_create(mem_ctx
, &state
,
3887 struct cli_smb2_shadow_copy_data_fnum_state
);
3892 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3893 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3894 return tevent_req_post(req
, ev
);
3900 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
3901 if (tevent_req_nterror(req
, status
)) {
3902 return tevent_req_post(req
, ev
);
3906 * TODO. Under SMB2 we should send a zero max_output_length
3907 * ioctl to get the required size, then send another ioctl
3908 * to get the data, but the current SMB1 implementation just
3909 * does one roundtrip with a 64K buffer size. Do the same
3913 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
3914 state
->cli
->timeout
,
3915 state
->cli
->smb2
.session
,
3916 state
->cli
->smb2
.tcon
,
3917 state
->ph
->fid_persistent
, /* in_fid_persistent */
3918 state
->ph
->fid_volatile
, /* in_fid_volatile */
3919 FSCTL_GET_SHADOW_COPY_DATA
,
3920 0, /* in_max_input_length */
3921 NULL
, /* in_input_buffer */
3923 CLI_BUFFER_SIZE
: 16, /* in_max_output_length */
3924 NULL
, /* in_output_buffer */
3925 SMB2_IOCTL_FLAG_IS_FSCTL
);
3927 if (tevent_req_nomem(subreq
, req
)) {
3928 return tevent_req_post(req
, ev
);
3930 tevent_req_set_callback(subreq
,
3931 cli_smb2_shadow_copy_data_fnum_done
,
3937 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
)
3939 struct tevent_req
*req
= tevent_req_callback_data(
3940 subreq
, struct tevent_req
);
3941 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
3942 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
3945 status
= smb2cli_ioctl_recv(subreq
, state
,
3946 &state
->out_input_buffer
,
3947 &state
->out_output_buffer
);
3948 TALLOC_FREE(subreq
);
3949 if (tevent_req_nterror(req
, status
)) {
3952 tevent_req_done(req
);
3955 static NTSTATUS
cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req
*req
,
3956 TALLOC_CTX
*mem_ctx
,
3961 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
3962 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
3963 char **names
= NULL
;
3964 uint32_t num_names
= 0;
3965 uint32_t num_names_returned
= 0;
3966 uint32_t dlength
= 0;
3968 uint8_t *endp
= NULL
;
3971 if (tevent_req_is_nterror(req
, &status
)) {
3975 if (state
->out_output_buffer
.length
< 16) {
3976 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3979 num_names
= IVAL(state
->out_output_buffer
.data
, 0);
3980 num_names_returned
= IVAL(state
->out_output_buffer
.data
, 4);
3981 dlength
= IVAL(state
->out_output_buffer
.data
, 8);
3983 if (num_names
> 0x7FFFFFFF) {
3984 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3987 if (get_names
== false) {
3988 *pnum_names
= (int)num_names
;
3989 return NT_STATUS_OK
;
3991 if (num_names
!= num_names_returned
) {
3992 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3994 if (dlength
+ 12 < 12) {
3995 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3998 * NB. The below is an allowable return if there are
3999 * more snapshots than the buffer size we told the
4000 * server we can receive. We currently don't support
4003 if (dlength
+ 12 > state
->out_output_buffer
.length
) {
4004 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4006 if (state
->out_output_buffer
.length
+
4007 (2 * sizeof(SHADOW_COPY_LABEL
)) <
4008 state
->out_output_buffer
.length
) {
4009 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4012 names
= talloc_array(mem_ctx
, char *, num_names_returned
);
4013 if (names
== NULL
) {
4014 return NT_STATUS_NO_MEMORY
;
4017 endp
= state
->out_output_buffer
.data
+
4018 state
->out_output_buffer
.length
;
4020 for (i
=0; i
<num_names_returned
; i
++) {
4023 size_t converted_size
;
4025 src
= state
->out_output_buffer
.data
+ 12 +
4026 (i
* 2 * sizeof(SHADOW_COPY_LABEL
));
4028 if (src
+ (2 * sizeof(SHADOW_COPY_LABEL
)) > endp
) {
4029 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4031 ret
= convert_string_talloc(
4032 names
, CH_UTF16LE
, CH_UNIX
,
4033 src
, 2 * sizeof(SHADOW_COPY_LABEL
),
4034 &names
[i
], &converted_size
);
4037 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4040 *pnum_names
= num_names
;
4042 return NT_STATUS_OK
;
4045 NTSTATUS
cli_smb2_shadow_copy_data(TALLOC_CTX
*mem_ctx
,
4046 struct cli_state
*cli
,
4052 TALLOC_CTX
*frame
= talloc_stackframe();
4053 struct tevent_context
*ev
;
4054 struct tevent_req
*req
;
4055 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
4057 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4059 * Can't use sync call while an async call is in flight
4061 status
= NT_STATUS_INVALID_PARAMETER
;
4064 ev
= samba_tevent_context_init(frame
);
4068 req
= cli_smb2_shadow_copy_data_fnum_send(frame
,
4076 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4079 status
= cli_smb2_shadow_copy_data_fnum_recv(req
,
4085 cli
->raw_status
= status
;
4091 /***************************************************************
4092 Wrapper that allows SMB2 to truncate a file.
4094 ***************************************************************/
4096 NTSTATUS
cli_smb2_ftruncate(struct cli_state
*cli
,
4101 DATA_BLOB inbuf
= data_blob_null
;
4102 struct smb2_hnd
*ph
= NULL
;
4103 TALLOC_CTX
*frame
= talloc_stackframe();
4105 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4107 * Can't use sync call while an async call is in flight
4109 status
= NT_STATUS_INVALID_PARAMETER
;
4113 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
4114 status
= NT_STATUS_INVALID_PARAMETER
;
4118 status
= map_fnum_to_smb2_handle(cli
,
4121 if (!NT_STATUS_IS_OK(status
)) {
4125 inbuf
= data_blob_talloc_zero(frame
, 8);
4126 if (inbuf
.data
== NULL
) {
4127 status
= NT_STATUS_NO_MEMORY
;
4131 SBVAL(inbuf
.data
, 0, newsize
);
4133 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4134 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4136 status
= smb2cli_set_info(cli
->conn
,
4140 1, /* in_info_type */
4141 /* in_file_info_class */
4142 SMB_FILE_END_OF_FILE_INFORMATION
- 1000,
4143 &inbuf
, /* in_input_buffer */
4144 0, /* in_additional_info */
4150 cli
->raw_status
= status
;
4156 NTSTATUS
cli_smb2_notify(struct cli_state
*cli
, uint16_t fnum
,
4157 uint32_t buffer_size
, uint32_t completion_filter
,
4158 bool recursive
, TALLOC_CTX
*mem_ctx
,
4159 struct notify_change
**pchanges
,
4160 uint32_t *pnum_changes
)
4163 struct smb2_hnd
*ph
= NULL
;
4164 TALLOC_CTX
*frame
= talloc_stackframe();
4167 struct notify_change
*changes
= NULL
;
4168 size_t num_changes
= 0;
4170 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4172 * Can't use sync call while an async call is in flight
4174 status
= NT_STATUS_INVALID_PARAMETER
;
4178 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
4179 status
= NT_STATUS_INVALID_PARAMETER
;
4183 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
4184 if (!NT_STATUS_IS_OK(status
)) {
4188 status
= smb2cli_notify(cli
->conn
, cli
->timeout
,
4189 cli
->smb2
.session
, cli
->smb2
.tcon
,
4191 ph
->fid_persistent
, ph
->fid_volatile
,
4192 completion_filter
, recursive
,
4193 frame
, &base
, &len
);
4197 while (len
- ofs
>= 12) {
4198 struct notify_change
*tmp
;
4199 struct notify_change
*c
;
4200 uint32_t next_ofs
= IVAL(base
, ofs
);
4201 uint32_t file_name_length
= IVAL(base
, ofs
+8);
4205 tmp
= talloc_realloc(frame
, changes
, struct notify_change
,
4208 status
= NT_STATUS_NO_MEMORY
;
4212 c
= &changes
[num_changes
];
4215 if (smb_buffer_oob(len
, ofs
, next_ofs
) ||
4216 smb_buffer_oob(len
, ofs
+12, file_name_length
)) {
4217 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
4221 c
->action
= IVAL(base
, ofs
+4);
4223 ok
= convert_string_talloc(changes
, CH_UTF16LE
, CH_UNIX
,
4224 base
+ ofs
+ 12, file_name_length
,
4225 &c
->name
, &namelen
);
4227 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
4231 if (next_ofs
== 0) {
4237 *pchanges
= talloc_move(mem_ctx
, &changes
);
4238 *pnum_changes
= num_changes
;
4239 status
= NT_STATUS_OK
;
4242 cli
->raw_status
= status
;
4248 struct cli_smb2_set_reparse_point_fnum_state
{
4249 struct cli_state
*cli
;
4251 struct smb2_hnd
*ph
;
4252 DATA_BLOB input_buffer
;
4255 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req
*subreq
);
4257 struct tevent_req
*cli_smb2_set_reparse_point_fnum_send(
4258 TALLOC_CTX
*mem_ctx
,
4259 struct tevent_context
*ev
,
4260 struct cli_state
*cli
,
4264 struct tevent_req
*req
, *subreq
;
4265 struct cli_smb2_set_reparse_point_fnum_state
*state
= NULL
;
4268 req
= tevent_req_create(mem_ctx
, &state
,
4269 struct cli_smb2_set_reparse_point_fnum_state
);
4274 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
4275 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
4276 return tevent_req_post(req
, ev
);
4282 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
4283 if (tevent_req_nterror(req
, status
)) {
4284 return tevent_req_post(req
, ev
);
4287 state
->input_buffer
= data_blob_talloc(state
,
4290 if (state
->input_buffer
.data
== NULL
) {
4291 tevent_req_nterror(req
, NT_STATUS_NO_MEMORY
);
4292 return tevent_req_post(req
, ev
);
4295 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
4296 state
->cli
->timeout
,
4297 state
->cli
->smb2
.session
,
4298 state
->cli
->smb2
.tcon
,
4299 state
->ph
->fid_persistent
, /* in_fid_persistent */
4300 state
->ph
->fid_volatile
, /* in_fid_volatile */
4301 FSCTL_SET_REPARSE_POINT
,
4302 0, /* in_max_input_length */
4303 &state
->input_buffer
,
4306 SMB2_IOCTL_FLAG_IS_FSCTL
);
4308 if (tevent_req_nomem(subreq
, req
)) {
4309 return tevent_req_post(req
, ev
);
4311 tevent_req_set_callback(subreq
,
4312 cli_smb2_set_reparse_point_fnum_done
,
4318 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req
*subreq
)
4320 struct tevent_req
*req
= tevent_req_callback_data(
4321 subreq
, struct tevent_req
);
4322 struct cli_smb2_set_reparse_point_fnum_state
*state
= tevent_req_data(
4323 req
, struct cli_smb2_set_reparse_point_fnum_state
);
4326 status
= smb2cli_ioctl_recv(subreq
, state
,
4329 TALLOC_FREE(subreq
);
4330 if (tevent_req_nterror(req
, status
)) {
4333 tevent_req_done(req
);
4336 NTSTATUS
cli_smb2_set_reparse_point_fnum_recv(struct tevent_req
*req
)
4338 return tevent_req_simple_recv_ntstatus(req
);
4341 struct cli_smb2_get_reparse_point_fnum_state
{
4342 struct cli_state
*cli
;
4344 struct smb2_hnd
*ph
;
4345 DATA_BLOB output_buffer
;
4348 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req
*subreq
);
4350 struct tevent_req
*cli_smb2_get_reparse_point_fnum_send(
4351 TALLOC_CTX
*mem_ctx
,
4352 struct tevent_context
*ev
,
4353 struct cli_state
*cli
,
4356 struct tevent_req
*req
, *subreq
;
4357 struct cli_smb2_set_reparse_point_fnum_state
*state
= NULL
;
4360 req
= tevent_req_create(mem_ctx
, &state
,
4361 struct cli_smb2_get_reparse_point_fnum_state
);
4366 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
4367 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
4368 return tevent_req_post(req
, ev
);
4374 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
4375 if (tevent_req_nterror(req
, status
)) {
4376 return tevent_req_post(req
, ev
);
4379 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
4380 state
->cli
->timeout
,
4381 state
->cli
->smb2
.session
,
4382 state
->cli
->smb2
.tcon
,
4383 state
->ph
->fid_persistent
, /* in_fid_persistent */
4384 state
->ph
->fid_volatile
, /* in_fid_volatile */
4385 FSCTL_GET_REPARSE_POINT
,
4386 0, /* in_max_input_length */
4390 SMB2_IOCTL_FLAG_IS_FSCTL
);
4392 if (tevent_req_nomem(subreq
, req
)) {
4393 return tevent_req_post(req
, ev
);
4395 tevent_req_set_callback(subreq
,
4396 cli_smb2_get_reparse_point_fnum_done
,
4402 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req
*subreq
)
4404 struct tevent_req
*req
= tevent_req_callback_data(
4405 subreq
, struct tevent_req
);
4406 struct cli_smb2_get_reparse_point_fnum_state
*state
= tevent_req_data(
4407 req
, struct cli_smb2_get_reparse_point_fnum_state
);
4410 status
= smb2cli_ioctl_recv(subreq
, state
,
4412 &state
->output_buffer
);
4413 TALLOC_FREE(subreq
);
4414 if (tevent_req_nterror(req
, status
)) {
4415 state
->cli
->raw_status
= status
;
4418 tevent_req_done(req
);
4421 NTSTATUS
cli_smb2_get_reparse_point_fnum_recv(struct tevent_req
*req
,
4422 TALLOC_CTX
*mem_ctx
,
4425 struct cli_smb2_get_reparse_point_fnum_state
*state
= tevent_req_data(
4426 req
, struct cli_smb2_get_reparse_point_fnum_state
);
4428 if (tevent_req_is_nterror(req
, &state
->cli
->raw_status
)) {
4429 tevent_req_received(req
);
4430 return state
->cli
->raw_status
;
4432 *output
= data_blob_dup_talloc(mem_ctx
, state
->output_buffer
);
4433 if (output
->data
== NULL
) {
4434 tevent_req_received(req
);
4435 return NT_STATUS_NO_MEMORY
;
4437 tevent_req_received(req
);
4438 return NT_STATUS_OK
;