2 Unix SMB/CIFS implementation.
4 Copyright (C) Jeremy Allison 2013
5 Copyright (C) Volker Lendecke 2013
6 Copyright (C) Stefan Metzmacher 2013
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This code is a thin wrapper around the existing
24 cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c,
25 but allows the handles to be mapped to uint16_t fnums,
26 which are easier for smbclient to use.
31 #include "async_smb.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "cli_smb2_fnum.h"
36 #include "../libcli/smb/smb2_create_blob.h"
37 #include "libsmb/proto.h"
38 #include "lib/util/tevent_ntstatus.h"
39 #include "../libcli/security/security.h"
40 #include "../librpc/gen_ndr/ndr_security.h"
41 #include "lib/util_ea.h"
42 #include "librpc/gen_ndr/ndr_ioctl.h"
44 #include "librpc/gen_ndr/ndr_quota.h"
47 uint64_t fid_persistent
;
48 uint64_t fid_volatile
;
52 * Handle mapping code.
55 /***************************************************************
56 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
57 Ensures handle is owned by cli struct.
58 ***************************************************************/
60 static NTSTATUS
map_smb2_handle_to_fnum(struct cli_state
*cli
,
61 const struct smb2_hnd
*ph
, /* In */
62 uint16_t *pfnum
) /* Out */
65 struct idr_context
*idp
= cli
->smb2
.open_handles
;
66 struct smb2_hnd
*owned_h
= talloc_memdup(cli
,
68 sizeof(struct smb2_hnd
));
70 if (owned_h
== NULL
) {
71 return NT_STATUS_NO_MEMORY
;
76 cli
->smb2
.open_handles
= idr_init(cli
);
77 if (cli
->smb2
.open_handles
== NULL
) {
79 return NT_STATUS_NO_MEMORY
;
81 idp
= cli
->smb2
.open_handles
;
84 ret
= idr_get_new_above(idp
, owned_h
, 1, 0xFFFE);
87 return NT_STATUS_NO_MEMORY
;
90 *pfnum
= (uint16_t)ret
;
94 /***************************************************************
95 Return the smb2_hnd pointer associated with the given fnum.
96 ***************************************************************/
98 static NTSTATUS
map_fnum_to_smb2_handle(struct cli_state
*cli
,
99 uint16_t fnum
, /* In */
100 struct smb2_hnd
**pph
) /* Out */
102 struct idr_context
*idp
= cli
->smb2
.open_handles
;
105 return NT_STATUS_INVALID_PARAMETER
;
107 *pph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
109 return NT_STATUS_INVALID_HANDLE
;
114 /***************************************************************
115 Delete the fnum to smb2_hnd mapping. Zeros out handle on
117 ***************************************************************/
119 static NTSTATUS
delete_smb2_handle_mapping(struct cli_state
*cli
,
120 struct smb2_hnd
**pph
, /* In */
121 uint16_t fnum
) /* In */
123 struct idr_context
*idp
= cli
->smb2
.open_handles
;
127 return NT_STATUS_INVALID_PARAMETER
;
130 ph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
132 return NT_STATUS_INVALID_PARAMETER
;
134 idr_remove(idp
, fnum
);
139 /***************************************************************
141 ***************************************************************/
143 static uint8_t flags_to_smb2_oplock(uint32_t create_flags
)
145 if (create_flags
& REQUEST_BATCH_OPLOCK
) {
146 return SMB2_OPLOCK_LEVEL_BATCH
;
147 } else if (create_flags
& REQUEST_OPLOCK
) {
148 return SMB2_OPLOCK_LEVEL_EXCLUSIVE
;
151 /* create_flags doesn't do a level2 request. */
152 return SMB2_OPLOCK_LEVEL_NONE
;
155 /***************************************************************
156 Small wrapper that allows SMB2 create to return a uint16_t fnum.
157 ***************************************************************/
159 struct cli_smb2_create_fnum_state
{
160 struct cli_state
*cli
;
161 struct smb_create_returns cr
;
163 struct tevent_req
*subreq
;
166 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
);
167 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
);
169 struct tevent_req
*cli_smb2_create_fnum_send(TALLOC_CTX
*mem_ctx
,
170 struct tevent_context
*ev
,
171 struct cli_state
*cli
,
173 uint32_t create_flags
,
174 uint32_t impersonation_level
,
175 uint32_t desired_access
,
176 uint32_t file_attributes
,
177 uint32_t share_access
,
178 uint32_t create_disposition
,
179 uint32_t create_options
)
181 struct tevent_req
*req
, *subreq
;
182 struct cli_smb2_create_fnum_state
*state
;
183 size_t fname_len
= 0;
184 const char *startp
= NULL
;
185 const char *endp
= NULL
;
186 time_t tstamp
= (time_t)0;
187 struct smb2_create_blobs
*cblobs
= NULL
;
189 req
= tevent_req_create(mem_ctx
, &state
,
190 struct cli_smb2_create_fnum_state
);
196 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
197 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
198 return tevent_req_post(req
, ev
);
201 if (cli
->backup_intent
) {
202 create_options
|= FILE_OPEN_FOR_BACKUP_INTENT
;
205 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
206 fname_len
= strlen(fname
);
207 if (clistr_is_previous_version_path(fname
, &startp
, &endp
, &tstamp
)) {
208 size_t len_before_gmt
= startp
- fname
;
209 size_t len_after_gmt
= fname
+ fname_len
- endp
;
214 char *new_fname
= talloc_array(state
, char,
215 len_before_gmt
+ len_after_gmt
+ 1);
217 if (tevent_req_nomem(new_fname
, req
)) {
218 return tevent_req_post(req
, ev
);
221 memcpy(new_fname
, fname
, len_before_gmt
);
222 memcpy(new_fname
+ len_before_gmt
, endp
, len_after_gmt
+ 1);
224 fname_len
= len_before_gmt
+ len_after_gmt
;
226 unix_to_nt_time(&ntt
, tstamp
);
227 twrp_blob
= data_blob_const((const void *)&ntt
, 8);
229 cblobs
= talloc_zero(state
, struct smb2_create_blobs
);
230 if (tevent_req_nomem(cblobs
, req
)) {
231 return tevent_req_post(req
, ev
);
234 status
= smb2_create_blob_add(state
, cblobs
,
235 SMB2_CREATE_TAG_TWRP
, twrp_blob
);
236 if (!NT_STATUS_IS_OK(status
)) {
237 tevent_req_nterror(req
, status
);
238 return tevent_req_post(req
, ev
);
242 /* SMB2 is pickier about pathnames. Ensure it doesn't
244 if (*fname
== '\\') {
249 /* Or end in a '\' */
250 if (fname_len
> 0 && fname
[fname_len
-1] == '\\') {
251 char *new_fname
= talloc_strdup(state
, fname
);
252 if (tevent_req_nomem(new_fname
, req
)) {
253 return tevent_req_post(req
, ev
);
255 new_fname
[fname_len
-1] = '\0';
259 subreq
= smb2cli_create_send(state
, ev
,
265 flags_to_smb2_oplock(create_flags
),
273 if (tevent_req_nomem(subreq
, req
)) {
274 return tevent_req_post(req
, ev
);
276 tevent_req_set_callback(subreq
, cli_smb2_create_fnum_done
, req
);
278 state
->subreq
= subreq
;
279 tevent_req_set_cancel_fn(req
, cli_smb2_create_fnum_cancel
);
284 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
)
286 struct tevent_req
*req
= tevent_req_callback_data(
287 subreq
, struct tevent_req
);
288 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
289 req
, struct cli_smb2_create_fnum_state
);
293 status
= smb2cli_create_recv(subreq
, &h
.fid_persistent
,
294 &h
.fid_volatile
, &state
->cr
, NULL
, NULL
);
296 if (tevent_req_nterror(req
, status
)) {
300 status
= map_smb2_handle_to_fnum(state
->cli
, &h
, &state
->fnum
);
301 if (tevent_req_nterror(req
, status
)) {
304 tevent_req_done(req
);
307 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
)
309 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
310 req
, struct cli_smb2_create_fnum_state
);
311 return tevent_req_cancel(state
->subreq
);
314 NTSTATUS
cli_smb2_create_fnum_recv(struct tevent_req
*req
, uint16_t *pfnum
,
315 struct smb_create_returns
*cr
)
317 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
318 req
, struct cli_smb2_create_fnum_state
);
321 if (tevent_req_is_nterror(req
, &status
)) {
322 state
->cli
->raw_status
= status
;
326 *pfnum
= state
->fnum
;
331 state
->cli
->raw_status
= NT_STATUS_OK
;
335 NTSTATUS
cli_smb2_create_fnum(struct cli_state
*cli
,
337 uint32_t create_flags
,
338 uint32_t impersonation_level
,
339 uint32_t desired_access
,
340 uint32_t file_attributes
,
341 uint32_t share_access
,
342 uint32_t create_disposition
,
343 uint32_t create_options
,
345 struct smb_create_returns
*cr
)
347 TALLOC_CTX
*frame
= talloc_stackframe();
348 struct tevent_context
*ev
;
349 struct tevent_req
*req
;
350 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
352 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
354 * Can't use sync call while an async call is in flight
356 status
= NT_STATUS_INVALID_PARAMETER
;
359 ev
= samba_tevent_context_init(frame
);
363 req
= cli_smb2_create_fnum_send(frame
, ev
, cli
, fname
, create_flags
,
365 desired_access
, file_attributes
,
366 share_access
, create_disposition
,
371 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
374 status
= cli_smb2_create_fnum_recv(req
, pfid
, cr
);
380 /***************************************************************
381 Small wrapper that allows SMB2 close to use a uint16_t fnum.
382 ***************************************************************/
384 struct cli_smb2_close_fnum_state
{
385 struct cli_state
*cli
;
390 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
);
392 struct tevent_req
*cli_smb2_close_fnum_send(TALLOC_CTX
*mem_ctx
,
393 struct tevent_context
*ev
,
394 struct cli_state
*cli
,
397 struct tevent_req
*req
, *subreq
;
398 struct cli_smb2_close_fnum_state
*state
;
401 req
= tevent_req_create(mem_ctx
, &state
,
402 struct cli_smb2_close_fnum_state
);
409 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
410 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
411 return tevent_req_post(req
, ev
);
414 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
415 if (tevent_req_nterror(req
, status
)) {
416 return tevent_req_post(req
, ev
);
419 subreq
= smb2cli_close_send(state
, ev
, cli
->conn
, cli
->timeout
,
420 cli
->smb2
.session
, cli
->smb2
.tcon
,
421 0, state
->ph
->fid_persistent
,
422 state
->ph
->fid_volatile
);
423 if (tevent_req_nomem(subreq
, req
)) {
424 return tevent_req_post(req
, ev
);
426 tevent_req_set_callback(subreq
, cli_smb2_close_fnum_done
, req
);
430 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
)
432 struct tevent_req
*req
= tevent_req_callback_data(
433 subreq
, struct tevent_req
);
434 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
435 req
, struct cli_smb2_close_fnum_state
);
438 status
= smb2cli_close_recv(subreq
);
439 if (tevent_req_nterror(req
, status
)) {
443 /* Delete the fnum -> handle mapping. */
444 status
= delete_smb2_handle_mapping(state
->cli
, &state
->ph
,
446 if (tevent_req_nterror(req
, status
)) {
449 tevent_req_done(req
);
452 NTSTATUS
cli_smb2_close_fnum_recv(struct tevent_req
*req
)
454 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
455 req
, struct cli_smb2_close_fnum_state
);
456 NTSTATUS status
= NT_STATUS_OK
;
458 if (tevent_req_is_nterror(req
, &status
)) {
459 state
->cli
->raw_status
= status
;
461 tevent_req_received(req
);
465 NTSTATUS
cli_smb2_close_fnum(struct cli_state
*cli
, uint16_t fnum
)
467 TALLOC_CTX
*frame
= talloc_stackframe();
468 struct tevent_context
*ev
;
469 struct tevent_req
*req
;
470 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
472 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
474 * Can't use sync call while an async call is in flight
476 status
= NT_STATUS_INVALID_PARAMETER
;
479 ev
= samba_tevent_context_init(frame
);
483 req
= cli_smb2_close_fnum_send(frame
, ev
, cli
, fnum
);
487 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
490 status
= cli_smb2_close_fnum_recv(req
);
496 struct cli_smb2_delete_on_close_state
{
497 struct cli_state
*cli
;
504 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
);
506 struct tevent_req
*cli_smb2_delete_on_close_send(TALLOC_CTX
*mem_ctx
,
507 struct tevent_context
*ev
,
508 struct cli_state
*cli
,
512 struct tevent_req
*req
= NULL
;
513 struct cli_smb2_delete_on_close_state
*state
= NULL
;
514 struct tevent_req
*subreq
= NULL
;
515 uint8_t in_info_type
;
516 uint8_t in_file_info_class
;
519 req
= tevent_req_create(mem_ctx
, &state
,
520 struct cli_smb2_delete_on_close_state
);
527 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
528 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
529 return tevent_req_post(req
, ev
);
532 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
533 if (tevent_req_nterror(req
, status
)) {
534 return tevent_req_post(req
, ev
);
538 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
539 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
542 in_file_info_class
= SMB_FILE_DISPOSITION_INFORMATION
- 1000;
543 /* Setup data array. */
544 SCVAL(&state
->data
[0], 0, flag
? 1 : 0);
545 state
->inbuf
.data
= &state
->data
[0];
546 state
->inbuf
.length
= 1;
548 subreq
= smb2cli_set_info_send(state
, ev
,
555 &state
->inbuf
, /* in_input_buffer */
556 0, /* in_additional_info */
557 state
->ph
->fid_persistent
,
558 state
->ph
->fid_volatile
);
559 if (tevent_req_nomem(subreq
, req
)) {
560 return tevent_req_post(req
, ev
);
562 tevent_req_set_callback(subreq
,
563 cli_smb2_delete_on_close_done
,
568 static void cli_smb2_delete_on_close_done(struct tevent_req
*subreq
)
570 NTSTATUS status
= smb2cli_set_info_recv(subreq
);
571 tevent_req_simple_finish_ntstatus(subreq
, status
);
574 NTSTATUS
cli_smb2_delete_on_close_recv(struct tevent_req
*req
)
576 struct cli_smb2_delete_on_close_state
*state
=
578 struct cli_smb2_delete_on_close_state
);
581 if (tevent_req_is_nterror(req
, &status
)) {
582 state
->cli
->raw_status
= status
;
583 tevent_req_received(req
);
587 state
->cli
->raw_status
= NT_STATUS_OK
;
588 tevent_req_received(req
);
592 NTSTATUS
cli_smb2_delete_on_close(struct cli_state
*cli
, uint16_t fnum
, bool flag
)
594 TALLOC_CTX
*frame
= talloc_stackframe();
595 struct tevent_context
*ev
;
596 struct tevent_req
*req
;
597 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
599 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
601 * Can't use sync call while an async call is in flight
603 status
= NT_STATUS_INVALID_PARAMETER
;
606 ev
= samba_tevent_context_init(frame
);
610 req
= cli_smb2_delete_on_close_send(frame
, ev
, cli
, fnum
, flag
);
614 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
617 status
= cli_smb2_delete_on_close_recv(req
);
623 /***************************************************************
624 Small wrapper that allows SMB2 to create a directory
626 ***************************************************************/
628 NTSTATUS
cli_smb2_mkdir(struct cli_state
*cli
, const char *dname
)
633 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
635 * Can't use sync call while an async call is in flight
637 return NT_STATUS_INVALID_PARAMETER
;
640 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
641 return NT_STATUS_INVALID_PARAMETER
;
644 status
= cli_smb2_create_fnum(cli
,
646 0, /* create_flags */
647 SMB2_IMPERSONATION_IMPERSONATION
,
648 FILE_READ_ATTRIBUTES
, /* desired_access */
649 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
650 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
651 FILE_CREATE
, /* create_disposition */
652 FILE_DIRECTORY_FILE
, /* create_options */
656 if (!NT_STATUS_IS_OK(status
)) {
659 return cli_smb2_close_fnum(cli
, fnum
);
662 /***************************************************************
663 Small wrapper that allows SMB2 to delete a directory
665 ***************************************************************/
667 NTSTATUS
cli_smb2_rmdir(struct cli_state
*cli
, const char *dname
)
672 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
674 * Can't use sync call while an async call is in flight
676 return NT_STATUS_INVALID_PARAMETER
;
679 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
680 return NT_STATUS_INVALID_PARAMETER
;
683 status
= cli_smb2_create_fnum(cli
,
685 0, /* create_flags */
686 SMB2_IMPERSONATION_IMPERSONATION
,
687 DELETE_ACCESS
, /* desired_access */
688 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
689 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
690 FILE_OPEN
, /* create_disposition */
691 FILE_DIRECTORY_FILE
, /* create_options */
695 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
697 * Naive option to match our SMB1 code. Assume the
698 * symlink path that tripped us up was the last
699 * component and try again. Eventually we will have to
700 * deal with the returned path unprocessed component. JRA.
702 status
= cli_smb2_create_fnum(cli
,
704 0, /* create_flags */
705 SMB2_IMPERSONATION_IMPERSONATION
,
706 DELETE_ACCESS
, /* desired_access */
707 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
708 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
709 FILE_OPEN
, /* create_disposition */
711 FILE_DELETE_ON_CLOSE
|
712 FILE_OPEN_REPARSE_POINT
, /* create_options */
717 if (!NT_STATUS_IS_OK(status
)) {
721 status
= cli_smb2_delete_on_close(cli
, fnum
, true);
722 if (!NT_STATUS_IS_OK(status
)) {
723 cli_smb2_close_fnum(cli
, fnum
);
727 return cli_smb2_close_fnum(cli
, fnum
);
730 /***************************************************************
731 Small wrapper that allows SMB2 to unlink a pathname.
733 ***************************************************************/
735 NTSTATUS
cli_smb2_unlink(struct cli_state
*cli
, const char *fname
)
740 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
742 * Can't use sync call while an async call is in flight
744 return NT_STATUS_INVALID_PARAMETER
;
747 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
748 return NT_STATUS_INVALID_PARAMETER
;
751 status
= cli_smb2_create_fnum(cli
,
753 0, /* create_flags */
754 SMB2_IMPERSONATION_IMPERSONATION
,
755 DELETE_ACCESS
, /* desired_access */
756 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
757 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
758 FILE_OPEN
, /* create_disposition */
759 FILE_DELETE_ON_CLOSE
, /* create_options */
763 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
765 * Naive option to match our SMB1 code. Assume the
766 * symlink path that tripped us up was the last
767 * component and try again. Eventually we will have to
768 * deal with the returned path unprocessed component. JRA.
770 status
= cli_smb2_create_fnum(cli
,
772 0, /* create_flags */
773 SMB2_IMPERSONATION_IMPERSONATION
,
774 DELETE_ACCESS
, /* desired_access */
775 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
776 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
777 FILE_OPEN
, /* create_disposition */
778 FILE_DELETE_ON_CLOSE
|
779 FILE_OPEN_REPARSE_POINT
, /* create_options */
784 if (!NT_STATUS_IS_OK(status
)) {
787 return cli_smb2_close_fnum(cli
, fnum
);
790 /***************************************************************
791 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
792 ***************************************************************/
794 static NTSTATUS
parse_finfo_id_both_directory_info(uint8_t *dir_data
,
795 uint32_t dir_data_length
,
796 struct file_info
*finfo
,
797 uint32_t *next_offset
)
803 if (dir_data_length
< 4) {
804 return NT_STATUS_INFO_LENGTH_MISMATCH
;
807 *next_offset
= IVAL(dir_data
, 0);
809 if (*next_offset
> dir_data_length
) {
810 return NT_STATUS_INFO_LENGTH_MISMATCH
;
813 if (*next_offset
!= 0) {
814 /* Ensure we only read what in this record. */
815 dir_data_length
= *next_offset
;
818 if (dir_data_length
< 105) {
819 return NT_STATUS_INFO_LENGTH_MISMATCH
;
822 finfo
->btime_ts
= interpret_long_date((const char *)dir_data
+ 8);
823 finfo
->atime_ts
= interpret_long_date((const char *)dir_data
+ 16);
824 finfo
->mtime_ts
= interpret_long_date((const char *)dir_data
+ 24);
825 finfo
->ctime_ts
= interpret_long_date((const char *)dir_data
+ 32);
826 finfo
->size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 40, 0);
827 finfo
->allocated_size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 48, 0);
828 finfo
->mode
= CVAL(dir_data
+ 56, 0);
829 finfo
->ino
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 96, 0);
830 namelen
= IVAL(dir_data
+ 60,0);
831 if (namelen
> (dir_data_length
- 104)) {
832 return NT_STATUS_INFO_LENGTH_MISMATCH
;
834 slen
= CVAL(dir_data
+ 68, 0);
836 return NT_STATUS_INFO_LENGTH_MISMATCH
;
838 ret
= pull_string_talloc(finfo
,
840 FLAGS2_UNICODE_STRINGS
,
845 if (ret
== (size_t)-1) {
846 /* Bad conversion. */
847 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
850 ret
= pull_string_talloc(finfo
,
852 FLAGS2_UNICODE_STRINGS
,
857 if (ret
== (size_t)-1) {
858 /* Bad conversion. */
859 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
864 /*******************************************************************
865 Given a filename - get its directory name
866 ********************************************************************/
868 static bool windows_parent_dirname(TALLOC_CTX
*mem_ctx
,
876 p
= strrchr_m(dir
, '\\'); /* Find final '\\', if any */
879 if (!(*parent
= talloc_strdup(mem_ctx
, "\\"))) {
890 if (!(*parent
= (char *)talloc_memdup(mem_ctx
, dir
, len
+1))) {
893 (*parent
)[len
] = '\0';
901 /***************************************************************
902 Wrapper that allows SMB2 to list a directory.
904 ***************************************************************/
906 NTSTATUS
cli_smb2_list(struct cli_state
*cli
,
907 const char *pathname
,
909 NTSTATUS (*fn
)(const char *,
916 uint16_t fnum
= 0xffff;
917 char *parent_dir
= NULL
;
918 const char *mask
= NULL
;
919 struct smb2_hnd
*ph
= NULL
;
920 bool processed_file
= false;
921 TALLOC_CTX
*frame
= talloc_stackframe();
922 TALLOC_CTX
*subframe
= NULL
;
925 uint32_t max_avail_len
;
928 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
930 * Can't use sync call while an async call is in flight
932 status
= NT_STATUS_INVALID_PARAMETER
;
936 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
937 status
= NT_STATUS_INVALID_PARAMETER
;
941 /* Get the directory name. */
942 if (!windows_parent_dirname(frame
,
946 status
= NT_STATUS_NO_MEMORY
;
950 mask_has_wild
= ms_has_wild(mask
);
952 status
= cli_smb2_create_fnum(cli
,
954 0, /* create_flags */
955 SMB2_IMPERSONATION_IMPERSONATION
,
956 SEC_DIR_LIST
|SEC_DIR_READ_ATTRIBUTE
,/* desired_access */
957 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
958 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
959 FILE_OPEN
, /* create_disposition */
960 FILE_DIRECTORY_FILE
, /* create_options */
964 if (!NT_STATUS_IS_OK(status
)) {
968 status
= map_fnum_to_smb2_handle(cli
,
971 if (!NT_STATUS_IS_OK(status
)) {
976 * ideally, use the max transaction size, but don't send a request
977 * bigger than we have credits available for
979 max_trans
= smb2cli_conn_max_trans_size(cli
->conn
);
980 ok
= smb2cli_conn_req_possible(cli
->conn
, &max_avail_len
);
982 max_trans
= MIN(max_trans
, max_avail_len
);
986 uint8_t *dir_data
= NULL
;
987 uint32_t dir_data_length
= 0;
988 uint32_t next_offset
= 0;
989 subframe
= talloc_stackframe();
991 status
= smb2cli_query_directory(cli
->conn
,
995 SMB2_FIND_ID_BOTH_DIRECTORY_INFO
,
1006 if (!NT_STATUS_IS_OK(status
)) {
1007 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
1014 struct file_info
*finfo
= talloc_zero(subframe
,
1017 if (finfo
== NULL
) {
1018 status
= NT_STATUS_NO_MEMORY
;
1022 status
= parse_finfo_id_both_directory_info(dir_data
,
1027 if (!NT_STATUS_IS_OK(status
)) {
1031 if (dir_check_ftype((uint32_t)finfo
->mode
,
1032 (uint32_t)attribute
)) {
1034 * Only process if attributes match.
1035 * On SMB1 server does this, so on
1036 * SMB2 we need to emulate in the
1039 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1041 processed_file
= true;
1043 status
= fn(cli
->dfs_mountpoint
,
1048 if (!NT_STATUS_IS_OK(status
)) {
1055 /* Move to next entry. */
1057 dir_data
+= next_offset
;
1058 dir_data_length
-= next_offset
;
1060 } while (next_offset
!= 0);
1062 TALLOC_FREE(subframe
);
1064 if (!mask_has_wild
) {
1066 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1067 * when handed a non-wildcard path. Do it
1068 * for the server (with a non-wildcard path
1069 * there should only ever be one file returned.
1071 status
= STATUS_NO_MORE_FILES
;
1075 } while (NT_STATUS_IS_OK(status
));
1077 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
1078 status
= NT_STATUS_OK
;
1081 if (NT_STATUS_IS_OK(status
) && !processed_file
) {
1083 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1084 * if no files match. Emulate this in the client.
1086 status
= NT_STATUS_NO_SUCH_FILE
;
1091 if (fnum
!= 0xffff) {
1092 cli_smb2_close_fnum(cli
, fnum
);
1095 cli
->raw_status
= status
;
1097 TALLOC_FREE(subframe
);
1102 /***************************************************************
1103 Wrapper that allows SMB2 to query a path info (basic level).
1105 ***************************************************************/
1107 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
1109 SMB_STRUCT_STAT
*sbuf
,
1110 uint32_t *attributes
)
1113 struct smb_create_returns cr
;
1114 uint16_t fnum
= 0xffff;
1115 size_t namelen
= strlen(name
);
1117 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1119 * Can't use sync call while an async call is in flight
1121 return NT_STATUS_INVALID_PARAMETER
;
1124 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1125 return NT_STATUS_INVALID_PARAMETER
;
1128 /* SMB2 is pickier about pathnames. Ensure it doesn't
1130 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1131 char *modname
= talloc_strdup(talloc_tos(), name
);
1132 modname
[namelen
-1] = '\0';
1136 /* This is commonly used as a 'cd'. Try qpathinfo on
1137 a directory handle first. */
1139 status
= cli_smb2_create_fnum(cli
,
1141 0, /* create_flags */
1142 SMB2_IMPERSONATION_IMPERSONATION
,
1143 FILE_READ_ATTRIBUTES
, /* desired_access */
1144 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1145 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1146 FILE_OPEN
, /* create_disposition */
1147 FILE_DIRECTORY_FILE
, /* create_options */
1151 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
1152 /* Maybe a file ? */
1153 status
= cli_smb2_create_fnum(cli
,
1155 0, /* create_flags */
1156 SMB2_IMPERSONATION_IMPERSONATION
,
1157 FILE_READ_ATTRIBUTES
, /* desired_access */
1158 0, /* file attributes */
1159 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1160 FILE_OPEN
, /* create_disposition */
1161 0, /* create_options */
1166 if (!NT_STATUS_IS_OK(status
)) {
1170 status
= cli_smb2_close_fnum(cli
, fnum
);
1174 sbuf
->st_ex_atime
= nt_time_to_unix_timespec(cr
.last_access_time
);
1175 sbuf
->st_ex_mtime
= nt_time_to_unix_timespec(cr
.last_write_time
);
1176 sbuf
->st_ex_ctime
= nt_time_to_unix_timespec(cr
.change_time
);
1177 sbuf
->st_ex_size
= cr
.end_of_file
;
1178 *attributes
= cr
.file_attributes
;
1183 /***************************************************************
1184 Wrapper that allows SMB2 to check if a path is a directory.
1186 ***************************************************************/
1188 NTSTATUS
cli_smb2_chkpath(struct cli_state
*cli
,
1192 uint16_t fnum
= 0xffff;
1194 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1196 * Can't use sync call while an async call is in flight
1198 return NT_STATUS_INVALID_PARAMETER
;
1201 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1202 return NT_STATUS_INVALID_PARAMETER
;
1205 /* Ensure this is a directory. */
1206 status
= cli_smb2_create_fnum(cli
,
1208 0, /* create_flags */
1209 SMB2_IMPERSONATION_IMPERSONATION
,
1210 FILE_READ_ATTRIBUTES
, /* desired_access */
1211 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1212 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1213 FILE_OPEN
, /* create_disposition */
1214 FILE_DIRECTORY_FILE
, /* create_options */
1218 if (!NT_STATUS_IS_OK(status
)) {
1222 return cli_smb2_close_fnum(cli
, fnum
);
1225 /***************************************************************
1226 Helper function for pathname operations.
1227 ***************************************************************/
1229 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
1231 uint32_t desired_access
,
1235 size_t namelen
= strlen(name
);
1236 TALLOC_CTX
*frame
= talloc_stackframe();
1237 uint32_t create_options
= 0;
1239 /* SMB2 is pickier about pathnames. Ensure it doesn't
1241 if (namelen
> 0 && name
[namelen
-1] == '\\') {
1242 char *modname
= talloc_strdup(frame
, name
);
1243 if (modname
== NULL
) {
1244 status
= NT_STATUS_NO_MEMORY
;
1247 modname
[namelen
-1] = '\0';
1251 /* Try to open a file handle first. */
1252 status
= cli_smb2_create_fnum(cli
,
1254 0, /* create_flags */
1255 SMB2_IMPERSONATION_IMPERSONATION
,
1257 0, /* file attributes */
1258 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1259 FILE_OPEN
, /* create_disposition */
1264 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
1266 * Naive option to match our SMB1 code. Assume the
1267 * symlink path that tripped us up was the last
1268 * component and try again. Eventually we will have to
1269 * deal with the returned path unprocessed component. JRA.
1271 create_options
|= FILE_OPEN_REPARSE_POINT
;
1272 status
= cli_smb2_create_fnum(cli
,
1274 0, /* create_flags */
1275 SMB2_IMPERSONATION_IMPERSONATION
,
1277 0, /* file attributes */
1278 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1279 FILE_OPEN
, /* create_disposition */
1285 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
1286 create_options
|= FILE_DIRECTORY_FILE
;
1287 status
= cli_smb2_create_fnum(cli
,
1289 0, /* create_flags */
1290 SMB2_IMPERSONATION_IMPERSONATION
,
1292 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1293 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1294 FILE_OPEN
, /* create_disposition */
1295 FILE_DIRECTORY_FILE
, /* create_options */
1306 /***************************************************************
1307 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1309 ***************************************************************/
1311 NTSTATUS
cli_smb2_qpathinfo_alt_name(struct cli_state
*cli
,
1316 DATA_BLOB outbuf
= data_blob_null
;
1317 uint16_t fnum
= 0xffff;
1318 struct smb2_hnd
*ph
= NULL
;
1319 uint32_t altnamelen
= 0;
1320 TALLOC_CTX
*frame
= talloc_stackframe();
1322 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1324 * Can't use sync call while an async call is in flight
1326 status
= NT_STATUS_INVALID_PARAMETER
;
1330 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1331 status
= NT_STATUS_INVALID_PARAMETER
;
1335 status
= get_fnum_from_path(cli
,
1337 FILE_READ_ATTRIBUTES
,
1340 if (!NT_STATUS_IS_OK(status
)) {
1344 status
= map_fnum_to_smb2_handle(cli
,
1347 if (!NT_STATUS_IS_OK(status
)) {
1351 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1352 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1354 status
= smb2cli_query_info(cli
->conn
,
1358 1, /* in_info_type */
1359 (SMB_FILE_ALTERNATE_NAME_INFORMATION
- 1000), /* in_file_info_class */
1360 0xFFFF, /* in_max_output_length */
1361 NULL
, /* in_input_buffer */
1362 0, /* in_additional_info */
1369 if (!NT_STATUS_IS_OK(status
)) {
1373 /* Parse the reply. */
1374 if (outbuf
.length
< 4) {
1375 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1379 altnamelen
= IVAL(outbuf
.data
, 0);
1380 if (altnamelen
> outbuf
.length
- 4) {
1381 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1385 if (altnamelen
> 0) {
1387 char *short_name
= NULL
;
1388 ret
= pull_string_talloc(frame
,
1390 FLAGS2_UNICODE_STRINGS
,
1395 if (ret
== (size_t)-1) {
1396 /* Bad conversion. */
1397 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1401 fstrcpy(alt_name
, short_name
);
1406 status
= NT_STATUS_OK
;
1410 if (fnum
!= 0xffff) {
1411 cli_smb2_close_fnum(cli
, fnum
);
1414 cli
->raw_status
= status
;
1421 /***************************************************************
1422 Wrapper that allows SMB2 to query a fnum info (basic level).
1424 ***************************************************************/
1426 NTSTATUS
cli_smb2_qfileinfo_basic(struct cli_state
*cli
,
1430 struct timespec
*create_time
,
1431 struct timespec
*access_time
,
1432 struct timespec
*write_time
,
1433 struct timespec
*change_time
,
1437 DATA_BLOB outbuf
= data_blob_null
;
1438 struct smb2_hnd
*ph
= NULL
;
1439 TALLOC_CTX
*frame
= talloc_stackframe();
1441 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1443 * Can't use sync call while an async call is in flight
1445 status
= NT_STATUS_INVALID_PARAMETER
;
1449 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1450 status
= NT_STATUS_INVALID_PARAMETER
;
1454 status
= map_fnum_to_smb2_handle(cli
,
1457 if (!NT_STATUS_IS_OK(status
)) {
1461 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1462 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1464 status
= smb2cli_query_info(cli
->conn
,
1468 1, /* in_info_type */
1469 (SMB_FILE_ALL_INFORMATION
- 1000), /* in_file_info_class */
1470 0xFFFF, /* in_max_output_length */
1471 NULL
, /* in_input_buffer */
1472 0, /* in_additional_info */
1478 if (!NT_STATUS_IS_OK(status
)) {
1482 /* Parse the reply. */
1483 if (outbuf
.length
< 0x60) {
1484 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1489 *create_time
= interpret_long_date((const char *)outbuf
.data
+ 0x0);
1492 *access_time
= interpret_long_date((const char *)outbuf
.data
+ 0x8);
1495 *write_time
= interpret_long_date((const char *)outbuf
.data
+ 0x10);
1498 *change_time
= interpret_long_date((const char *)outbuf
.data
+ 0x18);
1501 uint32_t attr
= IVAL(outbuf
.data
, 0x20);
1502 *mode
= (uint16_t)attr
;
1505 uint64_t file_size
= BVAL(outbuf
.data
, 0x30);
1506 *size
= (off_t
)file_size
;
1509 uint64_t file_index
= BVAL(outbuf
.data
, 0x40);
1510 *ino
= (SMB_INO_T
)file_index
;
1515 cli
->raw_status
= status
;
1521 /***************************************************************
1522 Wrapper that allows SMB2 to query an fnum.
1523 Implement on top of cli_smb2_qfileinfo_basic().
1525 ***************************************************************/
1527 NTSTATUS
cli_smb2_getattrE(struct cli_state
*cli
,
1531 time_t *change_time
,
1532 time_t *access_time
,
1535 struct timespec access_time_ts
;
1536 struct timespec write_time_ts
;
1537 struct timespec change_time_ts
;
1538 NTSTATUS status
= cli_smb2_qfileinfo_basic(cli
,
1548 cli
->raw_status
= status
;
1550 if (!NT_STATUS_IS_OK(status
)) {
1555 *change_time
= change_time_ts
.tv_sec
;
1558 *access_time
= access_time_ts
.tv_sec
;
1561 *write_time
= write_time_ts
.tv_sec
;
1563 return NT_STATUS_OK
;
1566 /***************************************************************
1567 Wrapper that allows SMB2 to get pathname attributes.
1569 ***************************************************************/
1571 NTSTATUS
cli_smb2_getatr(struct cli_state
*cli
,
1578 uint16_t fnum
= 0xffff;
1579 struct smb2_hnd
*ph
= NULL
;
1580 TALLOC_CTX
*frame
= talloc_stackframe();
1582 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1584 * Can't use sync call while an async call is in flight
1586 status
= NT_STATUS_INVALID_PARAMETER
;
1590 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1591 status
= NT_STATUS_INVALID_PARAMETER
;
1595 status
= get_fnum_from_path(cli
,
1597 FILE_READ_ATTRIBUTES
,
1600 if (!NT_STATUS_IS_OK(status
)) {
1604 status
= map_fnum_to_smb2_handle(cli
,
1607 if (!NT_STATUS_IS_OK(status
)) {
1610 status
= cli_smb2_getattrE(cli
,
1617 if (!NT_STATUS_IS_OK(status
)) {
1623 if (fnum
!= 0xffff) {
1624 cli_smb2_close_fnum(cli
, fnum
);
1627 cli
->raw_status
= status
;
1633 /***************************************************************
1634 Wrapper that allows SMB2 to query a pathname info (basic level).
1635 Implement on top of cli_smb2_qfileinfo_basic().
1637 ***************************************************************/
1639 NTSTATUS
cli_smb2_qpathinfo2(struct cli_state
*cli
,
1641 struct timespec
*create_time
,
1642 struct timespec
*access_time
,
1643 struct timespec
*write_time
,
1644 struct timespec
*change_time
,
1650 struct smb2_hnd
*ph
= NULL
;
1651 uint16_t fnum
= 0xffff;
1652 TALLOC_CTX
*frame
= talloc_stackframe();
1654 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1656 * Can't use sync call while an async call is in flight
1658 status
= NT_STATUS_INVALID_PARAMETER
;
1662 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1663 status
= NT_STATUS_INVALID_PARAMETER
;
1667 status
= get_fnum_from_path(cli
,
1669 FILE_READ_ATTRIBUTES
,
1672 if (!NT_STATUS_IS_OK(status
)) {
1676 status
= map_fnum_to_smb2_handle(cli
,
1679 if (!NT_STATUS_IS_OK(status
)) {
1683 status
= cli_smb2_qfileinfo_basic(cli
,
1695 if (fnum
!= 0xffff) {
1696 cli_smb2_close_fnum(cli
, fnum
);
1699 cli
->raw_status
= status
;
1705 /***************************************************************
1706 Wrapper that allows SMB2 to query pathname streams.
1708 ***************************************************************/
1710 NTSTATUS
cli_smb2_qpathinfo_streams(struct cli_state
*cli
,
1712 TALLOC_CTX
*mem_ctx
,
1713 unsigned int *pnum_streams
,
1714 struct stream_struct
**pstreams
)
1717 struct smb2_hnd
*ph
= NULL
;
1718 uint16_t fnum
= 0xffff;
1719 DATA_BLOB outbuf
= data_blob_null
;
1720 TALLOC_CTX
*frame
= talloc_stackframe();
1722 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1724 * Can't use sync call while an async call is in flight
1726 status
= NT_STATUS_INVALID_PARAMETER
;
1730 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1731 status
= NT_STATUS_INVALID_PARAMETER
;
1735 status
= get_fnum_from_path(cli
,
1737 FILE_READ_ATTRIBUTES
,
1740 if (!NT_STATUS_IS_OK(status
)) {
1744 status
= map_fnum_to_smb2_handle(cli
,
1747 if (!NT_STATUS_IS_OK(status
)) {
1751 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1752 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1754 status
= smb2cli_query_info(cli
->conn
,
1758 1, /* in_info_type */
1759 (SMB_FILE_STREAM_INFORMATION
- 1000), /* in_file_info_class */
1760 0xFFFF, /* in_max_output_length */
1761 NULL
, /* in_input_buffer */
1762 0, /* in_additional_info */
1769 if (!NT_STATUS_IS_OK(status
)) {
1773 /* Parse the reply. */
1774 if (!parse_streams_blob(mem_ctx
,
1779 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1785 if (fnum
!= 0xffff) {
1786 cli_smb2_close_fnum(cli
, fnum
);
1789 cli
->raw_status
= status
;
1795 /***************************************************************
1796 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
1799 ***************************************************************/
1801 NTSTATUS
cli_smb2_setpathinfo(struct cli_state
*cli
,
1803 uint8_t in_info_type
,
1804 uint8_t in_file_info_class
,
1805 const DATA_BLOB
*p_in_data
)
1808 uint16_t fnum
= 0xffff;
1809 struct smb2_hnd
*ph
= NULL
;
1810 TALLOC_CTX
*frame
= talloc_stackframe();
1812 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1814 * Can't use sync call while an async call is in flight
1816 status
= NT_STATUS_INVALID_PARAMETER
;
1820 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1821 status
= NT_STATUS_INVALID_PARAMETER
;
1825 status
= get_fnum_from_path(cli
,
1827 FILE_WRITE_ATTRIBUTES
,
1830 if (!NT_STATUS_IS_OK(status
)) {
1834 status
= map_fnum_to_smb2_handle(cli
,
1837 if (!NT_STATUS_IS_OK(status
)) {
1841 status
= smb2cli_set_info(cli
->conn
,
1847 p_in_data
, /* in_input_buffer */
1848 0, /* in_additional_info */
1853 if (fnum
!= 0xffff) {
1854 cli_smb2_close_fnum(cli
, fnum
);
1857 cli
->raw_status
= status
;
1864 /***************************************************************
1865 Wrapper that allows SMB2 to set pathname attributes.
1867 ***************************************************************/
1869 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
1874 uint8_t inbuf_store
[40];
1875 DATA_BLOB inbuf
= data_blob_null
;
1877 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1878 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1880 inbuf
.data
= inbuf_store
;
1881 inbuf
.length
= sizeof(inbuf_store
);
1882 data_blob_clear(&inbuf
);
1885 * SMB1 uses attr == 0 to clear all attributes
1886 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
1887 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
1888 * request attribute change.
1890 * SMB2 uses exactly the reverse. Unfortunately as the
1891 * cli_setatr() ABI is exposed inside libsmbclient,
1892 * we must make the SMB2 cli_smb2_setatr() call
1893 * export the same ABI as the SMB1 cli_setatr()
1894 * which calls it. This means reversing the sense
1895 * of the requested attr argument if it's zero
1896 * or FILE_ATTRIBUTE_NORMAL.
1898 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
1902 attr
= FILE_ATTRIBUTE_NORMAL
;
1903 } else if (attr
== FILE_ATTRIBUTE_NORMAL
) {
1907 SSVAL(inbuf
.data
, 32, attr
);
1909 put_long_date((char *)inbuf
.data
+ 16,mtime
);
1911 /* Set all the other times to -1. */
1912 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1913 SBVAL(inbuf
.data
, 8, 0xFFFFFFFFFFFFFFFFLL
);
1914 SBVAL(inbuf
.data
, 24, 0xFFFFFFFFFFFFFFFFLL
);
1916 return cli_smb2_setpathinfo(cli
,
1918 1, /* in_info_type */
1919 /* in_file_info_class */
1920 SMB_FILE_BASIC_INFORMATION
- 1000,
1925 /***************************************************************
1926 Wrapper that allows SMB2 to set file handle times.
1928 ***************************************************************/
1930 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
1937 struct smb2_hnd
*ph
= NULL
;
1938 uint8_t inbuf_store
[40];
1939 DATA_BLOB inbuf
= data_blob_null
;
1941 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1943 * Can't use sync call while an async call is in flight
1945 return NT_STATUS_INVALID_PARAMETER
;
1948 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1949 return NT_STATUS_INVALID_PARAMETER
;
1952 status
= map_fnum_to_smb2_handle(cli
,
1955 if (!NT_STATUS_IS_OK(status
)) {
1959 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1960 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1962 inbuf
.data
= inbuf_store
;
1963 inbuf
.length
= sizeof(inbuf_store
);
1964 data_blob_clear(&inbuf
);
1966 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1967 if (change_time
!= 0) {
1968 put_long_date((char *)inbuf
.data
+ 24, change_time
);
1970 if (access_time
!= 0) {
1971 put_long_date((char *)inbuf
.data
+ 8, access_time
);
1973 if (write_time
!= 0) {
1974 put_long_date((char *)inbuf
.data
+ 16, write_time
);
1977 cli
->raw_status
= smb2cli_set_info(cli
->conn
,
1981 1, /* in_info_type */
1982 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1983 &inbuf
, /* in_input_buffer */
1984 0, /* in_additional_info */
1988 return cli
->raw_status
;
1991 /***************************************************************
1992 Wrapper that allows SMB2 to query disk attributes (size).
1994 ***************************************************************/
1996 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, const char *path
,
1997 uint64_t *bsize
, uint64_t *total
, uint64_t *avail
)
2000 uint16_t fnum
= 0xffff;
2001 DATA_BLOB outbuf
= data_blob_null
;
2002 struct smb2_hnd
*ph
= NULL
;
2003 uint32_t sectors_per_unit
= 0;
2004 uint32_t bytes_per_sector
= 0;
2005 uint64_t total_size
= 0;
2006 uint64_t size_free
= 0;
2007 TALLOC_CTX
*frame
= talloc_stackframe();
2009 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2011 * Can't use sync call while an async call is in flight
2013 status
= NT_STATUS_INVALID_PARAMETER
;
2017 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2018 status
= NT_STATUS_INVALID_PARAMETER
;
2022 /* First open the top level directory. */
2023 status
= cli_smb2_create_fnum(cli
,
2025 0, /* create_flags */
2026 SMB2_IMPERSONATION_IMPERSONATION
,
2027 FILE_READ_ATTRIBUTES
, /* desired_access */
2028 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2029 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
2030 FILE_OPEN
, /* create_disposition */
2031 FILE_DIRECTORY_FILE
, /* create_options */
2035 if (!NT_STATUS_IS_OK(status
)) {
2039 status
= map_fnum_to_smb2_handle(cli
,
2042 if (!NT_STATUS_IS_OK(status
)) {
2046 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2047 level 3 (SMB_FS_SIZE_INFORMATION). */
2049 status
= smb2cli_query_info(cli
->conn
,
2053 2, /* in_info_type */
2054 3, /* in_file_info_class */
2055 0xFFFF, /* in_max_output_length */
2056 NULL
, /* in_input_buffer */
2057 0, /* in_additional_info */
2063 if (!NT_STATUS_IS_OK(status
)) {
2067 /* Parse the reply. */
2068 if (outbuf
.length
!= 24) {
2069 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2073 total_size
= BVAL(outbuf
.data
, 0);
2074 size_free
= BVAL(outbuf
.data
, 8);
2075 sectors_per_unit
= IVAL(outbuf
.data
, 16);
2076 bytes_per_sector
= IVAL(outbuf
.data
, 20);
2079 *bsize
= (uint64_t)sectors_per_unit
* (uint64_t)bytes_per_sector
;
2082 *total
= total_size
;
2088 status
= NT_STATUS_OK
;
2092 if (fnum
!= 0xffff) {
2093 cli_smb2_close_fnum(cli
, fnum
);
2096 cli
->raw_status
= status
;
2102 /***************************************************************
2103 Wrapper that allows SMB2 to query file system sizes.
2105 ***************************************************************/
2107 NTSTATUS
cli_smb2_get_fs_full_size_info(struct cli_state
*cli
,
2108 uint64_t *total_allocation_units
,
2109 uint64_t *caller_allocation_units
,
2110 uint64_t *actual_allocation_units
,
2111 uint64_t *sectors_per_allocation_unit
,
2112 uint64_t *bytes_per_sector
)
2115 uint16_t fnum
= 0xffff;
2116 DATA_BLOB outbuf
= data_blob_null
;
2117 struct smb2_hnd
*ph
= NULL
;
2118 TALLOC_CTX
*frame
= talloc_stackframe();
2120 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2122 * Can't use sync call while an async call is in flight
2124 status
= NT_STATUS_INVALID_PARAMETER
;
2128 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2129 status
= NT_STATUS_INVALID_PARAMETER
;
2133 /* First open the top level directory. */
2135 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2136 SMB2_IMPERSONATION_IMPERSONATION
,
2137 FILE_READ_ATTRIBUTES
, /* desired_access */
2138 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2139 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2140 FILE_SHARE_DELETE
, /* share_access */
2141 FILE_OPEN
, /* create_disposition */
2142 FILE_DIRECTORY_FILE
, /* create_options */
2146 if (!NT_STATUS_IS_OK(status
)) {
2150 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
2151 if (!NT_STATUS_IS_OK(status
)) {
2155 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2156 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2158 status
= smb2cli_query_info(cli
->conn
,
2162 SMB2_GETINFO_FS
, /* in_info_type */
2163 /* in_file_info_class */
2164 SMB_FS_FULL_SIZE_INFORMATION
- 1000,
2165 0xFFFF, /* in_max_output_length */
2166 NULL
, /* in_input_buffer */
2167 0, /* in_additional_info */
2173 if (!NT_STATUS_IS_OK(status
)) {
2177 if (outbuf
.length
< 32) {
2178 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2182 *total_allocation_units
= BIG_UINT(outbuf
.data
, 0);
2183 *caller_allocation_units
= BIG_UINT(outbuf
.data
, 8);
2184 *actual_allocation_units
= BIG_UINT(outbuf
.data
, 16);
2185 *sectors_per_allocation_unit
= (uint64_t)IVAL(outbuf
.data
, 24);
2186 *bytes_per_sector
= (uint64_t)IVAL(outbuf
.data
, 28);
2190 if (fnum
!= 0xffff) {
2191 cli_smb2_close_fnum(cli
, fnum
);
2194 cli
->raw_status
= status
;
2200 /***************************************************************
2201 Wrapper that allows SMB2 to query file system attributes.
2203 ***************************************************************/
2205 NTSTATUS
cli_smb2_get_fs_attr_info(struct cli_state
*cli
, uint32_t *fs_attr
)
2208 uint16_t fnum
= 0xffff;
2209 DATA_BLOB outbuf
= data_blob_null
;
2210 struct smb2_hnd
*ph
= NULL
;
2211 TALLOC_CTX
*frame
= talloc_stackframe();
2213 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2215 * Can't use sync call while an async call is in flight
2217 status
= NT_STATUS_INVALID_PARAMETER
;
2221 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2222 status
= NT_STATUS_INVALID_PARAMETER
;
2226 /* First open the top level directory. */
2228 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2229 SMB2_IMPERSONATION_IMPERSONATION
,
2230 FILE_READ_ATTRIBUTES
, /* desired_access */
2231 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2232 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2233 FILE_SHARE_DELETE
, /* share_access */
2234 FILE_OPEN
, /* create_disposition */
2235 FILE_DIRECTORY_FILE
, /* create_options */
2239 if (!NT_STATUS_IS_OK(status
)) {
2243 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
2244 if (!NT_STATUS_IS_OK(status
)) {
2248 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
2249 cli
->smb2
.tcon
, 2, /* in_info_type */
2250 5, /* in_file_info_class */
2251 0xFFFF, /* in_max_output_length */
2252 NULL
, /* in_input_buffer */
2253 0, /* in_additional_info */
2255 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
2257 if (!NT_STATUS_IS_OK(status
)) {
2261 if (outbuf
.length
< 12) {
2262 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2266 *fs_attr
= IVAL(outbuf
.data
, 0);
2270 if (fnum
!= 0xffff) {
2271 cli_smb2_close_fnum(cli
, fnum
);
2274 cli
->raw_status
= status
;
2280 /***************************************************************
2281 Wrapper that allows SMB2 to query file system volume info.
2283 ***************************************************************/
2285 NTSTATUS
cli_smb2_get_fs_volume_info(struct cli_state
*cli
,
2286 TALLOC_CTX
*mem_ctx
,
2287 char **_volume_name
,
2288 uint32_t *pserial_number
,
2292 uint16_t fnum
= 0xffff;
2293 DATA_BLOB outbuf
= data_blob_null
;
2294 struct smb2_hnd
*ph
= NULL
;
2296 char *volume_name
= NULL
;
2297 TALLOC_CTX
*frame
= talloc_stackframe();
2299 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2301 * Can't use sync call while an async call is in flight
2303 status
= NT_STATUS_INVALID_PARAMETER
;
2307 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2308 status
= NT_STATUS_INVALID_PARAMETER
;
2312 /* First open the top level directory. */
2314 cli_smb2_create_fnum(cli
, "", 0, /* create_flags */
2315 SMB2_IMPERSONATION_IMPERSONATION
,
2316 FILE_READ_ATTRIBUTES
, /* desired_access */
2317 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
2318 FILE_SHARE_READ
| FILE_SHARE_WRITE
|
2319 FILE_SHARE_DELETE
, /* share_access */
2320 FILE_OPEN
, /* create_disposition */
2321 FILE_DIRECTORY_FILE
, /* create_options */
2325 if (!NT_STATUS_IS_OK(status
)) {
2329 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
2330 if (!NT_STATUS_IS_OK(status
)) {
2334 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2335 level 1 (SMB_FS_VOLUME_INFORMATION). */
2337 status
= smb2cli_query_info(cli
->conn
,
2341 SMB2_GETINFO_FS
, /* in_info_type */
2342 /* in_file_info_class */
2343 SMB_FS_VOLUME_INFORMATION
- 1000,
2344 0xFFFF, /* in_max_output_length */
2345 NULL
, /* in_input_buffer */
2346 0, /* in_additional_info */
2352 if (!NT_STATUS_IS_OK(status
)) {
2356 if (outbuf
.length
< 24) {
2357 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2363 ts
= interpret_long_date((char *)outbuf
.data
);
2366 if (pserial_number
) {
2367 *pserial_number
= IVAL(outbuf
.data
,8);
2369 nlen
= IVAL(outbuf
.data
,12);
2370 if (nlen
+ 18 < 18) {
2372 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2376 * The next check is safe as we know outbuf.length >= 24
2379 if (nlen
> (outbuf
.length
- 18)) {
2380 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2384 clistr_pull_talloc(mem_ctx
,
2385 (const char *)outbuf
.data
,
2391 if (volume_name
== NULL
) {
2392 status
= map_nt_error_from_unix(errno
);
2396 *_volume_name
= volume_name
;
2400 if (fnum
!= 0xffff) {
2401 cli_smb2_close_fnum(cli
, fnum
);
2404 cli
->raw_status
= status
;
2411 /***************************************************************
2412 Wrapper that allows SMB2 to query a security descriptor.
2414 ***************************************************************/
2416 NTSTATUS
cli_smb2_query_security_descriptor(struct cli_state
*cli
,
2419 TALLOC_CTX
*mem_ctx
,
2420 struct security_descriptor
**ppsd
)
2423 DATA_BLOB outbuf
= data_blob_null
;
2424 struct smb2_hnd
*ph
= NULL
;
2425 struct security_descriptor
*lsd
= NULL
;
2426 TALLOC_CTX
*frame
= talloc_stackframe();
2428 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2430 * Can't use sync call while an async call is in flight
2432 status
= NT_STATUS_INVALID_PARAMETER
;
2436 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2437 status
= NT_STATUS_INVALID_PARAMETER
;
2441 status
= map_fnum_to_smb2_handle(cli
,
2444 if (!NT_STATUS_IS_OK(status
)) {
2448 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2450 status
= smb2cli_query_info(cli
->conn
,
2454 3, /* in_info_type */
2455 0, /* in_file_info_class */
2456 0xFFFF, /* in_max_output_length */
2457 NULL
, /* in_input_buffer */
2458 sec_info
, /* in_additional_info */
2465 if (!NT_STATUS_IS_OK(status
)) {
2469 /* Parse the reply. */
2470 status
= unmarshall_sec_desc(mem_ctx
,
2475 if (!NT_STATUS_IS_OK(status
)) {
2487 cli
->raw_status
= status
;
2493 /***************************************************************
2494 Wrapper that allows SMB2 to set a security descriptor.
2496 ***************************************************************/
2498 NTSTATUS
cli_smb2_set_security_descriptor(struct cli_state
*cli
,
2501 const struct security_descriptor
*sd
)
2504 DATA_BLOB inbuf
= data_blob_null
;
2505 struct smb2_hnd
*ph
= NULL
;
2506 TALLOC_CTX
*frame
= talloc_stackframe();
2508 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2510 * Can't use sync call while an async call is in flight
2512 status
= NT_STATUS_INVALID_PARAMETER
;
2516 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2517 status
= NT_STATUS_INVALID_PARAMETER
;
2521 status
= map_fnum_to_smb2_handle(cli
,
2524 if (!NT_STATUS_IS_OK(status
)) {
2528 status
= marshall_sec_desc(frame
,
2533 if (!NT_STATUS_IS_OK(status
)) {
2537 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2539 status
= smb2cli_set_info(cli
->conn
,
2543 3, /* in_info_type */
2544 0, /* in_file_info_class */
2545 &inbuf
, /* in_input_buffer */
2546 sec_info
, /* in_additional_info */
2552 cli
->raw_status
= status
;
2558 /***************************************************************
2559 Wrapper that allows SMB2 to rename a file.
2561 ***************************************************************/
2563 NTSTATUS
cli_smb2_rename(struct cli_state
*cli
,
2564 const char *fname_src
,
2565 const char *fname_dst
,
2569 DATA_BLOB inbuf
= data_blob_null
;
2570 uint16_t fnum
= 0xffff;
2571 struct smb2_hnd
*ph
= NULL
;
2572 smb_ucs2_t
*converted_str
= NULL
;
2573 size_t converted_size_bytes
= 0;
2575 TALLOC_CTX
*frame
= talloc_stackframe();
2577 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2579 * Can't use sync call while an async call is in flight
2581 status
= NT_STATUS_INVALID_PARAMETER
;
2585 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2586 status
= NT_STATUS_INVALID_PARAMETER
;
2590 status
= get_fnum_from_path(cli
,
2595 if (!NT_STATUS_IS_OK(status
)) {
2599 status
= map_fnum_to_smb2_handle(cli
,
2602 if (!NT_STATUS_IS_OK(status
)) {
2606 /* SMB2 is pickier about pathnames. Ensure it doesn't
2608 if (*fname_dst
== '\\') {
2612 /* SMB2 is pickier about pathnames. Ensure it doesn't
2614 namelen
= strlen(fname_dst
);
2615 if (namelen
> 0 && fname_dst
[namelen
-1] == '\\') {
2616 char *modname
= talloc_strdup(frame
, fname_dst
);
2617 modname
[namelen
-1] = '\0';
2618 fname_dst
= modname
;
2621 if (!push_ucs2_talloc(frame
,
2624 &converted_size_bytes
)) {
2625 status
= NT_STATUS_INVALID_PARAMETER
;
2629 /* W2K8 insists the dest name is not null
2630 terminated. Remove the last 2 zero bytes
2631 and reduce the name length. */
2633 if (converted_size_bytes
< 2) {
2634 status
= NT_STATUS_INVALID_PARAMETER
;
2637 converted_size_bytes
-= 2;
2639 inbuf
= data_blob_talloc_zero(frame
,
2640 20 + converted_size_bytes
);
2641 if (inbuf
.data
== NULL
) {
2642 status
= NT_STATUS_NO_MEMORY
;
2647 SCVAL(inbuf
.data
, 0, 1);
2650 SIVAL(inbuf
.data
, 16, converted_size_bytes
);
2651 memcpy(inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
2653 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2654 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2656 status
= smb2cli_set_info(cli
->conn
,
2660 1, /* in_info_type */
2661 SMB_FILE_RENAME_INFORMATION
- 1000, /* in_file_info_class */
2662 &inbuf
, /* in_input_buffer */
2663 0, /* in_additional_info */
2669 if (fnum
!= 0xffff) {
2670 cli_smb2_close_fnum(cli
, fnum
);
2673 cli
->raw_status
= status
;
2679 /***************************************************************
2680 Wrapper that allows SMB2 to set an EA on a fnum.
2682 ***************************************************************/
2684 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
2686 const char *ea_name
,
2691 DATA_BLOB inbuf
= data_blob_null
;
2693 char *ea_name_ascii
= NULL
;
2695 struct smb2_hnd
*ph
= NULL
;
2696 TALLOC_CTX
*frame
= talloc_stackframe();
2698 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2700 * Can't use sync call while an async call is in flight
2702 status
= NT_STATUS_INVALID_PARAMETER
;
2706 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2707 status
= NT_STATUS_INVALID_PARAMETER
;
2711 status
= map_fnum_to_smb2_handle(cli
,
2714 if (!NT_STATUS_IS_OK(status
)) {
2718 /* Marshall the SMB2 EA data. */
2719 if (ea_len
> 0xFFFF) {
2720 status
= NT_STATUS_INVALID_PARAMETER
;
2724 if (!push_ascii_talloc(frame
,
2728 status
= NT_STATUS_INVALID_PARAMETER
;
2732 if (namelen
< 2 || namelen
> 0xFF) {
2733 status
= NT_STATUS_INVALID_PARAMETER
;
2737 bloblen
= 8 + ea_len
+ namelen
;
2738 /* Round up to a 4 byte boundary. */
2739 bloblen
= ((bloblen
+ 3)&~3);
2741 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
2742 if (inbuf
.data
== NULL
) {
2743 status
= NT_STATUS_NO_MEMORY
;
2746 /* namelen doesn't include the NULL byte. */
2747 SCVAL(inbuf
.data
, 5, namelen
- 1);
2748 SSVAL(inbuf
.data
, 6, ea_len
);
2749 memcpy(inbuf
.data
+ 8, ea_name_ascii
, namelen
);
2750 memcpy(inbuf
.data
+ 8 + namelen
, ea_val
, ea_len
);
2752 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2753 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2755 status
= smb2cli_set_info(cli
->conn
,
2759 1, /* in_info_type */
2760 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
2761 &inbuf
, /* in_input_buffer */
2762 0, /* in_additional_info */
2768 cli
->raw_status
= status
;
2774 /***************************************************************
2775 Wrapper that allows SMB2 to set an EA on a pathname.
2777 ***************************************************************/
2779 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
2781 const char *ea_name
,
2786 uint16_t fnum
= 0xffff;
2788 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2790 * Can't use sync call while an async call is in flight
2792 status
= NT_STATUS_INVALID_PARAMETER
;
2796 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2797 status
= NT_STATUS_INVALID_PARAMETER
;
2801 status
= get_fnum_from_path(cli
,
2806 if (!NT_STATUS_IS_OK(status
)) {
2810 status
= cli_set_ea_fnum(cli
,
2815 if (!NT_STATUS_IS_OK(status
)) {
2821 if (fnum
!= 0xffff) {
2822 cli_smb2_close_fnum(cli
, fnum
);
2825 cli
->raw_status
= status
;
2830 /***************************************************************
2831 Wrapper that allows SMB2 to get an EA list on a pathname.
2833 ***************************************************************/
2835 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
2839 struct ea_struct
**pea_array
)
2842 uint16_t fnum
= 0xffff;
2843 DATA_BLOB outbuf
= data_blob_null
;
2844 struct smb2_hnd
*ph
= NULL
;
2845 struct ea_list
*ea_list
= NULL
;
2846 struct ea_list
*eal
= NULL
;
2847 size_t ea_count
= 0;
2848 TALLOC_CTX
*frame
= talloc_stackframe();
2853 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2855 * Can't use sync call while an async call is in flight
2857 status
= NT_STATUS_INVALID_PARAMETER
;
2861 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2862 status
= NT_STATUS_INVALID_PARAMETER
;
2866 status
= get_fnum_from_path(cli
,
2871 if (!NT_STATUS_IS_OK(status
)) {
2875 status
= map_fnum_to_smb2_handle(cli
,
2878 if (!NT_STATUS_IS_OK(status
)) {
2882 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2883 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2885 status
= smb2cli_query_info(cli
->conn
,
2889 1, /* in_info_type */
2890 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
2891 0xFFFF, /* in_max_output_length */
2892 NULL
, /* in_input_buffer */
2893 0, /* in_additional_info */
2900 if (!NT_STATUS_IS_OK(status
)) {
2904 /* Parse the reply. */
2905 ea_list
= read_nttrans_ea_list(ctx
,
2906 (const char *)outbuf
.data
,
2908 if (ea_list
== NULL
) {
2909 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2913 /* Convert to an array. */
2914 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2919 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
2920 if (*pea_array
== NULL
) {
2921 status
= NT_STATUS_NO_MEMORY
;
2925 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2926 (*pea_array
)[ea_count
++] = eal
->ea
;
2928 *pnum_eas
= ea_count
;
2933 if (fnum
!= 0xffff) {
2934 cli_smb2_close_fnum(cli
, fnum
);
2937 cli
->raw_status
= status
;
2943 /***************************************************************
2944 Wrapper that allows SMB2 to get user quota.
2946 ***************************************************************/
2948 NTSTATUS
cli_smb2_get_user_quota(struct cli_state
*cli
,
2950 SMB_NTQUOTA_STRUCT
*pqt
)
2953 DATA_BLOB inbuf
= data_blob_null
;
2954 DATA_BLOB info_blob
= data_blob_null
;
2955 DATA_BLOB outbuf
= data_blob_null
;
2956 struct smb2_hnd
*ph
= NULL
;
2957 TALLOC_CTX
*frame
= talloc_stackframe();
2959 unsigned int offset
;
2960 struct smb2_query_quota_info query
= {0};
2961 struct file_get_quota_info info
= {0};
2962 enum ndr_err_code err
;
2963 struct ndr_push
*ndr_push
= NULL
;
2965 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2967 * Can't use sync call while an async call is in flight
2969 status
= NT_STATUS_INVALID_PARAMETER
;
2973 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2974 status
= NT_STATUS_INVALID_PARAMETER
;
2978 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
2979 if (!NT_STATUS_IS_OK(status
)) {
2983 sid_len
= ndr_size_dom_sid(&pqt
->sid
, 0);
2985 query
.return_single
= 1;
2987 info
.next_entry_offset
= 0;
2988 info
.sid_length
= sid_len
;
2989 info
.sid
= pqt
->sid
;
2991 err
= ndr_push_struct_blob(
2995 (ndr_push_flags_fn_t
)ndr_push_file_get_quota_info
);
2997 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
2998 status
= NT_STATUS_INTERNAL_ERROR
;
3002 query
.sid_list_length
= info_blob
.length
;
3003 ndr_push
= ndr_push_init_ctx(frame
);
3005 status
= NT_STATUS_NO_MEMORY
;
3009 err
= ndr_push_smb2_query_quota_info(ndr_push
,
3010 NDR_SCALARS
| NDR_BUFFERS
,
3013 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3014 status
= NT_STATUS_INTERNAL_ERROR
;
3018 err
= ndr_push_array_uint8(ndr_push
, NDR_SCALARS
, info_blob
.data
,
3021 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3022 status
= NT_STATUS_INTERNAL_ERROR
;
3025 inbuf
.data
= ndr_push
->data
;
3026 inbuf
.length
= ndr_push
->offset
;
3028 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
3029 cli
->smb2
.tcon
, 4, /* in_info_type */
3030 0, /* in_file_info_class */
3031 0xFFFF, /* in_max_output_length */
3032 &inbuf
, /* in_input_buffer */
3033 0, /* in_additional_info */
3035 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
3038 if (!NT_STATUS_IS_OK(status
)) {
3042 if (!parse_user_quota_record(outbuf
.data
, outbuf
.length
, &offset
,
3044 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
3045 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3049 cli
->raw_status
= status
;
3055 /***************************************************************
3056 Wrapper that allows SMB2 to list user quota.
3058 ***************************************************************/
3060 NTSTATUS
cli_smb2_list_user_quota_step(struct cli_state
*cli
,
3061 TALLOC_CTX
*mem_ctx
,
3063 SMB_NTQUOTA_LIST
**pqt_list
,
3067 DATA_BLOB inbuf
= data_blob_null
;
3068 DATA_BLOB outbuf
= data_blob_null
;
3069 struct smb2_hnd
*ph
= NULL
;
3070 TALLOC_CTX
*frame
= talloc_stackframe();
3071 struct smb2_query_quota_info info
= {0};
3072 enum ndr_err_code err
;
3074 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3076 * Can't use sync call while an async call is in flight
3078 status
= NT_STATUS_INVALID_PARAMETER
;
3082 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3083 status
= NT_STATUS_INVALID_PARAMETER
;
3087 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
3088 if (!NT_STATUS_IS_OK(status
)) {
3093 info
.restart_scan
= first
? 1 : 0;
3095 err
= ndr_push_struct_blob(
3099 (ndr_push_flags_fn_t
)ndr_push_smb2_query_quota_info
);
3101 if (!NDR_ERR_CODE_IS_SUCCESS(err
)) {
3102 status
= NT_STATUS_INTERNAL_ERROR
;
3106 status
= smb2cli_query_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
3107 cli
->smb2
.tcon
, 4, /* in_info_type */
3108 0, /* in_file_info_class */
3109 0xFFFF, /* in_max_output_length */
3110 &inbuf
, /* in_input_buffer */
3111 0, /* in_additional_info */
3113 ph
->fid_persistent
, ph
->fid_volatile
, frame
,
3117 * safeguard against panic from calling parse_user_quota_list with
3120 if (NT_STATUS_IS_OK(status
) && outbuf
.length
== 0) {
3121 status
= NT_STATUS_NO_MORE_ENTRIES
;
3124 if (!NT_STATUS_IS_OK(status
)) {
3128 status
= parse_user_quota_list(outbuf
.data
, outbuf
.length
, mem_ctx
,
3132 cli
->raw_status
= status
;
3138 /***************************************************************
3139 Wrapper that allows SMB2 to get file system quota.
3141 ***************************************************************/
3143 NTSTATUS
cli_smb2_get_fs_quota_info(struct cli_state
*cli
,
3145 SMB_NTQUOTA_STRUCT
*pqt
)
3148 DATA_BLOB outbuf
= data_blob_null
;
3149 struct smb2_hnd
*ph
= NULL
;
3150 TALLOC_CTX
*frame
= talloc_stackframe();
3152 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3154 * Can't use sync call while an async call is in flight
3156 status
= NT_STATUS_INVALID_PARAMETER
;
3160 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3161 status
= NT_STATUS_INVALID_PARAMETER
;
3165 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
3166 if (!NT_STATUS_IS_OK(status
)) {
3170 status
= smb2cli_query_info(
3171 cli
->conn
, cli
->timeout
, cli
->smb2
.session
, cli
->smb2
.tcon
,
3172 2, /* in_info_type */
3173 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
3174 0xFFFF, /* in_max_output_length */
3175 NULL
, /* in_input_buffer */
3176 0, /* in_additional_info */
3178 ph
->fid_persistent
, ph
->fid_volatile
, frame
, &outbuf
);
3180 if (!NT_STATUS_IS_OK(status
)) {
3184 status
= parse_fs_quota_buffer(outbuf
.data
, outbuf
.length
, pqt
);
3187 cli
->raw_status
= status
;
3193 /***************************************************************
3194 Wrapper that allows SMB2 to set user quota.
3196 ***************************************************************/
3198 NTSTATUS
cli_smb2_set_user_quota(struct cli_state
*cli
,
3200 SMB_NTQUOTA_LIST
*qtl
)
3203 DATA_BLOB inbuf
= data_blob_null
;
3204 struct smb2_hnd
*ph
= NULL
;
3205 TALLOC_CTX
*frame
= talloc_stackframe();
3207 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3209 * Can't use sync call while an async call is in flight
3211 status
= NT_STATUS_INVALID_PARAMETER
;
3215 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3216 status
= NT_STATUS_INVALID_PARAMETER
;
3220 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
3221 if (!NT_STATUS_IS_OK(status
)) {
3225 status
= build_user_quota_buffer(qtl
, 0, talloc_tos(), &inbuf
, NULL
);
3226 if (!NT_STATUS_IS_OK(status
)) {
3230 status
= smb2cli_set_info(cli
->conn
, cli
->timeout
, cli
->smb2
.session
,
3231 cli
->smb2
.tcon
, 4, /* in_info_type */
3232 0, /* in_file_info_class */
3233 &inbuf
, /* in_input_buffer */
3234 0, /* in_additional_info */
3235 ph
->fid_persistent
, ph
->fid_volatile
);
3238 cli
->raw_status
= status
;
3245 NTSTATUS
cli_smb2_set_fs_quota_info(struct cli_state
*cli
,
3247 SMB_NTQUOTA_STRUCT
*pqt
)
3250 DATA_BLOB inbuf
= data_blob_null
;
3251 struct smb2_hnd
*ph
= NULL
;
3252 TALLOC_CTX
*frame
= talloc_stackframe();
3254 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3256 * Can't use sync call while an async call is in flight
3258 status
= NT_STATUS_INVALID_PARAMETER
;
3262 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3263 status
= NT_STATUS_INVALID_PARAMETER
;
3267 status
= map_fnum_to_smb2_handle(cli
, quota_fnum
, &ph
);
3268 if (!NT_STATUS_IS_OK(status
)) {
3272 status
= build_fs_quota_buffer(talloc_tos(), pqt
, &inbuf
, 0);
3273 if (!NT_STATUS_IS_OK(status
)) {
3277 status
= smb2cli_set_info(
3278 cli
->conn
, cli
->timeout
, cli
->smb2
.session
, cli
->smb2
.tcon
,
3279 2, /* in_info_type */
3280 SMB_FS_QUOTA_INFORMATION
- 1000, /* in_file_info_class */
3281 &inbuf
, /* in_input_buffer */
3282 0, /* in_additional_info */
3283 ph
->fid_persistent
, ph
->fid_volatile
);
3285 cli
->raw_status
= status
;
3291 struct cli_smb2_read_state
{
3292 struct tevent_context
*ev
;
3293 struct cli_state
*cli
;
3294 struct smb2_hnd
*ph
;
3295 uint64_t start_offset
;
3301 static void cli_smb2_read_done(struct tevent_req
*subreq
);
3303 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
3304 struct tevent_context
*ev
,
3305 struct cli_state
*cli
,
3311 struct tevent_req
*req
, *subreq
;
3312 struct cli_smb2_read_state
*state
;
3314 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
3320 state
->start_offset
= (uint64_t)offset
;
3321 state
->size
= (uint32_t)size
;
3322 state
->received
= 0;
3325 status
= map_fnum_to_smb2_handle(cli
,
3328 if (tevent_req_nterror(req
, status
)) {
3329 return tevent_req_post(req
, ev
);
3332 subreq
= smb2cli_read_send(state
,
3335 state
->cli
->timeout
,
3336 state
->cli
->smb2
.session
,
3337 state
->cli
->smb2
.tcon
,
3339 state
->start_offset
,
3340 state
->ph
->fid_persistent
,
3341 state
->ph
->fid_volatile
,
3342 0, /* minimum_count */
3343 0); /* remaining_bytes */
3345 if (tevent_req_nomem(subreq
, req
)) {
3346 return tevent_req_post(req
, ev
);
3348 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
3352 static void cli_smb2_read_done(struct tevent_req
*subreq
)
3354 struct tevent_req
*req
= tevent_req_callback_data(
3355 subreq
, struct tevent_req
);
3356 struct cli_smb2_read_state
*state
= tevent_req_data(
3357 req
, struct cli_smb2_read_state
);
3360 status
= smb2cli_read_recv(subreq
, state
,
3361 &state
->buf
, &state
->received
);
3362 if (tevent_req_nterror(req
, status
)) {
3366 if (state
->received
> state
->size
) {
3367 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3371 tevent_req_done(req
);
3374 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
3379 struct cli_smb2_read_state
*state
= tevent_req_data(
3380 req
, struct cli_smb2_read_state
);
3382 if (tevent_req_is_nterror(req
, &status
)) {
3383 state
->cli
->raw_status
= status
;
3387 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3388 * better make sure that you copy it away before you talloc_free(req).
3389 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3391 *received
= (ssize_t
)state
->received
;
3392 *rcvbuf
= state
->buf
;
3393 state
->cli
->raw_status
= NT_STATUS_OK
;
3394 return NT_STATUS_OK
;
3397 struct cli_smb2_write_state
{
3398 struct tevent_context
*ev
;
3399 struct cli_state
*cli
;
3400 struct smb2_hnd
*ph
;
3408 static void cli_smb2_write_written(struct tevent_req
*req
);
3410 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
3411 struct tevent_context
*ev
,
3412 struct cli_state
*cli
,
3420 struct tevent_req
*req
, *subreq
= NULL
;
3421 struct cli_smb2_write_state
*state
= NULL
;
3423 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
3429 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3430 state
->flags
= (uint32_t)mode
;
3432 state
->offset
= (uint64_t)offset
;
3433 state
->size
= (uint32_t)size
;
3436 status
= map_fnum_to_smb2_handle(cli
,
3439 if (tevent_req_nterror(req
, status
)) {
3440 return tevent_req_post(req
, ev
);
3443 subreq
= smb2cli_write_send(state
,
3446 state
->cli
->timeout
,
3447 state
->cli
->smb2
.session
,
3448 state
->cli
->smb2
.tcon
,
3451 state
->ph
->fid_persistent
,
3452 state
->ph
->fid_volatile
,
3453 0, /* remaining_bytes */
3454 state
->flags
, /* flags */
3457 if (tevent_req_nomem(subreq
, req
)) {
3458 return tevent_req_post(req
, ev
);
3460 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
3464 static void cli_smb2_write_written(struct tevent_req
*subreq
)
3466 struct tevent_req
*req
= tevent_req_callback_data(
3467 subreq
, struct tevent_req
);
3468 struct cli_smb2_write_state
*state
= tevent_req_data(
3469 req
, struct cli_smb2_write_state
);
3473 status
= smb2cli_write_recv(subreq
, &written
);
3474 TALLOC_FREE(subreq
);
3475 if (tevent_req_nterror(req
, status
)) {
3479 state
->written
= written
;
3481 tevent_req_done(req
);
3484 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
3487 struct cli_smb2_write_state
*state
= tevent_req_data(
3488 req
, struct cli_smb2_write_state
);
3491 if (tevent_req_is_nterror(req
, &status
)) {
3492 state
->cli
->raw_status
= status
;
3493 tevent_req_received(req
);
3497 if (pwritten
!= NULL
) {
3498 *pwritten
= (size_t)state
->written
;
3500 state
->cli
->raw_status
= NT_STATUS_OK
;
3501 tevent_req_received(req
);
3502 return NT_STATUS_OK
;
3505 /***************************************************************
3506 Wrapper that allows SMB2 async write using an fnum.
3507 This is mostly cut-and-paste from Volker's code inside
3508 source3/libsmb/clireadwrite.c, adapted for SMB2.
3510 Done this way so I can reuse all the logic inside cli_push()
3512 ***************************************************************/
3514 struct cli_smb2_writeall_state
{
3515 struct tevent_context
*ev
;
3516 struct cli_state
*cli
;
3517 struct smb2_hnd
*ph
;
3525 static void cli_smb2_writeall_written(struct tevent_req
*req
);
3527 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
3528 struct tevent_context
*ev
,
3529 struct cli_state
*cli
,
3537 struct tevent_req
*req
, *subreq
= NULL
;
3538 struct cli_smb2_writeall_state
*state
= NULL
;
3543 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
3549 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3550 state
->flags
= (uint32_t)mode
;
3552 state
->offset
= (uint64_t)offset
;
3553 state
->size
= (uint32_t)size
;
3556 status
= map_fnum_to_smb2_handle(cli
,
3559 if (tevent_req_nterror(req
, status
)) {
3560 return tevent_req_post(req
, ev
);
3563 to_write
= state
->size
;
3564 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
3565 to_write
= MIN(max_size
, to_write
);
3566 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
3568 to_write
= MIN(max_size
, to_write
);
3571 subreq
= smb2cli_write_send(state
,
3574 state
->cli
->timeout
,
3575 state
->cli
->smb2
.session
,
3576 state
->cli
->smb2
.tcon
,
3579 state
->ph
->fid_persistent
,
3580 state
->ph
->fid_volatile
,
3581 0, /* remaining_bytes */
3582 state
->flags
, /* flags */
3583 state
->buf
+ state
->written
);
3585 if (tevent_req_nomem(subreq
, req
)) {
3586 return tevent_req_post(req
, ev
);
3588 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
3592 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
3594 struct tevent_req
*req
= tevent_req_callback_data(
3595 subreq
, struct tevent_req
);
3596 struct cli_smb2_writeall_state
*state
= tevent_req_data(
3597 req
, struct cli_smb2_writeall_state
);
3599 uint32_t written
, to_write
;
3603 status
= smb2cli_write_recv(subreq
, &written
);
3604 TALLOC_FREE(subreq
);
3605 if (tevent_req_nterror(req
, status
)) {
3609 state
->written
+= written
;
3611 if (state
->written
> state
->size
) {
3612 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3616 to_write
= state
->size
- state
->written
;
3618 if (to_write
== 0) {
3619 tevent_req_done(req
);
3623 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
3624 to_write
= MIN(max_size
, to_write
);
3625 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
3627 to_write
= MIN(max_size
, to_write
);
3630 subreq
= smb2cli_write_send(state
,
3633 state
->cli
->timeout
,
3634 state
->cli
->smb2
.session
,
3635 state
->cli
->smb2
.tcon
,
3637 state
->offset
+ state
->written
,
3638 state
->ph
->fid_persistent
,
3639 state
->ph
->fid_volatile
,
3640 0, /* remaining_bytes */
3641 state
->flags
, /* flags */
3642 state
->buf
+ state
->written
);
3644 if (tevent_req_nomem(subreq
, req
)) {
3647 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
3650 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
3653 struct cli_smb2_writeall_state
*state
= tevent_req_data(
3654 req
, struct cli_smb2_writeall_state
);
3657 if (tevent_req_is_nterror(req
, &status
)) {
3658 state
->cli
->raw_status
= status
;
3661 if (pwritten
!= NULL
) {
3662 *pwritten
= (size_t)state
->written
;
3664 state
->cli
->raw_status
= NT_STATUS_OK
;
3665 return NT_STATUS_OK
;
3668 struct cli_smb2_splice_state
{
3669 struct tevent_context
*ev
;
3670 struct cli_state
*cli
;
3671 struct smb2_hnd
*src_ph
;
3672 struct smb2_hnd
*dst_ph
;
3673 int (*splice_cb
)(off_t n
, void *priv
);
3680 struct req_resume_key_rsp resume_rsp
;
3681 struct srv_copychunk_copy cc_copy
;
3684 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
3685 struct tevent_req
*req
);
3687 static void cli_splice_copychunk_done(struct tevent_req
*subreq
)
3689 struct tevent_req
*req
= tevent_req_callback_data(
3690 subreq
, struct tevent_req
);
3691 struct cli_smb2_splice_state
*state
=
3692 tevent_req_data(req
,
3693 struct cli_smb2_splice_state
);
3694 struct smbXcli_conn
*conn
= state
->cli
->conn
;
3695 DATA_BLOB out_input_buffer
= data_blob_null
;
3696 DATA_BLOB out_output_buffer
= data_blob_null
;
3697 struct srv_copychunk_rsp cc_copy_rsp
;
3698 enum ndr_err_code ndr_ret
;
3701 status
= smb2cli_ioctl_recv(subreq
, state
,
3703 &out_output_buffer
);
3704 TALLOC_FREE(subreq
);
3705 if ((!NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
) ||
3706 state
->resized
) && tevent_req_nterror(req
, status
)) {
3710 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
, state
, &cc_copy_rsp
,
3711 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
3712 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
3713 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3714 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3718 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
3719 uint32_t max_chunks
= MIN(cc_copy_rsp
.chunks_written
,
3720 cc_copy_rsp
.total_bytes_written
/ cc_copy_rsp
.chunk_bytes_written
);
3721 if ((cc_copy_rsp
.chunk_bytes_written
> smb2cli_conn_cc_chunk_len(conn
) ||
3722 max_chunks
> smb2cli_conn_cc_max_chunks(conn
)) &&
3723 tevent_req_nterror(req
, status
)) {
3727 state
->resized
= true;
3728 smb2cli_conn_set_cc_chunk_len(conn
, cc_copy_rsp
.chunk_bytes_written
);
3729 smb2cli_conn_set_cc_max_chunks(conn
, max_chunks
);
3731 if ((state
->src_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
3732 (state
->dst_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
3733 (state
->written
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
)) {
3734 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
3737 state
->src_offset
+= cc_copy_rsp
.total_bytes_written
;
3738 state
->dst_offset
+= cc_copy_rsp
.total_bytes_written
;
3739 state
->written
+= cc_copy_rsp
.total_bytes_written
;
3740 if (!state
->splice_cb(state
->written
, state
->priv
)) {
3741 tevent_req_nterror(req
, NT_STATUS_CANCELLED
);
3746 cli_splice_copychunk_send(state
, req
);
3749 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
3750 struct tevent_req
*req
)
3752 struct tevent_req
*subreq
;
3753 enum ndr_err_code ndr_ret
;
3754 struct smbXcli_conn
*conn
= state
->cli
->conn
;
3755 struct srv_copychunk_copy
*cc_copy
= &state
->cc_copy
;
3756 off_t src_offset
= state
->src_offset
;
3757 off_t dst_offset
= state
->dst_offset
;
3758 uint32_t req_len
= MIN(smb2cli_conn_cc_chunk_len(conn
) * smb2cli_conn_cc_max_chunks(conn
),
3759 state
->size
- state
->written
);
3760 DATA_BLOB in_input_buffer
= data_blob_null
;
3761 DATA_BLOB in_output_buffer
= data_blob_null
;
3763 if (state
->size
- state
->written
== 0) {
3764 tevent_req_done(req
);
3768 cc_copy
->chunk_count
= 0;
3770 cc_copy
->chunks
[cc_copy
->chunk_count
].source_off
= src_offset
;
3771 cc_copy
->chunks
[cc_copy
->chunk_count
].target_off
= dst_offset
;
3772 cc_copy
->chunks
[cc_copy
->chunk_count
].length
= MIN(req_len
,
3773 smb2cli_conn_cc_chunk_len(conn
));
3774 if (req_len
< cc_copy
->chunks
[cc_copy
->chunk_count
].length
) {
3775 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
3778 req_len
-= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
3779 if ((src_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
) ||
3780 (dst_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
)) {
3781 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
3784 src_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
3785 dst_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
3786 cc_copy
->chunk_count
++;
3789 ndr_ret
= ndr_push_struct_blob(&in_input_buffer
, state
, cc_copy
,
3790 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
3791 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
3792 DEBUG(0, ("failed to marshall copy chunk req\n"));
3793 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
3797 subreq
= smb2cli_ioctl_send(state
, state
->ev
, state
->cli
->conn
,
3798 state
->cli
->timeout
,
3799 state
->cli
->smb2
.session
,
3800 state
->cli
->smb2
.tcon
,
3801 state
->dst_ph
->fid_persistent
, /* in_fid_persistent */
3802 state
->dst_ph
->fid_volatile
, /* in_fid_volatile */
3803 FSCTL_SRV_COPYCHUNK_WRITE
,
3804 0, /* in_max_input_length */
3806 12, /* in_max_output_length */
3808 SMB2_IOCTL_FLAG_IS_FSCTL
);
3809 if (tevent_req_nomem(subreq
, req
)) {
3812 tevent_req_set_callback(subreq
,
3813 cli_splice_copychunk_done
,
3817 static void cli_splice_key_done(struct tevent_req
*subreq
)
3819 struct tevent_req
*req
= tevent_req_callback_data(
3820 subreq
, struct tevent_req
);
3821 struct cli_smb2_splice_state
*state
=
3822 tevent_req_data(req
,
3823 struct cli_smb2_splice_state
);
3824 enum ndr_err_code ndr_ret
;
3827 DATA_BLOB out_input_buffer
= data_blob_null
;
3828 DATA_BLOB out_output_buffer
= data_blob_null
;
3830 status
= smb2cli_ioctl_recv(subreq
, state
,
3832 &out_output_buffer
);
3833 TALLOC_FREE(subreq
);
3834 if (tevent_req_nterror(req
, status
)) {
3838 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
,
3839 state
, &state
->resume_rsp
,
3840 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
3841 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
3842 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3843 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
3847 memcpy(&state
->cc_copy
.source_key
,
3848 &state
->resume_rsp
.resume_key
,
3849 sizeof state
->resume_rsp
.resume_key
);
3851 cli_splice_copychunk_send(state
, req
);
3854 struct tevent_req
*cli_smb2_splice_send(TALLOC_CTX
*mem_ctx
,
3855 struct tevent_context
*ev
,
3856 struct cli_state
*cli
,
3857 uint16_t src_fnum
, uint16_t dst_fnum
,
3858 off_t size
, off_t src_offset
, off_t dst_offset
,
3859 int (*splice_cb
)(off_t n
, void *priv
),
3862 struct tevent_req
*req
;
3863 struct tevent_req
*subreq
;
3864 struct cli_smb2_splice_state
*state
;
3866 DATA_BLOB in_input_buffer
= data_blob_null
;
3867 DATA_BLOB in_output_buffer
= data_blob_null
;
3869 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_splice_state
);
3875 state
->splice_cb
= splice_cb
;
3879 state
->src_offset
= src_offset
;
3880 state
->dst_offset
= dst_offset
;
3881 state
->cc_copy
.chunks
= talloc_array(state
,
3882 struct srv_copychunk
,
3883 smb2cli_conn_cc_max_chunks(cli
->conn
));
3884 if (state
->cc_copy
.chunks
== NULL
) {
3888 status
= map_fnum_to_smb2_handle(cli
, src_fnum
, &state
->src_ph
);
3889 if (tevent_req_nterror(req
, status
))
3890 return tevent_req_post(req
, ev
);
3892 status
= map_fnum_to_smb2_handle(cli
, dst_fnum
, &state
->dst_ph
);
3893 if (tevent_req_nterror(req
, status
))
3894 return tevent_req_post(req
, ev
);
3896 subreq
= smb2cli_ioctl_send(state
, ev
, cli
->conn
,
3900 state
->src_ph
->fid_persistent
, /* in_fid_persistent */
3901 state
->src_ph
->fid_volatile
, /* in_fid_volatile */
3902 FSCTL_SRV_REQUEST_RESUME_KEY
,
3903 0, /* in_max_input_length */
3905 32, /* in_max_output_length */
3907 SMB2_IOCTL_FLAG_IS_FSCTL
);
3908 if (tevent_req_nomem(subreq
, req
)) {
3911 tevent_req_set_callback(subreq
,
3912 cli_splice_key_done
,
3918 NTSTATUS
cli_smb2_splice_recv(struct tevent_req
*req
, off_t
*written
)
3920 struct cli_smb2_splice_state
*state
= tevent_req_data(
3921 req
, struct cli_smb2_splice_state
);
3924 if (tevent_req_is_nterror(req
, &status
)) {
3925 state
->cli
->raw_status
= status
;
3926 tevent_req_received(req
);
3929 if (written
!= NULL
) {
3930 *written
= state
->written
;
3932 state
->cli
->raw_status
= NT_STATUS_OK
;
3933 tevent_req_received(req
);
3934 return NT_STATUS_OK
;
3937 /***************************************************************
3938 SMB2 enum shadow copy data.
3939 ***************************************************************/
3941 struct cli_smb2_shadow_copy_data_fnum_state
{
3942 struct cli_state
*cli
;
3944 struct smb2_hnd
*ph
;
3945 DATA_BLOB out_input_buffer
;
3946 DATA_BLOB out_output_buffer
;
3949 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
);
3951 static struct tevent_req
*cli_smb2_shadow_copy_data_fnum_send(
3952 TALLOC_CTX
*mem_ctx
,
3953 struct tevent_context
*ev
,
3954 struct cli_state
*cli
,
3958 struct tevent_req
*req
, *subreq
;
3959 struct cli_smb2_shadow_copy_data_fnum_state
*state
;
3962 req
= tevent_req_create(mem_ctx
, &state
,
3963 struct cli_smb2_shadow_copy_data_fnum_state
);
3968 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
3969 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
3970 return tevent_req_post(req
, ev
);
3976 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
3977 if (tevent_req_nterror(req
, status
)) {
3978 return tevent_req_post(req
, ev
);
3982 * TODO. Under SMB2 we should send a zero max_output_length
3983 * ioctl to get the required size, then send another ioctl
3984 * to get the data, but the current SMB1 implementation just
3985 * does one roundtrip with a 64K buffer size. Do the same
3989 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
3990 state
->cli
->timeout
,
3991 state
->cli
->smb2
.session
,
3992 state
->cli
->smb2
.tcon
,
3993 state
->ph
->fid_persistent
, /* in_fid_persistent */
3994 state
->ph
->fid_volatile
, /* in_fid_volatile */
3995 FSCTL_GET_SHADOW_COPY_DATA
,
3996 0, /* in_max_input_length */
3997 NULL
, /* in_input_buffer */
3999 CLI_BUFFER_SIZE
: 16, /* in_max_output_length */
4000 NULL
, /* in_output_buffer */
4001 SMB2_IOCTL_FLAG_IS_FSCTL
);
4003 if (tevent_req_nomem(subreq
, req
)) {
4004 return tevent_req_post(req
, ev
);
4006 tevent_req_set_callback(subreq
,
4007 cli_smb2_shadow_copy_data_fnum_done
,
4013 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req
*subreq
)
4015 struct tevent_req
*req
= tevent_req_callback_data(
4016 subreq
, struct tevent_req
);
4017 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
4018 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
4021 status
= smb2cli_ioctl_recv(subreq
, state
,
4022 &state
->out_input_buffer
,
4023 &state
->out_output_buffer
);
4024 TALLOC_FREE(subreq
);
4025 if (tevent_req_nterror(req
, status
)) {
4028 tevent_req_done(req
);
4031 static NTSTATUS
cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req
*req
,
4032 TALLOC_CTX
*mem_ctx
,
4037 struct cli_smb2_shadow_copy_data_fnum_state
*state
= tevent_req_data(
4038 req
, struct cli_smb2_shadow_copy_data_fnum_state
);
4039 char **names
= NULL
;
4040 uint32_t num_names
= 0;
4041 uint32_t num_names_returned
= 0;
4042 uint32_t dlength
= 0;
4044 uint8_t *endp
= NULL
;
4047 if (tevent_req_is_nterror(req
, &status
)) {
4051 if (state
->out_output_buffer
.length
< 16) {
4052 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4055 num_names
= IVAL(state
->out_output_buffer
.data
, 0);
4056 num_names_returned
= IVAL(state
->out_output_buffer
.data
, 4);
4057 dlength
= IVAL(state
->out_output_buffer
.data
, 8);
4059 if (num_names
> 0x7FFFFFFF) {
4060 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4063 if (get_names
== false) {
4064 *pnum_names
= (int)num_names
;
4065 return NT_STATUS_OK
;
4067 if (num_names
!= num_names_returned
) {
4068 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4070 if (dlength
+ 12 < 12) {
4071 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4074 * NB. The below is an allowable return if there are
4075 * more snapshots than the buffer size we told the
4076 * server we can receive. We currently don't support
4079 if (dlength
+ 12 > state
->out_output_buffer
.length
) {
4080 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4082 if (state
->out_output_buffer
.length
+
4083 (2 * sizeof(SHADOW_COPY_LABEL
)) <
4084 state
->out_output_buffer
.length
) {
4085 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4088 names
= talloc_array(mem_ctx
, char *, num_names_returned
);
4089 if (names
== NULL
) {
4090 return NT_STATUS_NO_MEMORY
;
4093 endp
= state
->out_output_buffer
.data
+
4094 state
->out_output_buffer
.length
;
4096 for (i
=0; i
<num_names_returned
; i
++) {
4099 size_t converted_size
;
4101 src
= state
->out_output_buffer
.data
+ 12 +
4102 (i
* 2 * sizeof(SHADOW_COPY_LABEL
));
4104 if (src
+ (2 * sizeof(SHADOW_COPY_LABEL
)) > endp
) {
4105 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4107 ret
= convert_string_talloc(
4108 names
, CH_UTF16LE
, CH_UNIX
,
4109 src
, 2 * sizeof(SHADOW_COPY_LABEL
),
4110 &names
[i
], &converted_size
);
4113 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
4116 *pnum_names
= num_names
;
4118 return NT_STATUS_OK
;
4121 NTSTATUS
cli_smb2_shadow_copy_data(TALLOC_CTX
*mem_ctx
,
4122 struct cli_state
*cli
,
4128 TALLOC_CTX
*frame
= talloc_stackframe();
4129 struct tevent_context
*ev
;
4130 struct tevent_req
*req
;
4131 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
4133 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4135 * Can't use sync call while an async call is in flight
4137 status
= NT_STATUS_INVALID_PARAMETER
;
4140 ev
= samba_tevent_context_init(frame
);
4144 req
= cli_smb2_shadow_copy_data_fnum_send(frame
,
4152 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4155 status
= cli_smb2_shadow_copy_data_fnum_recv(req
,
4161 cli
->raw_status
= status
;
4167 /***************************************************************
4168 Wrapper that allows SMB2 to truncate a file.
4170 ***************************************************************/
4172 NTSTATUS
cli_smb2_ftruncate(struct cli_state
*cli
,
4177 DATA_BLOB inbuf
= data_blob_null
;
4178 struct smb2_hnd
*ph
= NULL
;
4179 TALLOC_CTX
*frame
= talloc_stackframe();
4181 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4183 * Can't use sync call while an async call is in flight
4185 status
= NT_STATUS_INVALID_PARAMETER
;
4189 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
4190 status
= NT_STATUS_INVALID_PARAMETER
;
4194 status
= map_fnum_to_smb2_handle(cli
,
4197 if (!NT_STATUS_IS_OK(status
)) {
4201 inbuf
= data_blob_talloc_zero(frame
, 8);
4202 if (inbuf
.data
== NULL
) {
4203 status
= NT_STATUS_NO_MEMORY
;
4207 SBVAL(inbuf
.data
, 0, newsize
);
4209 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4210 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4212 status
= smb2cli_set_info(cli
->conn
,
4216 1, /* in_info_type */
4217 /* in_file_info_class */
4218 SMB_FILE_END_OF_FILE_INFORMATION
- 1000,
4219 &inbuf
, /* in_input_buffer */
4220 0, /* in_additional_info */
4226 cli
->raw_status
= status
;
4232 struct cli_smb2_notify_state
{
4233 struct tevent_req
*subreq
;
4234 struct notify_change
*changes
;
4238 static void cli_smb2_notify_done(struct tevent_req
*subreq
);
4239 static bool cli_smb2_notify_cancel(struct tevent_req
*req
);
4241 struct tevent_req
*cli_smb2_notify_send(
4242 TALLOC_CTX
*mem_ctx
,
4243 struct tevent_context
*ev
,
4244 struct cli_state
*cli
,
4246 uint32_t buffer_size
,
4247 uint32_t completion_filter
,
4250 struct tevent_req
*req
= NULL
;
4251 struct cli_smb2_notify_state
*state
= NULL
;
4252 struct smb2_hnd
*ph
= NULL
;
4255 req
= tevent_req_create(mem_ctx
, &state
,
4256 struct cli_smb2_notify_state
);
4261 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
4262 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
4263 return tevent_req_post(req
, ev
);
4266 status
= map_fnum_to_smb2_handle(cli
, fnum
, &ph
);
4267 if (tevent_req_nterror(req
, status
)) {
4268 return tevent_req_post(req
, ev
);
4271 state
->subreq
= smb2cli_notify_send(
4283 if (tevent_req_nomem(state
->subreq
, req
)) {
4284 return tevent_req_post(req
, ev
);
4286 tevent_req_set_callback(state
->subreq
, cli_smb2_notify_done
, req
);
4287 tevent_req_set_cancel_fn(req
, cli_smb2_notify_cancel
);
4291 static bool cli_smb2_notify_cancel(struct tevent_req
*req
)
4293 struct cli_smb2_notify_state
*state
= tevent_req_data(
4294 req
, struct cli_smb2_notify_state
);
4297 ok
= tevent_req_cancel(state
->subreq
);
4301 static void cli_smb2_notify_done(struct tevent_req
*subreq
)
4303 struct tevent_req
*req
= tevent_req_callback_data(
4304 subreq
, struct tevent_req
);
4305 struct cli_smb2_notify_state
*state
= tevent_req_data(
4306 req
, struct cli_smb2_notify_state
);
4312 status
= smb2cli_notify_recv(subreq
, state
, &base
, &len
);
4313 TALLOC_FREE(subreq
);
4315 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
4316 tevent_req_done(req
);
4319 if (tevent_req_nterror(req
, status
)) {
4325 while (len
- ofs
>= 12) {
4326 struct notify_change
*tmp
;
4327 struct notify_change
*c
;
4328 uint32_t next_ofs
= IVAL(base
, ofs
);
4329 uint32_t file_name_length
= IVAL(base
, ofs
+8);
4333 tmp
= talloc_realloc(
4336 struct notify_change
,
4337 state
->num_changes
+ 1);
4338 if (tevent_req_nomem(tmp
, req
)) {
4341 state
->changes
= tmp
;
4342 c
= &state
->changes
[state
->num_changes
];
4343 state
->num_changes
+= 1;
4345 if (smb_buffer_oob(len
, ofs
, next_ofs
) ||
4346 smb_buffer_oob(len
, ofs
+12, file_name_length
)) {
4348 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4352 c
->action
= IVAL(base
, ofs
+4);
4354 ok
= convert_string_talloc(
4364 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
4368 if (next_ofs
== 0) {
4374 tevent_req_done(req
);
4377 NTSTATUS
cli_smb2_notify_recv(struct tevent_req
*req
,
4378 TALLOC_CTX
*mem_ctx
,
4379 struct notify_change
**pchanges
,
4380 uint32_t *pnum_changes
)
4382 struct cli_smb2_notify_state
*state
= tevent_req_data(
4383 req
, struct cli_smb2_notify_state
);
4386 if (tevent_req_is_nterror(req
, &status
)) {
4389 *pchanges
= talloc_move(mem_ctx
, &state
->changes
);
4390 *pnum_changes
= state
->num_changes
;
4391 return NT_STATUS_OK
;
4394 NTSTATUS
cli_smb2_notify(struct cli_state
*cli
, uint16_t fnum
,
4395 uint32_t buffer_size
, uint32_t completion_filter
,
4396 bool recursive
, TALLOC_CTX
*mem_ctx
,
4397 struct notify_change
**pchanges
,
4398 uint32_t *pnum_changes
)
4400 TALLOC_CTX
*frame
= talloc_stackframe();
4401 struct tevent_context
*ev
;
4402 struct tevent_req
*req
;
4403 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
4405 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4407 * Can't use sync call while an async call is in flight
4409 status
= NT_STATUS_INVALID_PARAMETER
;
4412 ev
= samba_tevent_context_init(frame
);
4416 req
= cli_smb2_notify_send(
4427 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4430 status
= cli_smb2_notify_recv(req
, mem_ctx
, pchanges
, pnum_changes
);
4436 struct cli_smb2_set_reparse_point_fnum_state
{
4437 struct cli_state
*cli
;
4439 struct smb2_hnd
*ph
;
4440 DATA_BLOB input_buffer
;
4443 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req
*subreq
);
4445 struct tevent_req
*cli_smb2_set_reparse_point_fnum_send(
4446 TALLOC_CTX
*mem_ctx
,
4447 struct tevent_context
*ev
,
4448 struct cli_state
*cli
,
4452 struct tevent_req
*req
, *subreq
;
4453 struct cli_smb2_set_reparse_point_fnum_state
*state
= NULL
;
4456 req
= tevent_req_create(mem_ctx
, &state
,
4457 struct cli_smb2_set_reparse_point_fnum_state
);
4462 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
4463 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
4464 return tevent_req_post(req
, ev
);
4470 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
4471 if (tevent_req_nterror(req
, status
)) {
4472 return tevent_req_post(req
, ev
);
4475 state
->input_buffer
= data_blob_talloc(state
,
4478 if (state
->input_buffer
.data
== NULL
) {
4479 tevent_req_nterror(req
, NT_STATUS_NO_MEMORY
);
4480 return tevent_req_post(req
, ev
);
4483 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
4484 state
->cli
->timeout
,
4485 state
->cli
->smb2
.session
,
4486 state
->cli
->smb2
.tcon
,
4487 state
->ph
->fid_persistent
, /* in_fid_persistent */
4488 state
->ph
->fid_volatile
, /* in_fid_volatile */
4489 FSCTL_SET_REPARSE_POINT
,
4490 0, /* in_max_input_length */
4491 &state
->input_buffer
,
4494 SMB2_IOCTL_FLAG_IS_FSCTL
);
4496 if (tevent_req_nomem(subreq
, req
)) {
4497 return tevent_req_post(req
, ev
);
4499 tevent_req_set_callback(subreq
,
4500 cli_smb2_set_reparse_point_fnum_done
,
4506 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req
*subreq
)
4508 struct tevent_req
*req
= tevent_req_callback_data(
4509 subreq
, struct tevent_req
);
4510 struct cli_smb2_set_reparse_point_fnum_state
*state
= tevent_req_data(
4511 req
, struct cli_smb2_set_reparse_point_fnum_state
);
4514 status
= smb2cli_ioctl_recv(subreq
, state
,
4517 TALLOC_FREE(subreq
);
4518 if (tevent_req_nterror(req
, status
)) {
4521 tevent_req_done(req
);
4524 NTSTATUS
cli_smb2_set_reparse_point_fnum_recv(struct tevent_req
*req
)
4526 return tevent_req_simple_recv_ntstatus(req
);
4529 struct cli_smb2_get_reparse_point_fnum_state
{
4530 struct cli_state
*cli
;
4532 struct smb2_hnd
*ph
;
4533 DATA_BLOB output_buffer
;
4536 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req
*subreq
);
4538 struct tevent_req
*cli_smb2_get_reparse_point_fnum_send(
4539 TALLOC_CTX
*mem_ctx
,
4540 struct tevent_context
*ev
,
4541 struct cli_state
*cli
,
4544 struct tevent_req
*req
, *subreq
;
4545 struct cli_smb2_set_reparse_point_fnum_state
*state
= NULL
;
4548 req
= tevent_req_create(mem_ctx
, &state
,
4549 struct cli_smb2_get_reparse_point_fnum_state
);
4554 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
4555 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
4556 return tevent_req_post(req
, ev
);
4562 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
4563 if (tevent_req_nterror(req
, status
)) {
4564 return tevent_req_post(req
, ev
);
4567 subreq
= smb2cli_ioctl_send(state
, ev
, state
->cli
->conn
,
4568 state
->cli
->timeout
,
4569 state
->cli
->smb2
.session
,
4570 state
->cli
->smb2
.tcon
,
4571 state
->ph
->fid_persistent
, /* in_fid_persistent */
4572 state
->ph
->fid_volatile
, /* in_fid_volatile */
4573 FSCTL_GET_REPARSE_POINT
,
4574 0, /* in_max_input_length */
4578 SMB2_IOCTL_FLAG_IS_FSCTL
);
4580 if (tevent_req_nomem(subreq
, req
)) {
4581 return tevent_req_post(req
, ev
);
4583 tevent_req_set_callback(subreq
,
4584 cli_smb2_get_reparse_point_fnum_done
,
4590 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req
*subreq
)
4592 struct tevent_req
*req
= tevent_req_callback_data(
4593 subreq
, struct tevent_req
);
4594 struct cli_smb2_get_reparse_point_fnum_state
*state
= tevent_req_data(
4595 req
, struct cli_smb2_get_reparse_point_fnum_state
);
4598 status
= smb2cli_ioctl_recv(subreq
, state
,
4600 &state
->output_buffer
);
4601 TALLOC_FREE(subreq
);
4602 if (tevent_req_nterror(req
, status
)) {
4603 state
->cli
->raw_status
= status
;
4606 tevent_req_done(req
);
4609 NTSTATUS
cli_smb2_get_reparse_point_fnum_recv(struct tevent_req
*req
,
4610 TALLOC_CTX
*mem_ctx
,
4613 struct cli_smb2_get_reparse_point_fnum_state
*state
= tevent_req_data(
4614 req
, struct cli_smb2_get_reparse_point_fnum_state
);
4616 if (tevent_req_is_nterror(req
, &state
->cli
->raw_status
)) {
4617 tevent_req_received(req
);
4618 return state
->cli
->raw_status
;
4620 *output
= data_blob_dup_talloc(mem_ctx
, state
->output_buffer
);
4621 if (output
->data
== NULL
) {
4622 tevent_req_received(req
);
4623 return NT_STATUS_NO_MEMORY
;
4625 tevent_req_received(req
);
4626 return NT_STATUS_OK
;