2 Unix SMB/CIFS implementation.
4 Copyright (C) Jeremy Allison 2013
5 Copyright (C) Volker Lendecke 2013
6 Copyright (C) Stefan Metzmacher 2013
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This code is a thin wrapper around the existing
24 cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c,
25 but allows the handles to be mapped to uint16_t fnums,
26 which are easier for smbclient to use.
31 #include "async_smb.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "cli_smb2_fnum.h"
36 #include "../libcli/smb/smb2_create_blob.h"
37 #include "libsmb/proto.h"
38 #include "lib/util/tevent_ntstatus.h"
39 #include "../libcli/security/security.h"
40 #include "../librpc/gen_ndr/ndr_security.h"
41 #include "lib/util_ea.h"
42 #include "librpc/gen_ndr/ndr_ioctl.h"
46 uint64_t fid_persistent;
47 uint64_t fid_volatile;
51 * Handle mapping code.
54 /***************************************************************
55 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
56 Ensures handle is owned by cli struct.
57 ***************************************************************/
59 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
60 const struct smb2_hnd *ph, /* In */
61 uint16_t *pfnum) /* Out */
64 struct idr_context *idp = cli->smb2.open_handles;
65 struct smb2_hnd *owned_h = talloc_memdup(cli,
67 sizeof(struct smb2_hnd));
69 if (owned_h == NULL) {
70 return NT_STATUS_NO_MEMORY;
75 cli->smb2.open_handles = idr_init(cli);
76 if (cli->smb2.open_handles == NULL) {
78 return NT_STATUS_NO_MEMORY;
80 idp = cli->smb2.open_handles;
83 ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
86 return NT_STATUS_NO_MEMORY;
89 *pfnum = (uint16_t)ret;
93 /***************************************************************
94 Return the smb2_hnd pointer associated with the given fnum.
95 ***************************************************************/
97 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
98 uint16_t fnum, /* In */
99 struct smb2_hnd **pph) /* Out */
101 struct idr_context *idp = cli->smb2.open_handles;
104 return NT_STATUS_INVALID_PARAMETER;
106 *pph = (struct smb2_hnd *)idr_find(idp, fnum);
108 return NT_STATUS_INVALID_HANDLE;
113 /***************************************************************
114 Delete the fnum to smb2_hnd mapping. Zeros out handle on
116 ***************************************************************/
118 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
119 struct smb2_hnd **pph, /* In */
120 uint16_t fnum) /* In */
122 struct idr_context *idp = cli->smb2.open_handles;
126 return NT_STATUS_INVALID_PARAMETER;
129 ph = (struct smb2_hnd *)idr_find(idp, fnum);
131 return NT_STATUS_INVALID_PARAMETER;
133 idr_remove(idp, fnum);
138 /***************************************************************
140 ***************************************************************/
142 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
144 if (create_flags & REQUEST_BATCH_OPLOCK) {
145 return SMB2_OPLOCK_LEVEL_BATCH;
146 } else if (create_flags & REQUEST_OPLOCK) {
147 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
150 /* create_flags doesn't do a level2 request. */
151 return SMB2_OPLOCK_LEVEL_NONE;
154 /***************************************************************
155 Small wrapper that allows SMB2 create to return a uint16_t fnum.
156 ***************************************************************/
158 struct cli_smb2_create_fnum_state {
159 struct cli_state *cli;
160 struct smb_create_returns cr;
162 struct tevent_req *subreq;
165 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
166 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
168 struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
169 struct tevent_context *ev,
170 struct cli_state *cli,
172 uint32_t create_flags,
173 uint32_t desired_access,
174 uint32_t file_attributes,
175 uint32_t share_access,
176 uint32_t create_disposition,
177 uint32_t create_options)
179 struct tevent_req *req, *subreq;
180 struct cli_smb2_create_fnum_state *state;
181 size_t fname_len = 0;
182 const char *startp = NULL;
183 const char *endp = NULL;
184 time_t tstamp = (time_t)0;
185 struct smb2_create_blobs *cblobs = NULL;
187 req = tevent_req_create(mem_ctx, &state,
188 struct cli_smb2_create_fnum_state);
194 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
195 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
196 return tevent_req_post(req, ev);
199 if (cli->backup_intent) {
200 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
203 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
204 fname_len = strlen(fname);
205 if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
206 size_t len_before_gmt = startp - fname;
207 size_t len_after_gmt = fname + fname_len - endp;
212 char *new_fname = talloc_array(state, char,
213 len_before_gmt + len_after_gmt + 1);
215 if (tevent_req_nomem(new_fname, req)) {
216 return tevent_req_post(req, ev);
219 memcpy(new_fname, fname, len_before_gmt);
220 memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
222 fname_len = len_before_gmt + len_after_gmt;
224 unix_to_nt_time(&ntt, tstamp);
225 twrp_blob = data_blob_const((const void *)&ntt, 8);
227 cblobs = talloc_zero(state, struct smb2_create_blobs);
228 if (tevent_req_nomem(cblobs, req)) {
229 return tevent_req_post(req, ev);
232 status = smb2_create_blob_add(state, cblobs,
233 SMB2_CREATE_TAG_TWRP, twrp_blob);
234 if (!NT_STATUS_IS_OK(status)) {
235 tevent_req_nterror(req, status);
236 return tevent_req_post(req, ev);
240 /* SMB2 is pickier about pathnames. Ensure it doesn't
242 if (*fname == '\\') {
247 /* Or end in a '\' */
248 if (fname_len > 0 && fname[fname_len-1] == '\\') {
249 char *new_fname = talloc_strdup(state, fname);
250 if (tevent_req_nomem(new_fname, req)) {
251 return tevent_req_post(req, ev);
253 new_fname[fname_len-1] = '\0';
257 subreq = smb2cli_create_send(state, ev,
263 flags_to_smb2_oplock(create_flags),
264 SMB2_IMPERSONATION_IMPERSONATION,
271 if (tevent_req_nomem(subreq, req)) {
272 return tevent_req_post(req, ev);
274 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
276 state->subreq = subreq;
277 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
282 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
284 struct tevent_req *req = tevent_req_callback_data(
285 subreq, struct tevent_req);
286 struct cli_smb2_create_fnum_state *state = tevent_req_data(
287 req, struct cli_smb2_create_fnum_state);
291 status = smb2cli_create_recv(subreq, &h.fid_persistent,
292 &h.fid_volatile, &state->cr, NULL, NULL);
294 if (tevent_req_nterror(req, status)) {
298 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
299 if (tevent_req_nterror(req, status)) {
302 tevent_req_done(req);
305 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
307 struct cli_smb2_create_fnum_state *state = tevent_req_data(
308 req, struct cli_smb2_create_fnum_state);
309 return tevent_req_cancel(state->subreq);
312 NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum,
313 struct smb_create_returns *cr)
315 struct cli_smb2_create_fnum_state *state = tevent_req_data(
316 req, struct cli_smb2_create_fnum_state);
319 if (tevent_req_is_nterror(req, &status)) {
320 state->cli->raw_status = status;
324 *pfnum = state->fnum;
329 state->cli->raw_status = NT_STATUS_OK;
333 NTSTATUS cli_smb2_create_fnum(struct cli_state *cli,
335 uint32_t create_flags,
336 uint32_t desired_access,
337 uint32_t file_attributes,
338 uint32_t share_access,
339 uint32_t create_disposition,
340 uint32_t create_options,
342 struct smb_create_returns *cr)
344 TALLOC_CTX *frame = talloc_stackframe();
345 struct tevent_context *ev;
346 struct tevent_req *req;
347 NTSTATUS status = NT_STATUS_NO_MEMORY;
349 if (smbXcli_conn_has_async_calls(cli->conn)) {
351 * Can't use sync call while an async call is in flight
353 status = NT_STATUS_INVALID_PARAMETER;
356 ev = samba_tevent_context_init(frame);
360 req = cli_smb2_create_fnum_send(frame, ev, cli, fname, create_flags,
361 desired_access, file_attributes,
362 share_access, create_disposition,
367 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
370 status = cli_smb2_create_fnum_recv(req, pfid, cr);
376 /***************************************************************
377 Small wrapper that allows SMB2 close to use a uint16_t fnum.
378 ***************************************************************/
380 struct cli_smb2_close_fnum_state {
381 struct cli_state *cli;
386 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
388 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
389 struct tevent_context *ev,
390 struct cli_state *cli,
393 struct tevent_req *req, *subreq;
394 struct cli_smb2_close_fnum_state *state;
397 req = tevent_req_create(mem_ctx, &state,
398 struct cli_smb2_close_fnum_state);
405 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
406 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
407 return tevent_req_post(req, ev);
410 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
411 if (tevent_req_nterror(req, status)) {
412 return tevent_req_post(req, ev);
415 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
416 cli->smb2.session, cli->smb2.tcon,
417 0, state->ph->fid_persistent,
418 state->ph->fid_volatile);
419 if (tevent_req_nomem(subreq, req)) {
420 return tevent_req_post(req, ev);
422 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
426 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
428 struct tevent_req *req = tevent_req_callback_data(
429 subreq, struct tevent_req);
430 struct cli_smb2_close_fnum_state *state = tevent_req_data(
431 req, struct cli_smb2_close_fnum_state);
434 status = smb2cli_close_recv(subreq);
435 if (tevent_req_nterror(req, status)) {
439 /* Delete the fnum -> handle mapping. */
440 status = delete_smb2_handle_mapping(state->cli, &state->ph,
442 if (tevent_req_nterror(req, status)) {
445 tevent_req_done(req);
448 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
450 struct cli_smb2_close_fnum_state *state = tevent_req_data(
451 req, struct cli_smb2_close_fnum_state);
452 NTSTATUS status = tevent_req_simple_recv_ntstatus(req);
453 state->cli->raw_status = status;
457 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
459 TALLOC_CTX *frame = talloc_stackframe();
460 struct tevent_context *ev;
461 struct tevent_req *req;
462 NTSTATUS status = NT_STATUS_NO_MEMORY;
464 if (smbXcli_conn_has_async_calls(cli->conn)) {
466 * Can't use sync call while an async call is in flight
468 status = NT_STATUS_INVALID_PARAMETER;
471 ev = samba_tevent_context_init(frame);
475 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
479 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
482 status = cli_smb2_close_fnum_recv(req);
488 /***************************************************************
489 Small wrapper that allows SMB2 to create a directory
491 ***************************************************************/
493 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
498 if (smbXcli_conn_has_async_calls(cli->conn)) {
500 * Can't use sync call while an async call is in flight
502 return NT_STATUS_INVALID_PARAMETER;
505 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
506 return NT_STATUS_INVALID_PARAMETER;
509 status = cli_smb2_create_fnum(cli,
511 0, /* create_flags */
512 FILE_READ_ATTRIBUTES, /* desired_access */
513 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
514 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
515 FILE_CREATE, /* create_disposition */
516 FILE_DIRECTORY_FILE, /* create_options */
520 if (!NT_STATUS_IS_OK(status)) {
523 return cli_smb2_close_fnum(cli, fnum);
526 /***************************************************************
527 Small wrapper that allows SMB2 to delete a directory
529 ***************************************************************/
531 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
536 if (smbXcli_conn_has_async_calls(cli->conn)) {
538 * Can't use sync call while an async call is in flight
540 return NT_STATUS_INVALID_PARAMETER;
543 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
544 return NT_STATUS_INVALID_PARAMETER;
547 status = cli_smb2_create_fnum(cli,
549 0, /* create_flags */
550 DELETE_ACCESS, /* desired_access */
551 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
552 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
553 FILE_OPEN, /* create_disposition */
554 FILE_DIRECTORY_FILE|FILE_DELETE_ON_CLOSE, /* create_options */
558 if (!NT_STATUS_IS_OK(status)) {
561 return cli_smb2_close_fnum(cli, fnum);
564 /***************************************************************
565 Small wrapper that allows SMB2 to unlink a pathname.
567 ***************************************************************/
569 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
574 if (smbXcli_conn_has_async_calls(cli->conn)) {
576 * Can't use sync call while an async call is in flight
578 return NT_STATUS_INVALID_PARAMETER;
581 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
582 return NT_STATUS_INVALID_PARAMETER;
585 status = cli_smb2_create_fnum(cli,
587 0, /* create_flags */
588 DELETE_ACCESS, /* desired_access */
589 FILE_ATTRIBUTE_NORMAL, /* file attributes */
590 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
591 FILE_OPEN, /* create_disposition */
592 FILE_DELETE_ON_CLOSE, /* create_options */
596 if (!NT_STATUS_IS_OK(status)) {
599 return cli_smb2_close_fnum(cli, fnum);
602 /***************************************************************
603 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
604 ***************************************************************/
606 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
607 uint32_t dir_data_length,
608 struct file_info *finfo,
609 uint32_t *next_offset)
615 if (dir_data_length < 4) {
616 return NT_STATUS_INFO_LENGTH_MISMATCH;
619 *next_offset = IVAL(dir_data, 0);
621 if (*next_offset > dir_data_length) {
622 return NT_STATUS_INFO_LENGTH_MISMATCH;
625 if (*next_offset != 0) {
626 /* Ensure we only read what in this record. */
627 dir_data_length = *next_offset;
630 if (dir_data_length < 105) {
631 return NT_STATUS_INFO_LENGTH_MISMATCH;
634 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
635 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
636 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
637 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
638 finfo->mode = CVAL(dir_data + 56, 0);
639 namelen = IVAL(dir_data + 60,0);
640 if (namelen > (dir_data_length - 104)) {
641 return NT_STATUS_INFO_LENGTH_MISMATCH;
643 slen = CVAL(dir_data + 68, 0);
645 return NT_STATUS_INFO_LENGTH_MISMATCH;
647 ret = pull_string_talloc(finfo,
649 FLAGS2_UNICODE_STRINGS,
654 if (ret == (size_t)-1) {
655 /* Bad conversion. */
656 return NT_STATUS_INVALID_NETWORK_RESPONSE;
659 ret = pull_string_talloc(finfo,
661 FLAGS2_UNICODE_STRINGS,
666 if (ret == (size_t)-1) {
667 /* Bad conversion. */
668 return NT_STATUS_INVALID_NETWORK_RESPONSE;
673 /*******************************************************************
674 Given a filename - get its directory name
675 ********************************************************************/
677 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
685 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
688 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
699 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
702 (*parent)[len] = '\0';
710 /***************************************************************
711 Wrapper that allows SMB2 to list a directory.
713 ***************************************************************/
715 NTSTATUS cli_smb2_list(struct cli_state *cli,
716 const char *pathname,
718 NTSTATUS (*fn)(const char *,
725 uint16_t fnum = 0xffff;
726 char *parent_dir = NULL;
727 const char *mask = NULL;
728 struct smb2_hnd *ph = NULL;
729 bool processed_file = false;
730 TALLOC_CTX *frame = talloc_stackframe();
731 TALLOC_CTX *subframe = NULL;
734 if (smbXcli_conn_has_async_calls(cli->conn)) {
736 * Can't use sync call while an async call is in flight
738 status = NT_STATUS_INVALID_PARAMETER;
742 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
743 status = NT_STATUS_INVALID_PARAMETER;
747 /* Get the directory name. */
748 if (!windows_parent_dirname(frame,
752 status = NT_STATUS_NO_MEMORY;
756 mask_has_wild = ms_has_wild(mask);
758 status = cli_smb2_create_fnum(cli,
760 0, /* create_flags */
761 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
762 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
763 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
764 FILE_OPEN, /* create_disposition */
765 FILE_DIRECTORY_FILE, /* create_options */
769 if (!NT_STATUS_IS_OK(status)) {
773 status = map_fnum_to_smb2_handle(cli,
776 if (!NT_STATUS_IS_OK(status)) {
781 uint8_t *dir_data = NULL;
782 uint32_t dir_data_length = 0;
783 uint32_t next_offset = 0;
784 subframe = talloc_stackframe();
786 status = smb2cli_query_directory(cli->conn,
790 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
801 if (!NT_STATUS_IS_OK(status)) {
802 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
809 struct file_info *finfo = talloc_zero(subframe,
813 status = NT_STATUS_NO_MEMORY;
817 status = parse_finfo_id_both_directory_info(dir_data,
822 if (!NT_STATUS_IS_OK(status)) {
826 if (dir_check_ftype((uint32_t)finfo->mode,
827 (uint32_t)attribute)) {
829 * Only process if attributes match.
830 * On SMB1 server does this, so on
831 * SMB2 we need to emulate in the
834 * https://bugzilla.samba.org/show_bug.cgi?id=10260
836 processed_file = true;
838 status = fn(cli->dfs_mountpoint,
843 if (!NT_STATUS_IS_OK(status)) {
850 /* Move to next entry. */
852 dir_data += next_offset;
853 dir_data_length -= next_offset;
855 } while (next_offset != 0);
857 TALLOC_FREE(subframe);
859 if (!mask_has_wild) {
861 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
862 * when handed a non-wildcard path. Do it
863 * for the server (with a non-wildcard path
864 * there should only ever be one file returned.
866 status = STATUS_NO_MORE_FILES;
870 } while (NT_STATUS_IS_OK(status));
872 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
873 status = NT_STATUS_OK;
876 if (NT_STATUS_IS_OK(status) && !processed_file) {
878 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
879 * if no files match. Emulate this in the client.
881 status = NT_STATUS_NO_SUCH_FILE;
886 if (fnum != 0xffff) {
887 cli_smb2_close_fnum(cli, fnum);
889 TALLOC_FREE(subframe);
894 /***************************************************************
895 Wrapper that allows SMB2 to query a path info (basic level).
897 ***************************************************************/
899 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
901 SMB_STRUCT_STAT *sbuf,
902 uint32_t *attributes)
905 struct smb_create_returns cr;
906 uint16_t fnum = 0xffff;
907 size_t namelen = strlen(name);
909 if (smbXcli_conn_has_async_calls(cli->conn)) {
911 * Can't use sync call while an async call is in flight
913 return NT_STATUS_INVALID_PARAMETER;
916 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
917 return NT_STATUS_INVALID_PARAMETER;
920 /* SMB2 is pickier about pathnames. Ensure it doesn't
922 if (namelen > 0 && name[namelen-1] == '\\') {
923 char *modname = talloc_strdup(talloc_tos(), name);
924 modname[namelen-1] = '\0';
928 /* This is commonly used as a 'cd'. Try qpathinfo on
929 a directory handle first. */
931 status = cli_smb2_create_fnum(cli,
933 0, /* create_flags */
934 FILE_READ_ATTRIBUTES, /* desired_access */
935 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
936 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
937 FILE_OPEN, /* create_disposition */
938 FILE_DIRECTORY_FILE, /* create_options */
942 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
944 status = cli_smb2_create_fnum(cli,
946 0, /* create_flags */
947 FILE_READ_ATTRIBUTES, /* desired_access */
948 0, /* file attributes */
949 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
950 FILE_OPEN, /* create_disposition */
951 0, /* create_options */
956 if (!NT_STATUS_IS_OK(status)) {
960 cli_smb2_close_fnum(cli, fnum);
964 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
965 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
966 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
967 sbuf->st_ex_size = cr.end_of_file;
968 *attributes = cr.file_attributes;
973 /***************************************************************
974 Helper function for pathname operations.
975 ***************************************************************/
977 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
979 uint32_t desired_access,
983 size_t namelen = strlen(name);
984 TALLOC_CTX *frame = talloc_stackframe();
986 /* SMB2 is pickier about pathnames. Ensure it doesn't
988 if (namelen > 0 && name[namelen-1] == '\\') {
989 char *modname = talloc_strdup(frame, name);
990 if (modname == NULL) {
991 status = NT_STATUS_NO_MEMORY;
994 modname[namelen-1] = '\0';
998 /* Try to open a file handle first. */
999 status = cli_smb2_create_fnum(cli,
1001 0, /* create_flags */
1003 0, /* file attributes */
1004 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1005 FILE_OPEN, /* create_disposition */
1006 0, /* create_options */
1010 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1011 status = cli_smb2_create_fnum(cli,
1013 0, /* create_flags */
1015 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1016 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1017 FILE_OPEN, /* create_disposition */
1018 FILE_DIRECTORY_FILE, /* create_options */
1029 /***************************************************************
1030 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1032 ***************************************************************/
1034 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1039 DATA_BLOB outbuf = data_blob_null;
1040 uint16_t fnum = 0xffff;
1041 struct smb2_hnd *ph = NULL;
1042 uint32_t altnamelen = 0;
1043 TALLOC_CTX *frame = talloc_stackframe();
1045 if (smbXcli_conn_has_async_calls(cli->conn)) {
1047 * Can't use sync call while an async call is in flight
1049 status = NT_STATUS_INVALID_PARAMETER;
1053 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1054 status = NT_STATUS_INVALID_PARAMETER;
1058 status = get_fnum_from_path(cli,
1060 FILE_READ_ATTRIBUTES,
1063 if (!NT_STATUS_IS_OK(status)) {
1067 status = map_fnum_to_smb2_handle(cli,
1070 if (!NT_STATUS_IS_OK(status)) {
1074 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1075 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1077 status = smb2cli_query_info(cli->conn,
1081 1, /* in_info_type */
1082 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1083 0xFFFF, /* in_max_output_length */
1084 NULL, /* in_input_buffer */
1085 0, /* in_additional_info */
1092 if (!NT_STATUS_IS_OK(status)) {
1096 /* Parse the reply. */
1097 if (outbuf.length < 4) {
1098 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1102 altnamelen = IVAL(outbuf.data, 0);
1103 if (altnamelen > outbuf.length - 4) {
1104 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1108 if (altnamelen > 0) {
1110 char *short_name = NULL;
1111 ret = pull_string_talloc(frame,
1113 FLAGS2_UNICODE_STRINGS,
1118 if (ret == (size_t)-1) {
1119 /* Bad conversion. */
1120 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1124 fstrcpy(alt_name, short_name);
1129 status = NT_STATUS_OK;
1133 if (fnum != 0xffff) {
1134 cli_smb2_close_fnum(cli, fnum);
1141 /***************************************************************
1142 Wrapper that allows SMB2 to query a fnum info (basic level).
1144 ***************************************************************/
1146 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1150 struct timespec *create_time,
1151 struct timespec *access_time,
1152 struct timespec *write_time,
1153 struct timespec *change_time,
1157 DATA_BLOB outbuf = data_blob_null;
1158 struct smb2_hnd *ph = NULL;
1159 TALLOC_CTX *frame = talloc_stackframe();
1161 if (smbXcli_conn_has_async_calls(cli->conn)) {
1163 * Can't use sync call while an async call is in flight
1165 status = NT_STATUS_INVALID_PARAMETER;
1169 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1170 status = NT_STATUS_INVALID_PARAMETER;
1174 status = map_fnum_to_smb2_handle(cli,
1177 if (!NT_STATUS_IS_OK(status)) {
1181 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1182 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1184 status = smb2cli_query_info(cli->conn,
1188 1, /* in_info_type */
1189 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1190 0xFFFF, /* in_max_output_length */
1191 NULL, /* in_input_buffer */
1192 0, /* in_additional_info */
1198 if (!NT_STATUS_IS_OK(status)) {
1202 /* Parse the reply. */
1203 if (outbuf.length < 0x60) {
1204 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1209 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1212 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1215 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1218 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1221 uint32_t attr = IVAL(outbuf.data, 0x20);
1222 *mode = (uint16_t)attr;
1225 uint64_t file_size = BVAL(outbuf.data, 0x30);
1226 *size = (off_t)file_size;
1229 uint64_t file_index = BVAL(outbuf.data, 0x40);
1230 *ino = (SMB_INO_T)file_index;
1239 /***************************************************************
1240 Wrapper that allows SMB2 to query an fnum.
1241 Implement on top of cli_smb2_qfileinfo_basic().
1243 ***************************************************************/
1245 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1249 time_t *change_time,
1250 time_t *access_time,
1253 struct timespec access_time_ts;
1254 struct timespec write_time_ts;
1255 struct timespec change_time_ts;
1256 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1266 if (!NT_STATUS_IS_OK(status)) {
1271 *change_time = change_time_ts.tv_sec;
1274 *access_time = access_time_ts.tv_sec;
1277 *write_time = write_time_ts.tv_sec;
1279 return NT_STATUS_OK;
1282 /***************************************************************
1283 Wrapper that allows SMB2 to get pathname attributes.
1285 ***************************************************************/
1287 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1294 uint16_t fnum = 0xffff;
1295 struct smb2_hnd *ph = NULL;
1296 TALLOC_CTX *frame = talloc_stackframe();
1298 if (smbXcli_conn_has_async_calls(cli->conn)) {
1300 * Can't use sync call while an async call is in flight
1302 status = NT_STATUS_INVALID_PARAMETER;
1306 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1307 status = NT_STATUS_INVALID_PARAMETER;
1311 status = get_fnum_from_path(cli,
1313 FILE_READ_ATTRIBUTES,
1316 if (!NT_STATUS_IS_OK(status)) {
1320 status = map_fnum_to_smb2_handle(cli,
1323 if (!NT_STATUS_IS_OK(status)) {
1326 status = cli_smb2_getattrE(cli,
1333 if (!NT_STATUS_IS_OK(status)) {
1339 if (fnum != 0xffff) {
1340 cli_smb2_close_fnum(cli, fnum);
1347 /***************************************************************
1348 Wrapper that allows SMB2 to query a pathname info (basic level).
1349 Implement on top of cli_smb2_qfileinfo_basic().
1351 ***************************************************************/
1353 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1355 struct timespec *create_time,
1356 struct timespec *access_time,
1357 struct timespec *write_time,
1358 struct timespec *change_time,
1364 struct smb2_hnd *ph = NULL;
1365 uint16_t fnum = 0xffff;
1366 TALLOC_CTX *frame = talloc_stackframe();
1368 if (smbXcli_conn_has_async_calls(cli->conn)) {
1370 * Can't use sync call while an async call is in flight
1372 status = NT_STATUS_INVALID_PARAMETER;
1376 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1377 status = NT_STATUS_INVALID_PARAMETER;
1381 status = get_fnum_from_path(cli,
1383 FILE_READ_ATTRIBUTES,
1386 if (!NT_STATUS_IS_OK(status)) {
1390 status = map_fnum_to_smb2_handle(cli,
1393 if (!NT_STATUS_IS_OK(status)) {
1397 status = cli_smb2_qfileinfo_basic(cli,
1409 if (fnum != 0xffff) {
1410 cli_smb2_close_fnum(cli, fnum);
1417 /***************************************************************
1418 Wrapper that allows SMB2 to query pathname streams.
1420 ***************************************************************/
1422 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1424 TALLOC_CTX *mem_ctx,
1425 unsigned int *pnum_streams,
1426 struct stream_struct **pstreams)
1429 struct smb2_hnd *ph = NULL;
1430 uint16_t fnum = 0xffff;
1431 DATA_BLOB outbuf = data_blob_null;
1432 TALLOC_CTX *frame = talloc_stackframe();
1434 if (smbXcli_conn_has_async_calls(cli->conn)) {
1436 * Can't use sync call while an async call is in flight
1438 status = NT_STATUS_INVALID_PARAMETER;
1442 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1443 status = NT_STATUS_INVALID_PARAMETER;
1447 status = get_fnum_from_path(cli,
1449 FILE_READ_ATTRIBUTES,
1452 if (!NT_STATUS_IS_OK(status)) {
1456 status = map_fnum_to_smb2_handle(cli,
1459 if (!NT_STATUS_IS_OK(status)) {
1463 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1464 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1466 status = smb2cli_query_info(cli->conn,
1470 1, /* in_info_type */
1471 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1472 0xFFFF, /* in_max_output_length */
1473 NULL, /* in_input_buffer */
1474 0, /* in_additional_info */
1481 if (!NT_STATUS_IS_OK(status)) {
1485 /* Parse the reply. */
1486 if (!parse_streams_blob(mem_ctx,
1491 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1497 if (fnum != 0xffff) {
1498 cli_smb2_close_fnum(cli, fnum);
1505 /***************************************************************
1506 Wrapper that allows SMB2 to set pathname attributes.
1508 ***************************************************************/
1510 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1516 uint16_t fnum = 0xffff;
1517 struct smb2_hnd *ph = NULL;
1518 uint8_t inbuf_store[40];
1519 DATA_BLOB inbuf = data_blob_null;
1520 TALLOC_CTX *frame = talloc_stackframe();
1522 if (smbXcli_conn_has_async_calls(cli->conn)) {
1524 * Can't use sync call while an async call is in flight
1526 status = NT_STATUS_INVALID_PARAMETER;
1530 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1531 status = NT_STATUS_INVALID_PARAMETER;
1535 status = get_fnum_from_path(cli,
1537 FILE_WRITE_ATTRIBUTES,
1540 if (!NT_STATUS_IS_OK(status)) {
1544 status = map_fnum_to_smb2_handle(cli,
1547 if (!NT_STATUS_IS_OK(status)) {
1551 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1552 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1554 inbuf.data = inbuf_store;
1555 inbuf.length = sizeof(inbuf_store);
1556 data_blob_clear(&inbuf);
1558 SSVAL(inbuf.data, 32, attr);
1560 put_long_date((char *)inbuf.data + 16,mtime);
1562 /* Set all the other times to -1. */
1563 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1564 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1565 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1567 status = smb2cli_set_info(cli->conn,
1571 1, /* in_info_type */
1572 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1573 &inbuf, /* in_input_buffer */
1574 0, /* in_additional_info */
1579 if (fnum != 0xffff) {
1580 cli_smb2_close_fnum(cli, fnum);
1587 /***************************************************************
1588 Wrapper that allows SMB2 to set file handle times.
1590 ***************************************************************/
1592 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1599 struct smb2_hnd *ph = NULL;
1600 uint8_t inbuf_store[40];
1601 DATA_BLOB inbuf = data_blob_null;
1603 if (smbXcli_conn_has_async_calls(cli->conn)) {
1605 * Can't use sync call while an async call is in flight
1607 return NT_STATUS_INVALID_PARAMETER;
1610 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1611 return NT_STATUS_INVALID_PARAMETER;
1614 status = map_fnum_to_smb2_handle(cli,
1617 if (!NT_STATUS_IS_OK(status)) {
1621 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1622 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1624 inbuf.data = inbuf_store;
1625 inbuf.length = sizeof(inbuf_store);
1626 data_blob_clear(&inbuf);
1628 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1629 if (change_time != 0) {
1630 put_long_date((char *)inbuf.data + 24, change_time);
1632 if (access_time != 0) {
1633 put_long_date((char *)inbuf.data + 8, access_time);
1635 if (write_time != 0) {
1636 put_long_date((char *)inbuf.data + 16, write_time);
1639 return smb2cli_set_info(cli->conn,
1643 1, /* in_info_type */
1644 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1645 &inbuf, /* in_input_buffer */
1646 0, /* in_additional_info */
1651 /***************************************************************
1652 Wrapper that allows SMB2 to query disk attributes (size).
1654 ***************************************************************/
1656 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
1657 uint64_t *bsize, uint64_t *total, uint64_t *avail)
1660 uint16_t fnum = 0xffff;
1661 DATA_BLOB outbuf = data_blob_null;
1662 struct smb2_hnd *ph = NULL;
1663 uint32_t sectors_per_unit = 0;
1664 uint32_t bytes_per_sector = 0;
1665 uint64_t total_size = 0;
1666 uint64_t size_free = 0;
1667 TALLOC_CTX *frame = talloc_stackframe();
1669 if (smbXcli_conn_has_async_calls(cli->conn)) {
1671 * Can't use sync call while an async call is in flight
1673 status = NT_STATUS_INVALID_PARAMETER;
1677 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1678 status = NT_STATUS_INVALID_PARAMETER;
1682 /* First open the top level directory. */
1683 status = cli_smb2_create_fnum(cli,
1685 0, /* create_flags */
1686 FILE_READ_ATTRIBUTES, /* desired_access */
1687 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1688 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1689 FILE_OPEN, /* create_disposition */
1690 FILE_DIRECTORY_FILE, /* create_options */
1694 if (!NT_STATUS_IS_OK(status)) {
1698 status = map_fnum_to_smb2_handle(cli,
1701 if (!NT_STATUS_IS_OK(status)) {
1705 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1706 level 3 (SMB_FS_SIZE_INFORMATION). */
1708 status = smb2cli_query_info(cli->conn,
1712 2, /* in_info_type */
1713 3, /* in_file_info_class */
1714 0xFFFF, /* in_max_output_length */
1715 NULL, /* in_input_buffer */
1716 0, /* in_additional_info */
1722 if (!NT_STATUS_IS_OK(status)) {
1726 /* Parse the reply. */
1727 if (outbuf.length != 24) {
1728 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1732 total_size = BVAL(outbuf.data, 0);
1733 size_free = BVAL(outbuf.data, 8);
1734 sectors_per_unit = IVAL(outbuf.data, 16);
1735 bytes_per_sector = IVAL(outbuf.data, 20);
1738 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
1741 *total = total_size;
1747 status = NT_STATUS_OK;
1751 if (fnum != 0xffff) {
1752 cli_smb2_close_fnum(cli, fnum);
1759 /***************************************************************
1760 Wrapper that allows SMB2 to query file system attributes.
1762 ***************************************************************/
1764 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
1767 uint16_t fnum = 0xffff;
1768 DATA_BLOB outbuf = data_blob_null;
1769 struct smb2_hnd *ph = NULL;
1770 TALLOC_CTX *frame = talloc_stackframe();
1772 if (smbXcli_conn_has_async_calls(cli->conn)) {
1774 * Can't use sync call while an async call is in flight
1776 status = NT_STATUS_INVALID_PARAMETER;
1780 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1781 status = NT_STATUS_INVALID_PARAMETER;
1785 /* First open the top level directory. */
1787 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
1788 FILE_READ_ATTRIBUTES, /* desired_access */
1789 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1790 FILE_SHARE_READ | FILE_SHARE_WRITE |
1791 FILE_SHARE_DELETE, /* share_access */
1792 FILE_OPEN, /* create_disposition */
1793 FILE_DIRECTORY_FILE, /* create_options */
1797 if (!NT_STATUS_IS_OK(status)) {
1801 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1802 if (!NT_STATUS_IS_OK(status)) {
1806 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
1807 cli->smb2.tcon, 2, /* in_info_type */
1808 5, /* in_file_info_class */
1809 0xFFFF, /* in_max_output_length */
1810 NULL, /* in_input_buffer */
1811 0, /* in_additional_info */
1813 ph->fid_persistent, ph->fid_volatile, frame,
1815 if (!NT_STATUS_IS_OK(status)) {
1819 if (outbuf.length < 12) {
1820 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1824 *fs_attr = IVAL(outbuf.data, 0);
1828 if (fnum != 0xffff) {
1829 cli_smb2_close_fnum(cli, fnum);
1836 /***************************************************************
1837 Wrapper that allows SMB2 to query a security descriptor.
1839 ***************************************************************/
1841 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
1844 TALLOC_CTX *mem_ctx,
1845 struct security_descriptor **ppsd)
1848 DATA_BLOB outbuf = data_blob_null;
1849 struct smb2_hnd *ph = NULL;
1850 struct security_descriptor *lsd = NULL;
1851 TALLOC_CTX *frame = talloc_stackframe();
1853 if (smbXcli_conn_has_async_calls(cli->conn)) {
1855 * Can't use sync call while an async call is in flight
1857 status = NT_STATUS_INVALID_PARAMETER;
1861 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1862 status = NT_STATUS_INVALID_PARAMETER;
1866 status = map_fnum_to_smb2_handle(cli,
1869 if (!NT_STATUS_IS_OK(status)) {
1873 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1875 status = smb2cli_query_info(cli->conn,
1879 3, /* in_info_type */
1880 0, /* in_file_info_class */
1881 0xFFFF, /* in_max_output_length */
1882 NULL, /* in_input_buffer */
1883 sec_info, /* in_additional_info */
1890 if (!NT_STATUS_IS_OK(status)) {
1894 /* Parse the reply. */
1895 status = unmarshall_sec_desc(mem_ctx,
1900 if (!NT_STATUS_IS_OK(status)) {
1916 /***************************************************************
1917 Wrapper that allows SMB2 to set a security descriptor.
1919 ***************************************************************/
1921 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
1924 const struct security_descriptor *sd)
1927 DATA_BLOB inbuf = data_blob_null;
1928 struct smb2_hnd *ph = NULL;
1929 TALLOC_CTX *frame = talloc_stackframe();
1931 if (smbXcli_conn_has_async_calls(cli->conn)) {
1933 * Can't use sync call while an async call is in flight
1935 status = NT_STATUS_INVALID_PARAMETER;
1939 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1940 status = NT_STATUS_INVALID_PARAMETER;
1944 status = map_fnum_to_smb2_handle(cli,
1947 if (!NT_STATUS_IS_OK(status)) {
1951 status = marshall_sec_desc(frame,
1956 if (!NT_STATUS_IS_OK(status)) {
1960 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1962 status = smb2cli_set_info(cli->conn,
1966 3, /* in_info_type */
1967 0, /* in_file_info_class */
1968 &inbuf, /* in_input_buffer */
1969 sec_info, /* in_additional_info */
1979 /***************************************************************
1980 Wrapper that allows SMB2 to rename a file.
1982 ***************************************************************/
1984 NTSTATUS cli_smb2_rename(struct cli_state *cli,
1985 const char *fname_src,
1986 const char *fname_dst)
1989 DATA_BLOB inbuf = data_blob_null;
1990 uint16_t fnum = 0xffff;
1991 struct smb2_hnd *ph = NULL;
1992 smb_ucs2_t *converted_str = NULL;
1993 size_t converted_size_bytes = 0;
1995 TALLOC_CTX *frame = talloc_stackframe();
1997 if (smbXcli_conn_has_async_calls(cli->conn)) {
1999 * Can't use sync call while an async call is in flight
2001 status = NT_STATUS_INVALID_PARAMETER;
2005 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2006 status = NT_STATUS_INVALID_PARAMETER;
2010 status = get_fnum_from_path(cli,
2015 if (!NT_STATUS_IS_OK(status)) {
2019 status = map_fnum_to_smb2_handle(cli,
2022 if (!NT_STATUS_IS_OK(status)) {
2026 /* SMB2 is pickier about pathnames. Ensure it doesn't
2028 if (*fname_dst == '\\') {
2032 /* SMB2 is pickier about pathnames. Ensure it doesn't
2034 namelen = strlen(fname_dst);
2035 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2036 char *modname = talloc_strdup(frame, fname_dst);
2037 modname[namelen-1] = '\0';
2038 fname_dst = modname;
2041 if (!push_ucs2_talloc(frame,
2044 &converted_size_bytes)) {
2045 status = NT_STATUS_INVALID_PARAMETER;
2049 /* W2K8 insists the dest name is not null
2050 terminated. Remove the last 2 zero bytes
2051 and reduce the name length. */
2053 if (converted_size_bytes < 2) {
2054 status = NT_STATUS_INVALID_PARAMETER;
2057 converted_size_bytes -= 2;
2059 inbuf = data_blob_talloc_zero(frame,
2060 20 + converted_size_bytes);
2061 if (inbuf.data == NULL) {
2062 status = NT_STATUS_NO_MEMORY;
2066 SIVAL(inbuf.data, 16, converted_size_bytes);
2067 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2069 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2070 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2072 status = smb2cli_set_info(cli->conn,
2076 1, /* in_info_type */
2077 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2078 &inbuf, /* in_input_buffer */
2079 0, /* in_additional_info */
2085 if (fnum != 0xffff) {
2086 cli_smb2_close_fnum(cli, fnum);
2093 /***************************************************************
2094 Wrapper that allows SMB2 to set an EA on a fnum.
2096 ***************************************************************/
2098 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2100 const char *ea_name,
2105 DATA_BLOB inbuf = data_blob_null;
2107 char *ea_name_ascii = NULL;
2109 struct smb2_hnd *ph = NULL;
2110 TALLOC_CTX *frame = talloc_stackframe();
2112 if (smbXcli_conn_has_async_calls(cli->conn)) {
2114 * Can't use sync call while an async call is in flight
2116 status = NT_STATUS_INVALID_PARAMETER;
2120 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2121 status = NT_STATUS_INVALID_PARAMETER;
2125 status = map_fnum_to_smb2_handle(cli,
2128 if (!NT_STATUS_IS_OK(status)) {
2132 /* Marshall the SMB2 EA data. */
2133 if (ea_len > 0xFFFF) {
2134 status = NT_STATUS_INVALID_PARAMETER;
2138 if (!push_ascii_talloc(frame,
2142 status = NT_STATUS_INVALID_PARAMETER;
2146 if (namelen < 2 || namelen > 0xFF) {
2147 status = NT_STATUS_INVALID_PARAMETER;
2151 bloblen = 8 + ea_len + namelen;
2152 /* Round up to a 4 byte boundary. */
2153 bloblen = ((bloblen + 3)&~3);
2155 inbuf = data_blob_talloc_zero(frame, bloblen);
2156 if (inbuf.data == NULL) {
2157 status = NT_STATUS_NO_MEMORY;
2160 /* namelen doesn't include the NULL byte. */
2161 SCVAL(inbuf.data, 5, namelen - 1);
2162 SSVAL(inbuf.data, 6, ea_len);
2163 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2164 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2166 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2167 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2169 status = smb2cli_set_info(cli->conn,
2173 1, /* in_info_type */
2174 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2175 &inbuf, /* in_input_buffer */
2176 0, /* in_additional_info */
2186 /***************************************************************
2187 Wrapper that allows SMB2 to set an EA on a pathname.
2189 ***************************************************************/
2191 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2193 const char *ea_name,
2198 uint16_t fnum = 0xffff;
2200 if (smbXcli_conn_has_async_calls(cli->conn)) {
2202 * Can't use sync call while an async call is in flight
2204 status = NT_STATUS_INVALID_PARAMETER;
2208 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2209 status = NT_STATUS_INVALID_PARAMETER;
2213 status = get_fnum_from_path(cli,
2218 if (!NT_STATUS_IS_OK(status)) {
2222 status = cli_set_ea_fnum(cli,
2227 if (!NT_STATUS_IS_OK(status)) {
2233 if (fnum != 0xffff) {
2234 cli_smb2_close_fnum(cli, fnum);
2240 /***************************************************************
2241 Wrapper that allows SMB2 to get an EA list on a pathname.
2243 ***************************************************************/
2245 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2249 struct ea_struct **pea_array)
2252 uint16_t fnum = 0xffff;
2253 DATA_BLOB outbuf = data_blob_null;
2254 struct smb2_hnd *ph = NULL;
2255 struct ea_list *ea_list = NULL;
2256 struct ea_list *eal = NULL;
2257 size_t ea_count = 0;
2258 TALLOC_CTX *frame = talloc_stackframe();
2263 if (smbXcli_conn_has_async_calls(cli->conn)) {
2265 * Can't use sync call while an async call is in flight
2267 status = NT_STATUS_INVALID_PARAMETER;
2271 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2272 status = NT_STATUS_INVALID_PARAMETER;
2276 status = get_fnum_from_path(cli,
2281 if (!NT_STATUS_IS_OK(status)) {
2285 status = map_fnum_to_smb2_handle(cli,
2288 if (!NT_STATUS_IS_OK(status)) {
2292 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2293 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2295 status = smb2cli_query_info(cli->conn,
2299 1, /* in_info_type */
2300 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2301 0xFFFF, /* in_max_output_length */
2302 NULL, /* in_input_buffer */
2303 0, /* in_additional_info */
2310 if (!NT_STATUS_IS_OK(status)) {
2314 /* Parse the reply. */
2315 ea_list = read_nttrans_ea_list(ctx,
2316 (const char *)outbuf.data,
2318 if (ea_list == NULL) {
2319 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2323 /* Convert to an array. */
2324 for (eal = ea_list; eal; eal = eal->next) {
2329 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2330 if (*pea_array == NULL) {
2331 status = NT_STATUS_NO_MEMORY;
2335 for (eal = ea_list; eal; eal = eal->next) {
2336 (*pea_array)[ea_count++] = eal->ea;
2338 *pnum_eas = ea_count;
2343 if (fnum != 0xffff) {
2344 cli_smb2_close_fnum(cli, fnum);
2351 /***************************************************************
2352 Wrapper that allows SMB2 to get user quota.
2354 ***************************************************************/
2356 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
2358 SMB_NTQUOTA_STRUCT *pqt)
2361 DATA_BLOB inbuf = data_blob_null;
2362 DATA_BLOB outbuf = data_blob_null;
2363 struct smb2_hnd *ph = NULL;
2364 TALLOC_CTX *frame = talloc_stackframe();
2366 unsigned int offset;
2369 if (smbXcli_conn_has_async_calls(cli->conn)) {
2371 * Can't use sync call while an async call is in flight
2373 status = NT_STATUS_INVALID_PARAMETER;
2377 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2378 status = NT_STATUS_INVALID_PARAMETER;
2382 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2383 if (!NT_STATUS_IS_OK(status)) {
2387 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
2389 inbuf = data_blob_talloc_zero(frame, 24 + sid_len);
2390 if (inbuf.data == NULL) {
2391 status = NT_STATUS_NO_MEMORY;
2397 SCVAL(buf, 0, 1); /* ReturnSingle */
2398 SCVAL(buf, 1, 0); /* RestartScan */
2399 SSVAL(buf, 2, 0); /* Reserved */
2400 if (8 + sid_len < 8) {
2401 status = NT_STATUS_INVALID_PARAMETER;
2404 SIVAL(buf, 4, 8 + sid_len); /* SidListLength */
2405 SIVAL(buf, 8, 0); /* StartSidLength */
2406 SIVAL(buf, 12, 0); /* StartSidOffset */
2407 SIVAL(buf, 16, 0); /* NextEntryOffset */
2408 SIVAL(buf, 20, sid_len); /* SidLength */
2409 sid_linearize(buf + 24, sid_len, &pqt->sid);
2411 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2412 cli->smb2.tcon, 4, /* in_info_type */
2413 0, /* in_file_info_class */
2414 0xFFFF, /* in_max_output_length */
2415 &inbuf, /* in_input_buffer */
2416 0, /* in_additional_info */
2418 ph->fid_persistent, ph->fid_volatile, frame,
2421 if (!NT_STATUS_IS_OK(status)) {
2425 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
2427 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2428 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
2436 struct cli_smb2_read_state {
2437 struct tevent_context *ev;
2438 struct cli_state *cli;
2439 struct smb2_hnd *ph;
2440 uint64_t start_offset;
2446 static void cli_smb2_read_done(struct tevent_req *subreq);
2448 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
2449 struct tevent_context *ev,
2450 struct cli_state *cli,
2456 struct tevent_req *req, *subreq;
2457 struct cli_smb2_read_state *state;
2459 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
2465 state->start_offset = (uint64_t)offset;
2466 state->size = (uint32_t)size;
2467 state->received = 0;
2470 status = map_fnum_to_smb2_handle(cli,
2473 if (tevent_req_nterror(req, status)) {
2474 return tevent_req_post(req, ev);
2477 subreq = smb2cli_read_send(state,
2480 state->cli->timeout,
2481 state->cli->smb2.session,
2482 state->cli->smb2.tcon,
2484 state->start_offset,
2485 state->ph->fid_persistent,
2486 state->ph->fid_volatile,
2487 0, /* minimum_count */
2488 0); /* remaining_bytes */
2490 if (tevent_req_nomem(subreq, req)) {
2491 return tevent_req_post(req, ev);
2493 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
2497 static void cli_smb2_read_done(struct tevent_req *subreq)
2499 struct tevent_req *req = tevent_req_callback_data(
2500 subreq, struct tevent_req);
2501 struct cli_smb2_read_state *state = tevent_req_data(
2502 req, struct cli_smb2_read_state);
2505 status = smb2cli_read_recv(subreq, state,
2506 &state->buf, &state->received);
2507 if (tevent_req_nterror(req, status)) {
2511 if (state->received > state->size) {
2512 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2516 tevent_req_done(req);
2519 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
2524 struct cli_smb2_read_state *state = tevent_req_data(
2525 req, struct cli_smb2_read_state);
2527 if (tevent_req_is_nterror(req, &status)) {
2528 state->cli->raw_status = status;
2532 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2533 * better make sure that you copy it away before you talloc_free(req).
2534 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2536 *received = (ssize_t)state->received;
2537 *rcvbuf = state->buf;
2538 state->cli->raw_status = NT_STATUS_OK;
2539 return NT_STATUS_OK;
2542 struct cli_smb2_write_state {
2543 struct tevent_context *ev;
2544 struct cli_state *cli;
2545 struct smb2_hnd *ph;
2553 static void cli_smb2_write_written(struct tevent_req *req);
2555 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
2556 struct tevent_context *ev,
2557 struct cli_state *cli,
2565 struct tevent_req *req, *subreq = NULL;
2566 struct cli_smb2_write_state *state = NULL;
2568 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
2574 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2575 state->flags = (uint32_t)mode;
2577 state->offset = (uint64_t)offset;
2578 state->size = (uint32_t)size;
2581 status = map_fnum_to_smb2_handle(cli,
2584 if (tevent_req_nterror(req, status)) {
2585 return tevent_req_post(req, ev);
2588 subreq = smb2cli_write_send(state,
2591 state->cli->timeout,
2592 state->cli->smb2.session,
2593 state->cli->smb2.tcon,
2596 state->ph->fid_persistent,
2597 state->ph->fid_volatile,
2598 0, /* remaining_bytes */
2599 state->flags, /* flags */
2602 if (tevent_req_nomem(subreq, req)) {
2603 return tevent_req_post(req, ev);
2605 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
2609 static void cli_smb2_write_written(struct tevent_req *subreq)
2611 struct tevent_req *req = tevent_req_callback_data(
2612 subreq, struct tevent_req);
2613 struct cli_smb2_write_state *state = tevent_req_data(
2614 req, struct cli_smb2_write_state);
2618 status = smb2cli_write_recv(subreq, &written);
2619 TALLOC_FREE(subreq);
2620 if (tevent_req_nterror(req, status)) {
2624 state->written = written;
2626 tevent_req_done(req);
2629 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
2632 struct cli_smb2_write_state *state = tevent_req_data(
2633 req, struct cli_smb2_write_state);
2636 if (tevent_req_is_nterror(req, &status)) {
2637 state->cli->raw_status = status;
2638 tevent_req_received(req);
2642 if (pwritten != NULL) {
2643 *pwritten = (size_t)state->written;
2645 state->cli->raw_status = NT_STATUS_OK;
2646 tevent_req_received(req);
2647 return NT_STATUS_OK;
2650 /***************************************************************
2651 Wrapper that allows SMB2 async write using an fnum.
2652 This is mostly cut-and-paste from Volker's code inside
2653 source3/libsmb/clireadwrite.c, adapted for SMB2.
2655 Done this way so I can reuse all the logic inside cli_push()
2657 ***************************************************************/
2659 struct cli_smb2_writeall_state {
2660 struct tevent_context *ev;
2661 struct cli_state *cli;
2662 struct smb2_hnd *ph;
2670 static void cli_smb2_writeall_written(struct tevent_req *req);
2672 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
2673 struct tevent_context *ev,
2674 struct cli_state *cli,
2682 struct tevent_req *req, *subreq = NULL;
2683 struct cli_smb2_writeall_state *state = NULL;
2688 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
2694 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2695 state->flags = (uint32_t)mode;
2697 state->offset = (uint64_t)offset;
2698 state->size = (uint32_t)size;
2701 status = map_fnum_to_smb2_handle(cli,
2704 if (tevent_req_nterror(req, status)) {
2705 return tevent_req_post(req, ev);
2708 to_write = state->size;
2709 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2710 to_write = MIN(max_size, to_write);
2711 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2713 to_write = MIN(max_size, to_write);
2716 subreq = smb2cli_write_send(state,
2719 state->cli->timeout,
2720 state->cli->smb2.session,
2721 state->cli->smb2.tcon,
2724 state->ph->fid_persistent,
2725 state->ph->fid_volatile,
2726 0, /* remaining_bytes */
2727 state->flags, /* flags */
2728 state->buf + state->written);
2730 if (tevent_req_nomem(subreq, req)) {
2731 return tevent_req_post(req, ev);
2733 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2737 static void cli_smb2_writeall_written(struct tevent_req *subreq)
2739 struct tevent_req *req = tevent_req_callback_data(
2740 subreq, struct tevent_req);
2741 struct cli_smb2_writeall_state *state = tevent_req_data(
2742 req, struct cli_smb2_writeall_state);
2744 uint32_t written, to_write;
2748 status = smb2cli_write_recv(subreq, &written);
2749 TALLOC_FREE(subreq);
2750 if (tevent_req_nterror(req, status)) {
2754 state->written += written;
2756 if (state->written > state->size) {
2757 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2761 to_write = state->size - state->written;
2763 if (to_write == 0) {
2764 tevent_req_done(req);
2768 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2769 to_write = MIN(max_size, to_write);
2770 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2772 to_write = MIN(max_size, to_write);
2775 subreq = smb2cli_write_send(state,
2778 state->cli->timeout,
2779 state->cli->smb2.session,
2780 state->cli->smb2.tcon,
2782 state->offset + state->written,
2783 state->ph->fid_persistent,
2784 state->ph->fid_volatile,
2785 0, /* remaining_bytes */
2786 state->flags, /* flags */
2787 state->buf + state->written);
2789 if (tevent_req_nomem(subreq, req)) {
2792 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2795 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
2798 struct cli_smb2_writeall_state *state = tevent_req_data(
2799 req, struct cli_smb2_writeall_state);
2802 if (tevent_req_is_nterror(req, &status)) {
2803 state->cli->raw_status = status;
2806 if (pwritten != NULL) {
2807 *pwritten = (size_t)state->written;
2809 state->cli->raw_status = NT_STATUS_OK;
2810 return NT_STATUS_OK;
2813 struct cli_smb2_splice_state {
2814 struct tevent_context *ev;
2815 struct cli_state *cli;
2816 struct smb2_hnd *src_ph;
2817 struct smb2_hnd *dst_ph;
2818 int (*splice_cb)(off_t n, void *priv);
2825 struct req_resume_key_rsp resume_rsp;
2826 struct srv_copychunk_copy cc_copy;
2829 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
2830 struct tevent_req *req);
2832 static void cli_splice_copychunk_done(struct tevent_req *subreq)
2834 struct tevent_req *req = tevent_req_callback_data(
2835 subreq, struct tevent_req);
2836 struct cli_smb2_splice_state *state =
2837 tevent_req_data(req,
2838 struct cli_smb2_splice_state);
2839 struct smbXcli_conn *conn = state->cli->conn;
2840 DATA_BLOB out_input_buffer = data_blob_null;
2841 DATA_BLOB out_output_buffer = data_blob_null;
2842 struct srv_copychunk_rsp cc_copy_rsp;
2843 enum ndr_err_code ndr_ret;
2846 status = smb2cli_ioctl_recv(subreq, state,
2848 &out_output_buffer);
2849 TALLOC_FREE(subreq);
2850 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
2851 state->resized) && tevent_req_nterror(req, status)) {
2855 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
2856 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
2857 if (ndr_ret != NDR_ERR_SUCCESS) {
2858 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
2859 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2863 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
2864 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
2865 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
2866 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
2867 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
2868 tevent_req_nterror(req, status)) {
2872 state->resized = true;
2873 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
2874 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
2876 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
2877 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
2878 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
2879 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
2882 state->src_offset += cc_copy_rsp.total_bytes_written;
2883 state->dst_offset += cc_copy_rsp.total_bytes_written;
2884 state->written += cc_copy_rsp.total_bytes_written;
2885 if (!state->splice_cb(state->written, state->priv)) {
2886 tevent_req_nterror(req, NT_STATUS_CANCELLED);
2891 cli_splice_copychunk_send(state, req);
2894 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
2895 struct tevent_req *req)
2897 struct tevent_req *subreq;
2898 enum ndr_err_code ndr_ret;
2899 struct smbXcli_conn *conn = state->cli->conn;
2900 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
2901 off_t src_offset = state->src_offset;
2902 off_t dst_offset = state->dst_offset;
2903 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
2904 state->size - state->written);
2905 DATA_BLOB in_input_buffer = data_blob_null;
2906 DATA_BLOB in_output_buffer = data_blob_null;
2908 if (state->size - state->written == 0) {
2909 tevent_req_done(req);
2913 cc_copy->chunk_count = 0;
2915 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
2916 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
2917 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
2918 smb2cli_conn_cc_chunk_len(conn));
2919 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
2920 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2923 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
2924 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
2925 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
2926 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
2929 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
2930 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
2931 cc_copy->chunk_count++;
2934 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
2935 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
2936 if (ndr_ret != NDR_ERR_SUCCESS) {
2937 DEBUG(0, ("failed to marshall copy chunk req\n"));
2938 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2942 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
2943 state->cli->timeout,
2944 state->cli->smb2.session,
2945 state->cli->smb2.tcon,
2946 state->dst_ph->fid_persistent, /* in_fid_persistent */
2947 state->dst_ph->fid_volatile, /* in_fid_volatile */
2948 FSCTL_SRV_COPYCHUNK_WRITE,
2949 0, /* in_max_input_length */
2951 12, /* in_max_output_length */
2953 SMB2_IOCTL_FLAG_IS_FSCTL);
2954 if (tevent_req_nomem(subreq, req)) {
2957 tevent_req_set_callback(subreq,
2958 cli_splice_copychunk_done,
2962 static void cli_splice_key_done(struct tevent_req *subreq)
2964 struct tevent_req *req = tevent_req_callback_data(
2965 subreq, struct tevent_req);
2966 struct cli_smb2_splice_state *state =
2967 tevent_req_data(req,
2968 struct cli_smb2_splice_state);
2969 enum ndr_err_code ndr_ret;
2972 DATA_BLOB out_input_buffer = data_blob_null;
2973 DATA_BLOB out_output_buffer = data_blob_null;
2975 status = smb2cli_ioctl_recv(subreq, state,
2977 &out_output_buffer);
2978 TALLOC_FREE(subreq);
2979 if (tevent_req_nterror(req, status)) {
2983 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
2984 state, &state->resume_rsp,
2985 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
2986 if (ndr_ret != NDR_ERR_SUCCESS) {
2987 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
2988 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2992 memcpy(&state->cc_copy.source_key,
2993 &state->resume_rsp.resume_key,
2994 sizeof state->resume_rsp.resume_key);
2996 cli_splice_copychunk_send(state, req);
2999 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
3000 struct tevent_context *ev,
3001 struct cli_state *cli,
3002 uint16_t src_fnum, uint16_t dst_fnum,
3003 off_t size, off_t src_offset, off_t dst_offset,
3004 int (*splice_cb)(off_t n, void *priv),
3007 struct tevent_req *req;
3008 struct tevent_req *subreq;
3009 struct cli_smb2_splice_state *state;
3011 DATA_BLOB in_input_buffer = data_blob_null;
3012 DATA_BLOB in_output_buffer = data_blob_null;
3014 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
3020 state->splice_cb = splice_cb;
3024 state->src_offset = src_offset;
3025 state->dst_offset = dst_offset;
3026 state->cc_copy.chunks = talloc_array(state,
3027 struct srv_copychunk,
3028 smb2cli_conn_cc_max_chunks(cli->conn));
3029 if (state->cc_copy.chunks == NULL) {
3033 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
3034 if (tevent_req_nterror(req, status))
3035 return tevent_req_post(req, ev);
3037 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
3038 if (tevent_req_nterror(req, status))
3039 return tevent_req_post(req, ev);
3041 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
3045 state->src_ph->fid_persistent, /* in_fid_persistent */
3046 state->src_ph->fid_volatile, /* in_fid_volatile */
3047 FSCTL_SRV_REQUEST_RESUME_KEY,
3048 0, /* in_max_input_length */
3050 32, /* in_max_output_length */
3052 SMB2_IOCTL_FLAG_IS_FSCTL);
3053 if (tevent_req_nomem(subreq, req)) {
3056 tevent_req_set_callback(subreq,
3057 cli_splice_key_done,
3063 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
3065 struct cli_smb2_splice_state *state = tevent_req_data(
3066 req, struct cli_smb2_splice_state);
3069 if (tevent_req_is_nterror(req, &status)) {
3070 state->cli->raw_status = status;
3071 tevent_req_received(req);
3074 if (written != NULL) {
3075 *written = state->written;
3077 state->cli->raw_status = NT_STATUS_OK;
3078 tevent_req_received(req);
3079 return NT_STATUS_OK;
3082 /***************************************************************
3083 SMB2 enum shadow copy data.
3084 ***************************************************************/
3086 struct cli_smb2_shadow_copy_data_fnum_state {
3087 struct cli_state *cli;
3089 struct smb2_hnd *ph;
3090 DATA_BLOB out_input_buffer;
3091 DATA_BLOB out_output_buffer;
3094 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
3096 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
3097 TALLOC_CTX *mem_ctx,
3098 struct tevent_context *ev,
3099 struct cli_state *cli,
3103 struct tevent_req *req, *subreq;
3104 struct cli_smb2_close_fnum_state *state;
3107 req = tevent_req_create(mem_ctx, &state,
3108 struct cli_smb2_shadow_copy_data_fnum_state);
3113 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3114 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3115 return tevent_req_post(req, ev);
3121 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
3122 if (tevent_req_nterror(req, status)) {
3123 return tevent_req_post(req, ev);
3127 * TODO. Under SMB2 we should send a zero max_output_length
3128 * ioctl to get the required size, then send another ioctl
3129 * to get the data, but the current SMB1 implementation just
3130 * does one roundtrip with a 64K buffer size. Do the same
3134 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
3135 state->cli->timeout,
3136 state->cli->smb2.session,
3137 state->cli->smb2.tcon,
3138 state->ph->fid_persistent, /* in_fid_persistent */
3139 state->ph->fid_volatile, /* in_fid_volatile */
3140 FSCTL_GET_SHADOW_COPY_DATA,
3141 0, /* in_max_input_length */
3142 NULL, /* in_input_buffer */
3144 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
3145 NULL, /* in_output_buffer */
3146 SMB2_IOCTL_FLAG_IS_FSCTL);
3148 if (tevent_req_nomem(subreq, req)) {
3149 return tevent_req_post(req, ev);
3151 tevent_req_set_callback(subreq,
3152 cli_smb2_shadow_copy_data_fnum_done,
3158 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
3160 struct tevent_req *req = tevent_req_callback_data(
3161 subreq, struct tevent_req);
3162 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3163 req, struct cli_smb2_shadow_copy_data_fnum_state);
3166 status = smb2cli_ioctl_recv(subreq, state,
3167 &state->out_input_buffer,
3168 &state->out_output_buffer);
3169 TALLOC_FREE(subreq);
3170 if (tevent_req_nterror(req, status)) {
3173 tevent_req_done(req);
3176 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
3177 TALLOC_CTX *mem_ctx,
3182 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3183 req, struct cli_smb2_shadow_copy_data_fnum_state);
3184 char **names = NULL;
3185 uint32_t num_names = 0;
3186 uint32_t num_names_returned = 0;
3187 uint32_t dlength = 0;
3189 uint8_t *endp = NULL;
3192 if (tevent_req_is_nterror(req, &status)) {
3196 if (state->out_output_buffer.length < 16) {
3197 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3200 num_names = IVAL(state->out_output_buffer.data, 0);
3201 num_names_returned = IVAL(state->out_output_buffer.data, 4);
3202 dlength = IVAL(state->out_output_buffer.data, 8);
3204 if (num_names > 0x7FFFFFFF) {
3205 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3208 if (get_names == false) {
3209 *pnum_names = (int)num_names;
3210 return NT_STATUS_OK;
3212 if (num_names != num_names_returned) {
3213 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3215 if (dlength + 12 < 12) {
3216 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3219 * NB. The below is an allowable return if there are
3220 * more snapshots than the buffer size we told the
3221 * server we can receive. We currently don't support
3224 if (dlength + 12 > state->out_output_buffer.length) {
3225 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3227 if (state->out_output_buffer.length +
3228 (2 * sizeof(SHADOW_COPY_LABEL)) <
3229 state->out_output_buffer.length) {
3230 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3233 names = talloc_array(mem_ctx, char *, num_names_returned);
3234 if (names == NULL) {
3235 return NT_STATUS_NO_MEMORY;
3238 endp = state->out_output_buffer.data +
3239 state->out_output_buffer.length;
3241 for (i=0; i<num_names_returned; i++) {
3244 size_t converted_size;
3246 src = state->out_output_buffer.data + 12 +
3247 (i * 2 * sizeof(SHADOW_COPY_LABEL));
3249 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
3250 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3252 ret = convert_string_talloc(
3253 names, CH_UTF16LE, CH_UNIX,
3254 src, 2 * sizeof(SHADOW_COPY_LABEL),
3255 &names[i], &converted_size);
3258 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3261 *pnum_names = num_names;
3263 return NT_STATUS_OK;
3266 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
3267 struct cli_state *cli,
3273 TALLOC_CTX *frame = talloc_stackframe();
3274 struct tevent_context *ev;
3275 struct tevent_req *req;
3276 NTSTATUS status = NT_STATUS_NO_MEMORY;
3278 if (smbXcli_conn_has_async_calls(cli->conn)) {
3280 * Can't use sync call while an async call is in flight
3282 status = NT_STATUS_INVALID_PARAMETER;
3285 ev = samba_tevent_context_init(frame);
3289 req = cli_smb2_shadow_copy_data_fnum_send(frame,
3297 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3300 status = cli_smb2_shadow_copy_data_fnum_recv(req,