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 "lib/util_ea.h"
43 uint64_t fid_persistent
;
44 uint64_t fid_volatile
;
48 * Handle mapping code.
51 /***************************************************************
52 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
53 Ensures handle is owned by cli struct.
54 ***************************************************************/
56 static NTSTATUS
map_smb2_handle_to_fnum(struct cli_state
*cli
,
57 const struct smb2_hnd
*ph
, /* In */
58 uint16_t *pfnum
) /* Out */
61 struct idr_context
*idp
= cli
->smb2
.open_handles
;
62 struct smb2_hnd
*owned_h
= talloc_memdup(cli
,
64 sizeof(struct smb2_hnd
));
66 if (owned_h
== NULL
) {
67 return NT_STATUS_NO_MEMORY
;
72 cli
->smb2
.open_handles
= idr_init(cli
);
73 if (cli
->smb2
.open_handles
== NULL
) {
75 return NT_STATUS_NO_MEMORY
;
77 idp
= cli
->smb2
.open_handles
;
80 ret
= idr_get_new_above(idp
, owned_h
, 1, 0xFFFE);
83 return NT_STATUS_NO_MEMORY
;
86 *pfnum
= (uint16_t)ret
;
90 /***************************************************************
91 Return the smb2_hnd pointer associated with the given fnum.
92 ***************************************************************/
94 static NTSTATUS
map_fnum_to_smb2_handle(struct cli_state
*cli
,
95 uint16_t fnum
, /* In */
96 struct smb2_hnd
**pph
) /* Out */
98 struct idr_context
*idp
= cli
->smb2
.open_handles
;
101 return NT_STATUS_INVALID_PARAMETER
;
103 *pph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
105 return NT_STATUS_INVALID_HANDLE
;
110 /***************************************************************
111 Delete the fnum to smb2_hnd mapping. Zeros out handle on
113 ***************************************************************/
115 static NTSTATUS
delete_smb2_handle_mapping(struct cli_state
*cli
,
116 struct smb2_hnd
**pph
, /* In */
117 uint16_t fnum
) /* In */
119 struct idr_context
*idp
= cli
->smb2
.open_handles
;
123 return NT_STATUS_INVALID_PARAMETER
;
126 ph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
128 return NT_STATUS_INVALID_PARAMETER
;
130 idr_remove(idp
, fnum
);
135 /***************************************************************
137 ***************************************************************/
139 static uint8_t flags_to_smb2_oplock(uint32_t create_flags
)
141 if (create_flags
& REQUEST_BATCH_OPLOCK
) {
142 return SMB2_OPLOCK_LEVEL_BATCH
;
143 } else if (create_flags
& REQUEST_OPLOCK
) {
144 return SMB2_OPLOCK_LEVEL_EXCLUSIVE
;
147 /* create_flags doesn't do a level2 request. */
148 return SMB2_OPLOCK_LEVEL_NONE
;
151 /***************************************************************
152 Small wrapper that allows SMB2 create to return a uint16_t fnum.
153 ***************************************************************/
155 struct cli_smb2_create_fnum_state
{
156 struct cli_state
*cli
;
157 struct smb_create_returns cr
;
159 struct tevent_req
*subreq
;
162 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
);
163 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
);
165 struct tevent_req
*cli_smb2_create_fnum_send(TALLOC_CTX
*mem_ctx
,
166 struct tevent_context
*ev
,
167 struct cli_state
*cli
,
169 uint32_t create_flags
,
170 uint32_t desired_access
,
171 uint32_t file_attributes
,
172 uint32_t share_access
,
173 uint32_t create_disposition
,
174 uint32_t create_options
)
176 struct tevent_req
*req
, *subreq
;
177 struct cli_smb2_create_fnum_state
*state
;
179 req
= tevent_req_create(mem_ctx
, &state
,
180 struct cli_smb2_create_fnum_state
);
186 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
187 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
188 return tevent_req_post(req
, ev
);
191 if (cli
->backup_intent
) {
192 create_options
|= FILE_OPEN_FOR_BACKUP_INTENT
;
195 /* SMB2 is pickier about pathnames. Ensure it doesn't
197 if (*fname
== '\\') {
201 subreq
= smb2cli_create_send(state
, ev
,
207 flags_to_smb2_oplock(create_flags
),
208 SMB2_IMPERSONATION_IMPERSONATION
,
215 if (tevent_req_nomem(subreq
, req
)) {
216 return tevent_req_post(req
, ev
);
218 tevent_req_set_callback(subreq
, cli_smb2_create_fnum_done
, req
);
220 state
->subreq
= subreq
;
221 tevent_req_set_cancel_fn(req
, cli_smb2_create_fnum_cancel
);
226 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
)
228 struct tevent_req
*req
= tevent_req_callback_data(
229 subreq
, struct tevent_req
);
230 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
231 req
, struct cli_smb2_create_fnum_state
);
235 status
= smb2cli_create_recv(subreq
, &h
.fid_persistent
,
236 &h
.fid_volatile
, &state
->cr
, NULL
, NULL
);
238 if (tevent_req_nterror(req
, status
)) {
242 status
= map_smb2_handle_to_fnum(state
->cli
, &h
, &state
->fnum
);
243 if (tevent_req_nterror(req
, status
)) {
246 tevent_req_done(req
);
249 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
)
251 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
252 req
, struct cli_smb2_create_fnum_state
);
253 return tevent_req_cancel(state
->subreq
);
256 NTSTATUS
cli_smb2_create_fnum_recv(struct tevent_req
*req
, uint16_t *pfnum
,
257 struct smb_create_returns
*cr
)
259 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
260 req
, struct cli_smb2_create_fnum_state
);
263 if (tevent_req_is_nterror(req
, &status
)) {
267 *pfnum
= state
->fnum
;
275 NTSTATUS
cli_smb2_create_fnum(struct cli_state
*cli
,
277 uint32_t create_flags
,
278 uint32_t desired_access
,
279 uint32_t file_attributes
,
280 uint32_t share_access
,
281 uint32_t create_disposition
,
282 uint32_t create_options
,
284 struct smb_create_returns
*cr
)
286 TALLOC_CTX
*frame
= talloc_stackframe();
287 struct tevent_context
*ev
;
288 struct tevent_req
*req
;
289 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
291 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
293 * Can't use sync call while an async call is in flight
295 status
= NT_STATUS_INVALID_PARAMETER
;
298 ev
= samba_tevent_context_init(frame
);
302 req
= cli_smb2_create_fnum_send(frame
, ev
, cli
, fname
, create_flags
,
303 desired_access
, file_attributes
,
304 share_access
, create_disposition
,
309 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
312 status
= cli_smb2_create_fnum_recv(req
, pfid
, cr
);
318 /***************************************************************
319 Small wrapper that allows SMB2 close to use a uint16_t fnum.
320 ***************************************************************/
322 struct cli_smb2_close_fnum_state
{
323 struct cli_state
*cli
;
328 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
);
330 struct tevent_req
*cli_smb2_close_fnum_send(TALLOC_CTX
*mem_ctx
,
331 struct tevent_context
*ev
,
332 struct cli_state
*cli
,
335 struct tevent_req
*req
, *subreq
;
336 struct cli_smb2_close_fnum_state
*state
;
339 req
= tevent_req_create(mem_ctx
, &state
,
340 struct cli_smb2_close_fnum_state
);
347 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
348 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
349 return tevent_req_post(req
, ev
);
352 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
353 if (tevent_req_nterror(req
, status
)) {
354 return tevent_req_post(req
, ev
);
357 subreq
= smb2cli_close_send(state
, ev
, cli
->conn
, cli
->timeout
,
358 cli
->smb2
.session
, cli
->smb2
.tcon
,
359 0, state
->ph
->fid_persistent
,
360 state
->ph
->fid_volatile
);
361 if (tevent_req_nomem(subreq
, req
)) {
362 return tevent_req_post(req
, ev
);
364 tevent_req_set_callback(subreq
, cli_smb2_close_fnum_done
, req
);
368 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
)
370 struct tevent_req
*req
= tevent_req_callback_data(
371 subreq
, struct tevent_req
);
372 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
373 req
, struct cli_smb2_close_fnum_state
);
376 status
= smb2cli_close_recv(subreq
);
377 if (tevent_req_nterror(req
, status
)) {
381 /* Delete the fnum -> handle mapping. */
382 status
= delete_smb2_handle_mapping(state
->cli
, &state
->ph
,
384 if (tevent_req_nterror(req
, status
)) {
387 tevent_req_done(req
);
390 NTSTATUS
cli_smb2_close_fnum_recv(struct tevent_req
*req
)
392 return tevent_req_simple_recv_ntstatus(req
);
395 NTSTATUS
cli_smb2_close_fnum(struct cli_state
*cli
, uint16_t fnum
)
397 TALLOC_CTX
*frame
= talloc_stackframe();
398 struct tevent_context
*ev
;
399 struct tevent_req
*req
;
400 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
402 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
404 * Can't use sync call while an async call is in flight
406 status
= NT_STATUS_INVALID_PARAMETER
;
409 ev
= samba_tevent_context_init(frame
);
413 req
= cli_smb2_close_fnum_send(frame
, ev
, cli
, fnum
);
417 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
420 status
= cli_smb2_close_fnum_recv(req
);
426 /***************************************************************
427 Small wrapper that allows SMB2 to create a directory
429 ***************************************************************/
431 NTSTATUS
cli_smb2_mkdir(struct cli_state
*cli
, const char *dname
)
436 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
438 * Can't use sync call while an async call is in flight
440 return NT_STATUS_INVALID_PARAMETER
;
443 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
444 return NT_STATUS_INVALID_PARAMETER
;
447 status
= cli_smb2_create_fnum(cli
,
449 0, /* create_flags */
450 FILE_READ_ATTRIBUTES
, /* desired_access */
451 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
452 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
453 FILE_CREATE
, /* create_disposition */
454 FILE_DIRECTORY_FILE
, /* create_options */
458 if (!NT_STATUS_IS_OK(status
)) {
461 return cli_smb2_close_fnum(cli
, fnum
);
464 /***************************************************************
465 Small wrapper that allows SMB2 to delete a directory
467 ***************************************************************/
469 NTSTATUS
cli_smb2_rmdir(struct cli_state
*cli
, const char *dname
)
474 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
476 * Can't use sync call while an async call is in flight
478 return NT_STATUS_INVALID_PARAMETER
;
481 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
482 return NT_STATUS_INVALID_PARAMETER
;
485 status
= cli_smb2_create_fnum(cli
,
487 0, /* create_flags */
488 DELETE_ACCESS
, /* desired_access */
489 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
490 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
491 FILE_OPEN
, /* create_disposition */
492 FILE_DIRECTORY_FILE
|FILE_DELETE_ON_CLOSE
, /* create_options */
496 if (!NT_STATUS_IS_OK(status
)) {
499 return cli_smb2_close_fnum(cli
, fnum
);
502 /***************************************************************
503 Small wrapper that allows SMB2 to unlink a pathname.
505 ***************************************************************/
507 NTSTATUS
cli_smb2_unlink(struct cli_state
*cli
, const char *fname
)
512 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
514 * Can't use sync call while an async call is in flight
516 return NT_STATUS_INVALID_PARAMETER
;
519 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
520 return NT_STATUS_INVALID_PARAMETER
;
523 status
= cli_smb2_create_fnum(cli
,
525 0, /* create_flags */
526 DELETE_ACCESS
, /* desired_access */
527 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
528 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
529 FILE_OPEN
, /* create_disposition */
530 FILE_DELETE_ON_CLOSE
, /* create_options */
534 if (!NT_STATUS_IS_OK(status
)) {
537 return cli_smb2_close_fnum(cli
, fnum
);
540 /***************************************************************
541 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
542 ***************************************************************/
544 static NTSTATUS
parse_finfo_id_both_directory_info(uint8_t *dir_data
,
545 uint32_t dir_data_length
,
546 struct file_info
*finfo
,
547 uint32_t *next_offset
)
553 if (dir_data_length
< 4) {
554 return NT_STATUS_INFO_LENGTH_MISMATCH
;
557 *next_offset
= IVAL(dir_data
, 0);
559 if (*next_offset
> dir_data_length
) {
560 return NT_STATUS_INFO_LENGTH_MISMATCH
;
563 if (*next_offset
!= 0) {
564 /* Ensure we only read what in this record. */
565 dir_data_length
= *next_offset
;
568 if (dir_data_length
< 105) {
569 return NT_STATUS_INFO_LENGTH_MISMATCH
;
572 finfo
->atime_ts
= interpret_long_date((const char *)dir_data
+ 16);
573 finfo
->mtime_ts
= interpret_long_date((const char *)dir_data
+ 24);
574 finfo
->ctime_ts
= interpret_long_date((const char *)dir_data
+ 32);
575 finfo
->size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 40, 0);
576 finfo
->mode
= CVAL(dir_data
+ 56, 0);
577 namelen
= IVAL(dir_data
+ 60,0);
578 if (namelen
> (dir_data_length
- 104)) {
579 return NT_STATUS_INFO_LENGTH_MISMATCH
;
581 slen
= CVAL(dir_data
+ 68, 0);
583 return NT_STATUS_INFO_LENGTH_MISMATCH
;
585 ret
= pull_string_talloc(finfo
,
587 FLAGS2_UNICODE_STRINGS
,
592 if (ret
== (size_t)-1) {
593 /* Bad conversion. */
594 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
597 ret
= pull_string_talloc(finfo
,
599 FLAGS2_UNICODE_STRINGS
,
604 if (ret
== (size_t)-1) {
605 /* Bad conversion. */
606 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
611 /*******************************************************************
612 Given a filename - get its directory name
613 ********************************************************************/
615 static bool windows_parent_dirname(TALLOC_CTX
*mem_ctx
,
623 p
= strrchr_m(dir
, '\\'); /* Find final '\\', if any */
626 if (!(*parent
= talloc_strdup(mem_ctx
, "\\"))) {
637 if (!(*parent
= (char *)talloc_memdup(mem_ctx
, dir
, len
+1))) {
640 (*parent
)[len
] = '\0';
648 /***************************************************************
649 Wrapper that allows SMB2 to list a directory.
651 ***************************************************************/
653 NTSTATUS
cli_smb2_list(struct cli_state
*cli
,
654 const char *pathname
,
656 NTSTATUS (*fn
)(const char *,
663 uint16_t fnum
= 0xffff;
664 char *parent_dir
= NULL
;
665 const char *mask
= NULL
;
666 struct smb2_hnd
*ph
= NULL
;
667 bool processed_file
= false;
668 TALLOC_CTX
*frame
= talloc_stackframe();
669 TALLOC_CTX
*subframe
= NULL
;
671 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
673 * Can't use sync call while an async call is in flight
675 status
= NT_STATUS_INVALID_PARAMETER
;
679 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
680 status
= NT_STATUS_INVALID_PARAMETER
;
684 /* Get the directory name. */
685 if (!windows_parent_dirname(frame
,
689 status
= NT_STATUS_NO_MEMORY
;
693 status
= cli_smb2_create_fnum(cli
,
695 0, /* create_flags */
696 SEC_DIR_LIST
|SEC_DIR_READ_ATTRIBUTE
,/* desired_access */
697 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
698 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
699 FILE_OPEN
, /* create_disposition */
700 FILE_DIRECTORY_FILE
, /* create_options */
704 if (!NT_STATUS_IS_OK(status
)) {
708 status
= map_fnum_to_smb2_handle(cli
,
711 if (!NT_STATUS_IS_OK(status
)) {
716 uint8_t *dir_data
= NULL
;
717 uint32_t dir_data_length
= 0;
718 uint32_t next_offset
= 0;
719 subframe
= talloc_stackframe();
721 status
= smb2cli_query_directory(cli
->conn
,
725 SMB2_FIND_ID_BOTH_DIRECTORY_INFO
,
736 if (!NT_STATUS_IS_OK(status
)) {
737 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
744 struct file_info
*finfo
= talloc_zero(subframe
,
748 status
= NT_STATUS_NO_MEMORY
;
752 status
= parse_finfo_id_both_directory_info(dir_data
,
757 if (!NT_STATUS_IS_OK(status
)) {
761 if (dir_check_ftype((uint32_t)finfo
->mode
,
762 (uint32_t)attribute
)) {
764 * Only process if attributes match.
765 * On SMB1 server does this, so on
766 * SMB2 we need to emulate in the
769 * https://bugzilla.samba.org/show_bug.cgi?id=10260
771 processed_file
= true;
773 status
= fn(cli
->dfs_mountpoint
,
778 if (!NT_STATUS_IS_OK(status
)) {
785 /* Move to next entry. */
787 dir_data
+= next_offset
;
788 dir_data_length
-= next_offset
;
790 } while (next_offset
!= 0);
792 TALLOC_FREE(subframe
);
794 } while (NT_STATUS_IS_OK(status
));
796 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
797 status
= NT_STATUS_OK
;
800 if (NT_STATUS_IS_OK(status
) && !processed_file
) {
802 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
803 * if no files match. Emulate this in the client.
805 status
= NT_STATUS_NO_SUCH_FILE
;
810 if (fnum
!= 0xffff) {
811 cli_smb2_close_fnum(cli
, fnum
);
813 TALLOC_FREE(subframe
);
818 /***************************************************************
819 Wrapper that allows SMB2 to query a path info (basic level).
821 ***************************************************************/
823 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
825 SMB_STRUCT_STAT
*sbuf
,
826 uint32_t *attributes
)
829 struct smb_create_returns cr
;
830 uint16_t fnum
= 0xffff;
831 size_t namelen
= strlen(name
);
833 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
835 * Can't use sync call while an async call is in flight
837 return NT_STATUS_INVALID_PARAMETER
;
840 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
841 return NT_STATUS_INVALID_PARAMETER
;
844 /* SMB2 is pickier about pathnames. Ensure it doesn't
846 if (namelen
> 0 && name
[namelen
-1] == '\\') {
847 char *modname
= talloc_strdup(talloc_tos(), name
);
848 modname
[namelen
-1] = '\0';
852 /* This is commonly used as a 'cd'. Try qpathinfo on
853 a directory handle first. */
855 status
= cli_smb2_create_fnum(cli
,
857 0, /* create_flags */
858 FILE_READ_ATTRIBUTES
, /* desired_access */
859 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
860 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
861 FILE_OPEN
, /* create_disposition */
862 FILE_DIRECTORY_FILE
, /* create_options */
866 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
868 status
= cli_smb2_create_fnum(cli
,
870 0, /* create_flags */
871 FILE_READ_ATTRIBUTES
, /* desired_access */
872 0, /* file attributes */
873 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
874 FILE_OPEN
, /* create_disposition */
875 0, /* create_options */
880 if (!NT_STATUS_IS_OK(status
)) {
884 cli_smb2_close_fnum(cli
, fnum
);
888 sbuf
->st_ex_atime
= nt_time_to_unix_timespec(cr
.last_access_time
);
889 sbuf
->st_ex_mtime
= nt_time_to_unix_timespec(cr
.last_write_time
);
890 sbuf
->st_ex_ctime
= nt_time_to_unix_timespec(cr
.change_time
);
891 sbuf
->st_ex_size
= cr
.end_of_file
;
892 *attributes
= cr
.file_attributes
;
897 /***************************************************************
898 Helper function for pathname operations.
899 ***************************************************************/
901 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
903 uint32_t desired_access
,
907 size_t namelen
= strlen(name
);
908 TALLOC_CTX
*frame
= talloc_stackframe();
910 /* SMB2 is pickier about pathnames. Ensure it doesn't
912 if (namelen
> 0 && name
[namelen
-1] == '\\') {
913 char *modname
= talloc_strdup(frame
, name
);
914 if (modname
== NULL
) {
915 status
= NT_STATUS_NO_MEMORY
;
918 modname
[namelen
-1] = '\0';
922 /* Try to open a file handle first. */
923 status
= cli_smb2_create_fnum(cli
,
925 0, /* create_flags */
927 0, /* file attributes */
928 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
929 FILE_OPEN
, /* create_disposition */
930 0, /* create_options */
934 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
935 status
= cli_smb2_create_fnum(cli
,
937 0, /* create_flags */
939 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
940 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
941 FILE_OPEN
, /* create_disposition */
942 FILE_DIRECTORY_FILE
, /* create_options */
953 /***************************************************************
954 Wrapper that allows SMB2 to query a path info (ALTNAME level).
956 ***************************************************************/
958 NTSTATUS
cli_smb2_qpathinfo_alt_name(struct cli_state
*cli
,
963 DATA_BLOB outbuf
= data_blob_null
;
964 uint16_t fnum
= 0xffff;
965 struct smb2_hnd
*ph
= NULL
;
966 uint32_t altnamelen
= 0;
967 TALLOC_CTX
*frame
= talloc_stackframe();
969 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
971 * Can't use sync call while an async call is in flight
973 status
= NT_STATUS_INVALID_PARAMETER
;
977 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
978 status
= NT_STATUS_INVALID_PARAMETER
;
982 status
= get_fnum_from_path(cli
,
984 FILE_READ_ATTRIBUTES
,
987 if (!NT_STATUS_IS_OK(status
)) {
991 status
= map_fnum_to_smb2_handle(cli
,
994 if (!NT_STATUS_IS_OK(status
)) {
998 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
999 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1001 status
= smb2cli_query_info(cli
->conn
,
1005 1, /* in_info_type */
1006 (SMB_FILE_ALTERNATE_NAME_INFORMATION
- 1000), /* in_file_info_class */
1007 0xFFFF, /* in_max_output_length */
1008 NULL
, /* in_input_buffer */
1009 0, /* in_additional_info */
1016 if (!NT_STATUS_IS_OK(status
)) {
1020 /* Parse the reply. */
1021 if (outbuf
.length
< 4) {
1022 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1026 altnamelen
= IVAL(outbuf
.data
, 0);
1027 if (altnamelen
> outbuf
.length
- 4) {
1028 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1032 if (altnamelen
> 0) {
1034 char *short_name
= NULL
;
1035 ret
= pull_string_talloc(frame
,
1037 FLAGS2_UNICODE_STRINGS
,
1042 if (ret
== (size_t)-1) {
1043 /* Bad conversion. */
1044 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1048 fstrcpy(alt_name
, short_name
);
1053 status
= NT_STATUS_OK
;
1057 if (fnum
!= 0xffff) {
1058 cli_smb2_close_fnum(cli
, fnum
);
1065 /***************************************************************
1066 Wrapper that allows SMB2 to query a fnum info (basic level).
1068 ***************************************************************/
1070 NTSTATUS
cli_smb2_qfileinfo_basic(struct cli_state
*cli
,
1074 struct timespec
*create_time
,
1075 struct timespec
*access_time
,
1076 struct timespec
*write_time
,
1077 struct timespec
*change_time
,
1081 DATA_BLOB outbuf
= data_blob_null
;
1082 struct smb2_hnd
*ph
= NULL
;
1083 TALLOC_CTX
*frame
= talloc_stackframe();
1085 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1087 * Can't use sync call while an async call is in flight
1089 status
= NT_STATUS_INVALID_PARAMETER
;
1093 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1094 status
= NT_STATUS_INVALID_PARAMETER
;
1098 status
= map_fnum_to_smb2_handle(cli
,
1101 if (!NT_STATUS_IS_OK(status
)) {
1105 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1106 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1108 status
= smb2cli_query_info(cli
->conn
,
1112 1, /* in_info_type */
1113 (SMB_FILE_ALL_INFORMATION
- 1000), /* in_file_info_class */
1114 0xFFFF, /* in_max_output_length */
1115 NULL
, /* in_input_buffer */
1116 0, /* in_additional_info */
1122 if (!NT_STATUS_IS_OK(status
)) {
1126 /* Parse the reply. */
1127 if (outbuf
.length
< 0x60) {
1128 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1133 *create_time
= interpret_long_date((const char *)outbuf
.data
+ 0x0);
1136 *access_time
= interpret_long_date((const char *)outbuf
.data
+ 0x8);
1139 *write_time
= interpret_long_date((const char *)outbuf
.data
+ 0x10);
1142 *change_time
= interpret_long_date((const char *)outbuf
.data
+ 0x18);
1145 uint32_t attr
= IVAL(outbuf
.data
, 0x20);
1146 *mode
= (uint16_t)attr
;
1149 uint64_t file_size
= BVAL(outbuf
.data
, 0x30);
1150 *size
= (off_t
)file_size
;
1153 uint64_t file_index
= BVAL(outbuf
.data
, 0x40);
1154 *ino
= (SMB_INO_T
)file_index
;
1163 /***************************************************************
1164 Wrapper that allows SMB2 to query an fnum.
1165 Implement on top of cli_smb2_qfileinfo_basic().
1167 ***************************************************************/
1169 NTSTATUS
cli_smb2_getattrE(struct cli_state
*cli
,
1173 time_t *change_time
,
1174 time_t *access_time
,
1177 struct timespec access_time_ts
;
1178 struct timespec write_time_ts
;
1179 struct timespec change_time_ts
;
1180 NTSTATUS status
= cli_smb2_qfileinfo_basic(cli
,
1190 if (!NT_STATUS_IS_OK(status
)) {
1195 *change_time
= change_time_ts
.tv_sec
;
1198 *access_time
= access_time_ts
.tv_sec
;
1201 *write_time
= write_time_ts
.tv_sec
;
1203 return NT_STATUS_OK
;
1206 /***************************************************************
1207 Wrapper that allows SMB2 to get pathname attributes.
1209 ***************************************************************/
1211 NTSTATUS
cli_smb2_getatr(struct cli_state
*cli
,
1218 uint16_t fnum
= 0xffff;
1219 struct smb2_hnd
*ph
= NULL
;
1220 TALLOC_CTX
*frame
= talloc_stackframe();
1222 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1224 * Can't use sync call while an async call is in flight
1226 status
= NT_STATUS_INVALID_PARAMETER
;
1230 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1231 status
= NT_STATUS_INVALID_PARAMETER
;
1235 status
= get_fnum_from_path(cli
,
1237 FILE_READ_ATTRIBUTES
,
1240 if (!NT_STATUS_IS_OK(status
)) {
1244 status
= map_fnum_to_smb2_handle(cli
,
1247 if (!NT_STATUS_IS_OK(status
)) {
1250 status
= cli_smb2_getattrE(cli
,
1257 if (!NT_STATUS_IS_OK(status
)) {
1263 if (fnum
!= 0xffff) {
1264 cli_smb2_close_fnum(cli
, fnum
);
1271 /***************************************************************
1272 Wrapper that allows SMB2 to query a pathname info (basic level).
1273 Implement on top of cli_smb2_qfileinfo_basic().
1275 ***************************************************************/
1277 NTSTATUS
cli_smb2_qpathinfo2(struct cli_state
*cli
,
1279 struct timespec
*create_time
,
1280 struct timespec
*access_time
,
1281 struct timespec
*write_time
,
1282 struct timespec
*change_time
,
1288 struct smb2_hnd
*ph
= NULL
;
1289 uint16_t fnum
= 0xffff;
1290 TALLOC_CTX
*frame
= talloc_stackframe();
1292 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1294 * Can't use sync call while an async call is in flight
1296 status
= NT_STATUS_INVALID_PARAMETER
;
1300 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1301 status
= NT_STATUS_INVALID_PARAMETER
;
1305 status
= get_fnum_from_path(cli
,
1307 FILE_READ_ATTRIBUTES
,
1310 if (!NT_STATUS_IS_OK(status
)) {
1314 status
= map_fnum_to_smb2_handle(cli
,
1317 if (!NT_STATUS_IS_OK(status
)) {
1321 status
= cli_smb2_qfileinfo_basic(cli
,
1333 if (fnum
!= 0xffff) {
1334 cli_smb2_close_fnum(cli
, fnum
);
1341 /***************************************************************
1342 Wrapper that allows SMB2 to query pathname streams.
1344 ***************************************************************/
1346 NTSTATUS
cli_smb2_qpathinfo_streams(struct cli_state
*cli
,
1348 TALLOC_CTX
*mem_ctx
,
1349 unsigned int *pnum_streams
,
1350 struct stream_struct
**pstreams
)
1353 struct smb2_hnd
*ph
= NULL
;
1354 uint16_t fnum
= 0xffff;
1355 DATA_BLOB outbuf
= data_blob_null
;
1356 TALLOC_CTX
*frame
= talloc_stackframe();
1358 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1360 * Can't use sync call while an async call is in flight
1362 status
= NT_STATUS_INVALID_PARAMETER
;
1366 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1367 status
= NT_STATUS_INVALID_PARAMETER
;
1371 status
= get_fnum_from_path(cli
,
1373 FILE_READ_ATTRIBUTES
,
1376 if (!NT_STATUS_IS_OK(status
)) {
1380 status
= map_fnum_to_smb2_handle(cli
,
1383 if (!NT_STATUS_IS_OK(status
)) {
1387 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1388 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1390 status
= smb2cli_query_info(cli
->conn
,
1394 1, /* in_info_type */
1395 (SMB_FILE_STREAM_INFORMATION
- 1000), /* in_file_info_class */
1396 0xFFFF, /* in_max_output_length */
1397 NULL
, /* in_input_buffer */
1398 0, /* in_additional_info */
1405 if (!NT_STATUS_IS_OK(status
)) {
1409 /* Parse the reply. */
1410 if (!parse_streams_blob(mem_ctx
,
1415 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1421 if (fnum
!= 0xffff) {
1422 cli_smb2_close_fnum(cli
, fnum
);
1429 /***************************************************************
1430 Wrapper that allows SMB2 to set pathname attributes.
1432 ***************************************************************/
1434 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
1440 uint16_t fnum
= 0xffff;
1441 struct smb2_hnd
*ph
= NULL
;
1442 uint8_t inbuf_store
[40];
1443 DATA_BLOB inbuf
= data_blob_null
;
1444 TALLOC_CTX
*frame
= talloc_stackframe();
1446 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1448 * Can't use sync call while an async call is in flight
1450 status
= NT_STATUS_INVALID_PARAMETER
;
1454 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1455 status
= NT_STATUS_INVALID_PARAMETER
;
1459 status
= get_fnum_from_path(cli
,
1461 FILE_WRITE_ATTRIBUTES
,
1464 if (!NT_STATUS_IS_OK(status
)) {
1468 status
= map_fnum_to_smb2_handle(cli
,
1471 if (!NT_STATUS_IS_OK(status
)) {
1475 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1476 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1478 inbuf
.data
= inbuf_store
;
1479 inbuf
.length
= sizeof(inbuf_store
);
1480 data_blob_clear(&inbuf
);
1482 SSVAL(inbuf
.data
, 32, attr
);
1484 put_long_date((char *)inbuf
.data
+ 16,mtime
);
1486 /* Set all the other times to -1. */
1487 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1488 SBVAL(inbuf
.data
, 8, 0xFFFFFFFFFFFFFFFFLL
);
1489 SBVAL(inbuf
.data
, 24, 0xFFFFFFFFFFFFFFFFLL
);
1491 status
= smb2cli_set_info(cli
->conn
,
1495 1, /* in_info_type */
1496 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1497 &inbuf
, /* in_input_buffer */
1498 0, /* in_additional_info */
1503 if (fnum
!= 0xffff) {
1504 cli_smb2_close_fnum(cli
, fnum
);
1511 /***************************************************************
1512 Wrapper that allows SMB2 to set file handle times.
1514 ***************************************************************/
1516 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
1523 struct smb2_hnd
*ph
= NULL
;
1524 uint8_t inbuf_store
[40];
1525 DATA_BLOB inbuf
= data_blob_null
;
1527 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1529 * Can't use sync call while an async call is in flight
1531 return NT_STATUS_INVALID_PARAMETER
;
1534 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1535 return NT_STATUS_INVALID_PARAMETER
;
1538 status
= map_fnum_to_smb2_handle(cli
,
1541 if (!NT_STATUS_IS_OK(status
)) {
1545 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1546 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1548 inbuf
.data
= inbuf_store
;
1549 inbuf
.length
= sizeof(inbuf_store
);
1550 data_blob_clear(&inbuf
);
1552 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1553 if (change_time
!= 0) {
1554 put_long_date((char *)inbuf
.data
+ 24, change_time
);
1556 if (access_time
!= 0) {
1557 put_long_date((char *)inbuf
.data
+ 8, access_time
);
1559 if (write_time
!= 0) {
1560 put_long_date((char *)inbuf
.data
+ 16, write_time
);
1563 return smb2cli_set_info(cli
->conn
,
1567 1, /* in_info_type */
1568 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1569 &inbuf
, /* in_input_buffer */
1570 0, /* in_additional_info */
1575 /***************************************************************
1576 Wrapper that allows SMB2 to query disk attributes (size).
1578 ***************************************************************/
1580 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, uint64_t *bsize
, uint64_t *total
, uint64_t *avail
)
1583 uint16_t fnum
= 0xffff;
1584 DATA_BLOB outbuf
= data_blob_null
;
1585 struct smb2_hnd
*ph
= NULL
;
1586 uint32_t sectors_per_unit
= 0;
1587 uint32_t bytes_per_sector
= 0;
1588 uint64_t total_size
= 0;
1589 uint64_t size_free
= 0;
1590 TALLOC_CTX
*frame
= talloc_stackframe();
1592 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1594 * Can't use sync call while an async call is in flight
1596 status
= NT_STATUS_INVALID_PARAMETER
;
1600 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1601 status
= NT_STATUS_INVALID_PARAMETER
;
1605 /* First open the top level directory. */
1606 status
= cli_smb2_create_fnum(cli
,
1608 0, /* create_flags */
1609 FILE_READ_ATTRIBUTES
, /* desired_access */
1610 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1611 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1612 FILE_OPEN
, /* create_disposition */
1613 FILE_DIRECTORY_FILE
, /* create_options */
1617 if (!NT_STATUS_IS_OK(status
)) {
1621 status
= map_fnum_to_smb2_handle(cli
,
1624 if (!NT_STATUS_IS_OK(status
)) {
1628 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1629 level 3 (SMB_FS_SIZE_INFORMATION). */
1631 status
= smb2cli_query_info(cli
->conn
,
1635 2, /* in_info_type */
1636 3, /* in_file_info_class */
1637 0xFFFF, /* in_max_output_length */
1638 NULL
, /* in_input_buffer */
1639 0, /* in_additional_info */
1645 if (!NT_STATUS_IS_OK(status
)) {
1649 /* Parse the reply. */
1650 if (outbuf
.length
!= 24) {
1651 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1655 total_size
= BVAL(outbuf
.data
, 0);
1656 size_free
= BVAL(outbuf
.data
, 8);
1657 sectors_per_unit
= IVAL(outbuf
.data
, 16);
1658 bytes_per_sector
= IVAL(outbuf
.data
, 20);
1661 *bsize
= (uint64_t)sectors_per_unit
* (uint64_t)bytes_per_sector
;
1664 *total
= total_size
;
1670 status
= NT_STATUS_OK
;
1674 if (fnum
!= 0xffff) {
1675 cli_smb2_close_fnum(cli
, fnum
);
1682 /***************************************************************
1683 Wrapper that allows SMB2 to query a security descriptor.
1685 ***************************************************************/
1687 NTSTATUS
cli_smb2_query_security_descriptor(struct cli_state
*cli
,
1690 TALLOC_CTX
*mem_ctx
,
1691 struct security_descriptor
**ppsd
)
1694 DATA_BLOB outbuf
= data_blob_null
;
1695 struct smb2_hnd
*ph
= NULL
;
1696 struct security_descriptor
*lsd
= NULL
;
1697 TALLOC_CTX
*frame
= talloc_stackframe();
1699 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1701 * Can't use sync call while an async call is in flight
1703 status
= NT_STATUS_INVALID_PARAMETER
;
1707 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1708 status
= NT_STATUS_INVALID_PARAMETER
;
1712 status
= map_fnum_to_smb2_handle(cli
,
1715 if (!NT_STATUS_IS_OK(status
)) {
1719 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1721 status
= smb2cli_query_info(cli
->conn
,
1725 3, /* in_info_type */
1726 0, /* in_file_info_class */
1727 0xFFFF, /* in_max_output_length */
1728 NULL
, /* in_input_buffer */
1729 sec_info
, /* in_additional_info */
1736 if (!NT_STATUS_IS_OK(status
)) {
1740 /* Parse the reply. */
1741 status
= unmarshall_sec_desc(mem_ctx
,
1746 if (!NT_STATUS_IS_OK(status
)) {
1762 /***************************************************************
1763 Wrapper that allows SMB2 to set a security descriptor.
1765 ***************************************************************/
1767 NTSTATUS
cli_smb2_set_security_descriptor(struct cli_state
*cli
,
1770 const struct security_descriptor
*sd
)
1773 DATA_BLOB inbuf
= data_blob_null
;
1774 struct smb2_hnd
*ph
= NULL
;
1775 TALLOC_CTX
*frame
= talloc_stackframe();
1777 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1779 * Can't use sync call while an async call is in flight
1781 status
= NT_STATUS_INVALID_PARAMETER
;
1785 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1786 status
= NT_STATUS_INVALID_PARAMETER
;
1790 status
= map_fnum_to_smb2_handle(cli
,
1793 if (!NT_STATUS_IS_OK(status
)) {
1797 status
= marshall_sec_desc(frame
,
1802 if (!NT_STATUS_IS_OK(status
)) {
1806 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1808 status
= smb2cli_set_info(cli
->conn
,
1812 3, /* in_info_type */
1813 0, /* in_file_info_class */
1814 &inbuf
, /* in_input_buffer */
1815 sec_info
, /* in_additional_info */
1825 /***************************************************************
1826 Wrapper that allows SMB2 to rename a file.
1828 ***************************************************************/
1830 NTSTATUS
cli_smb2_rename(struct cli_state
*cli
,
1831 const char *fname_src
,
1832 const char *fname_dst
)
1835 DATA_BLOB inbuf
= data_blob_null
;
1836 uint16_t fnum
= 0xffff;
1837 struct smb2_hnd
*ph
= NULL
;
1838 smb_ucs2_t
*converted_str
= NULL
;
1839 size_t converted_size_bytes
= 0;
1841 TALLOC_CTX
*frame
= talloc_stackframe();
1843 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1845 * Can't use sync call while an async call is in flight
1847 status
= NT_STATUS_INVALID_PARAMETER
;
1851 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1852 status
= NT_STATUS_INVALID_PARAMETER
;
1856 status
= get_fnum_from_path(cli
,
1861 if (!NT_STATUS_IS_OK(status
)) {
1865 status
= map_fnum_to_smb2_handle(cli
,
1868 if (!NT_STATUS_IS_OK(status
)) {
1872 /* SMB2 is pickier about pathnames. Ensure it doesn't
1874 if (*fname_dst
== '\\') {
1878 /* SMB2 is pickier about pathnames. Ensure it doesn't
1880 namelen
= strlen(fname_dst
);
1881 if (namelen
> 0 && fname_dst
[namelen
-1] == '\\') {
1882 char *modname
= talloc_strdup(frame
, fname_dst
);
1883 modname
[namelen
-1] = '\0';
1884 fname_dst
= modname
;
1887 if (!push_ucs2_talloc(frame
,
1890 &converted_size_bytes
)) {
1891 status
= NT_STATUS_INVALID_PARAMETER
;
1895 /* W2K8 insists the dest name is not null
1896 terminated. Remove the last 2 zero bytes
1897 and reduce the name length. */
1899 if (converted_size_bytes
< 2) {
1900 status
= NT_STATUS_INVALID_PARAMETER
;
1903 converted_size_bytes
-= 2;
1905 inbuf
= data_blob_talloc_zero(frame
,
1906 20 + converted_size_bytes
);
1907 if (inbuf
.data
== NULL
) {
1908 status
= NT_STATUS_NO_MEMORY
;
1912 SIVAL(inbuf
.data
, 16, converted_size_bytes
);
1913 memcpy(inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
1915 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
1916 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
1918 status
= smb2cli_set_info(cli
->conn
,
1922 1, /* in_info_type */
1923 SMB_FILE_RENAME_INFORMATION
- 1000, /* in_file_info_class */
1924 &inbuf
, /* in_input_buffer */
1925 0, /* in_additional_info */
1931 if (fnum
!= 0xffff) {
1932 cli_smb2_close_fnum(cli
, fnum
);
1939 /***************************************************************
1940 Wrapper that allows SMB2 to set an EA on a fnum.
1942 ***************************************************************/
1944 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
1946 const char *ea_name
,
1951 DATA_BLOB inbuf
= data_blob_null
;
1953 char *ea_name_ascii
= NULL
;
1955 struct smb2_hnd
*ph
= NULL
;
1956 TALLOC_CTX
*frame
= talloc_stackframe();
1958 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1960 * Can't use sync call while an async call is in flight
1962 status
= NT_STATUS_INVALID_PARAMETER
;
1966 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1967 status
= NT_STATUS_INVALID_PARAMETER
;
1971 status
= map_fnum_to_smb2_handle(cli
,
1974 if (!NT_STATUS_IS_OK(status
)) {
1978 /* Marshall the SMB2 EA data. */
1979 if (ea_len
> 0xFFFF) {
1980 status
= NT_STATUS_INVALID_PARAMETER
;
1984 if (!push_ascii_talloc(frame
,
1988 status
= NT_STATUS_INVALID_PARAMETER
;
1992 if (namelen
< 2 || namelen
> 0xFF) {
1993 status
= NT_STATUS_INVALID_PARAMETER
;
1997 bloblen
= 8 + ea_len
+ namelen
;
1998 /* Round up to a 4 byte boundary. */
1999 bloblen
= ((bloblen
+ 3)&~3);
2001 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
2002 if (inbuf
.data
== NULL
) {
2003 status
= NT_STATUS_NO_MEMORY
;
2006 /* namelen doesn't include the NULL byte. */
2007 SCVAL(inbuf
.data
, 5, namelen
- 1);
2008 SSVAL(inbuf
.data
, 6, ea_len
);
2009 memcpy(inbuf
.data
+ 8, ea_name_ascii
, namelen
);
2010 memcpy(inbuf
.data
+ 8 + namelen
, ea_val
, ea_len
);
2012 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2013 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2015 status
= smb2cli_set_info(cli
->conn
,
2019 1, /* in_info_type */
2020 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
2021 &inbuf
, /* in_input_buffer */
2022 0, /* in_additional_info */
2032 /***************************************************************
2033 Wrapper that allows SMB2 to set an EA on a pathname.
2035 ***************************************************************/
2037 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
2039 const char *ea_name
,
2044 uint16_t fnum
= 0xffff;
2046 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2048 * Can't use sync call while an async call is in flight
2050 status
= NT_STATUS_INVALID_PARAMETER
;
2054 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2055 status
= NT_STATUS_INVALID_PARAMETER
;
2059 status
= get_fnum_from_path(cli
,
2064 if (!NT_STATUS_IS_OK(status
)) {
2068 status
= cli_set_ea_fnum(cli
,
2073 if (!NT_STATUS_IS_OK(status
)) {
2079 if (fnum
!= 0xffff) {
2080 cli_smb2_close_fnum(cli
, fnum
);
2086 /***************************************************************
2087 Wrapper that allows SMB2 to get an EA list on a pathname.
2089 ***************************************************************/
2091 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
2095 struct ea_struct
**pea_array
)
2098 uint16_t fnum
= 0xffff;
2099 DATA_BLOB outbuf
= data_blob_null
;
2100 struct smb2_hnd
*ph
= NULL
;
2101 struct ea_list
*ea_list
= NULL
;
2102 struct ea_list
*eal
= NULL
;
2103 size_t ea_count
= 0;
2104 TALLOC_CTX
*frame
= talloc_stackframe();
2109 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2111 * Can't use sync call while an async call is in flight
2113 status
= NT_STATUS_INVALID_PARAMETER
;
2117 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2118 status
= NT_STATUS_INVALID_PARAMETER
;
2122 status
= get_fnum_from_path(cli
,
2127 if (!NT_STATUS_IS_OK(status
)) {
2131 status
= map_fnum_to_smb2_handle(cli
,
2134 if (!NT_STATUS_IS_OK(status
)) {
2138 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2139 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2141 status
= smb2cli_query_info(cli
->conn
,
2145 1, /* in_info_type */
2146 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
2147 0xFFFF, /* in_max_output_length */
2148 NULL
, /* in_input_buffer */
2149 0, /* in_additional_info */
2156 if (!NT_STATUS_IS_OK(status
)) {
2160 /* Parse the reply. */
2161 ea_list
= read_nttrans_ea_list(ctx
,
2162 (const char *)outbuf
.data
,
2164 if (ea_list
== NULL
) {
2165 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2169 /* Convert to an array. */
2170 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2175 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
2176 if (*pea_array
== NULL
) {
2177 status
= NT_STATUS_NO_MEMORY
;
2181 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2182 (*pea_array
)[ea_count
++] = ea_list
->ea
;
2184 *pnum_eas
= ea_count
;
2189 if (fnum
!= 0xffff) {
2190 cli_smb2_close_fnum(cli
, fnum
);
2197 struct cli_smb2_read_state
{
2198 struct tevent_context
*ev
;
2199 struct cli_state
*cli
;
2200 struct smb2_hnd
*ph
;
2201 uint64_t start_offset
;
2207 static void cli_smb2_read_done(struct tevent_req
*subreq
);
2209 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
2210 struct tevent_context
*ev
,
2211 struct cli_state
*cli
,
2217 struct tevent_req
*req
, *subreq
;
2218 struct cli_smb2_read_state
*state
;
2220 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
2226 state
->start_offset
= (uint64_t)offset
;
2227 state
->size
= (uint32_t)size
;
2228 state
->received
= 0;
2231 status
= map_fnum_to_smb2_handle(cli
,
2234 if (tevent_req_nterror(req
, status
)) {
2235 return tevent_req_post(req
, ev
);
2238 subreq
= smb2cli_read_send(state
,
2241 state
->cli
->timeout
,
2242 state
->cli
->smb2
.session
,
2243 state
->cli
->smb2
.tcon
,
2245 state
->start_offset
,
2246 state
->ph
->fid_persistent
,
2247 state
->ph
->fid_volatile
,
2248 0, /* minimum_count */
2249 0); /* remaining_bytes */
2251 if (tevent_req_nomem(subreq
, req
)) {
2252 return tevent_req_post(req
, ev
);
2254 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
2258 static void cli_smb2_read_done(struct tevent_req
*subreq
)
2260 struct tevent_req
*req
= tevent_req_callback_data(
2261 subreq
, struct tevent_req
);
2262 struct cli_smb2_read_state
*state
= tevent_req_data(
2263 req
, struct cli_smb2_read_state
);
2266 status
= smb2cli_read_recv(subreq
, state
,
2267 &state
->buf
, &state
->received
);
2268 if (tevent_req_nterror(req
, status
)) {
2272 if (state
->received
> state
->size
) {
2273 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2277 tevent_req_done(req
);
2280 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
2285 struct cli_smb2_read_state
*state
= tevent_req_data(
2286 req
, struct cli_smb2_read_state
);
2288 if (tevent_req_is_nterror(req
, &status
)) {
2292 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2293 * better make sure that you copy it away before you talloc_free(req).
2294 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2296 *received
= (ssize_t
)state
->received
;
2297 *rcvbuf
= state
->buf
;
2298 return NT_STATUS_OK
;
2301 struct cli_smb2_write_state
{
2302 struct tevent_context
*ev
;
2303 struct cli_state
*cli
;
2304 struct smb2_hnd
*ph
;
2312 static void cli_smb2_write_written(struct tevent_req
*req
);
2314 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
2315 struct tevent_context
*ev
,
2316 struct cli_state
*cli
,
2324 struct tevent_req
*req
, *subreq
= NULL
;
2325 struct cli_smb2_write_state
*state
= NULL
;
2327 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
2333 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2334 state
->flags
= (uint32_t)mode
;
2336 state
->offset
= (uint64_t)offset
;
2337 state
->size
= (uint32_t)size
;
2340 status
= map_fnum_to_smb2_handle(cli
,
2343 if (tevent_req_nterror(req
, status
)) {
2344 return tevent_req_post(req
, ev
);
2347 subreq
= smb2cli_write_send(state
,
2350 state
->cli
->timeout
,
2351 state
->cli
->smb2
.session
,
2352 state
->cli
->smb2
.tcon
,
2355 state
->ph
->fid_persistent
,
2356 state
->ph
->fid_volatile
,
2357 0, /* remaining_bytes */
2358 state
->flags
, /* flags */
2361 if (tevent_req_nomem(subreq
, req
)) {
2362 return tevent_req_post(req
, ev
);
2364 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
2368 static void cli_smb2_write_written(struct tevent_req
*subreq
)
2370 struct tevent_req
*req
= tevent_req_callback_data(
2371 subreq
, struct tevent_req
);
2372 struct cli_smb2_write_state
*state
= tevent_req_data(
2373 req
, struct cli_smb2_write_state
);
2377 status
= smb2cli_write_recv(subreq
, &written
);
2378 TALLOC_FREE(subreq
);
2379 if (tevent_req_nterror(req
, status
)) {
2383 state
->written
= written
;
2385 tevent_req_done(req
);
2388 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
2391 struct cli_smb2_write_state
*state
= tevent_req_data(
2392 req
, struct cli_smb2_write_state
);
2395 if (tevent_req_is_nterror(req
, &status
)) {
2396 tevent_req_received(req
);
2400 if (pwritten
!= NULL
) {
2401 *pwritten
= (size_t)state
->written
;
2403 tevent_req_received(req
);
2404 return NT_STATUS_OK
;
2407 /***************************************************************
2408 Wrapper that allows SMB2 async write using an fnum.
2409 This is mostly cut-and-paste from Volker's code inside
2410 source3/libsmb/clireadwrite.c, adapted for SMB2.
2412 Done this way so I can reuse all the logic inside cli_push()
2414 ***************************************************************/
2416 struct cli_smb2_writeall_state
{
2417 struct tevent_context
*ev
;
2418 struct cli_state
*cli
;
2419 struct smb2_hnd
*ph
;
2427 static void cli_smb2_writeall_written(struct tevent_req
*req
);
2429 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
2430 struct tevent_context
*ev
,
2431 struct cli_state
*cli
,
2439 struct tevent_req
*req
, *subreq
= NULL
;
2440 struct cli_smb2_writeall_state
*state
= NULL
;
2445 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
2451 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2452 state
->flags
= (uint32_t)mode
;
2454 state
->offset
= (uint64_t)offset
;
2455 state
->size
= (uint32_t)size
;
2458 status
= map_fnum_to_smb2_handle(cli
,
2461 if (tevent_req_nterror(req
, status
)) {
2462 return tevent_req_post(req
, ev
);
2465 to_write
= state
->size
;
2466 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
2467 to_write
= MIN(max_size
, to_write
);
2468 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
2470 to_write
= MIN(max_size
, to_write
);
2473 subreq
= smb2cli_write_send(state
,
2476 state
->cli
->timeout
,
2477 state
->cli
->smb2
.session
,
2478 state
->cli
->smb2
.tcon
,
2481 state
->ph
->fid_persistent
,
2482 state
->ph
->fid_volatile
,
2483 0, /* remaining_bytes */
2484 state
->flags
, /* flags */
2485 state
->buf
+ state
->written
);
2487 if (tevent_req_nomem(subreq
, req
)) {
2488 return tevent_req_post(req
, ev
);
2490 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
2494 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
2496 struct tevent_req
*req
= tevent_req_callback_data(
2497 subreq
, struct tevent_req
);
2498 struct cli_smb2_writeall_state
*state
= tevent_req_data(
2499 req
, struct cli_smb2_writeall_state
);
2501 uint32_t written
, to_write
;
2505 status
= smb2cli_write_recv(subreq
, &written
);
2506 TALLOC_FREE(subreq
);
2507 if (tevent_req_nterror(req
, status
)) {
2511 state
->written
+= written
;
2513 if (state
->written
> state
->size
) {
2514 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2518 to_write
= state
->size
- state
->written
;
2520 if (to_write
== 0) {
2521 tevent_req_done(req
);
2525 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
2526 to_write
= MIN(max_size
, to_write
);
2527 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
2529 to_write
= MIN(max_size
, to_write
);
2532 subreq
= smb2cli_write_send(state
,
2535 state
->cli
->timeout
,
2536 state
->cli
->smb2
.session
,
2537 state
->cli
->smb2
.tcon
,
2539 state
->offset
+ state
->written
,
2540 state
->ph
->fid_persistent
,
2541 state
->ph
->fid_volatile
,
2542 0, /* remaining_bytes */
2543 state
->flags
, /* flags */
2544 state
->buf
+ state
->written
);
2546 if (tevent_req_nomem(subreq
, req
)) {
2549 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
2552 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
2555 struct cli_smb2_writeall_state
*state
= tevent_req_data(
2556 req
, struct cli_smb2_writeall_state
);
2559 if (tevent_req_is_nterror(req
, &status
)) {
2562 if (pwritten
!= NULL
) {
2563 *pwritten
= (size_t)state
->written
;
2565 return NT_STATUS_OK
;