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
;
672 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
674 * Can't use sync call while an async call is in flight
676 status
= NT_STATUS_INVALID_PARAMETER
;
680 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
681 status
= NT_STATUS_INVALID_PARAMETER
;
685 /* Get the directory name. */
686 if (!windows_parent_dirname(frame
,
690 status
= NT_STATUS_NO_MEMORY
;
694 mask_has_wild
= ms_has_wild(mask
);
696 status
= cli_smb2_create_fnum(cli
,
698 0, /* create_flags */
699 SEC_DIR_LIST
|SEC_DIR_READ_ATTRIBUTE
,/* desired_access */
700 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
701 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
702 FILE_OPEN
, /* create_disposition */
703 FILE_DIRECTORY_FILE
, /* create_options */
707 if (!NT_STATUS_IS_OK(status
)) {
711 status
= map_fnum_to_smb2_handle(cli
,
714 if (!NT_STATUS_IS_OK(status
)) {
719 uint8_t *dir_data
= NULL
;
720 uint32_t dir_data_length
= 0;
721 uint32_t next_offset
= 0;
722 subframe
= talloc_stackframe();
724 status
= smb2cli_query_directory(cli
->conn
,
728 SMB2_FIND_ID_BOTH_DIRECTORY_INFO
,
739 if (!NT_STATUS_IS_OK(status
)) {
740 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
747 struct file_info
*finfo
= talloc_zero(subframe
,
751 status
= NT_STATUS_NO_MEMORY
;
755 status
= parse_finfo_id_both_directory_info(dir_data
,
760 if (!NT_STATUS_IS_OK(status
)) {
764 if (dir_check_ftype((uint32_t)finfo
->mode
,
765 (uint32_t)attribute
)) {
767 * Only process if attributes match.
768 * On SMB1 server does this, so on
769 * SMB2 we need to emulate in the
772 * https://bugzilla.samba.org/show_bug.cgi?id=10260
774 processed_file
= true;
776 status
= fn(cli
->dfs_mountpoint
,
781 if (!NT_STATUS_IS_OK(status
)) {
788 /* Move to next entry. */
790 dir_data
+= next_offset
;
791 dir_data_length
-= next_offset
;
793 } while (next_offset
!= 0);
795 TALLOC_FREE(subframe
);
797 if (!mask_has_wild
) {
799 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
800 * when handed a non-wildcard path. Do it
801 * for the server (with a non-wildcard path
802 * there should only ever be one file returned.
804 status
= STATUS_NO_MORE_FILES
;
808 } while (NT_STATUS_IS_OK(status
));
810 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
811 status
= NT_STATUS_OK
;
814 if (NT_STATUS_IS_OK(status
) && !processed_file
) {
816 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
817 * if no files match. Emulate this in the client.
819 status
= NT_STATUS_NO_SUCH_FILE
;
824 if (fnum
!= 0xffff) {
825 cli_smb2_close_fnum(cli
, fnum
);
827 TALLOC_FREE(subframe
);
832 /***************************************************************
833 Wrapper that allows SMB2 to query a path info (basic level).
835 ***************************************************************/
837 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
839 SMB_STRUCT_STAT
*sbuf
,
840 uint32_t *attributes
)
843 struct smb_create_returns cr
;
844 uint16_t fnum
= 0xffff;
845 size_t namelen
= strlen(name
);
847 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
849 * Can't use sync call while an async call is in flight
851 return NT_STATUS_INVALID_PARAMETER
;
854 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
855 return NT_STATUS_INVALID_PARAMETER
;
858 /* SMB2 is pickier about pathnames. Ensure it doesn't
860 if (namelen
> 0 && name
[namelen
-1] == '\\') {
861 char *modname
= talloc_strdup(talloc_tos(), name
);
862 modname
[namelen
-1] = '\0';
866 /* This is commonly used as a 'cd'. Try qpathinfo on
867 a directory handle first. */
869 status
= cli_smb2_create_fnum(cli
,
871 0, /* create_flags */
872 FILE_READ_ATTRIBUTES
, /* desired_access */
873 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
874 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
875 FILE_OPEN
, /* create_disposition */
876 FILE_DIRECTORY_FILE
, /* create_options */
880 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
882 status
= cli_smb2_create_fnum(cli
,
884 0, /* create_flags */
885 FILE_READ_ATTRIBUTES
, /* desired_access */
886 0, /* file attributes */
887 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
888 FILE_OPEN
, /* create_disposition */
889 0, /* create_options */
894 if (!NT_STATUS_IS_OK(status
)) {
898 cli_smb2_close_fnum(cli
, fnum
);
902 sbuf
->st_ex_atime
= nt_time_to_unix_timespec(cr
.last_access_time
);
903 sbuf
->st_ex_mtime
= nt_time_to_unix_timespec(cr
.last_write_time
);
904 sbuf
->st_ex_ctime
= nt_time_to_unix_timespec(cr
.change_time
);
905 sbuf
->st_ex_size
= cr
.end_of_file
;
906 *attributes
= cr
.file_attributes
;
911 /***************************************************************
912 Helper function for pathname operations.
913 ***************************************************************/
915 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
917 uint32_t desired_access
,
921 size_t namelen
= strlen(name
);
922 TALLOC_CTX
*frame
= talloc_stackframe();
924 /* SMB2 is pickier about pathnames. Ensure it doesn't
926 if (namelen
> 0 && name
[namelen
-1] == '\\') {
927 char *modname
= talloc_strdup(frame
, name
);
928 if (modname
== NULL
) {
929 status
= NT_STATUS_NO_MEMORY
;
932 modname
[namelen
-1] = '\0';
936 /* Try to open a file handle first. */
937 status
= cli_smb2_create_fnum(cli
,
939 0, /* create_flags */
941 0, /* file attributes */
942 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
943 FILE_OPEN
, /* create_disposition */
944 0, /* create_options */
948 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
949 status
= cli_smb2_create_fnum(cli
,
951 0, /* create_flags */
953 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
954 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
955 FILE_OPEN
, /* create_disposition */
956 FILE_DIRECTORY_FILE
, /* create_options */
967 /***************************************************************
968 Wrapper that allows SMB2 to query a path info (ALTNAME level).
970 ***************************************************************/
972 NTSTATUS
cli_smb2_qpathinfo_alt_name(struct cli_state
*cli
,
977 DATA_BLOB outbuf
= data_blob_null
;
978 uint16_t fnum
= 0xffff;
979 struct smb2_hnd
*ph
= NULL
;
980 uint32_t altnamelen
= 0;
981 TALLOC_CTX
*frame
= talloc_stackframe();
983 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
985 * Can't use sync call while an async call is in flight
987 status
= NT_STATUS_INVALID_PARAMETER
;
991 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
992 status
= NT_STATUS_INVALID_PARAMETER
;
996 status
= get_fnum_from_path(cli
,
998 FILE_READ_ATTRIBUTES
,
1001 if (!NT_STATUS_IS_OK(status
)) {
1005 status
= map_fnum_to_smb2_handle(cli
,
1008 if (!NT_STATUS_IS_OK(status
)) {
1012 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1013 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1015 status
= smb2cli_query_info(cli
->conn
,
1019 1, /* in_info_type */
1020 (SMB_FILE_ALTERNATE_NAME_INFORMATION
- 1000), /* in_file_info_class */
1021 0xFFFF, /* in_max_output_length */
1022 NULL
, /* in_input_buffer */
1023 0, /* in_additional_info */
1030 if (!NT_STATUS_IS_OK(status
)) {
1034 /* Parse the reply. */
1035 if (outbuf
.length
< 4) {
1036 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1040 altnamelen
= IVAL(outbuf
.data
, 0);
1041 if (altnamelen
> outbuf
.length
- 4) {
1042 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1046 if (altnamelen
> 0) {
1048 char *short_name
= NULL
;
1049 ret
= pull_string_talloc(frame
,
1051 FLAGS2_UNICODE_STRINGS
,
1056 if (ret
== (size_t)-1) {
1057 /* Bad conversion. */
1058 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1062 fstrcpy(alt_name
, short_name
);
1067 status
= NT_STATUS_OK
;
1071 if (fnum
!= 0xffff) {
1072 cli_smb2_close_fnum(cli
, fnum
);
1079 /***************************************************************
1080 Wrapper that allows SMB2 to query a fnum info (basic level).
1082 ***************************************************************/
1084 NTSTATUS
cli_smb2_qfileinfo_basic(struct cli_state
*cli
,
1088 struct timespec
*create_time
,
1089 struct timespec
*access_time
,
1090 struct timespec
*write_time
,
1091 struct timespec
*change_time
,
1095 DATA_BLOB outbuf
= data_blob_null
;
1096 struct smb2_hnd
*ph
= NULL
;
1097 TALLOC_CTX
*frame
= talloc_stackframe();
1099 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1101 * Can't use sync call while an async call is in flight
1103 status
= NT_STATUS_INVALID_PARAMETER
;
1107 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1108 status
= NT_STATUS_INVALID_PARAMETER
;
1112 status
= map_fnum_to_smb2_handle(cli
,
1115 if (!NT_STATUS_IS_OK(status
)) {
1119 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1120 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1122 status
= smb2cli_query_info(cli
->conn
,
1126 1, /* in_info_type */
1127 (SMB_FILE_ALL_INFORMATION
- 1000), /* in_file_info_class */
1128 0xFFFF, /* in_max_output_length */
1129 NULL
, /* in_input_buffer */
1130 0, /* in_additional_info */
1136 if (!NT_STATUS_IS_OK(status
)) {
1140 /* Parse the reply. */
1141 if (outbuf
.length
< 0x60) {
1142 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1147 *create_time
= interpret_long_date((const char *)outbuf
.data
+ 0x0);
1150 *access_time
= interpret_long_date((const char *)outbuf
.data
+ 0x8);
1153 *write_time
= interpret_long_date((const char *)outbuf
.data
+ 0x10);
1156 *change_time
= interpret_long_date((const char *)outbuf
.data
+ 0x18);
1159 uint32_t attr
= IVAL(outbuf
.data
, 0x20);
1160 *mode
= (uint16_t)attr
;
1163 uint64_t file_size
= BVAL(outbuf
.data
, 0x30);
1164 *size
= (off_t
)file_size
;
1167 uint64_t file_index
= BVAL(outbuf
.data
, 0x40);
1168 *ino
= (SMB_INO_T
)file_index
;
1177 /***************************************************************
1178 Wrapper that allows SMB2 to query an fnum.
1179 Implement on top of cli_smb2_qfileinfo_basic().
1181 ***************************************************************/
1183 NTSTATUS
cli_smb2_getattrE(struct cli_state
*cli
,
1187 time_t *change_time
,
1188 time_t *access_time
,
1191 struct timespec access_time_ts
;
1192 struct timespec write_time_ts
;
1193 struct timespec change_time_ts
;
1194 NTSTATUS status
= cli_smb2_qfileinfo_basic(cli
,
1204 if (!NT_STATUS_IS_OK(status
)) {
1209 *change_time
= change_time_ts
.tv_sec
;
1212 *access_time
= access_time_ts
.tv_sec
;
1215 *write_time
= write_time_ts
.tv_sec
;
1217 return NT_STATUS_OK
;
1220 /***************************************************************
1221 Wrapper that allows SMB2 to get pathname attributes.
1223 ***************************************************************/
1225 NTSTATUS
cli_smb2_getatr(struct cli_state
*cli
,
1232 uint16_t fnum
= 0xffff;
1233 struct smb2_hnd
*ph
= NULL
;
1234 TALLOC_CTX
*frame
= talloc_stackframe();
1236 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1238 * Can't use sync call while an async call is in flight
1240 status
= NT_STATUS_INVALID_PARAMETER
;
1244 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1245 status
= NT_STATUS_INVALID_PARAMETER
;
1249 status
= get_fnum_from_path(cli
,
1251 FILE_READ_ATTRIBUTES
,
1254 if (!NT_STATUS_IS_OK(status
)) {
1258 status
= map_fnum_to_smb2_handle(cli
,
1261 if (!NT_STATUS_IS_OK(status
)) {
1264 status
= cli_smb2_getattrE(cli
,
1271 if (!NT_STATUS_IS_OK(status
)) {
1277 if (fnum
!= 0xffff) {
1278 cli_smb2_close_fnum(cli
, fnum
);
1285 /***************************************************************
1286 Wrapper that allows SMB2 to query a pathname info (basic level).
1287 Implement on top of cli_smb2_qfileinfo_basic().
1289 ***************************************************************/
1291 NTSTATUS
cli_smb2_qpathinfo2(struct cli_state
*cli
,
1293 struct timespec
*create_time
,
1294 struct timespec
*access_time
,
1295 struct timespec
*write_time
,
1296 struct timespec
*change_time
,
1302 struct smb2_hnd
*ph
= NULL
;
1303 uint16_t fnum
= 0xffff;
1304 TALLOC_CTX
*frame
= talloc_stackframe();
1306 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1308 * Can't use sync call while an async call is in flight
1310 status
= NT_STATUS_INVALID_PARAMETER
;
1314 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1315 status
= NT_STATUS_INVALID_PARAMETER
;
1319 status
= get_fnum_from_path(cli
,
1321 FILE_READ_ATTRIBUTES
,
1324 if (!NT_STATUS_IS_OK(status
)) {
1328 status
= map_fnum_to_smb2_handle(cli
,
1331 if (!NT_STATUS_IS_OK(status
)) {
1335 status
= cli_smb2_qfileinfo_basic(cli
,
1347 if (fnum
!= 0xffff) {
1348 cli_smb2_close_fnum(cli
, fnum
);
1355 /***************************************************************
1356 Wrapper that allows SMB2 to query pathname streams.
1358 ***************************************************************/
1360 NTSTATUS
cli_smb2_qpathinfo_streams(struct cli_state
*cli
,
1362 TALLOC_CTX
*mem_ctx
,
1363 unsigned int *pnum_streams
,
1364 struct stream_struct
**pstreams
)
1367 struct smb2_hnd
*ph
= NULL
;
1368 uint16_t fnum
= 0xffff;
1369 DATA_BLOB outbuf
= data_blob_null
;
1370 TALLOC_CTX
*frame
= talloc_stackframe();
1372 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1374 * Can't use sync call while an async call is in flight
1376 status
= NT_STATUS_INVALID_PARAMETER
;
1380 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1381 status
= NT_STATUS_INVALID_PARAMETER
;
1385 status
= get_fnum_from_path(cli
,
1387 FILE_READ_ATTRIBUTES
,
1390 if (!NT_STATUS_IS_OK(status
)) {
1394 status
= map_fnum_to_smb2_handle(cli
,
1397 if (!NT_STATUS_IS_OK(status
)) {
1401 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1402 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1404 status
= smb2cli_query_info(cli
->conn
,
1408 1, /* in_info_type */
1409 (SMB_FILE_STREAM_INFORMATION
- 1000), /* in_file_info_class */
1410 0xFFFF, /* in_max_output_length */
1411 NULL
, /* in_input_buffer */
1412 0, /* in_additional_info */
1419 if (!NT_STATUS_IS_OK(status
)) {
1423 /* Parse the reply. */
1424 if (!parse_streams_blob(mem_ctx
,
1429 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1435 if (fnum
!= 0xffff) {
1436 cli_smb2_close_fnum(cli
, fnum
);
1443 /***************************************************************
1444 Wrapper that allows SMB2 to set pathname attributes.
1446 ***************************************************************/
1448 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
1454 uint16_t fnum
= 0xffff;
1455 struct smb2_hnd
*ph
= NULL
;
1456 uint8_t inbuf_store
[40];
1457 DATA_BLOB inbuf
= data_blob_null
;
1458 TALLOC_CTX
*frame
= talloc_stackframe();
1460 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1462 * Can't use sync call while an async call is in flight
1464 status
= NT_STATUS_INVALID_PARAMETER
;
1468 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1469 status
= NT_STATUS_INVALID_PARAMETER
;
1473 status
= get_fnum_from_path(cli
,
1475 FILE_WRITE_ATTRIBUTES
,
1478 if (!NT_STATUS_IS_OK(status
)) {
1482 status
= map_fnum_to_smb2_handle(cli
,
1485 if (!NT_STATUS_IS_OK(status
)) {
1489 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1490 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1492 inbuf
.data
= inbuf_store
;
1493 inbuf
.length
= sizeof(inbuf_store
);
1494 data_blob_clear(&inbuf
);
1496 SSVAL(inbuf
.data
, 32, attr
);
1498 put_long_date((char *)inbuf
.data
+ 16,mtime
);
1500 /* Set all the other times to -1. */
1501 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1502 SBVAL(inbuf
.data
, 8, 0xFFFFFFFFFFFFFFFFLL
);
1503 SBVAL(inbuf
.data
, 24, 0xFFFFFFFFFFFFFFFFLL
);
1505 status
= smb2cli_set_info(cli
->conn
,
1509 1, /* in_info_type */
1510 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1511 &inbuf
, /* in_input_buffer */
1512 0, /* in_additional_info */
1517 if (fnum
!= 0xffff) {
1518 cli_smb2_close_fnum(cli
, fnum
);
1525 /***************************************************************
1526 Wrapper that allows SMB2 to set file handle times.
1528 ***************************************************************/
1530 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
1537 struct smb2_hnd
*ph
= NULL
;
1538 uint8_t inbuf_store
[40];
1539 DATA_BLOB inbuf
= data_blob_null
;
1541 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1543 * Can't use sync call while an async call is in flight
1545 return NT_STATUS_INVALID_PARAMETER
;
1548 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1549 return NT_STATUS_INVALID_PARAMETER
;
1552 status
= map_fnum_to_smb2_handle(cli
,
1555 if (!NT_STATUS_IS_OK(status
)) {
1559 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1560 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1562 inbuf
.data
= inbuf_store
;
1563 inbuf
.length
= sizeof(inbuf_store
);
1564 data_blob_clear(&inbuf
);
1566 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1567 if (change_time
!= 0) {
1568 put_long_date((char *)inbuf
.data
+ 24, change_time
);
1570 if (access_time
!= 0) {
1571 put_long_date((char *)inbuf
.data
+ 8, access_time
);
1573 if (write_time
!= 0) {
1574 put_long_date((char *)inbuf
.data
+ 16, write_time
);
1577 return smb2cli_set_info(cli
->conn
,
1581 1, /* in_info_type */
1582 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1583 &inbuf
, /* in_input_buffer */
1584 0, /* in_additional_info */
1589 /***************************************************************
1590 Wrapper that allows SMB2 to query disk attributes (size).
1592 ***************************************************************/
1594 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, uint64_t *bsize
, uint64_t *total
, uint64_t *avail
)
1597 uint16_t fnum
= 0xffff;
1598 DATA_BLOB outbuf
= data_blob_null
;
1599 struct smb2_hnd
*ph
= NULL
;
1600 uint32_t sectors_per_unit
= 0;
1601 uint32_t bytes_per_sector
= 0;
1602 uint64_t total_size
= 0;
1603 uint64_t size_free
= 0;
1604 TALLOC_CTX
*frame
= talloc_stackframe();
1606 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1608 * Can't use sync call while an async call is in flight
1610 status
= NT_STATUS_INVALID_PARAMETER
;
1614 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1615 status
= NT_STATUS_INVALID_PARAMETER
;
1619 /* First open the top level directory. */
1620 status
= cli_smb2_create_fnum(cli
,
1622 0, /* create_flags */
1623 FILE_READ_ATTRIBUTES
, /* desired_access */
1624 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1625 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1626 FILE_OPEN
, /* create_disposition */
1627 FILE_DIRECTORY_FILE
, /* create_options */
1631 if (!NT_STATUS_IS_OK(status
)) {
1635 status
= map_fnum_to_smb2_handle(cli
,
1638 if (!NT_STATUS_IS_OK(status
)) {
1642 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1643 level 3 (SMB_FS_SIZE_INFORMATION). */
1645 status
= smb2cli_query_info(cli
->conn
,
1649 2, /* in_info_type */
1650 3, /* in_file_info_class */
1651 0xFFFF, /* in_max_output_length */
1652 NULL
, /* in_input_buffer */
1653 0, /* in_additional_info */
1659 if (!NT_STATUS_IS_OK(status
)) {
1663 /* Parse the reply. */
1664 if (outbuf
.length
!= 24) {
1665 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1669 total_size
= BVAL(outbuf
.data
, 0);
1670 size_free
= BVAL(outbuf
.data
, 8);
1671 sectors_per_unit
= IVAL(outbuf
.data
, 16);
1672 bytes_per_sector
= IVAL(outbuf
.data
, 20);
1675 *bsize
= (uint64_t)sectors_per_unit
* (uint64_t)bytes_per_sector
;
1678 *total
= total_size
;
1684 status
= NT_STATUS_OK
;
1688 if (fnum
!= 0xffff) {
1689 cli_smb2_close_fnum(cli
, fnum
);
1696 /***************************************************************
1697 Wrapper that allows SMB2 to query a security descriptor.
1699 ***************************************************************/
1701 NTSTATUS
cli_smb2_query_security_descriptor(struct cli_state
*cli
,
1704 TALLOC_CTX
*mem_ctx
,
1705 struct security_descriptor
**ppsd
)
1708 DATA_BLOB outbuf
= data_blob_null
;
1709 struct smb2_hnd
*ph
= NULL
;
1710 struct security_descriptor
*lsd
= NULL
;
1711 TALLOC_CTX
*frame
= talloc_stackframe();
1713 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1715 * Can't use sync call while an async call is in flight
1717 status
= NT_STATUS_INVALID_PARAMETER
;
1721 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1722 status
= NT_STATUS_INVALID_PARAMETER
;
1726 status
= map_fnum_to_smb2_handle(cli
,
1729 if (!NT_STATUS_IS_OK(status
)) {
1733 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1735 status
= smb2cli_query_info(cli
->conn
,
1739 3, /* in_info_type */
1740 0, /* in_file_info_class */
1741 0xFFFF, /* in_max_output_length */
1742 NULL
, /* in_input_buffer */
1743 sec_info
, /* in_additional_info */
1750 if (!NT_STATUS_IS_OK(status
)) {
1754 /* Parse the reply. */
1755 status
= unmarshall_sec_desc(mem_ctx
,
1760 if (!NT_STATUS_IS_OK(status
)) {
1776 /***************************************************************
1777 Wrapper that allows SMB2 to set a security descriptor.
1779 ***************************************************************/
1781 NTSTATUS
cli_smb2_set_security_descriptor(struct cli_state
*cli
,
1784 const struct security_descriptor
*sd
)
1787 DATA_BLOB inbuf
= data_blob_null
;
1788 struct smb2_hnd
*ph
= NULL
;
1789 TALLOC_CTX
*frame
= talloc_stackframe();
1791 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1793 * Can't use sync call while an async call is in flight
1795 status
= NT_STATUS_INVALID_PARAMETER
;
1799 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1800 status
= NT_STATUS_INVALID_PARAMETER
;
1804 status
= map_fnum_to_smb2_handle(cli
,
1807 if (!NT_STATUS_IS_OK(status
)) {
1811 status
= marshall_sec_desc(frame
,
1816 if (!NT_STATUS_IS_OK(status
)) {
1820 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1822 status
= smb2cli_set_info(cli
->conn
,
1826 3, /* in_info_type */
1827 0, /* in_file_info_class */
1828 &inbuf
, /* in_input_buffer */
1829 sec_info
, /* in_additional_info */
1839 /***************************************************************
1840 Wrapper that allows SMB2 to rename a file.
1842 ***************************************************************/
1844 NTSTATUS
cli_smb2_rename(struct cli_state
*cli
,
1845 const char *fname_src
,
1846 const char *fname_dst
)
1849 DATA_BLOB inbuf
= data_blob_null
;
1850 uint16_t fnum
= 0xffff;
1851 struct smb2_hnd
*ph
= NULL
;
1852 smb_ucs2_t
*converted_str
= NULL
;
1853 size_t converted_size_bytes
= 0;
1855 TALLOC_CTX
*frame
= talloc_stackframe();
1857 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1859 * Can't use sync call while an async call is in flight
1861 status
= NT_STATUS_INVALID_PARAMETER
;
1865 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1866 status
= NT_STATUS_INVALID_PARAMETER
;
1870 status
= get_fnum_from_path(cli
,
1875 if (!NT_STATUS_IS_OK(status
)) {
1879 status
= map_fnum_to_smb2_handle(cli
,
1882 if (!NT_STATUS_IS_OK(status
)) {
1886 /* SMB2 is pickier about pathnames. Ensure it doesn't
1888 if (*fname_dst
== '\\') {
1892 /* SMB2 is pickier about pathnames. Ensure it doesn't
1894 namelen
= strlen(fname_dst
);
1895 if (namelen
> 0 && fname_dst
[namelen
-1] == '\\') {
1896 char *modname
= talloc_strdup(frame
, fname_dst
);
1897 modname
[namelen
-1] = '\0';
1898 fname_dst
= modname
;
1901 if (!push_ucs2_talloc(frame
,
1904 &converted_size_bytes
)) {
1905 status
= NT_STATUS_INVALID_PARAMETER
;
1909 /* W2K8 insists the dest name is not null
1910 terminated. Remove the last 2 zero bytes
1911 and reduce the name length. */
1913 if (converted_size_bytes
< 2) {
1914 status
= NT_STATUS_INVALID_PARAMETER
;
1917 converted_size_bytes
-= 2;
1919 inbuf
= data_blob_talloc_zero(frame
,
1920 20 + converted_size_bytes
);
1921 if (inbuf
.data
== NULL
) {
1922 status
= NT_STATUS_NO_MEMORY
;
1926 SIVAL(inbuf
.data
, 16, converted_size_bytes
);
1927 memcpy(inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
1929 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
1930 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
1932 status
= smb2cli_set_info(cli
->conn
,
1936 1, /* in_info_type */
1937 SMB_FILE_RENAME_INFORMATION
- 1000, /* in_file_info_class */
1938 &inbuf
, /* in_input_buffer */
1939 0, /* in_additional_info */
1945 if (fnum
!= 0xffff) {
1946 cli_smb2_close_fnum(cli
, fnum
);
1953 /***************************************************************
1954 Wrapper that allows SMB2 to set an EA on a fnum.
1956 ***************************************************************/
1958 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
1960 const char *ea_name
,
1965 DATA_BLOB inbuf
= data_blob_null
;
1967 char *ea_name_ascii
= NULL
;
1969 struct smb2_hnd
*ph
= NULL
;
1970 TALLOC_CTX
*frame
= talloc_stackframe();
1972 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1974 * Can't use sync call while an async call is in flight
1976 status
= NT_STATUS_INVALID_PARAMETER
;
1980 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1981 status
= NT_STATUS_INVALID_PARAMETER
;
1985 status
= map_fnum_to_smb2_handle(cli
,
1988 if (!NT_STATUS_IS_OK(status
)) {
1992 /* Marshall the SMB2 EA data. */
1993 if (ea_len
> 0xFFFF) {
1994 status
= NT_STATUS_INVALID_PARAMETER
;
1998 if (!push_ascii_talloc(frame
,
2002 status
= NT_STATUS_INVALID_PARAMETER
;
2006 if (namelen
< 2 || namelen
> 0xFF) {
2007 status
= NT_STATUS_INVALID_PARAMETER
;
2011 bloblen
= 8 + ea_len
+ namelen
;
2012 /* Round up to a 4 byte boundary. */
2013 bloblen
= ((bloblen
+ 3)&~3);
2015 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
2016 if (inbuf
.data
== NULL
) {
2017 status
= NT_STATUS_NO_MEMORY
;
2020 /* namelen doesn't include the NULL byte. */
2021 SCVAL(inbuf
.data
, 5, namelen
- 1);
2022 SSVAL(inbuf
.data
, 6, ea_len
);
2023 memcpy(inbuf
.data
+ 8, ea_name_ascii
, namelen
);
2024 memcpy(inbuf
.data
+ 8 + namelen
, ea_val
, ea_len
);
2026 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2027 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2029 status
= smb2cli_set_info(cli
->conn
,
2033 1, /* in_info_type */
2034 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
2035 &inbuf
, /* in_input_buffer */
2036 0, /* in_additional_info */
2046 /***************************************************************
2047 Wrapper that allows SMB2 to set an EA on a pathname.
2049 ***************************************************************/
2051 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
2053 const char *ea_name
,
2058 uint16_t fnum
= 0xffff;
2060 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2062 * Can't use sync call while an async call is in flight
2064 status
= NT_STATUS_INVALID_PARAMETER
;
2068 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2069 status
= NT_STATUS_INVALID_PARAMETER
;
2073 status
= get_fnum_from_path(cli
,
2078 if (!NT_STATUS_IS_OK(status
)) {
2082 status
= cli_set_ea_fnum(cli
,
2087 if (!NT_STATUS_IS_OK(status
)) {
2093 if (fnum
!= 0xffff) {
2094 cli_smb2_close_fnum(cli
, fnum
);
2100 /***************************************************************
2101 Wrapper that allows SMB2 to get an EA list on a pathname.
2103 ***************************************************************/
2105 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
2109 struct ea_struct
**pea_array
)
2112 uint16_t fnum
= 0xffff;
2113 DATA_BLOB outbuf
= data_blob_null
;
2114 struct smb2_hnd
*ph
= NULL
;
2115 struct ea_list
*ea_list
= NULL
;
2116 struct ea_list
*eal
= NULL
;
2117 size_t ea_count
= 0;
2118 TALLOC_CTX
*frame
= talloc_stackframe();
2123 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2125 * Can't use sync call while an async call is in flight
2127 status
= NT_STATUS_INVALID_PARAMETER
;
2131 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2132 status
= NT_STATUS_INVALID_PARAMETER
;
2136 status
= get_fnum_from_path(cli
,
2141 if (!NT_STATUS_IS_OK(status
)) {
2145 status
= map_fnum_to_smb2_handle(cli
,
2148 if (!NT_STATUS_IS_OK(status
)) {
2152 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2153 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2155 status
= smb2cli_query_info(cli
->conn
,
2159 1, /* in_info_type */
2160 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
2161 0xFFFF, /* in_max_output_length */
2162 NULL
, /* in_input_buffer */
2163 0, /* in_additional_info */
2170 if (!NT_STATUS_IS_OK(status
)) {
2174 /* Parse the reply. */
2175 ea_list
= read_nttrans_ea_list(ctx
,
2176 (const char *)outbuf
.data
,
2178 if (ea_list
== NULL
) {
2179 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2183 /* Convert to an array. */
2184 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2189 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
2190 if (*pea_array
== NULL
) {
2191 status
= NT_STATUS_NO_MEMORY
;
2195 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2196 (*pea_array
)[ea_count
++] = ea_list
->ea
;
2198 *pnum_eas
= ea_count
;
2203 if (fnum
!= 0xffff) {
2204 cli_smb2_close_fnum(cli
, fnum
);
2211 struct cli_smb2_read_state
{
2212 struct tevent_context
*ev
;
2213 struct cli_state
*cli
;
2214 struct smb2_hnd
*ph
;
2215 uint64_t start_offset
;
2221 static void cli_smb2_read_done(struct tevent_req
*subreq
);
2223 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
2224 struct tevent_context
*ev
,
2225 struct cli_state
*cli
,
2231 struct tevent_req
*req
, *subreq
;
2232 struct cli_smb2_read_state
*state
;
2234 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
2240 state
->start_offset
= (uint64_t)offset
;
2241 state
->size
= (uint32_t)size
;
2242 state
->received
= 0;
2245 status
= map_fnum_to_smb2_handle(cli
,
2248 if (tevent_req_nterror(req
, status
)) {
2249 return tevent_req_post(req
, ev
);
2252 subreq
= smb2cli_read_send(state
,
2255 state
->cli
->timeout
,
2256 state
->cli
->smb2
.session
,
2257 state
->cli
->smb2
.tcon
,
2259 state
->start_offset
,
2260 state
->ph
->fid_persistent
,
2261 state
->ph
->fid_volatile
,
2262 0, /* minimum_count */
2263 0); /* remaining_bytes */
2265 if (tevent_req_nomem(subreq
, req
)) {
2266 return tevent_req_post(req
, ev
);
2268 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
2272 static void cli_smb2_read_done(struct tevent_req
*subreq
)
2274 struct tevent_req
*req
= tevent_req_callback_data(
2275 subreq
, struct tevent_req
);
2276 struct cli_smb2_read_state
*state
= tevent_req_data(
2277 req
, struct cli_smb2_read_state
);
2280 status
= smb2cli_read_recv(subreq
, state
,
2281 &state
->buf
, &state
->received
);
2282 if (tevent_req_nterror(req
, status
)) {
2286 if (state
->received
> state
->size
) {
2287 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2291 tevent_req_done(req
);
2294 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
2299 struct cli_smb2_read_state
*state
= tevent_req_data(
2300 req
, struct cli_smb2_read_state
);
2302 if (tevent_req_is_nterror(req
, &status
)) {
2306 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2307 * better make sure that you copy it away before you talloc_free(req).
2308 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2310 *received
= (ssize_t
)state
->received
;
2311 *rcvbuf
= state
->buf
;
2312 return NT_STATUS_OK
;
2315 struct cli_smb2_write_state
{
2316 struct tevent_context
*ev
;
2317 struct cli_state
*cli
;
2318 struct smb2_hnd
*ph
;
2326 static void cli_smb2_write_written(struct tevent_req
*req
);
2328 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
2329 struct tevent_context
*ev
,
2330 struct cli_state
*cli
,
2338 struct tevent_req
*req
, *subreq
= NULL
;
2339 struct cli_smb2_write_state
*state
= NULL
;
2341 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
2347 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2348 state
->flags
= (uint32_t)mode
;
2350 state
->offset
= (uint64_t)offset
;
2351 state
->size
= (uint32_t)size
;
2354 status
= map_fnum_to_smb2_handle(cli
,
2357 if (tevent_req_nterror(req
, status
)) {
2358 return tevent_req_post(req
, ev
);
2361 subreq
= smb2cli_write_send(state
,
2364 state
->cli
->timeout
,
2365 state
->cli
->smb2
.session
,
2366 state
->cli
->smb2
.tcon
,
2369 state
->ph
->fid_persistent
,
2370 state
->ph
->fid_volatile
,
2371 0, /* remaining_bytes */
2372 state
->flags
, /* flags */
2375 if (tevent_req_nomem(subreq
, req
)) {
2376 return tevent_req_post(req
, ev
);
2378 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
2382 static void cli_smb2_write_written(struct tevent_req
*subreq
)
2384 struct tevent_req
*req
= tevent_req_callback_data(
2385 subreq
, struct tevent_req
);
2386 struct cli_smb2_write_state
*state
= tevent_req_data(
2387 req
, struct cli_smb2_write_state
);
2391 status
= smb2cli_write_recv(subreq
, &written
);
2392 TALLOC_FREE(subreq
);
2393 if (tevent_req_nterror(req
, status
)) {
2397 state
->written
= written
;
2399 tevent_req_done(req
);
2402 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
2405 struct cli_smb2_write_state
*state
= tevent_req_data(
2406 req
, struct cli_smb2_write_state
);
2409 if (tevent_req_is_nterror(req
, &status
)) {
2410 tevent_req_received(req
);
2414 if (pwritten
!= NULL
) {
2415 *pwritten
= (size_t)state
->written
;
2417 tevent_req_received(req
);
2418 return NT_STATUS_OK
;
2421 /***************************************************************
2422 Wrapper that allows SMB2 async write using an fnum.
2423 This is mostly cut-and-paste from Volker's code inside
2424 source3/libsmb/clireadwrite.c, adapted for SMB2.
2426 Done this way so I can reuse all the logic inside cli_push()
2428 ***************************************************************/
2430 struct cli_smb2_writeall_state
{
2431 struct tevent_context
*ev
;
2432 struct cli_state
*cli
;
2433 struct smb2_hnd
*ph
;
2441 static void cli_smb2_writeall_written(struct tevent_req
*req
);
2443 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
2444 struct tevent_context
*ev
,
2445 struct cli_state
*cli
,
2453 struct tevent_req
*req
, *subreq
= NULL
;
2454 struct cli_smb2_writeall_state
*state
= NULL
;
2459 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
2465 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2466 state
->flags
= (uint32_t)mode
;
2468 state
->offset
= (uint64_t)offset
;
2469 state
->size
= (uint32_t)size
;
2472 status
= map_fnum_to_smb2_handle(cli
,
2475 if (tevent_req_nterror(req
, status
)) {
2476 return tevent_req_post(req
, ev
);
2479 to_write
= state
->size
;
2480 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
2481 to_write
= MIN(max_size
, to_write
);
2482 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
2484 to_write
= MIN(max_size
, to_write
);
2487 subreq
= smb2cli_write_send(state
,
2490 state
->cli
->timeout
,
2491 state
->cli
->smb2
.session
,
2492 state
->cli
->smb2
.tcon
,
2495 state
->ph
->fid_persistent
,
2496 state
->ph
->fid_volatile
,
2497 0, /* remaining_bytes */
2498 state
->flags
, /* flags */
2499 state
->buf
+ state
->written
);
2501 if (tevent_req_nomem(subreq
, req
)) {
2502 return tevent_req_post(req
, ev
);
2504 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
2508 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
2510 struct tevent_req
*req
= tevent_req_callback_data(
2511 subreq
, struct tevent_req
);
2512 struct cli_smb2_writeall_state
*state
= tevent_req_data(
2513 req
, struct cli_smb2_writeall_state
);
2515 uint32_t written
, to_write
;
2519 status
= smb2cli_write_recv(subreq
, &written
);
2520 TALLOC_FREE(subreq
);
2521 if (tevent_req_nterror(req
, status
)) {
2525 state
->written
+= written
;
2527 if (state
->written
> state
->size
) {
2528 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2532 to_write
= state
->size
- state
->written
;
2534 if (to_write
== 0) {
2535 tevent_req_done(req
);
2539 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
2540 to_write
= MIN(max_size
, to_write
);
2541 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
2543 to_write
= MIN(max_size
, to_write
);
2546 subreq
= smb2cli_write_send(state
,
2549 state
->cli
->timeout
,
2550 state
->cli
->smb2
.session
,
2551 state
->cli
->smb2
.tcon
,
2553 state
->offset
+ state
->written
,
2554 state
->ph
->fid_persistent
,
2555 state
->ph
->fid_volatile
,
2556 0, /* remaining_bytes */
2557 state
->flags
, /* flags */
2558 state
->buf
+ state
->written
);
2560 if (tevent_req_nomem(subreq
, req
)) {
2563 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
2566 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
2569 struct cli_smb2_writeall_state
*state
= tevent_req_data(
2570 req
, struct cli_smb2_writeall_state
);
2573 if (tevent_req_is_nterror(req
, &status
)) {
2576 if (pwritten
!= NULL
) {
2577 *pwritten
= (size_t)state
->written
;
2579 return NT_STATUS_OK
;