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);
890 cli->raw_status = status;
892 TALLOC_FREE(subframe);
897 /***************************************************************
898 Wrapper that allows SMB2 to query a path info (basic level).
900 ***************************************************************/
902 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
904 SMB_STRUCT_STAT *sbuf,
905 uint32_t *attributes)
908 struct smb_create_returns cr;
909 uint16_t fnum = 0xffff;
910 size_t namelen = strlen(name);
912 if (smbXcli_conn_has_async_calls(cli->conn)) {
914 * Can't use sync call while an async call is in flight
916 return NT_STATUS_INVALID_PARAMETER;
919 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
920 return NT_STATUS_INVALID_PARAMETER;
923 /* SMB2 is pickier about pathnames. Ensure it doesn't
925 if (namelen > 0 && name[namelen-1] == '\\') {
926 char *modname = talloc_strdup(talloc_tos(), name);
927 modname[namelen-1] = '\0';
931 /* This is commonly used as a 'cd'. Try qpathinfo on
932 a directory handle first. */
934 status = cli_smb2_create_fnum(cli,
936 0, /* create_flags */
937 FILE_READ_ATTRIBUTES, /* desired_access */
938 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
939 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
940 FILE_OPEN, /* create_disposition */
941 FILE_DIRECTORY_FILE, /* create_options */
945 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
947 status = cli_smb2_create_fnum(cli,
949 0, /* create_flags */
950 FILE_READ_ATTRIBUTES, /* desired_access */
951 0, /* file attributes */
952 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
953 FILE_OPEN, /* create_disposition */
954 0, /* create_options */
959 if (!NT_STATUS_IS_OK(status)) {
963 status = cli_smb2_close_fnum(cli, fnum);
967 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
968 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
969 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
970 sbuf->st_ex_size = cr.end_of_file;
971 *attributes = cr.file_attributes;
976 /***************************************************************
977 Helper function for pathname operations.
978 ***************************************************************/
980 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
982 uint32_t desired_access,
986 size_t namelen = strlen(name);
987 TALLOC_CTX *frame = talloc_stackframe();
989 /* SMB2 is pickier about pathnames. Ensure it doesn't
991 if (namelen > 0 && name[namelen-1] == '\\') {
992 char *modname = talloc_strdup(frame, name);
993 if (modname == NULL) {
994 status = NT_STATUS_NO_MEMORY;
997 modname[namelen-1] = '\0';
1001 /* Try to open a file handle first. */
1002 status = cli_smb2_create_fnum(cli,
1004 0, /* create_flags */
1006 0, /* file attributes */
1007 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1008 FILE_OPEN, /* create_disposition */
1009 0, /* create_options */
1013 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1014 status = cli_smb2_create_fnum(cli,
1016 0, /* create_flags */
1018 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1019 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1020 FILE_OPEN, /* create_disposition */
1021 FILE_DIRECTORY_FILE, /* create_options */
1032 /***************************************************************
1033 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1035 ***************************************************************/
1037 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1042 DATA_BLOB outbuf = data_blob_null;
1043 uint16_t fnum = 0xffff;
1044 struct smb2_hnd *ph = NULL;
1045 uint32_t altnamelen = 0;
1046 TALLOC_CTX *frame = talloc_stackframe();
1048 if (smbXcli_conn_has_async_calls(cli->conn)) {
1050 * Can't use sync call while an async call is in flight
1052 status = NT_STATUS_INVALID_PARAMETER;
1056 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1057 status = NT_STATUS_INVALID_PARAMETER;
1061 status = get_fnum_from_path(cli,
1063 FILE_READ_ATTRIBUTES,
1066 if (!NT_STATUS_IS_OK(status)) {
1070 status = map_fnum_to_smb2_handle(cli,
1073 if (!NT_STATUS_IS_OK(status)) {
1077 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1078 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1080 status = smb2cli_query_info(cli->conn,
1084 1, /* in_info_type */
1085 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1086 0xFFFF, /* in_max_output_length */
1087 NULL, /* in_input_buffer */
1088 0, /* in_additional_info */
1095 if (!NT_STATUS_IS_OK(status)) {
1099 /* Parse the reply. */
1100 if (outbuf.length < 4) {
1101 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1105 altnamelen = IVAL(outbuf.data, 0);
1106 if (altnamelen > outbuf.length - 4) {
1107 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1111 if (altnamelen > 0) {
1113 char *short_name = NULL;
1114 ret = pull_string_talloc(frame,
1116 FLAGS2_UNICODE_STRINGS,
1121 if (ret == (size_t)-1) {
1122 /* Bad conversion. */
1123 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1127 fstrcpy(alt_name, short_name);
1132 status = NT_STATUS_OK;
1136 if (fnum != 0xffff) {
1137 cli_smb2_close_fnum(cli, fnum);
1140 cli->raw_status = status;
1147 /***************************************************************
1148 Wrapper that allows SMB2 to query a fnum info (basic level).
1150 ***************************************************************/
1152 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1156 struct timespec *create_time,
1157 struct timespec *access_time,
1158 struct timespec *write_time,
1159 struct timespec *change_time,
1163 DATA_BLOB outbuf = data_blob_null;
1164 struct smb2_hnd *ph = NULL;
1165 TALLOC_CTX *frame = talloc_stackframe();
1167 if (smbXcli_conn_has_async_calls(cli->conn)) {
1169 * Can't use sync call while an async call is in flight
1171 status = NT_STATUS_INVALID_PARAMETER;
1175 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1176 status = NT_STATUS_INVALID_PARAMETER;
1180 status = map_fnum_to_smb2_handle(cli,
1183 if (!NT_STATUS_IS_OK(status)) {
1187 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1188 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1190 status = smb2cli_query_info(cli->conn,
1194 1, /* in_info_type */
1195 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1196 0xFFFF, /* in_max_output_length */
1197 NULL, /* in_input_buffer */
1198 0, /* in_additional_info */
1204 if (!NT_STATUS_IS_OK(status)) {
1208 /* Parse the reply. */
1209 if (outbuf.length < 0x60) {
1210 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1215 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1218 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1221 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1224 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1227 uint32_t attr = IVAL(outbuf.data, 0x20);
1228 *mode = (uint16_t)attr;
1231 uint64_t file_size = BVAL(outbuf.data, 0x30);
1232 *size = (off_t)file_size;
1235 uint64_t file_index = BVAL(outbuf.data, 0x40);
1236 *ino = (SMB_INO_T)file_index;
1241 cli->raw_status = status;
1247 /***************************************************************
1248 Wrapper that allows SMB2 to query an fnum.
1249 Implement on top of cli_smb2_qfileinfo_basic().
1251 ***************************************************************/
1253 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1257 time_t *change_time,
1258 time_t *access_time,
1261 struct timespec access_time_ts;
1262 struct timespec write_time_ts;
1263 struct timespec change_time_ts;
1264 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1274 cli->raw_status = status;
1276 if (!NT_STATUS_IS_OK(status)) {
1281 *change_time = change_time_ts.tv_sec;
1284 *access_time = access_time_ts.tv_sec;
1287 *write_time = write_time_ts.tv_sec;
1289 return NT_STATUS_OK;
1292 /***************************************************************
1293 Wrapper that allows SMB2 to get pathname attributes.
1295 ***************************************************************/
1297 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1304 uint16_t fnum = 0xffff;
1305 struct smb2_hnd *ph = NULL;
1306 TALLOC_CTX *frame = talloc_stackframe();
1308 if (smbXcli_conn_has_async_calls(cli->conn)) {
1310 * Can't use sync call while an async call is in flight
1312 status = NT_STATUS_INVALID_PARAMETER;
1316 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1317 status = NT_STATUS_INVALID_PARAMETER;
1321 status = get_fnum_from_path(cli,
1323 FILE_READ_ATTRIBUTES,
1326 if (!NT_STATUS_IS_OK(status)) {
1330 status = map_fnum_to_smb2_handle(cli,
1333 if (!NT_STATUS_IS_OK(status)) {
1336 status = cli_smb2_getattrE(cli,
1343 if (!NT_STATUS_IS_OK(status)) {
1349 if (fnum != 0xffff) {
1350 cli_smb2_close_fnum(cli, fnum);
1353 cli->raw_status = status;
1359 /***************************************************************
1360 Wrapper that allows SMB2 to query a pathname info (basic level).
1361 Implement on top of cli_smb2_qfileinfo_basic().
1363 ***************************************************************/
1365 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1367 struct timespec *create_time,
1368 struct timespec *access_time,
1369 struct timespec *write_time,
1370 struct timespec *change_time,
1376 struct smb2_hnd *ph = NULL;
1377 uint16_t fnum = 0xffff;
1378 TALLOC_CTX *frame = talloc_stackframe();
1380 if (smbXcli_conn_has_async_calls(cli->conn)) {
1382 * Can't use sync call while an async call is in flight
1384 status = NT_STATUS_INVALID_PARAMETER;
1388 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1389 status = NT_STATUS_INVALID_PARAMETER;
1393 status = get_fnum_from_path(cli,
1395 FILE_READ_ATTRIBUTES,
1398 if (!NT_STATUS_IS_OK(status)) {
1402 status = map_fnum_to_smb2_handle(cli,
1405 if (!NT_STATUS_IS_OK(status)) {
1409 status = cli_smb2_qfileinfo_basic(cli,
1421 if (fnum != 0xffff) {
1422 cli_smb2_close_fnum(cli, fnum);
1425 cli->raw_status = status;
1431 /***************************************************************
1432 Wrapper that allows SMB2 to query pathname streams.
1434 ***************************************************************/
1436 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1438 TALLOC_CTX *mem_ctx,
1439 unsigned int *pnum_streams,
1440 struct stream_struct **pstreams)
1443 struct smb2_hnd *ph = NULL;
1444 uint16_t fnum = 0xffff;
1445 DATA_BLOB outbuf = data_blob_null;
1446 TALLOC_CTX *frame = talloc_stackframe();
1448 if (smbXcli_conn_has_async_calls(cli->conn)) {
1450 * Can't use sync call while an async call is in flight
1452 status = NT_STATUS_INVALID_PARAMETER;
1456 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1457 status = NT_STATUS_INVALID_PARAMETER;
1461 status = get_fnum_from_path(cli,
1463 FILE_READ_ATTRIBUTES,
1466 if (!NT_STATUS_IS_OK(status)) {
1470 status = map_fnum_to_smb2_handle(cli,
1473 if (!NT_STATUS_IS_OK(status)) {
1477 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1478 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1480 status = smb2cli_query_info(cli->conn,
1484 1, /* in_info_type */
1485 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1486 0xFFFF, /* in_max_output_length */
1487 NULL, /* in_input_buffer */
1488 0, /* in_additional_info */
1495 if (!NT_STATUS_IS_OK(status)) {
1499 /* Parse the reply. */
1500 if (!parse_streams_blob(mem_ctx,
1505 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1511 if (fnum != 0xffff) {
1512 cli_smb2_close_fnum(cli, fnum);
1515 cli->raw_status = status;
1521 /***************************************************************
1522 Wrapper that allows SMB2 to set pathname attributes.
1524 ***************************************************************/
1526 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1532 uint16_t fnum = 0xffff;
1533 struct smb2_hnd *ph = NULL;
1534 uint8_t inbuf_store[40];
1535 DATA_BLOB inbuf = data_blob_null;
1536 TALLOC_CTX *frame = talloc_stackframe();
1538 if (smbXcli_conn_has_async_calls(cli->conn)) {
1540 * Can't use sync call while an async call is in flight
1542 status = NT_STATUS_INVALID_PARAMETER;
1546 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1547 status = NT_STATUS_INVALID_PARAMETER;
1551 status = get_fnum_from_path(cli,
1553 FILE_WRITE_ATTRIBUTES,
1556 if (!NT_STATUS_IS_OK(status)) {
1560 status = map_fnum_to_smb2_handle(cli,
1563 if (!NT_STATUS_IS_OK(status)) {
1567 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1568 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1570 inbuf.data = inbuf_store;
1571 inbuf.length = sizeof(inbuf_store);
1572 data_blob_clear(&inbuf);
1574 SSVAL(inbuf.data, 32, attr);
1576 put_long_date((char *)inbuf.data + 16,mtime);
1578 /* Set all the other times to -1. */
1579 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1580 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1581 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1583 status = smb2cli_set_info(cli->conn,
1587 1, /* in_info_type */
1588 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1589 &inbuf, /* in_input_buffer */
1590 0, /* in_additional_info */
1595 if (fnum != 0xffff) {
1596 cli_smb2_close_fnum(cli, fnum);
1599 cli->raw_status = status;
1605 /***************************************************************
1606 Wrapper that allows SMB2 to set file handle times.
1608 ***************************************************************/
1610 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1617 struct smb2_hnd *ph = NULL;
1618 uint8_t inbuf_store[40];
1619 DATA_BLOB inbuf = data_blob_null;
1621 if (smbXcli_conn_has_async_calls(cli->conn)) {
1623 * Can't use sync call while an async call is in flight
1625 return NT_STATUS_INVALID_PARAMETER;
1628 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1629 return NT_STATUS_INVALID_PARAMETER;
1632 status = map_fnum_to_smb2_handle(cli,
1635 if (!NT_STATUS_IS_OK(status)) {
1639 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1640 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1642 inbuf.data = inbuf_store;
1643 inbuf.length = sizeof(inbuf_store);
1644 data_blob_clear(&inbuf);
1646 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1647 if (change_time != 0) {
1648 put_long_date((char *)inbuf.data + 24, change_time);
1650 if (access_time != 0) {
1651 put_long_date((char *)inbuf.data + 8, access_time);
1653 if (write_time != 0) {
1654 put_long_date((char *)inbuf.data + 16, write_time);
1657 cli->raw_status = smb2cli_set_info(cli->conn,
1661 1, /* in_info_type */
1662 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1663 &inbuf, /* in_input_buffer */
1664 0, /* in_additional_info */
1668 return cli->raw_status;
1671 /***************************************************************
1672 Wrapper that allows SMB2 to query disk attributes (size).
1674 ***************************************************************/
1676 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
1677 uint64_t *bsize, uint64_t *total, uint64_t *avail)
1680 uint16_t fnum = 0xffff;
1681 DATA_BLOB outbuf = data_blob_null;
1682 struct smb2_hnd *ph = NULL;
1683 uint32_t sectors_per_unit = 0;
1684 uint32_t bytes_per_sector = 0;
1685 uint64_t total_size = 0;
1686 uint64_t size_free = 0;
1687 TALLOC_CTX *frame = talloc_stackframe();
1689 if (smbXcli_conn_has_async_calls(cli->conn)) {
1691 * Can't use sync call while an async call is in flight
1693 status = NT_STATUS_INVALID_PARAMETER;
1697 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1698 status = NT_STATUS_INVALID_PARAMETER;
1702 /* First open the top level directory. */
1703 status = cli_smb2_create_fnum(cli,
1705 0, /* create_flags */
1706 FILE_READ_ATTRIBUTES, /* desired_access */
1707 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1708 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1709 FILE_OPEN, /* create_disposition */
1710 FILE_DIRECTORY_FILE, /* create_options */
1714 if (!NT_STATUS_IS_OK(status)) {
1718 status = map_fnum_to_smb2_handle(cli,
1721 if (!NT_STATUS_IS_OK(status)) {
1725 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1726 level 3 (SMB_FS_SIZE_INFORMATION). */
1728 status = smb2cli_query_info(cli->conn,
1732 2, /* in_info_type */
1733 3, /* in_file_info_class */
1734 0xFFFF, /* in_max_output_length */
1735 NULL, /* in_input_buffer */
1736 0, /* in_additional_info */
1742 if (!NT_STATUS_IS_OK(status)) {
1746 /* Parse the reply. */
1747 if (outbuf.length != 24) {
1748 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1752 total_size = BVAL(outbuf.data, 0);
1753 size_free = BVAL(outbuf.data, 8);
1754 sectors_per_unit = IVAL(outbuf.data, 16);
1755 bytes_per_sector = IVAL(outbuf.data, 20);
1758 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
1761 *total = total_size;
1767 status = NT_STATUS_OK;
1771 if (fnum != 0xffff) {
1772 cli_smb2_close_fnum(cli, fnum);
1775 cli->raw_status = status;
1781 /***************************************************************
1782 Wrapper that allows SMB2 to query file system attributes.
1784 ***************************************************************/
1786 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
1789 uint16_t fnum = 0xffff;
1790 DATA_BLOB outbuf = data_blob_null;
1791 struct smb2_hnd *ph = NULL;
1792 TALLOC_CTX *frame = talloc_stackframe();
1794 if (smbXcli_conn_has_async_calls(cli->conn)) {
1796 * Can't use sync call while an async call is in flight
1798 status = NT_STATUS_INVALID_PARAMETER;
1802 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1803 status = NT_STATUS_INVALID_PARAMETER;
1807 /* First open the top level directory. */
1809 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
1810 FILE_READ_ATTRIBUTES, /* desired_access */
1811 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1812 FILE_SHARE_READ | FILE_SHARE_WRITE |
1813 FILE_SHARE_DELETE, /* share_access */
1814 FILE_OPEN, /* create_disposition */
1815 FILE_DIRECTORY_FILE, /* create_options */
1819 if (!NT_STATUS_IS_OK(status)) {
1823 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1824 if (!NT_STATUS_IS_OK(status)) {
1828 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
1829 cli->smb2.tcon, 2, /* in_info_type */
1830 5, /* in_file_info_class */
1831 0xFFFF, /* in_max_output_length */
1832 NULL, /* in_input_buffer */
1833 0, /* in_additional_info */
1835 ph->fid_persistent, ph->fid_volatile, frame,
1837 if (!NT_STATUS_IS_OK(status)) {
1841 if (outbuf.length < 12) {
1842 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1846 *fs_attr = IVAL(outbuf.data, 0);
1850 if (fnum != 0xffff) {
1851 cli_smb2_close_fnum(cli, fnum);
1854 cli->raw_status = status;
1860 /***************************************************************
1861 Wrapper that allows SMB2 to query a security descriptor.
1863 ***************************************************************/
1865 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
1868 TALLOC_CTX *mem_ctx,
1869 struct security_descriptor **ppsd)
1872 DATA_BLOB outbuf = data_blob_null;
1873 struct smb2_hnd *ph = NULL;
1874 struct security_descriptor *lsd = NULL;
1875 TALLOC_CTX *frame = talloc_stackframe();
1877 if (smbXcli_conn_has_async_calls(cli->conn)) {
1879 * Can't use sync call while an async call is in flight
1881 status = NT_STATUS_INVALID_PARAMETER;
1885 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1886 status = NT_STATUS_INVALID_PARAMETER;
1890 status = map_fnum_to_smb2_handle(cli,
1893 if (!NT_STATUS_IS_OK(status)) {
1897 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1899 status = smb2cli_query_info(cli->conn,
1903 3, /* in_info_type */
1904 0, /* in_file_info_class */
1905 0xFFFF, /* in_max_output_length */
1906 NULL, /* in_input_buffer */
1907 sec_info, /* in_additional_info */
1914 if (!NT_STATUS_IS_OK(status)) {
1918 /* Parse the reply. */
1919 status = unmarshall_sec_desc(mem_ctx,
1924 if (!NT_STATUS_IS_OK(status)) {
1936 cli->raw_status = status;
1942 /***************************************************************
1943 Wrapper that allows SMB2 to set a security descriptor.
1945 ***************************************************************/
1947 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
1950 const struct security_descriptor *sd)
1953 DATA_BLOB inbuf = data_blob_null;
1954 struct smb2_hnd *ph = NULL;
1955 TALLOC_CTX *frame = talloc_stackframe();
1957 if (smbXcli_conn_has_async_calls(cli->conn)) {
1959 * Can't use sync call while an async call is in flight
1961 status = NT_STATUS_INVALID_PARAMETER;
1965 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1966 status = NT_STATUS_INVALID_PARAMETER;
1970 status = map_fnum_to_smb2_handle(cli,
1973 if (!NT_STATUS_IS_OK(status)) {
1977 status = marshall_sec_desc(frame,
1982 if (!NT_STATUS_IS_OK(status)) {
1986 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1988 status = smb2cli_set_info(cli->conn,
1992 3, /* in_info_type */
1993 0, /* in_file_info_class */
1994 &inbuf, /* in_input_buffer */
1995 sec_info, /* in_additional_info */
2001 cli->raw_status = status;
2007 /***************************************************************
2008 Wrapper that allows SMB2 to rename a file.
2010 ***************************************************************/
2012 NTSTATUS cli_smb2_rename(struct cli_state *cli,
2013 const char *fname_src,
2014 const char *fname_dst)
2017 DATA_BLOB inbuf = data_blob_null;
2018 uint16_t fnum = 0xffff;
2019 struct smb2_hnd *ph = NULL;
2020 smb_ucs2_t *converted_str = NULL;
2021 size_t converted_size_bytes = 0;
2023 TALLOC_CTX *frame = talloc_stackframe();
2025 if (smbXcli_conn_has_async_calls(cli->conn)) {
2027 * Can't use sync call while an async call is in flight
2029 status = NT_STATUS_INVALID_PARAMETER;
2033 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2034 status = NT_STATUS_INVALID_PARAMETER;
2038 status = get_fnum_from_path(cli,
2043 if (!NT_STATUS_IS_OK(status)) {
2047 status = map_fnum_to_smb2_handle(cli,
2050 if (!NT_STATUS_IS_OK(status)) {
2054 /* SMB2 is pickier about pathnames. Ensure it doesn't
2056 if (*fname_dst == '\\') {
2060 /* SMB2 is pickier about pathnames. Ensure it doesn't
2062 namelen = strlen(fname_dst);
2063 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2064 char *modname = talloc_strdup(frame, fname_dst);
2065 modname[namelen-1] = '\0';
2066 fname_dst = modname;
2069 if (!push_ucs2_talloc(frame,
2072 &converted_size_bytes)) {
2073 status = NT_STATUS_INVALID_PARAMETER;
2077 /* W2K8 insists the dest name is not null
2078 terminated. Remove the last 2 zero bytes
2079 and reduce the name length. */
2081 if (converted_size_bytes < 2) {
2082 status = NT_STATUS_INVALID_PARAMETER;
2085 converted_size_bytes -= 2;
2087 inbuf = data_blob_talloc_zero(frame,
2088 20 + converted_size_bytes);
2089 if (inbuf.data == NULL) {
2090 status = NT_STATUS_NO_MEMORY;
2094 SIVAL(inbuf.data, 16, converted_size_bytes);
2095 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2097 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2098 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2100 status = smb2cli_set_info(cli->conn,
2104 1, /* in_info_type */
2105 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2106 &inbuf, /* in_input_buffer */
2107 0, /* in_additional_info */
2113 if (fnum != 0xffff) {
2114 cli_smb2_close_fnum(cli, fnum);
2117 cli->raw_status = status;
2123 /***************************************************************
2124 Wrapper that allows SMB2 to set an EA on a fnum.
2126 ***************************************************************/
2128 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2130 const char *ea_name,
2135 DATA_BLOB inbuf = data_blob_null;
2137 char *ea_name_ascii = NULL;
2139 struct smb2_hnd *ph = NULL;
2140 TALLOC_CTX *frame = talloc_stackframe();
2142 if (smbXcli_conn_has_async_calls(cli->conn)) {
2144 * Can't use sync call while an async call is in flight
2146 status = NT_STATUS_INVALID_PARAMETER;
2150 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2151 status = NT_STATUS_INVALID_PARAMETER;
2155 status = map_fnum_to_smb2_handle(cli,
2158 if (!NT_STATUS_IS_OK(status)) {
2162 /* Marshall the SMB2 EA data. */
2163 if (ea_len > 0xFFFF) {
2164 status = NT_STATUS_INVALID_PARAMETER;
2168 if (!push_ascii_talloc(frame,
2172 status = NT_STATUS_INVALID_PARAMETER;
2176 if (namelen < 2 || namelen > 0xFF) {
2177 status = NT_STATUS_INVALID_PARAMETER;
2181 bloblen = 8 + ea_len + namelen;
2182 /* Round up to a 4 byte boundary. */
2183 bloblen = ((bloblen + 3)&~3);
2185 inbuf = data_blob_talloc_zero(frame, bloblen);
2186 if (inbuf.data == NULL) {
2187 status = NT_STATUS_NO_MEMORY;
2190 /* namelen doesn't include the NULL byte. */
2191 SCVAL(inbuf.data, 5, namelen - 1);
2192 SSVAL(inbuf.data, 6, ea_len);
2193 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2194 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2196 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2197 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2199 status = smb2cli_set_info(cli->conn,
2203 1, /* in_info_type */
2204 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2205 &inbuf, /* in_input_buffer */
2206 0, /* in_additional_info */
2212 cli->raw_status = status;
2218 /***************************************************************
2219 Wrapper that allows SMB2 to set an EA on a pathname.
2221 ***************************************************************/
2223 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2225 const char *ea_name,
2230 uint16_t fnum = 0xffff;
2232 if (smbXcli_conn_has_async_calls(cli->conn)) {
2234 * Can't use sync call while an async call is in flight
2236 status = NT_STATUS_INVALID_PARAMETER;
2240 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2241 status = NT_STATUS_INVALID_PARAMETER;
2245 status = get_fnum_from_path(cli,
2250 if (!NT_STATUS_IS_OK(status)) {
2254 status = cli_set_ea_fnum(cli,
2259 if (!NT_STATUS_IS_OK(status)) {
2265 if (fnum != 0xffff) {
2266 cli_smb2_close_fnum(cli, fnum);
2269 cli->raw_status = status;
2274 /***************************************************************
2275 Wrapper that allows SMB2 to get an EA list on a pathname.
2277 ***************************************************************/
2279 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2283 struct ea_struct **pea_array)
2286 uint16_t fnum = 0xffff;
2287 DATA_BLOB outbuf = data_blob_null;
2288 struct smb2_hnd *ph = NULL;
2289 struct ea_list *ea_list = NULL;
2290 struct ea_list *eal = NULL;
2291 size_t ea_count = 0;
2292 TALLOC_CTX *frame = talloc_stackframe();
2297 if (smbXcli_conn_has_async_calls(cli->conn)) {
2299 * Can't use sync call while an async call is in flight
2301 status = NT_STATUS_INVALID_PARAMETER;
2305 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2306 status = NT_STATUS_INVALID_PARAMETER;
2310 status = get_fnum_from_path(cli,
2315 if (!NT_STATUS_IS_OK(status)) {
2319 status = map_fnum_to_smb2_handle(cli,
2322 if (!NT_STATUS_IS_OK(status)) {
2326 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2327 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2329 status = smb2cli_query_info(cli->conn,
2333 1, /* in_info_type */
2334 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2335 0xFFFF, /* in_max_output_length */
2336 NULL, /* in_input_buffer */
2337 0, /* in_additional_info */
2344 if (!NT_STATUS_IS_OK(status)) {
2348 /* Parse the reply. */
2349 ea_list = read_nttrans_ea_list(ctx,
2350 (const char *)outbuf.data,
2352 if (ea_list == NULL) {
2353 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2357 /* Convert to an array. */
2358 for (eal = ea_list; eal; eal = eal->next) {
2363 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2364 if (*pea_array == NULL) {
2365 status = NT_STATUS_NO_MEMORY;
2369 for (eal = ea_list; eal; eal = eal->next) {
2370 (*pea_array)[ea_count++] = eal->ea;
2372 *pnum_eas = ea_count;
2377 if (fnum != 0xffff) {
2378 cli_smb2_close_fnum(cli, fnum);
2381 cli->raw_status = status;
2387 /***************************************************************
2388 Wrapper that allows SMB2 to get user quota.
2390 ***************************************************************/
2392 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
2394 SMB_NTQUOTA_STRUCT *pqt)
2397 DATA_BLOB inbuf = data_blob_null;
2398 DATA_BLOB outbuf = data_blob_null;
2399 struct smb2_hnd *ph = NULL;
2400 TALLOC_CTX *frame = talloc_stackframe();
2402 unsigned int offset;
2405 if (smbXcli_conn_has_async_calls(cli->conn)) {
2407 * Can't use sync call while an async call is in flight
2409 status = NT_STATUS_INVALID_PARAMETER;
2413 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2414 status = NT_STATUS_INVALID_PARAMETER;
2418 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2419 if (!NT_STATUS_IS_OK(status)) {
2423 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
2425 inbuf = data_blob_talloc_zero(frame, 24 + sid_len);
2426 if (inbuf.data == NULL) {
2427 status = NT_STATUS_NO_MEMORY;
2433 SCVAL(buf, 0, 1); /* ReturnSingle */
2434 SCVAL(buf, 1, 0); /* RestartScan */
2435 SSVAL(buf, 2, 0); /* Reserved */
2436 if (8 + sid_len < 8) {
2437 status = NT_STATUS_INVALID_PARAMETER;
2440 SIVAL(buf, 4, 8 + sid_len); /* SidListLength */
2441 SIVAL(buf, 8, 0); /* StartSidLength */
2442 SIVAL(buf, 12, 0); /* StartSidOffset */
2443 SIVAL(buf, 16, 0); /* NextEntryOffset */
2444 SIVAL(buf, 20, sid_len); /* SidLength */
2445 sid_linearize(buf + 24, sid_len, &pqt->sid);
2447 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2448 cli->smb2.tcon, 4, /* in_info_type */
2449 0, /* in_file_info_class */
2450 0xFFFF, /* in_max_output_length */
2451 &inbuf, /* in_input_buffer */
2452 0, /* in_additional_info */
2454 ph->fid_persistent, ph->fid_volatile, frame,
2457 if (!NT_STATUS_IS_OK(status)) {
2461 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
2463 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2464 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
2468 cli->raw_status = status;
2474 /***************************************************************
2475 Wrapper that allows SMB2 to list user quota.
2477 ***************************************************************/
2479 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
2480 TALLOC_CTX *mem_ctx,
2482 SMB_NTQUOTA_LIST **pqt_list,
2486 DATA_BLOB inbuf = data_blob_null;
2487 DATA_BLOB outbuf = data_blob_null;
2488 struct smb2_hnd *ph = NULL;
2489 TALLOC_CTX *frame = talloc_stackframe();
2492 if (smbXcli_conn_has_async_calls(cli->conn)) {
2494 * Can't use sync call while an async call is in flight
2496 status = NT_STATUS_INVALID_PARAMETER;
2500 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2501 status = NT_STATUS_INVALID_PARAMETER;
2505 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2506 if (!NT_STATUS_IS_OK(status)) {
2510 inbuf = data_blob_talloc_zero(frame, 16);
2511 if (inbuf.data == NULL) {
2512 status = NT_STATUS_NO_MEMORY;
2518 SCVAL(buf, 0, 0); /* ReturnSingle */
2519 SCVAL(buf, 1, first ? 1 : 0); /* RestartScan */
2520 SSVAL(buf, 2, 0); /* Reserved */
2521 SIVAL(buf, 4, 0); /* SidListLength */
2522 SIVAL(buf, 8, 0); /* StartSidLength */
2523 SIVAL(buf, 12, 0); /* StartSidOffset */
2525 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2526 cli->smb2.tcon, 4, /* in_info_type */
2527 0, /* in_file_info_class */
2528 0xFFFF, /* in_max_output_length */
2529 &inbuf, /* in_input_buffer */
2530 0, /* in_additional_info */
2532 ph->fid_persistent, ph->fid_volatile, frame,
2535 if (!NT_STATUS_IS_OK(status)) {
2539 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
2543 cli->raw_status = status;
2549 /***************************************************************
2550 Wrapper that allows SMB2 to get file system quota.
2552 ***************************************************************/
2554 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
2556 SMB_NTQUOTA_STRUCT *pqt)
2559 DATA_BLOB outbuf = data_blob_null;
2560 struct smb2_hnd *ph = NULL;
2561 TALLOC_CTX *frame = talloc_stackframe();
2563 if (smbXcli_conn_has_async_calls(cli->conn)) {
2565 * Can't use sync call while an async call is in flight
2567 status = NT_STATUS_INVALID_PARAMETER;
2571 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2572 status = NT_STATUS_INVALID_PARAMETER;
2576 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2577 if (!NT_STATUS_IS_OK(status)) {
2581 status = smb2cli_query_info(
2582 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
2583 2, /* in_info_type */
2584 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
2585 0xFFFF, /* in_max_output_length */
2586 NULL, /* in_input_buffer */
2587 0, /* in_additional_info */
2589 ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
2591 if (!NT_STATUS_IS_OK(status)) {
2595 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
2598 cli->raw_status = status;
2604 /***************************************************************
2605 Wrapper that allows SMB2 to set user quota.
2607 ***************************************************************/
2609 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
2611 SMB_NTQUOTA_LIST *qtl)
2614 DATA_BLOB inbuf = data_blob_null;
2615 struct smb2_hnd *ph = NULL;
2616 TALLOC_CTX *frame = talloc_stackframe();
2618 if (smbXcli_conn_has_async_calls(cli->conn)) {
2620 * Can't use sync call while an async call is in flight
2622 status = NT_STATUS_INVALID_PARAMETER;
2626 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2627 status = NT_STATUS_INVALID_PARAMETER;
2631 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2632 if (!NT_STATUS_IS_OK(status)) {
2636 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
2637 if (!NT_STATUS_IS_OK(status)) {
2641 status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
2642 cli->smb2.tcon, 4, /* in_info_type */
2643 0, /* in_file_info_class */
2644 &inbuf, /* in_input_buffer */
2645 0, /* in_additional_info */
2646 ph->fid_persistent, ph->fid_volatile);
2649 cli->raw_status = status;
2656 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
2658 SMB_NTQUOTA_STRUCT *pqt)
2661 DATA_BLOB inbuf = data_blob_null;
2662 struct smb2_hnd *ph = NULL;
2663 TALLOC_CTX *frame = talloc_stackframe();
2665 if (smbXcli_conn_has_async_calls(cli->conn)) {
2667 * Can't use sync call while an async call is in flight
2669 status = NT_STATUS_INVALID_PARAMETER;
2673 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2674 status = NT_STATUS_INVALID_PARAMETER;
2678 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2679 if (!NT_STATUS_IS_OK(status)) {
2683 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
2684 if (!NT_STATUS_IS_OK(status)) {
2688 status = smb2cli_set_info(
2689 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
2690 2, /* in_info_type */
2691 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
2692 &inbuf, /* in_input_buffer */
2693 0, /* in_additional_info */
2694 ph->fid_persistent, ph->fid_volatile);
2696 cli->raw_status = status;
2702 struct cli_smb2_read_state {
2703 struct tevent_context *ev;
2704 struct cli_state *cli;
2705 struct smb2_hnd *ph;
2706 uint64_t start_offset;
2712 static void cli_smb2_read_done(struct tevent_req *subreq);
2714 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
2715 struct tevent_context *ev,
2716 struct cli_state *cli,
2722 struct tevent_req *req, *subreq;
2723 struct cli_smb2_read_state *state;
2725 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
2731 state->start_offset = (uint64_t)offset;
2732 state->size = (uint32_t)size;
2733 state->received = 0;
2736 status = map_fnum_to_smb2_handle(cli,
2739 if (tevent_req_nterror(req, status)) {
2740 return tevent_req_post(req, ev);
2743 subreq = smb2cli_read_send(state,
2746 state->cli->timeout,
2747 state->cli->smb2.session,
2748 state->cli->smb2.tcon,
2750 state->start_offset,
2751 state->ph->fid_persistent,
2752 state->ph->fid_volatile,
2753 0, /* minimum_count */
2754 0); /* remaining_bytes */
2756 if (tevent_req_nomem(subreq, req)) {
2757 return tevent_req_post(req, ev);
2759 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
2763 static void cli_smb2_read_done(struct tevent_req *subreq)
2765 struct tevent_req *req = tevent_req_callback_data(
2766 subreq, struct tevent_req);
2767 struct cli_smb2_read_state *state = tevent_req_data(
2768 req, struct cli_smb2_read_state);
2771 status = smb2cli_read_recv(subreq, state,
2772 &state->buf, &state->received);
2773 if (tevent_req_nterror(req, status)) {
2777 if (state->received > state->size) {
2778 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2782 tevent_req_done(req);
2785 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
2790 struct cli_smb2_read_state *state = tevent_req_data(
2791 req, struct cli_smb2_read_state);
2793 if (tevent_req_is_nterror(req, &status)) {
2794 state->cli->raw_status = status;
2798 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2799 * better make sure that you copy it away before you talloc_free(req).
2800 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2802 *received = (ssize_t)state->received;
2803 *rcvbuf = state->buf;
2804 state->cli->raw_status = NT_STATUS_OK;
2805 return NT_STATUS_OK;
2808 struct cli_smb2_write_state {
2809 struct tevent_context *ev;
2810 struct cli_state *cli;
2811 struct smb2_hnd *ph;
2819 static void cli_smb2_write_written(struct tevent_req *req);
2821 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
2822 struct tevent_context *ev,
2823 struct cli_state *cli,
2831 struct tevent_req *req, *subreq = NULL;
2832 struct cli_smb2_write_state *state = NULL;
2834 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
2840 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2841 state->flags = (uint32_t)mode;
2843 state->offset = (uint64_t)offset;
2844 state->size = (uint32_t)size;
2847 status = map_fnum_to_smb2_handle(cli,
2850 if (tevent_req_nterror(req, status)) {
2851 return tevent_req_post(req, ev);
2854 subreq = smb2cli_write_send(state,
2857 state->cli->timeout,
2858 state->cli->smb2.session,
2859 state->cli->smb2.tcon,
2862 state->ph->fid_persistent,
2863 state->ph->fid_volatile,
2864 0, /* remaining_bytes */
2865 state->flags, /* flags */
2868 if (tevent_req_nomem(subreq, req)) {
2869 return tevent_req_post(req, ev);
2871 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
2875 static void cli_smb2_write_written(struct tevent_req *subreq)
2877 struct tevent_req *req = tevent_req_callback_data(
2878 subreq, struct tevent_req);
2879 struct cli_smb2_write_state *state = tevent_req_data(
2880 req, struct cli_smb2_write_state);
2884 status = smb2cli_write_recv(subreq, &written);
2885 TALLOC_FREE(subreq);
2886 if (tevent_req_nterror(req, status)) {
2890 state->written = written;
2892 tevent_req_done(req);
2895 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
2898 struct cli_smb2_write_state *state = tevent_req_data(
2899 req, struct cli_smb2_write_state);
2902 if (tevent_req_is_nterror(req, &status)) {
2903 state->cli->raw_status = status;
2904 tevent_req_received(req);
2908 if (pwritten != NULL) {
2909 *pwritten = (size_t)state->written;
2911 state->cli->raw_status = NT_STATUS_OK;
2912 tevent_req_received(req);
2913 return NT_STATUS_OK;
2916 /***************************************************************
2917 Wrapper that allows SMB2 async write using an fnum.
2918 This is mostly cut-and-paste from Volker's code inside
2919 source3/libsmb/clireadwrite.c, adapted for SMB2.
2921 Done this way so I can reuse all the logic inside cli_push()
2923 ***************************************************************/
2925 struct cli_smb2_writeall_state {
2926 struct tevent_context *ev;
2927 struct cli_state *cli;
2928 struct smb2_hnd *ph;
2936 static void cli_smb2_writeall_written(struct tevent_req *req);
2938 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
2939 struct tevent_context *ev,
2940 struct cli_state *cli,
2948 struct tevent_req *req, *subreq = NULL;
2949 struct cli_smb2_writeall_state *state = NULL;
2954 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
2960 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2961 state->flags = (uint32_t)mode;
2963 state->offset = (uint64_t)offset;
2964 state->size = (uint32_t)size;
2967 status = map_fnum_to_smb2_handle(cli,
2970 if (tevent_req_nterror(req, status)) {
2971 return tevent_req_post(req, ev);
2974 to_write = state->size;
2975 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2976 to_write = MIN(max_size, to_write);
2977 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2979 to_write = MIN(max_size, to_write);
2982 subreq = smb2cli_write_send(state,
2985 state->cli->timeout,
2986 state->cli->smb2.session,
2987 state->cli->smb2.tcon,
2990 state->ph->fid_persistent,
2991 state->ph->fid_volatile,
2992 0, /* remaining_bytes */
2993 state->flags, /* flags */
2994 state->buf + state->written);
2996 if (tevent_req_nomem(subreq, req)) {
2997 return tevent_req_post(req, ev);
2999 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3003 static void cli_smb2_writeall_written(struct tevent_req *subreq)
3005 struct tevent_req *req = tevent_req_callback_data(
3006 subreq, struct tevent_req);
3007 struct cli_smb2_writeall_state *state = tevent_req_data(
3008 req, struct cli_smb2_writeall_state);
3010 uint32_t written, to_write;
3014 status = smb2cli_write_recv(subreq, &written);
3015 TALLOC_FREE(subreq);
3016 if (tevent_req_nterror(req, status)) {
3020 state->written += written;
3022 if (state->written > state->size) {
3023 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3027 to_write = state->size - state->written;
3029 if (to_write == 0) {
3030 tevent_req_done(req);
3034 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3035 to_write = MIN(max_size, to_write);
3036 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3038 to_write = MIN(max_size, to_write);
3041 subreq = smb2cli_write_send(state,
3044 state->cli->timeout,
3045 state->cli->smb2.session,
3046 state->cli->smb2.tcon,
3048 state->offset + state->written,
3049 state->ph->fid_persistent,
3050 state->ph->fid_volatile,
3051 0, /* remaining_bytes */
3052 state->flags, /* flags */
3053 state->buf + state->written);
3055 if (tevent_req_nomem(subreq, req)) {
3058 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3061 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
3064 struct cli_smb2_writeall_state *state = tevent_req_data(
3065 req, struct cli_smb2_writeall_state);
3068 if (tevent_req_is_nterror(req, &status)) {
3069 state->cli->raw_status = status;
3072 if (pwritten != NULL) {
3073 *pwritten = (size_t)state->written;
3075 state->cli->raw_status = NT_STATUS_OK;
3076 return NT_STATUS_OK;
3079 struct cli_smb2_splice_state {
3080 struct tevent_context *ev;
3081 struct cli_state *cli;
3082 struct smb2_hnd *src_ph;
3083 struct smb2_hnd *dst_ph;
3084 int (*splice_cb)(off_t n, void *priv);
3091 struct req_resume_key_rsp resume_rsp;
3092 struct srv_copychunk_copy cc_copy;
3095 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3096 struct tevent_req *req);
3098 static void cli_splice_copychunk_done(struct tevent_req *subreq)
3100 struct tevent_req *req = tevent_req_callback_data(
3101 subreq, struct tevent_req);
3102 struct cli_smb2_splice_state *state =
3103 tevent_req_data(req,
3104 struct cli_smb2_splice_state);
3105 struct smbXcli_conn *conn = state->cli->conn;
3106 DATA_BLOB out_input_buffer = data_blob_null;
3107 DATA_BLOB out_output_buffer = data_blob_null;
3108 struct srv_copychunk_rsp cc_copy_rsp;
3109 enum ndr_err_code ndr_ret;
3112 status = smb2cli_ioctl_recv(subreq, state,
3114 &out_output_buffer);
3115 TALLOC_FREE(subreq);
3116 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
3117 state->resized) && tevent_req_nterror(req, status)) {
3121 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
3122 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
3123 if (ndr_ret != NDR_ERR_SUCCESS) {
3124 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3125 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3129 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
3130 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
3131 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
3132 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
3133 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
3134 tevent_req_nterror(req, status)) {
3138 state->resized = true;
3139 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
3140 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
3142 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3143 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3144 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
3145 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3148 state->src_offset += cc_copy_rsp.total_bytes_written;
3149 state->dst_offset += cc_copy_rsp.total_bytes_written;
3150 state->written += cc_copy_rsp.total_bytes_written;
3151 if (!state->splice_cb(state->written, state->priv)) {
3152 tevent_req_nterror(req, NT_STATUS_CANCELLED);
3157 cli_splice_copychunk_send(state, req);
3160 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3161 struct tevent_req *req)
3163 struct tevent_req *subreq;
3164 enum ndr_err_code ndr_ret;
3165 struct smbXcli_conn *conn = state->cli->conn;
3166 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
3167 off_t src_offset = state->src_offset;
3168 off_t dst_offset = state->dst_offset;
3169 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
3170 state->size - state->written);
3171 DATA_BLOB in_input_buffer = data_blob_null;
3172 DATA_BLOB in_output_buffer = data_blob_null;
3174 if (state->size - state->written == 0) {
3175 tevent_req_done(req);
3179 cc_copy->chunk_count = 0;
3181 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
3182 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
3183 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
3184 smb2cli_conn_cc_chunk_len(conn));
3185 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
3186 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3189 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
3190 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
3191 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
3192 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3195 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3196 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3197 cc_copy->chunk_count++;
3200 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
3201 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
3202 if (ndr_ret != NDR_ERR_SUCCESS) {
3203 DEBUG(0, ("failed to marshall copy chunk req\n"));
3204 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3208 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
3209 state->cli->timeout,
3210 state->cli->smb2.session,
3211 state->cli->smb2.tcon,
3212 state->dst_ph->fid_persistent, /* in_fid_persistent */
3213 state->dst_ph->fid_volatile, /* in_fid_volatile */
3214 FSCTL_SRV_COPYCHUNK_WRITE,
3215 0, /* in_max_input_length */
3217 12, /* in_max_output_length */
3219 SMB2_IOCTL_FLAG_IS_FSCTL);
3220 if (tevent_req_nomem(subreq, req)) {
3223 tevent_req_set_callback(subreq,
3224 cli_splice_copychunk_done,
3228 static void cli_splice_key_done(struct tevent_req *subreq)
3230 struct tevent_req *req = tevent_req_callback_data(
3231 subreq, struct tevent_req);
3232 struct cli_smb2_splice_state *state =
3233 tevent_req_data(req,
3234 struct cli_smb2_splice_state);
3235 enum ndr_err_code ndr_ret;
3238 DATA_BLOB out_input_buffer = data_blob_null;
3239 DATA_BLOB out_output_buffer = data_blob_null;
3241 status = smb2cli_ioctl_recv(subreq, state,
3243 &out_output_buffer);
3244 TALLOC_FREE(subreq);
3245 if (tevent_req_nterror(req, status)) {
3249 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
3250 state, &state->resume_rsp,
3251 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
3252 if (ndr_ret != NDR_ERR_SUCCESS) {
3253 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3254 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3258 memcpy(&state->cc_copy.source_key,
3259 &state->resume_rsp.resume_key,
3260 sizeof state->resume_rsp.resume_key);
3262 cli_splice_copychunk_send(state, req);
3265 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
3266 struct tevent_context *ev,
3267 struct cli_state *cli,
3268 uint16_t src_fnum, uint16_t dst_fnum,
3269 off_t size, off_t src_offset, off_t dst_offset,
3270 int (*splice_cb)(off_t n, void *priv),
3273 struct tevent_req *req;
3274 struct tevent_req *subreq;
3275 struct cli_smb2_splice_state *state;
3277 DATA_BLOB in_input_buffer = data_blob_null;
3278 DATA_BLOB in_output_buffer = data_blob_null;
3280 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
3286 state->splice_cb = splice_cb;
3290 state->src_offset = src_offset;
3291 state->dst_offset = dst_offset;
3292 state->cc_copy.chunks = talloc_array(state,
3293 struct srv_copychunk,
3294 smb2cli_conn_cc_max_chunks(cli->conn));
3295 if (state->cc_copy.chunks == NULL) {
3299 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
3300 if (tevent_req_nterror(req, status))
3301 return tevent_req_post(req, ev);
3303 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
3304 if (tevent_req_nterror(req, status))
3305 return tevent_req_post(req, ev);
3307 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
3311 state->src_ph->fid_persistent, /* in_fid_persistent */
3312 state->src_ph->fid_volatile, /* in_fid_volatile */
3313 FSCTL_SRV_REQUEST_RESUME_KEY,
3314 0, /* in_max_input_length */
3316 32, /* in_max_output_length */
3318 SMB2_IOCTL_FLAG_IS_FSCTL);
3319 if (tevent_req_nomem(subreq, req)) {
3322 tevent_req_set_callback(subreq,
3323 cli_splice_key_done,
3329 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
3331 struct cli_smb2_splice_state *state = tevent_req_data(
3332 req, struct cli_smb2_splice_state);
3335 if (tevent_req_is_nterror(req, &status)) {
3336 state->cli->raw_status = status;
3337 tevent_req_received(req);
3340 if (written != NULL) {
3341 *written = state->written;
3343 state->cli->raw_status = NT_STATUS_OK;
3344 tevent_req_received(req);
3345 return NT_STATUS_OK;
3348 /***************************************************************
3349 SMB2 enum shadow copy data.
3350 ***************************************************************/
3352 struct cli_smb2_shadow_copy_data_fnum_state {
3353 struct cli_state *cli;
3355 struct smb2_hnd *ph;
3356 DATA_BLOB out_input_buffer;
3357 DATA_BLOB out_output_buffer;
3360 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
3362 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
3363 TALLOC_CTX *mem_ctx,
3364 struct tevent_context *ev,
3365 struct cli_state *cli,
3369 struct tevent_req *req, *subreq;
3370 struct cli_smb2_shadow_copy_data_fnum_state *state;
3373 req = tevent_req_create(mem_ctx, &state,
3374 struct cli_smb2_shadow_copy_data_fnum_state);
3379 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3380 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3381 return tevent_req_post(req, ev);
3387 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
3388 if (tevent_req_nterror(req, status)) {
3389 return tevent_req_post(req, ev);
3393 * TODO. Under SMB2 we should send a zero max_output_length
3394 * ioctl to get the required size, then send another ioctl
3395 * to get the data, but the current SMB1 implementation just
3396 * does one roundtrip with a 64K buffer size. Do the same
3400 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
3401 state->cli->timeout,
3402 state->cli->smb2.session,
3403 state->cli->smb2.tcon,
3404 state->ph->fid_persistent, /* in_fid_persistent */
3405 state->ph->fid_volatile, /* in_fid_volatile */
3406 FSCTL_GET_SHADOW_COPY_DATA,
3407 0, /* in_max_input_length */
3408 NULL, /* in_input_buffer */
3410 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
3411 NULL, /* in_output_buffer */
3412 SMB2_IOCTL_FLAG_IS_FSCTL);
3414 if (tevent_req_nomem(subreq, req)) {
3415 return tevent_req_post(req, ev);
3417 tevent_req_set_callback(subreq,
3418 cli_smb2_shadow_copy_data_fnum_done,
3424 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
3426 struct tevent_req *req = tevent_req_callback_data(
3427 subreq, struct tevent_req);
3428 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3429 req, struct cli_smb2_shadow_copy_data_fnum_state);
3432 status = smb2cli_ioctl_recv(subreq, state,
3433 &state->out_input_buffer,
3434 &state->out_output_buffer);
3435 TALLOC_FREE(subreq);
3436 if (tevent_req_nterror(req, status)) {
3439 tevent_req_done(req);
3442 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
3443 TALLOC_CTX *mem_ctx,
3448 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3449 req, struct cli_smb2_shadow_copy_data_fnum_state);
3450 char **names = NULL;
3451 uint32_t num_names = 0;
3452 uint32_t num_names_returned = 0;
3453 uint32_t dlength = 0;
3455 uint8_t *endp = NULL;
3458 if (tevent_req_is_nterror(req, &status)) {
3462 if (state->out_output_buffer.length < 16) {
3463 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3466 num_names = IVAL(state->out_output_buffer.data, 0);
3467 num_names_returned = IVAL(state->out_output_buffer.data, 4);
3468 dlength = IVAL(state->out_output_buffer.data, 8);
3470 if (num_names > 0x7FFFFFFF) {
3471 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3474 if (get_names == false) {
3475 *pnum_names = (int)num_names;
3476 return NT_STATUS_OK;
3478 if (num_names != num_names_returned) {
3479 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3481 if (dlength + 12 < 12) {
3482 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3485 * NB. The below is an allowable return if there are
3486 * more snapshots than the buffer size we told the
3487 * server we can receive. We currently don't support
3490 if (dlength + 12 > state->out_output_buffer.length) {
3491 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3493 if (state->out_output_buffer.length +
3494 (2 * sizeof(SHADOW_COPY_LABEL)) <
3495 state->out_output_buffer.length) {
3496 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3499 names = talloc_array(mem_ctx, char *, num_names_returned);
3500 if (names == NULL) {
3501 return NT_STATUS_NO_MEMORY;
3504 endp = state->out_output_buffer.data +
3505 state->out_output_buffer.length;
3507 for (i=0; i<num_names_returned; i++) {
3510 size_t converted_size;
3512 src = state->out_output_buffer.data + 12 +
3513 (i * 2 * sizeof(SHADOW_COPY_LABEL));
3515 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
3516 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3518 ret = convert_string_talloc(
3519 names, CH_UTF16LE, CH_UNIX,
3520 src, 2 * sizeof(SHADOW_COPY_LABEL),
3521 &names[i], &converted_size);
3524 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3527 *pnum_names = num_names;
3529 return NT_STATUS_OK;
3532 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
3533 struct cli_state *cli,
3539 TALLOC_CTX *frame = talloc_stackframe();
3540 struct tevent_context *ev;
3541 struct tevent_req *req;
3542 NTSTATUS status = NT_STATUS_NO_MEMORY;
3544 if (smbXcli_conn_has_async_calls(cli->conn)) {
3546 * Can't use sync call while an async call is in flight
3548 status = NT_STATUS_INVALID_PARAMETER;
3551 ev = samba_tevent_context_init(frame);
3555 req = cli_smb2_shadow_copy_data_fnum_send(frame,
3563 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3566 status = cli_smb2_shadow_copy_data_fnum_recv(req,
3572 cli->raw_status = status;