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"
41 #include "librpc/gen_ndr/ndr_ioctl.h"
45 uint64_t fid_persistent;
46 uint64_t fid_volatile;
50 * Handle mapping code.
53 /***************************************************************
54 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
55 Ensures handle is owned by cli struct.
56 ***************************************************************/
58 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
59 const struct smb2_hnd *ph, /* In */
60 uint16_t *pfnum) /* Out */
63 struct idr_context *idp = cli->smb2.open_handles;
64 struct smb2_hnd *owned_h = talloc_memdup(cli,
66 sizeof(struct smb2_hnd));
68 if (owned_h == NULL) {
69 return NT_STATUS_NO_MEMORY;
74 cli->smb2.open_handles = idr_init(cli);
75 if (cli->smb2.open_handles == NULL) {
77 return NT_STATUS_NO_MEMORY;
79 idp = cli->smb2.open_handles;
82 ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
85 return NT_STATUS_NO_MEMORY;
88 *pfnum = (uint16_t)ret;
92 /***************************************************************
93 Return the smb2_hnd pointer associated with the given fnum.
94 ***************************************************************/
96 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
97 uint16_t fnum, /* In */
98 struct smb2_hnd **pph) /* Out */
100 struct idr_context *idp = cli->smb2.open_handles;
103 return NT_STATUS_INVALID_PARAMETER;
105 *pph = (struct smb2_hnd *)idr_find(idp, fnum);
107 return NT_STATUS_INVALID_HANDLE;
112 /***************************************************************
113 Delete the fnum to smb2_hnd mapping. Zeros out handle on
115 ***************************************************************/
117 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
118 struct smb2_hnd **pph, /* In */
119 uint16_t fnum) /* In */
121 struct idr_context *idp = cli->smb2.open_handles;
125 return NT_STATUS_INVALID_PARAMETER;
128 ph = (struct smb2_hnd *)idr_find(idp, fnum);
130 return NT_STATUS_INVALID_PARAMETER;
132 idr_remove(idp, fnum);
137 /***************************************************************
139 ***************************************************************/
141 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
143 if (create_flags & REQUEST_BATCH_OPLOCK) {
144 return SMB2_OPLOCK_LEVEL_BATCH;
145 } else if (create_flags & REQUEST_OPLOCK) {
146 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
149 /* create_flags doesn't do a level2 request. */
150 return SMB2_OPLOCK_LEVEL_NONE;
153 /***************************************************************
154 Small wrapper that allows SMB2 create to return a uint16_t fnum.
155 ***************************************************************/
157 struct cli_smb2_create_fnum_state {
158 struct cli_state *cli;
159 struct smb_create_returns cr;
161 struct tevent_req *subreq;
164 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
165 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
167 struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
168 struct tevent_context *ev,
169 struct cli_state *cli,
171 uint32_t create_flags,
172 uint32_t desired_access,
173 uint32_t file_attributes,
174 uint32_t share_access,
175 uint32_t create_disposition,
176 uint32_t create_options)
178 struct tevent_req *req, *subreq;
179 struct cli_smb2_create_fnum_state *state;
180 size_t fname_len = 0;
181 const char *startp = NULL;
182 const char *endp = NULL;
183 time_t tstamp = (time_t)0;
184 struct smb2_create_blobs *cblobs = NULL;
186 req = tevent_req_create(mem_ctx, &state,
187 struct cli_smb2_create_fnum_state);
193 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
194 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
195 return tevent_req_post(req, ev);
198 if (cli->backup_intent) {
199 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
202 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
203 fname_len = strlen(fname);
204 if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
205 size_t len_before_gmt = startp - fname;
206 size_t len_after_gmt = fname + fname_len - endp;
211 char *new_fname = talloc_array(state, char,
212 len_before_gmt + len_after_gmt + 1);
214 if (tevent_req_nomem(new_fname, req)) {
215 return tevent_req_post(req, ev);
218 memcpy(new_fname, fname, len_before_gmt);
219 memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
221 fname_len = len_before_gmt + len_after_gmt;
223 unix_to_nt_time(&ntt, tstamp);
224 twrp_blob = data_blob_const((const void *)&ntt, 8);
226 cblobs = talloc_zero(state, struct smb2_create_blobs);
227 if (tevent_req_nomem(cblobs, req)) {
228 return tevent_req_post(req, ev);
231 status = smb2_create_blob_add(state, cblobs,
232 SMB2_CREATE_TAG_TWRP, twrp_blob);
233 if (!NT_STATUS_IS_OK(status)) {
234 tevent_req_nterror(req, status);
235 return tevent_req_post(req, ev);
239 /* SMB2 is pickier about pathnames. Ensure it doesn't
241 if (*fname == '\\') {
246 /* Or end in a '\' */
247 if (fname_len > 0 && fname[fname_len-1] == '\\') {
248 char *new_fname = talloc_strdup(state, fname);
249 if (tevent_req_nomem(new_fname, req)) {
250 return tevent_req_post(req, ev);
252 new_fname[fname_len-1] = '\0';
256 subreq = smb2cli_create_send(state, ev,
262 flags_to_smb2_oplock(create_flags),
263 SMB2_IMPERSONATION_IMPERSONATION,
270 if (tevent_req_nomem(subreq, req)) {
271 return tevent_req_post(req, ev);
273 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
275 state->subreq = subreq;
276 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
281 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
283 struct tevent_req *req = tevent_req_callback_data(
284 subreq, struct tevent_req);
285 struct cli_smb2_create_fnum_state *state = tevent_req_data(
286 req, struct cli_smb2_create_fnum_state);
290 status = smb2cli_create_recv(subreq, &h.fid_persistent,
291 &h.fid_volatile, &state->cr, NULL, NULL);
293 if (tevent_req_nterror(req, status)) {
297 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
298 if (tevent_req_nterror(req, status)) {
301 tevent_req_done(req);
304 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
306 struct cli_smb2_create_fnum_state *state = tevent_req_data(
307 req, struct cli_smb2_create_fnum_state);
308 return tevent_req_cancel(state->subreq);
311 NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum,
312 struct smb_create_returns *cr)
314 struct cli_smb2_create_fnum_state *state = tevent_req_data(
315 req, struct cli_smb2_create_fnum_state);
318 if (tevent_req_is_nterror(req, &status)) {
319 state->cli->raw_status = status;
323 *pfnum = state->fnum;
328 state->cli->raw_status = NT_STATUS_OK;
332 NTSTATUS cli_smb2_create_fnum(struct cli_state *cli,
334 uint32_t create_flags,
335 uint32_t desired_access,
336 uint32_t file_attributes,
337 uint32_t share_access,
338 uint32_t create_disposition,
339 uint32_t create_options,
341 struct smb_create_returns *cr)
343 TALLOC_CTX *frame = talloc_stackframe();
344 struct tevent_context *ev;
345 struct tevent_req *req;
346 NTSTATUS status = NT_STATUS_NO_MEMORY;
348 if (smbXcli_conn_has_async_calls(cli->conn)) {
350 * Can't use sync call while an async call is in flight
352 status = NT_STATUS_INVALID_PARAMETER;
355 ev = samba_tevent_context_init(frame);
359 req = cli_smb2_create_fnum_send(frame, ev, cli, fname, create_flags,
360 desired_access, file_attributes,
361 share_access, create_disposition,
366 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
369 status = cli_smb2_create_fnum_recv(req, pfid, cr);
375 /***************************************************************
376 Small wrapper that allows SMB2 close to use a uint16_t fnum.
377 ***************************************************************/
379 struct cli_smb2_close_fnum_state {
380 struct cli_state *cli;
385 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
387 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
388 struct tevent_context *ev,
389 struct cli_state *cli,
392 struct tevent_req *req, *subreq;
393 struct cli_smb2_close_fnum_state *state;
396 req = tevent_req_create(mem_ctx, &state,
397 struct cli_smb2_close_fnum_state);
404 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
405 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
406 return tevent_req_post(req, ev);
409 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
410 if (tevent_req_nterror(req, status)) {
411 return tevent_req_post(req, ev);
414 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
415 cli->smb2.session, cli->smb2.tcon,
416 0, state->ph->fid_persistent,
417 state->ph->fid_volatile);
418 if (tevent_req_nomem(subreq, req)) {
419 return tevent_req_post(req, ev);
421 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
425 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
427 struct tevent_req *req = tevent_req_callback_data(
428 subreq, struct tevent_req);
429 struct cli_smb2_close_fnum_state *state = tevent_req_data(
430 req, struct cli_smb2_close_fnum_state);
433 status = smb2cli_close_recv(subreq);
434 if (tevent_req_nterror(req, status)) {
438 /* Delete the fnum -> handle mapping. */
439 status = delete_smb2_handle_mapping(state->cli, &state->ph,
441 if (tevent_req_nterror(req, status)) {
444 tevent_req_done(req);
447 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
449 struct cli_smb2_close_fnum_state *state = tevent_req_data(
450 req, struct cli_smb2_close_fnum_state);
451 NTSTATUS status = tevent_req_simple_recv_ntstatus(req);
452 state->cli->raw_status = status;
456 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
458 TALLOC_CTX *frame = talloc_stackframe();
459 struct tevent_context *ev;
460 struct tevent_req *req;
461 NTSTATUS status = NT_STATUS_NO_MEMORY;
463 if (smbXcli_conn_has_async_calls(cli->conn)) {
465 * Can't use sync call while an async call is in flight
467 status = NT_STATUS_INVALID_PARAMETER;
470 ev = samba_tevent_context_init(frame);
474 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
478 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
481 status = cli_smb2_close_fnum_recv(req);
487 /***************************************************************
488 Small wrapper that allows SMB2 to create a directory
490 ***************************************************************/
492 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
497 if (smbXcli_conn_has_async_calls(cli->conn)) {
499 * Can't use sync call while an async call is in flight
501 return NT_STATUS_INVALID_PARAMETER;
504 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
505 return NT_STATUS_INVALID_PARAMETER;
508 status = cli_smb2_create_fnum(cli,
510 0, /* create_flags */
511 FILE_READ_ATTRIBUTES, /* desired_access */
512 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
513 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
514 FILE_CREATE, /* create_disposition */
515 FILE_DIRECTORY_FILE, /* create_options */
519 if (!NT_STATUS_IS_OK(status)) {
522 return cli_smb2_close_fnum(cli, fnum);
525 /***************************************************************
526 Small wrapper that allows SMB2 to delete a directory
528 ***************************************************************/
530 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
535 if (smbXcli_conn_has_async_calls(cli->conn)) {
537 * Can't use sync call while an async call is in flight
539 return NT_STATUS_INVALID_PARAMETER;
542 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
543 return NT_STATUS_INVALID_PARAMETER;
546 status = cli_smb2_create_fnum(cli,
548 0, /* create_flags */
549 DELETE_ACCESS, /* desired_access */
550 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
551 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
552 FILE_OPEN, /* create_disposition */
553 FILE_DIRECTORY_FILE|FILE_DELETE_ON_CLOSE, /* create_options */
557 if (!NT_STATUS_IS_OK(status)) {
560 return cli_smb2_close_fnum(cli, fnum);
563 /***************************************************************
564 Small wrapper that allows SMB2 to unlink a pathname.
566 ***************************************************************/
568 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
573 if (smbXcli_conn_has_async_calls(cli->conn)) {
575 * Can't use sync call while an async call is in flight
577 return NT_STATUS_INVALID_PARAMETER;
580 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
581 return NT_STATUS_INVALID_PARAMETER;
584 status = cli_smb2_create_fnum(cli,
586 0, /* create_flags */
587 DELETE_ACCESS, /* desired_access */
588 FILE_ATTRIBUTE_NORMAL, /* file attributes */
589 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
590 FILE_OPEN, /* create_disposition */
591 FILE_DELETE_ON_CLOSE, /* create_options */
595 if (!NT_STATUS_IS_OK(status)) {
598 return cli_smb2_close_fnum(cli, fnum);
601 /***************************************************************
602 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
603 ***************************************************************/
605 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
606 uint32_t dir_data_length,
607 struct file_info *finfo,
608 uint32_t *next_offset)
614 if (dir_data_length < 4) {
615 return NT_STATUS_INFO_LENGTH_MISMATCH;
618 *next_offset = IVAL(dir_data, 0);
620 if (*next_offset > dir_data_length) {
621 return NT_STATUS_INFO_LENGTH_MISMATCH;
624 if (*next_offset != 0) {
625 /* Ensure we only read what in this record. */
626 dir_data_length = *next_offset;
629 if (dir_data_length < 105) {
630 return NT_STATUS_INFO_LENGTH_MISMATCH;
633 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
634 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
635 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
636 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
637 finfo->mode = CVAL(dir_data + 56, 0);
638 namelen = IVAL(dir_data + 60,0);
639 if (namelen > (dir_data_length - 104)) {
640 return NT_STATUS_INFO_LENGTH_MISMATCH;
642 slen = CVAL(dir_data + 68, 0);
644 return NT_STATUS_INFO_LENGTH_MISMATCH;
646 ret = pull_string_talloc(finfo,
648 FLAGS2_UNICODE_STRINGS,
653 if (ret == (size_t)-1) {
654 /* Bad conversion. */
655 return NT_STATUS_INVALID_NETWORK_RESPONSE;
658 ret = pull_string_talloc(finfo,
660 FLAGS2_UNICODE_STRINGS,
665 if (ret == (size_t)-1) {
666 /* Bad conversion. */
667 return NT_STATUS_INVALID_NETWORK_RESPONSE;
672 /*******************************************************************
673 Given a filename - get its directory name
674 ********************************************************************/
676 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
684 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
687 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
698 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
701 (*parent)[len] = '\0';
709 /***************************************************************
710 Wrapper that allows SMB2 to list a directory.
712 ***************************************************************/
714 NTSTATUS cli_smb2_list(struct cli_state *cli,
715 const char *pathname,
717 NTSTATUS (*fn)(const char *,
724 uint16_t fnum = 0xffff;
725 char *parent_dir = NULL;
726 const char *mask = NULL;
727 struct smb2_hnd *ph = NULL;
728 bool processed_file = false;
729 TALLOC_CTX *frame = talloc_stackframe();
730 TALLOC_CTX *subframe = NULL;
733 if (smbXcli_conn_has_async_calls(cli->conn)) {
735 * Can't use sync call while an async call is in flight
737 status = NT_STATUS_INVALID_PARAMETER;
741 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
742 status = NT_STATUS_INVALID_PARAMETER;
746 /* Get the directory name. */
747 if (!windows_parent_dirname(frame,
751 status = NT_STATUS_NO_MEMORY;
755 mask_has_wild = ms_has_wild(mask);
757 status = cli_smb2_create_fnum(cli,
759 0, /* create_flags */
760 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
761 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
762 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
763 FILE_OPEN, /* create_disposition */
764 FILE_DIRECTORY_FILE, /* create_options */
768 if (!NT_STATUS_IS_OK(status)) {
772 status = map_fnum_to_smb2_handle(cli,
775 if (!NT_STATUS_IS_OK(status)) {
780 uint8_t *dir_data = NULL;
781 uint32_t dir_data_length = 0;
782 uint32_t next_offset = 0;
783 subframe = talloc_stackframe();
785 status = smb2cli_query_directory(cli->conn,
789 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
800 if (!NT_STATUS_IS_OK(status)) {
801 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
808 struct file_info *finfo = talloc_zero(subframe,
812 status = NT_STATUS_NO_MEMORY;
816 status = parse_finfo_id_both_directory_info(dir_data,
821 if (!NT_STATUS_IS_OK(status)) {
825 if (dir_check_ftype((uint32_t)finfo->mode,
826 (uint32_t)attribute)) {
828 * Only process if attributes match.
829 * On SMB1 server does this, so on
830 * SMB2 we need to emulate in the
833 * https://bugzilla.samba.org/show_bug.cgi?id=10260
835 processed_file = true;
837 status = fn(cli->dfs_mountpoint,
842 if (!NT_STATUS_IS_OK(status)) {
849 /* Move to next entry. */
851 dir_data += next_offset;
852 dir_data_length -= next_offset;
854 } while (next_offset != 0);
856 TALLOC_FREE(subframe);
858 if (!mask_has_wild) {
860 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
861 * when handed a non-wildcard path. Do it
862 * for the server (with a non-wildcard path
863 * there should only ever be one file returned.
865 status = STATUS_NO_MORE_FILES;
869 } while (NT_STATUS_IS_OK(status));
871 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
872 status = NT_STATUS_OK;
875 if (NT_STATUS_IS_OK(status) && !processed_file) {
877 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
878 * if no files match. Emulate this in the client.
880 status = NT_STATUS_NO_SUCH_FILE;
885 if (fnum != 0xffff) {
886 cli_smb2_close_fnum(cli, fnum);
888 TALLOC_FREE(subframe);
893 /***************************************************************
894 Wrapper that allows SMB2 to query a path info (basic level).
896 ***************************************************************/
898 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
900 SMB_STRUCT_STAT *sbuf,
901 uint32_t *attributes)
904 struct smb_create_returns cr;
905 uint16_t fnum = 0xffff;
906 size_t namelen = strlen(name);
908 if (smbXcli_conn_has_async_calls(cli->conn)) {
910 * Can't use sync call while an async call is in flight
912 return NT_STATUS_INVALID_PARAMETER;
915 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
916 return NT_STATUS_INVALID_PARAMETER;
919 /* SMB2 is pickier about pathnames. Ensure it doesn't
921 if (namelen > 0 && name[namelen-1] == '\\') {
922 char *modname = talloc_strdup(talloc_tos(), name);
923 modname[namelen-1] = '\0';
927 /* This is commonly used as a 'cd'. Try qpathinfo on
928 a directory handle first. */
930 status = cli_smb2_create_fnum(cli,
932 0, /* create_flags */
933 FILE_READ_ATTRIBUTES, /* desired_access */
934 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
935 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
936 FILE_OPEN, /* create_disposition */
937 FILE_DIRECTORY_FILE, /* create_options */
941 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
943 status = cli_smb2_create_fnum(cli,
945 0, /* create_flags */
946 FILE_READ_ATTRIBUTES, /* desired_access */
947 0, /* file attributes */
948 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
949 FILE_OPEN, /* create_disposition */
950 0, /* create_options */
955 if (!NT_STATUS_IS_OK(status)) {
959 cli_smb2_close_fnum(cli, fnum);
963 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
964 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
965 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
966 sbuf->st_ex_size = cr.end_of_file;
967 *attributes = cr.file_attributes;
972 /***************************************************************
973 Helper function for pathname operations.
974 ***************************************************************/
976 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
978 uint32_t desired_access,
982 size_t namelen = strlen(name);
983 TALLOC_CTX *frame = talloc_stackframe();
985 /* SMB2 is pickier about pathnames. Ensure it doesn't
987 if (namelen > 0 && name[namelen-1] == '\\') {
988 char *modname = talloc_strdup(frame, name);
989 if (modname == NULL) {
990 status = NT_STATUS_NO_MEMORY;
993 modname[namelen-1] = '\0';
997 /* Try to open a file handle first. */
998 status = cli_smb2_create_fnum(cli,
1000 0, /* create_flags */
1002 0, /* file attributes */
1003 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1004 FILE_OPEN, /* create_disposition */
1005 0, /* create_options */
1009 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1010 status = cli_smb2_create_fnum(cli,
1012 0, /* create_flags */
1014 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1015 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1016 FILE_OPEN, /* create_disposition */
1017 FILE_DIRECTORY_FILE, /* create_options */
1028 /***************************************************************
1029 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1031 ***************************************************************/
1033 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1038 DATA_BLOB outbuf = data_blob_null;
1039 uint16_t fnum = 0xffff;
1040 struct smb2_hnd *ph = NULL;
1041 uint32_t altnamelen = 0;
1042 TALLOC_CTX *frame = talloc_stackframe();
1044 if (smbXcli_conn_has_async_calls(cli->conn)) {
1046 * Can't use sync call while an async call is in flight
1048 status = NT_STATUS_INVALID_PARAMETER;
1052 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1053 status = NT_STATUS_INVALID_PARAMETER;
1057 status = get_fnum_from_path(cli,
1059 FILE_READ_ATTRIBUTES,
1062 if (!NT_STATUS_IS_OK(status)) {
1066 status = map_fnum_to_smb2_handle(cli,
1069 if (!NT_STATUS_IS_OK(status)) {
1073 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1074 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1076 status = smb2cli_query_info(cli->conn,
1080 1, /* in_info_type */
1081 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1082 0xFFFF, /* in_max_output_length */
1083 NULL, /* in_input_buffer */
1084 0, /* in_additional_info */
1091 if (!NT_STATUS_IS_OK(status)) {
1095 /* Parse the reply. */
1096 if (outbuf.length < 4) {
1097 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1101 altnamelen = IVAL(outbuf.data, 0);
1102 if (altnamelen > outbuf.length - 4) {
1103 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1107 if (altnamelen > 0) {
1109 char *short_name = NULL;
1110 ret = pull_string_talloc(frame,
1112 FLAGS2_UNICODE_STRINGS,
1117 if (ret == (size_t)-1) {
1118 /* Bad conversion. */
1119 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1123 fstrcpy(alt_name, short_name);
1128 status = NT_STATUS_OK;
1132 if (fnum != 0xffff) {
1133 cli_smb2_close_fnum(cli, fnum);
1140 /***************************************************************
1141 Wrapper that allows SMB2 to query a fnum info (basic level).
1143 ***************************************************************/
1145 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1149 struct timespec *create_time,
1150 struct timespec *access_time,
1151 struct timespec *write_time,
1152 struct timespec *change_time,
1156 DATA_BLOB outbuf = data_blob_null;
1157 struct smb2_hnd *ph = NULL;
1158 TALLOC_CTX *frame = talloc_stackframe();
1160 if (smbXcli_conn_has_async_calls(cli->conn)) {
1162 * Can't use sync call while an async call is in flight
1164 status = NT_STATUS_INVALID_PARAMETER;
1168 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1169 status = NT_STATUS_INVALID_PARAMETER;
1173 status = map_fnum_to_smb2_handle(cli,
1176 if (!NT_STATUS_IS_OK(status)) {
1180 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1181 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1183 status = smb2cli_query_info(cli->conn,
1187 1, /* in_info_type */
1188 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1189 0xFFFF, /* in_max_output_length */
1190 NULL, /* in_input_buffer */
1191 0, /* in_additional_info */
1197 if (!NT_STATUS_IS_OK(status)) {
1201 /* Parse the reply. */
1202 if (outbuf.length < 0x60) {
1203 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1208 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1211 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1214 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1217 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1220 uint32_t attr = IVAL(outbuf.data, 0x20);
1221 *mode = (uint16_t)attr;
1224 uint64_t file_size = BVAL(outbuf.data, 0x30);
1225 *size = (off_t)file_size;
1228 uint64_t file_index = BVAL(outbuf.data, 0x40);
1229 *ino = (SMB_INO_T)file_index;
1238 /***************************************************************
1239 Wrapper that allows SMB2 to query an fnum.
1240 Implement on top of cli_smb2_qfileinfo_basic().
1242 ***************************************************************/
1244 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1248 time_t *change_time,
1249 time_t *access_time,
1252 struct timespec access_time_ts;
1253 struct timespec write_time_ts;
1254 struct timespec change_time_ts;
1255 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1265 if (!NT_STATUS_IS_OK(status)) {
1270 *change_time = change_time_ts.tv_sec;
1273 *access_time = access_time_ts.tv_sec;
1276 *write_time = write_time_ts.tv_sec;
1278 return NT_STATUS_OK;
1281 /***************************************************************
1282 Wrapper that allows SMB2 to get pathname attributes.
1284 ***************************************************************/
1286 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1293 uint16_t fnum = 0xffff;
1294 struct smb2_hnd *ph = NULL;
1295 TALLOC_CTX *frame = talloc_stackframe();
1297 if (smbXcli_conn_has_async_calls(cli->conn)) {
1299 * Can't use sync call while an async call is in flight
1301 status = NT_STATUS_INVALID_PARAMETER;
1305 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1306 status = NT_STATUS_INVALID_PARAMETER;
1310 status = get_fnum_from_path(cli,
1312 FILE_READ_ATTRIBUTES,
1315 if (!NT_STATUS_IS_OK(status)) {
1319 status = map_fnum_to_smb2_handle(cli,
1322 if (!NT_STATUS_IS_OK(status)) {
1325 status = cli_smb2_getattrE(cli,
1332 if (!NT_STATUS_IS_OK(status)) {
1338 if (fnum != 0xffff) {
1339 cli_smb2_close_fnum(cli, fnum);
1346 /***************************************************************
1347 Wrapper that allows SMB2 to query a pathname info (basic level).
1348 Implement on top of cli_smb2_qfileinfo_basic().
1350 ***************************************************************/
1352 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1354 struct timespec *create_time,
1355 struct timespec *access_time,
1356 struct timespec *write_time,
1357 struct timespec *change_time,
1363 struct smb2_hnd *ph = NULL;
1364 uint16_t fnum = 0xffff;
1365 TALLOC_CTX *frame = talloc_stackframe();
1367 if (smbXcli_conn_has_async_calls(cli->conn)) {
1369 * Can't use sync call while an async call is in flight
1371 status = NT_STATUS_INVALID_PARAMETER;
1375 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1376 status = NT_STATUS_INVALID_PARAMETER;
1380 status = get_fnum_from_path(cli,
1382 FILE_READ_ATTRIBUTES,
1385 if (!NT_STATUS_IS_OK(status)) {
1389 status = map_fnum_to_smb2_handle(cli,
1392 if (!NT_STATUS_IS_OK(status)) {
1396 status = cli_smb2_qfileinfo_basic(cli,
1408 if (fnum != 0xffff) {
1409 cli_smb2_close_fnum(cli, fnum);
1416 /***************************************************************
1417 Wrapper that allows SMB2 to query pathname streams.
1419 ***************************************************************/
1421 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1423 TALLOC_CTX *mem_ctx,
1424 unsigned int *pnum_streams,
1425 struct stream_struct **pstreams)
1428 struct smb2_hnd *ph = NULL;
1429 uint16_t fnum = 0xffff;
1430 DATA_BLOB outbuf = data_blob_null;
1431 TALLOC_CTX *frame = talloc_stackframe();
1433 if (smbXcli_conn_has_async_calls(cli->conn)) {
1435 * Can't use sync call while an async call is in flight
1437 status = NT_STATUS_INVALID_PARAMETER;
1441 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1442 status = NT_STATUS_INVALID_PARAMETER;
1446 status = get_fnum_from_path(cli,
1448 FILE_READ_ATTRIBUTES,
1451 if (!NT_STATUS_IS_OK(status)) {
1455 status = map_fnum_to_smb2_handle(cli,
1458 if (!NT_STATUS_IS_OK(status)) {
1462 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1463 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1465 status = smb2cli_query_info(cli->conn,
1469 1, /* in_info_type */
1470 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1471 0xFFFF, /* in_max_output_length */
1472 NULL, /* in_input_buffer */
1473 0, /* in_additional_info */
1480 if (!NT_STATUS_IS_OK(status)) {
1484 /* Parse the reply. */
1485 if (!parse_streams_blob(mem_ctx,
1490 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1496 if (fnum != 0xffff) {
1497 cli_smb2_close_fnum(cli, fnum);
1504 /***************************************************************
1505 Wrapper that allows SMB2 to set pathname attributes.
1507 ***************************************************************/
1509 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1515 uint16_t fnum = 0xffff;
1516 struct smb2_hnd *ph = NULL;
1517 uint8_t inbuf_store[40];
1518 DATA_BLOB inbuf = data_blob_null;
1519 TALLOC_CTX *frame = talloc_stackframe();
1521 if (smbXcli_conn_has_async_calls(cli->conn)) {
1523 * Can't use sync call while an async call is in flight
1525 status = NT_STATUS_INVALID_PARAMETER;
1529 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1530 status = NT_STATUS_INVALID_PARAMETER;
1534 status = get_fnum_from_path(cli,
1536 FILE_WRITE_ATTRIBUTES,
1539 if (!NT_STATUS_IS_OK(status)) {
1543 status = map_fnum_to_smb2_handle(cli,
1546 if (!NT_STATUS_IS_OK(status)) {
1550 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1551 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1553 inbuf.data = inbuf_store;
1554 inbuf.length = sizeof(inbuf_store);
1555 data_blob_clear(&inbuf);
1557 SSVAL(inbuf.data, 32, attr);
1559 put_long_date((char *)inbuf.data + 16,mtime);
1561 /* Set all the other times to -1. */
1562 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1563 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1564 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1566 status = smb2cli_set_info(cli->conn,
1570 1, /* in_info_type */
1571 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1572 &inbuf, /* in_input_buffer */
1573 0, /* in_additional_info */
1578 if (fnum != 0xffff) {
1579 cli_smb2_close_fnum(cli, fnum);
1586 /***************************************************************
1587 Wrapper that allows SMB2 to set file handle times.
1589 ***************************************************************/
1591 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1598 struct smb2_hnd *ph = NULL;
1599 uint8_t inbuf_store[40];
1600 DATA_BLOB inbuf = data_blob_null;
1602 if (smbXcli_conn_has_async_calls(cli->conn)) {
1604 * Can't use sync call while an async call is in flight
1606 return NT_STATUS_INVALID_PARAMETER;
1609 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1610 return NT_STATUS_INVALID_PARAMETER;
1613 status = map_fnum_to_smb2_handle(cli,
1616 if (!NT_STATUS_IS_OK(status)) {
1620 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1621 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1623 inbuf.data = inbuf_store;
1624 inbuf.length = sizeof(inbuf_store);
1625 data_blob_clear(&inbuf);
1627 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1628 if (change_time != 0) {
1629 put_long_date((char *)inbuf.data + 24, change_time);
1631 if (access_time != 0) {
1632 put_long_date((char *)inbuf.data + 8, access_time);
1634 if (write_time != 0) {
1635 put_long_date((char *)inbuf.data + 16, write_time);
1638 return smb2cli_set_info(cli->conn,
1642 1, /* in_info_type */
1643 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1644 &inbuf, /* in_input_buffer */
1645 0, /* in_additional_info */
1650 /***************************************************************
1651 Wrapper that allows SMB2 to query disk attributes (size).
1653 ***************************************************************/
1655 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
1656 uint64_t *bsize, uint64_t *total, uint64_t *avail)
1659 uint16_t fnum = 0xffff;
1660 DATA_BLOB outbuf = data_blob_null;
1661 struct smb2_hnd *ph = NULL;
1662 uint32_t sectors_per_unit = 0;
1663 uint32_t bytes_per_sector = 0;
1664 uint64_t total_size = 0;
1665 uint64_t size_free = 0;
1666 TALLOC_CTX *frame = talloc_stackframe();
1668 if (smbXcli_conn_has_async_calls(cli->conn)) {
1670 * Can't use sync call while an async call is in flight
1672 status = NT_STATUS_INVALID_PARAMETER;
1676 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1677 status = NT_STATUS_INVALID_PARAMETER;
1681 /* First open the top level directory. */
1682 status = cli_smb2_create_fnum(cli,
1684 0, /* create_flags */
1685 FILE_READ_ATTRIBUTES, /* desired_access */
1686 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1687 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1688 FILE_OPEN, /* create_disposition */
1689 FILE_DIRECTORY_FILE, /* create_options */
1693 if (!NT_STATUS_IS_OK(status)) {
1697 status = map_fnum_to_smb2_handle(cli,
1700 if (!NT_STATUS_IS_OK(status)) {
1704 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1705 level 3 (SMB_FS_SIZE_INFORMATION). */
1707 status = smb2cli_query_info(cli->conn,
1711 2, /* in_info_type */
1712 3, /* in_file_info_class */
1713 0xFFFF, /* in_max_output_length */
1714 NULL, /* in_input_buffer */
1715 0, /* in_additional_info */
1721 if (!NT_STATUS_IS_OK(status)) {
1725 /* Parse the reply. */
1726 if (outbuf.length != 24) {
1727 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1731 total_size = BVAL(outbuf.data, 0);
1732 size_free = BVAL(outbuf.data, 8);
1733 sectors_per_unit = IVAL(outbuf.data, 16);
1734 bytes_per_sector = IVAL(outbuf.data, 20);
1737 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
1740 *total = total_size;
1746 status = NT_STATUS_OK;
1750 if (fnum != 0xffff) {
1751 cli_smb2_close_fnum(cli, fnum);
1758 /***************************************************************
1759 Wrapper that allows SMB2 to query file system attributes.
1761 ***************************************************************/
1763 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
1766 uint16_t fnum = 0xffff;
1767 DATA_BLOB outbuf = data_blob_null;
1768 struct smb2_hnd *ph = NULL;
1769 TALLOC_CTX *frame = talloc_stackframe();
1771 if (smbXcli_conn_has_async_calls(cli->conn)) {
1773 * Can't use sync call while an async call is in flight
1775 status = NT_STATUS_INVALID_PARAMETER;
1779 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1780 status = NT_STATUS_INVALID_PARAMETER;
1784 /* First open the top level directory. */
1786 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
1787 FILE_READ_ATTRIBUTES, /* desired_access */
1788 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1789 FILE_SHARE_READ | FILE_SHARE_WRITE |
1790 FILE_SHARE_DELETE, /* share_access */
1791 FILE_OPEN, /* create_disposition */
1792 FILE_DIRECTORY_FILE, /* create_options */
1796 if (!NT_STATUS_IS_OK(status)) {
1800 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1801 if (!NT_STATUS_IS_OK(status)) {
1805 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
1806 cli->smb2.tcon, 2, /* in_info_type */
1807 5, /* in_file_info_class */
1808 0xFFFF, /* in_max_output_length */
1809 NULL, /* in_input_buffer */
1810 0, /* in_additional_info */
1812 ph->fid_persistent, ph->fid_volatile, frame,
1814 if (!NT_STATUS_IS_OK(status)) {
1818 if (outbuf.length < 12) {
1819 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1823 *fs_attr = IVAL(outbuf.data, 0);
1827 if (fnum != 0xffff) {
1828 cli_smb2_close_fnum(cli, fnum);
1835 /***************************************************************
1836 Wrapper that allows SMB2 to query a security descriptor.
1838 ***************************************************************/
1840 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
1843 TALLOC_CTX *mem_ctx,
1844 struct security_descriptor **ppsd)
1847 DATA_BLOB outbuf = data_blob_null;
1848 struct smb2_hnd *ph = NULL;
1849 struct security_descriptor *lsd = NULL;
1850 TALLOC_CTX *frame = talloc_stackframe();
1852 if (smbXcli_conn_has_async_calls(cli->conn)) {
1854 * Can't use sync call while an async call is in flight
1856 status = NT_STATUS_INVALID_PARAMETER;
1860 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1861 status = NT_STATUS_INVALID_PARAMETER;
1865 status = map_fnum_to_smb2_handle(cli,
1868 if (!NT_STATUS_IS_OK(status)) {
1872 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1874 status = smb2cli_query_info(cli->conn,
1878 3, /* in_info_type */
1879 0, /* in_file_info_class */
1880 0xFFFF, /* in_max_output_length */
1881 NULL, /* in_input_buffer */
1882 sec_info, /* in_additional_info */
1889 if (!NT_STATUS_IS_OK(status)) {
1893 /* Parse the reply. */
1894 status = unmarshall_sec_desc(mem_ctx,
1899 if (!NT_STATUS_IS_OK(status)) {
1915 /***************************************************************
1916 Wrapper that allows SMB2 to set a security descriptor.
1918 ***************************************************************/
1920 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
1923 const struct security_descriptor *sd)
1926 DATA_BLOB inbuf = data_blob_null;
1927 struct smb2_hnd *ph = NULL;
1928 TALLOC_CTX *frame = talloc_stackframe();
1930 if (smbXcli_conn_has_async_calls(cli->conn)) {
1932 * Can't use sync call while an async call is in flight
1934 status = NT_STATUS_INVALID_PARAMETER;
1938 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1939 status = NT_STATUS_INVALID_PARAMETER;
1943 status = map_fnum_to_smb2_handle(cli,
1946 if (!NT_STATUS_IS_OK(status)) {
1950 status = marshall_sec_desc(frame,
1955 if (!NT_STATUS_IS_OK(status)) {
1959 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1961 status = smb2cli_set_info(cli->conn,
1965 3, /* in_info_type */
1966 0, /* in_file_info_class */
1967 &inbuf, /* in_input_buffer */
1968 sec_info, /* in_additional_info */
1978 /***************************************************************
1979 Wrapper that allows SMB2 to rename a file.
1981 ***************************************************************/
1983 NTSTATUS cli_smb2_rename(struct cli_state *cli,
1984 const char *fname_src,
1985 const char *fname_dst)
1988 DATA_BLOB inbuf = data_blob_null;
1989 uint16_t fnum = 0xffff;
1990 struct smb2_hnd *ph = NULL;
1991 smb_ucs2_t *converted_str = NULL;
1992 size_t converted_size_bytes = 0;
1994 TALLOC_CTX *frame = talloc_stackframe();
1996 if (smbXcli_conn_has_async_calls(cli->conn)) {
1998 * Can't use sync call while an async call is in flight
2000 status = NT_STATUS_INVALID_PARAMETER;
2004 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2005 status = NT_STATUS_INVALID_PARAMETER;
2009 status = get_fnum_from_path(cli,
2014 if (!NT_STATUS_IS_OK(status)) {
2018 status = map_fnum_to_smb2_handle(cli,
2021 if (!NT_STATUS_IS_OK(status)) {
2025 /* SMB2 is pickier about pathnames. Ensure it doesn't
2027 if (*fname_dst == '\\') {
2031 /* SMB2 is pickier about pathnames. Ensure it doesn't
2033 namelen = strlen(fname_dst);
2034 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2035 char *modname = talloc_strdup(frame, fname_dst);
2036 modname[namelen-1] = '\0';
2037 fname_dst = modname;
2040 if (!push_ucs2_talloc(frame,
2043 &converted_size_bytes)) {
2044 status = NT_STATUS_INVALID_PARAMETER;
2048 /* W2K8 insists the dest name is not null
2049 terminated. Remove the last 2 zero bytes
2050 and reduce the name length. */
2052 if (converted_size_bytes < 2) {
2053 status = NT_STATUS_INVALID_PARAMETER;
2056 converted_size_bytes -= 2;
2058 inbuf = data_blob_talloc_zero(frame,
2059 20 + converted_size_bytes);
2060 if (inbuf.data == NULL) {
2061 status = NT_STATUS_NO_MEMORY;
2065 SIVAL(inbuf.data, 16, converted_size_bytes);
2066 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2068 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2069 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2071 status = smb2cli_set_info(cli->conn,
2075 1, /* in_info_type */
2076 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2077 &inbuf, /* in_input_buffer */
2078 0, /* in_additional_info */
2084 if (fnum != 0xffff) {
2085 cli_smb2_close_fnum(cli, fnum);
2092 /***************************************************************
2093 Wrapper that allows SMB2 to set an EA on a fnum.
2095 ***************************************************************/
2097 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2099 const char *ea_name,
2104 DATA_BLOB inbuf = data_blob_null;
2106 char *ea_name_ascii = NULL;
2108 struct smb2_hnd *ph = NULL;
2109 TALLOC_CTX *frame = talloc_stackframe();
2111 if (smbXcli_conn_has_async_calls(cli->conn)) {
2113 * Can't use sync call while an async call is in flight
2115 status = NT_STATUS_INVALID_PARAMETER;
2119 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2120 status = NT_STATUS_INVALID_PARAMETER;
2124 status = map_fnum_to_smb2_handle(cli,
2127 if (!NT_STATUS_IS_OK(status)) {
2131 /* Marshall the SMB2 EA data. */
2132 if (ea_len > 0xFFFF) {
2133 status = NT_STATUS_INVALID_PARAMETER;
2137 if (!push_ascii_talloc(frame,
2141 status = NT_STATUS_INVALID_PARAMETER;
2145 if (namelen < 2 || namelen > 0xFF) {
2146 status = NT_STATUS_INVALID_PARAMETER;
2150 bloblen = 8 + ea_len + namelen;
2151 /* Round up to a 4 byte boundary. */
2152 bloblen = ((bloblen + 3)&~3);
2154 inbuf = data_blob_talloc_zero(frame, bloblen);
2155 if (inbuf.data == NULL) {
2156 status = NT_STATUS_NO_MEMORY;
2159 /* namelen doesn't include the NULL byte. */
2160 SCVAL(inbuf.data, 5, namelen - 1);
2161 SSVAL(inbuf.data, 6, ea_len);
2162 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2163 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2165 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2166 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2168 status = smb2cli_set_info(cli->conn,
2172 1, /* in_info_type */
2173 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2174 &inbuf, /* in_input_buffer */
2175 0, /* in_additional_info */
2185 /***************************************************************
2186 Wrapper that allows SMB2 to set an EA on a pathname.
2188 ***************************************************************/
2190 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2192 const char *ea_name,
2197 uint16_t fnum = 0xffff;
2199 if (smbXcli_conn_has_async_calls(cli->conn)) {
2201 * Can't use sync call while an async call is in flight
2203 status = NT_STATUS_INVALID_PARAMETER;
2207 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2208 status = NT_STATUS_INVALID_PARAMETER;
2212 status = get_fnum_from_path(cli,
2217 if (!NT_STATUS_IS_OK(status)) {
2221 status = cli_set_ea_fnum(cli,
2226 if (!NT_STATUS_IS_OK(status)) {
2232 if (fnum != 0xffff) {
2233 cli_smb2_close_fnum(cli, fnum);
2239 /***************************************************************
2240 Wrapper that allows SMB2 to get an EA list on a pathname.
2242 ***************************************************************/
2244 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2248 struct ea_struct **pea_array)
2251 uint16_t fnum = 0xffff;
2252 DATA_BLOB outbuf = data_blob_null;
2253 struct smb2_hnd *ph = NULL;
2254 struct ea_list *ea_list = NULL;
2255 struct ea_list *eal = NULL;
2256 size_t ea_count = 0;
2257 TALLOC_CTX *frame = talloc_stackframe();
2262 if (smbXcli_conn_has_async_calls(cli->conn)) {
2264 * Can't use sync call while an async call is in flight
2266 status = NT_STATUS_INVALID_PARAMETER;
2270 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2271 status = NT_STATUS_INVALID_PARAMETER;
2275 status = get_fnum_from_path(cli,
2280 if (!NT_STATUS_IS_OK(status)) {
2284 status = map_fnum_to_smb2_handle(cli,
2287 if (!NT_STATUS_IS_OK(status)) {
2291 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2292 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2294 status = smb2cli_query_info(cli->conn,
2298 1, /* in_info_type */
2299 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2300 0xFFFF, /* in_max_output_length */
2301 NULL, /* in_input_buffer */
2302 0, /* in_additional_info */
2309 if (!NT_STATUS_IS_OK(status)) {
2313 /* Parse the reply. */
2314 ea_list = read_nttrans_ea_list(ctx,
2315 (const char *)outbuf.data,
2317 if (ea_list == NULL) {
2318 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2322 /* Convert to an array. */
2323 for (eal = ea_list; eal; eal = eal->next) {
2328 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2329 if (*pea_array == NULL) {
2330 status = NT_STATUS_NO_MEMORY;
2334 for (eal = ea_list; eal; eal = eal->next) {
2335 (*pea_array)[ea_count++] = eal->ea;
2337 *pnum_eas = ea_count;
2342 if (fnum != 0xffff) {
2343 cli_smb2_close_fnum(cli, fnum);
2350 struct cli_smb2_read_state {
2351 struct tevent_context *ev;
2352 struct cli_state *cli;
2353 struct smb2_hnd *ph;
2354 uint64_t start_offset;
2360 static void cli_smb2_read_done(struct tevent_req *subreq);
2362 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
2363 struct tevent_context *ev,
2364 struct cli_state *cli,
2370 struct tevent_req *req, *subreq;
2371 struct cli_smb2_read_state *state;
2373 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
2379 state->start_offset = (uint64_t)offset;
2380 state->size = (uint32_t)size;
2381 state->received = 0;
2384 status = map_fnum_to_smb2_handle(cli,
2387 if (tevent_req_nterror(req, status)) {
2388 return tevent_req_post(req, ev);
2391 subreq = smb2cli_read_send(state,
2394 state->cli->timeout,
2395 state->cli->smb2.session,
2396 state->cli->smb2.tcon,
2398 state->start_offset,
2399 state->ph->fid_persistent,
2400 state->ph->fid_volatile,
2401 0, /* minimum_count */
2402 0); /* remaining_bytes */
2404 if (tevent_req_nomem(subreq, req)) {
2405 return tevent_req_post(req, ev);
2407 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
2411 static void cli_smb2_read_done(struct tevent_req *subreq)
2413 struct tevent_req *req = tevent_req_callback_data(
2414 subreq, struct tevent_req);
2415 struct cli_smb2_read_state *state = tevent_req_data(
2416 req, struct cli_smb2_read_state);
2419 status = smb2cli_read_recv(subreq, state,
2420 &state->buf, &state->received);
2421 if (tevent_req_nterror(req, status)) {
2425 if (state->received > state->size) {
2426 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2430 tevent_req_done(req);
2433 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
2438 struct cli_smb2_read_state *state = tevent_req_data(
2439 req, struct cli_smb2_read_state);
2441 if (tevent_req_is_nterror(req, &status)) {
2442 state->cli->raw_status = status;
2446 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2447 * better make sure that you copy it away before you talloc_free(req).
2448 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2450 *received = (ssize_t)state->received;
2451 *rcvbuf = state->buf;
2452 state->cli->raw_status = NT_STATUS_OK;
2453 return NT_STATUS_OK;
2456 struct cli_smb2_write_state {
2457 struct tevent_context *ev;
2458 struct cli_state *cli;
2459 struct smb2_hnd *ph;
2467 static void cli_smb2_write_written(struct tevent_req *req);
2469 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
2470 struct tevent_context *ev,
2471 struct cli_state *cli,
2479 struct tevent_req *req, *subreq = NULL;
2480 struct cli_smb2_write_state *state = NULL;
2482 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
2488 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2489 state->flags = (uint32_t)mode;
2491 state->offset = (uint64_t)offset;
2492 state->size = (uint32_t)size;
2495 status = map_fnum_to_smb2_handle(cli,
2498 if (tevent_req_nterror(req, status)) {
2499 return tevent_req_post(req, ev);
2502 subreq = smb2cli_write_send(state,
2505 state->cli->timeout,
2506 state->cli->smb2.session,
2507 state->cli->smb2.tcon,
2510 state->ph->fid_persistent,
2511 state->ph->fid_volatile,
2512 0, /* remaining_bytes */
2513 state->flags, /* flags */
2516 if (tevent_req_nomem(subreq, req)) {
2517 return tevent_req_post(req, ev);
2519 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
2523 static void cli_smb2_write_written(struct tevent_req *subreq)
2525 struct tevent_req *req = tevent_req_callback_data(
2526 subreq, struct tevent_req);
2527 struct cli_smb2_write_state *state = tevent_req_data(
2528 req, struct cli_smb2_write_state);
2532 status = smb2cli_write_recv(subreq, &written);
2533 TALLOC_FREE(subreq);
2534 if (tevent_req_nterror(req, status)) {
2538 state->written = written;
2540 tevent_req_done(req);
2543 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
2546 struct cli_smb2_write_state *state = tevent_req_data(
2547 req, struct cli_smb2_write_state);
2550 if (tevent_req_is_nterror(req, &status)) {
2551 state->cli->raw_status = status;
2552 tevent_req_received(req);
2556 if (pwritten != NULL) {
2557 *pwritten = (size_t)state->written;
2559 state->cli->raw_status = NT_STATUS_OK;
2560 tevent_req_received(req);
2561 return NT_STATUS_OK;
2564 /***************************************************************
2565 Wrapper that allows SMB2 async write using an fnum.
2566 This is mostly cut-and-paste from Volker's code inside
2567 source3/libsmb/clireadwrite.c, adapted for SMB2.
2569 Done this way so I can reuse all the logic inside cli_push()
2571 ***************************************************************/
2573 struct cli_smb2_writeall_state {
2574 struct tevent_context *ev;
2575 struct cli_state *cli;
2576 struct smb2_hnd *ph;
2584 static void cli_smb2_writeall_written(struct tevent_req *req);
2586 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
2587 struct tevent_context *ev,
2588 struct cli_state *cli,
2596 struct tevent_req *req, *subreq = NULL;
2597 struct cli_smb2_writeall_state *state = NULL;
2602 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
2608 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2609 state->flags = (uint32_t)mode;
2611 state->offset = (uint64_t)offset;
2612 state->size = (uint32_t)size;
2615 status = map_fnum_to_smb2_handle(cli,
2618 if (tevent_req_nterror(req, status)) {
2619 return tevent_req_post(req, ev);
2622 to_write = state->size;
2623 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2624 to_write = MIN(max_size, to_write);
2625 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2627 to_write = MIN(max_size, to_write);
2630 subreq = smb2cli_write_send(state,
2633 state->cli->timeout,
2634 state->cli->smb2.session,
2635 state->cli->smb2.tcon,
2638 state->ph->fid_persistent,
2639 state->ph->fid_volatile,
2640 0, /* remaining_bytes */
2641 state->flags, /* flags */
2642 state->buf + state->written);
2644 if (tevent_req_nomem(subreq, req)) {
2645 return tevent_req_post(req, ev);
2647 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2651 static void cli_smb2_writeall_written(struct tevent_req *subreq)
2653 struct tevent_req *req = tevent_req_callback_data(
2654 subreq, struct tevent_req);
2655 struct cli_smb2_writeall_state *state = tevent_req_data(
2656 req, struct cli_smb2_writeall_state);
2658 uint32_t written, to_write;
2662 status = smb2cli_write_recv(subreq, &written);
2663 TALLOC_FREE(subreq);
2664 if (tevent_req_nterror(req, status)) {
2668 state->written += written;
2670 if (state->written > state->size) {
2671 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2675 to_write = state->size - state->written;
2677 if (to_write == 0) {
2678 tevent_req_done(req);
2682 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2683 to_write = MIN(max_size, to_write);
2684 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2686 to_write = MIN(max_size, to_write);
2689 subreq = smb2cli_write_send(state,
2692 state->cli->timeout,
2693 state->cli->smb2.session,
2694 state->cli->smb2.tcon,
2696 state->offset + state->written,
2697 state->ph->fid_persistent,
2698 state->ph->fid_volatile,
2699 0, /* remaining_bytes */
2700 state->flags, /* flags */
2701 state->buf + state->written);
2703 if (tevent_req_nomem(subreq, req)) {
2706 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2709 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
2712 struct cli_smb2_writeall_state *state = tevent_req_data(
2713 req, struct cli_smb2_writeall_state);
2716 if (tevent_req_is_nterror(req, &status)) {
2717 state->cli->raw_status = status;
2720 if (pwritten != NULL) {
2721 *pwritten = (size_t)state->written;
2723 state->cli->raw_status = NT_STATUS_OK;
2724 return NT_STATUS_OK;
2727 struct cli_smb2_splice_state {
2728 struct tevent_context *ev;
2729 struct cli_state *cli;
2730 struct smb2_hnd *src_ph;
2731 struct smb2_hnd *dst_ph;
2732 int (*splice_cb)(off_t n, void *priv);
2739 struct req_resume_key_rsp resume_rsp;
2740 struct srv_copychunk_copy cc_copy;
2743 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
2744 struct tevent_req *req);
2746 static void cli_splice_copychunk_done(struct tevent_req *subreq)
2748 struct tevent_req *req = tevent_req_callback_data(
2749 subreq, struct tevent_req);
2750 struct cli_smb2_splice_state *state =
2751 tevent_req_data(req,
2752 struct cli_smb2_splice_state);
2753 struct smbXcli_conn *conn = state->cli->conn;
2754 DATA_BLOB out_input_buffer = data_blob_null;
2755 DATA_BLOB out_output_buffer = data_blob_null;
2756 struct srv_copychunk_rsp cc_copy_rsp;
2757 enum ndr_err_code ndr_ret;
2760 status = smb2cli_ioctl_recv(subreq, state,
2762 &out_output_buffer);
2763 TALLOC_FREE(subreq);
2764 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
2765 state->resized) && tevent_req_nterror(req, status)) {
2769 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
2770 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
2771 if (ndr_ret != NDR_ERR_SUCCESS) {
2772 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
2773 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2777 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
2778 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
2779 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
2780 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
2781 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
2782 tevent_req_nterror(req, status)) {
2786 state->resized = true;
2787 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
2788 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
2790 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
2791 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
2792 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
2793 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
2796 state->src_offset += cc_copy_rsp.total_bytes_written;
2797 state->dst_offset += cc_copy_rsp.total_bytes_written;
2798 state->written += cc_copy_rsp.total_bytes_written;
2799 if (!state->splice_cb(state->written, state->priv)) {
2800 tevent_req_nterror(req, NT_STATUS_CANCELLED);
2805 cli_splice_copychunk_send(state, req);
2808 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
2809 struct tevent_req *req)
2811 struct tevent_req *subreq;
2812 enum ndr_err_code ndr_ret;
2813 struct smbXcli_conn *conn = state->cli->conn;
2814 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
2815 off_t src_offset = state->src_offset;
2816 off_t dst_offset = state->dst_offset;
2817 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
2818 state->size - state->written);
2819 DATA_BLOB in_input_buffer = data_blob_null;
2820 DATA_BLOB in_output_buffer = data_blob_null;
2822 if (state->size - state->written == 0) {
2823 tevent_req_done(req);
2827 cc_copy->chunk_count = 0;
2829 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
2830 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
2831 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
2832 smb2cli_conn_cc_chunk_len(conn));
2833 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
2834 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2837 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
2838 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
2839 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
2840 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
2843 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
2844 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
2845 cc_copy->chunk_count++;
2848 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
2849 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
2850 if (ndr_ret != NDR_ERR_SUCCESS) {
2851 DEBUG(0, ("failed to marshall copy chunk req\n"));
2852 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2856 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
2857 state->cli->timeout,
2858 state->cli->smb2.session,
2859 state->cli->smb2.tcon,
2860 state->dst_ph->fid_persistent, /* in_fid_persistent */
2861 state->dst_ph->fid_volatile, /* in_fid_volatile */
2862 FSCTL_SRV_COPYCHUNK_WRITE,
2863 0, /* in_max_input_length */
2865 12, /* in_max_output_length */
2867 SMB2_IOCTL_FLAG_IS_FSCTL);
2868 if (tevent_req_nomem(subreq, req)) {
2871 tevent_req_set_callback(subreq,
2872 cli_splice_copychunk_done,
2876 static void cli_splice_key_done(struct tevent_req *subreq)
2878 struct tevent_req *req = tevent_req_callback_data(
2879 subreq, struct tevent_req);
2880 struct cli_smb2_splice_state *state =
2881 tevent_req_data(req,
2882 struct cli_smb2_splice_state);
2883 enum ndr_err_code ndr_ret;
2886 DATA_BLOB out_input_buffer = data_blob_null;
2887 DATA_BLOB out_output_buffer = data_blob_null;
2889 status = smb2cli_ioctl_recv(subreq, state,
2891 &out_output_buffer);
2892 TALLOC_FREE(subreq);
2893 if (tevent_req_nterror(req, status)) {
2897 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
2898 state, &state->resume_rsp,
2899 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
2900 if (ndr_ret != NDR_ERR_SUCCESS) {
2901 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
2902 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2906 memcpy(&state->cc_copy.source_key,
2907 &state->resume_rsp.resume_key,
2908 sizeof state->resume_rsp.resume_key);
2910 cli_splice_copychunk_send(state, req);
2913 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
2914 struct tevent_context *ev,
2915 struct cli_state *cli,
2916 uint16_t src_fnum, uint16_t dst_fnum,
2917 off_t size, off_t src_offset, off_t dst_offset,
2918 int (*splice_cb)(off_t n, void *priv),
2921 struct tevent_req *req;
2922 struct tevent_req *subreq;
2923 struct cli_smb2_splice_state *state;
2925 DATA_BLOB in_input_buffer = data_blob_null;
2926 DATA_BLOB in_output_buffer = data_blob_null;
2928 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
2934 state->splice_cb = splice_cb;
2938 state->src_offset = src_offset;
2939 state->dst_offset = dst_offset;
2940 state->cc_copy.chunks = talloc_array(state,
2941 struct srv_copychunk,
2942 smb2cli_conn_cc_max_chunks(cli->conn));
2943 if (state->cc_copy.chunks == NULL) {
2947 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
2948 if (tevent_req_nterror(req, status))
2949 return tevent_req_post(req, ev);
2951 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
2952 if (tevent_req_nterror(req, status))
2953 return tevent_req_post(req, ev);
2955 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
2959 state->src_ph->fid_persistent, /* in_fid_persistent */
2960 state->src_ph->fid_volatile, /* in_fid_volatile */
2961 FSCTL_SRV_REQUEST_RESUME_KEY,
2962 0, /* in_max_input_length */
2964 32, /* in_max_output_length */
2966 SMB2_IOCTL_FLAG_IS_FSCTL);
2967 if (tevent_req_nomem(subreq, req)) {
2970 tevent_req_set_callback(subreq,
2971 cli_splice_key_done,
2977 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
2979 struct cli_smb2_splice_state *state = tevent_req_data(
2980 req, struct cli_smb2_splice_state);
2983 if (tevent_req_is_nterror(req, &status)) {
2984 state->cli->raw_status = status;
2985 tevent_req_received(req);
2988 if (written != NULL) {
2989 *written = state->written;
2991 state->cli->raw_status = NT_STATUS_OK;
2992 tevent_req_received(req);
2993 return NT_STATUS_OK;
2996 /***************************************************************
2997 SMB2 enum shadow copy data.
2998 ***************************************************************/
3000 struct cli_smb2_shadow_copy_data_fnum_state {
3001 struct cli_state *cli;
3003 struct smb2_hnd *ph;
3004 DATA_BLOB out_input_buffer;
3005 DATA_BLOB out_output_buffer;
3008 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
3010 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
3011 TALLOC_CTX *mem_ctx,
3012 struct tevent_context *ev,
3013 struct cli_state *cli,
3017 struct tevent_req *req, *subreq;
3018 struct cli_smb2_close_fnum_state *state;
3021 req = tevent_req_create(mem_ctx, &state,
3022 struct cli_smb2_shadow_copy_data_fnum_state);
3027 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3028 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3029 return tevent_req_post(req, ev);
3035 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
3036 if (tevent_req_nterror(req, status)) {
3037 return tevent_req_post(req, ev);
3041 * TODO. Under SMB2 we should send a zero max_output_length
3042 * ioctl to get the required size, then send another ioctl
3043 * to get the data, but the current SMB1 implementation just
3044 * does one roundtrip with a 64K buffer size. Do the same
3048 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
3049 state->cli->timeout,
3050 state->cli->smb2.session,
3051 state->cli->smb2.tcon,
3052 state->ph->fid_persistent, /* in_fid_persistent */
3053 state->ph->fid_volatile, /* in_fid_volatile */
3054 FSCTL_GET_SHADOW_COPY_DATA,
3055 0, /* in_max_input_length */
3056 NULL, /* in_input_buffer */
3058 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
3059 NULL, /* in_output_buffer */
3060 SMB2_IOCTL_FLAG_IS_FSCTL);
3062 if (tevent_req_nomem(subreq, req)) {
3063 return tevent_req_post(req, ev);
3065 tevent_req_set_callback(subreq,
3066 cli_smb2_shadow_copy_data_fnum_done,
3072 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
3074 struct tevent_req *req = tevent_req_callback_data(
3075 subreq, struct tevent_req);
3076 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3077 req, struct cli_smb2_shadow_copy_data_fnum_state);
3080 status = smb2cli_ioctl_recv(subreq, state,
3081 &state->out_input_buffer,
3082 &state->out_output_buffer);
3083 TALLOC_FREE(subreq);
3084 if (tevent_req_nterror(req, status)) {
3087 tevent_req_done(req);
3090 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
3091 TALLOC_CTX *mem_ctx,
3096 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3097 req, struct cli_smb2_shadow_copy_data_fnum_state);
3098 char **names = NULL;
3099 uint32_t num_names = 0;
3100 uint32_t num_names_returned = 0;
3101 uint32_t dlength = 0;
3103 uint8_t *endp = NULL;
3106 if (tevent_req_is_nterror(req, &status)) {
3110 if (state->out_output_buffer.length < 16) {
3111 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3114 num_names = IVAL(state->out_output_buffer.data, 0);
3115 num_names_returned = IVAL(state->out_output_buffer.data, 4);
3116 dlength = IVAL(state->out_output_buffer.data, 8);
3118 if (num_names > 0x7FFFFFFF) {
3119 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3122 if (get_names == false) {
3123 *pnum_names = (int)num_names;
3124 return NT_STATUS_OK;
3126 if (num_names != num_names_returned) {
3127 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3129 if (dlength + 12 < 12) {
3130 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3133 * NB. The below is an allowable return if there are
3134 * more snapshots than the buffer size we told the
3135 * server we can receive. We currently don't support
3138 if (dlength + 12 > state->out_output_buffer.length) {
3139 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3141 if (state->out_output_buffer.length +
3142 (2 * sizeof(SHADOW_COPY_LABEL)) <
3143 state->out_output_buffer.length) {
3144 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3147 names = talloc_array(mem_ctx, char *, num_names_returned);
3148 if (names == NULL) {
3149 return NT_STATUS_NO_MEMORY;
3152 endp = state->out_output_buffer.data +
3153 state->out_output_buffer.length;
3155 for (i=0; i<num_names_returned; i++) {
3158 size_t converted_size;
3160 src = state->out_output_buffer.data + 12 +
3161 (i * 2 * sizeof(SHADOW_COPY_LABEL));
3163 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
3164 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3166 ret = convert_string_talloc(
3167 names, CH_UTF16LE, CH_UNIX,
3168 src, 2 * sizeof(SHADOW_COPY_LABEL),
3169 &names[i], &converted_size);
3172 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3175 *pnum_names = num_names;
3177 return NT_STATUS_OK;
3180 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
3181 struct cli_state *cli,
3187 TALLOC_CTX *frame = talloc_stackframe();
3188 struct tevent_context *ev;
3189 struct tevent_req *req;
3190 NTSTATUS status = NT_STATUS_NO_MEMORY;
3192 if (smbXcli_conn_has_async_calls(cli->conn)) {
3194 * Can't use sync call while an async call is in flight
3196 status = NT_STATUS_INVALID_PARAMETER;
3199 ev = samba_tevent_context_init(frame);
3203 req = cli_smb2_shadow_copy_data_fnum_send(frame,
3211 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3214 status = cli_smb2_shadow_copy_data_fnum_recv(req,