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 struct cli_smb2_delete_on_close_state {
489 struct cli_state *cli;
496 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
498 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
499 struct tevent_context *ev,
500 struct cli_state *cli,
504 struct tevent_req *req = NULL;
505 struct cli_smb2_delete_on_close_state *state = NULL;
506 struct tevent_req *subreq = NULL;
507 uint8_t in_info_type;
508 uint8_t in_file_info_class;
511 req = tevent_req_create(mem_ctx, &state,
512 struct cli_smb2_delete_on_close_state);
519 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
520 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
521 return tevent_req_post(req, ev);
524 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
525 if (tevent_req_nterror(req, status)) {
526 return tevent_req_post(req, ev);
530 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
531 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
534 in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
535 /* Setup data array. */
536 SCVAL(&state->data[0], 0, flag ? 1 : 0);
537 state->inbuf.data = &state->data[0];
538 state->inbuf.length = 1;
540 subreq = smb2cli_set_info_send(state, ev,
547 &state->inbuf, /* in_input_buffer */
548 0, /* in_additional_info */
549 state->ph->fid_persistent,
550 state->ph->fid_volatile);
551 if (tevent_req_nomem(subreq, req)) {
552 return tevent_req_post(req, ev);
554 tevent_req_set_callback(subreq,
555 cli_smb2_delete_on_close_done,
560 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
562 NTSTATUS status = smb2cli_set_info_recv(subreq);
563 tevent_req_simple_finish_ntstatus(subreq, status);
566 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
568 struct cli_smb2_delete_on_close_state *state =
570 struct cli_smb2_delete_on_close_state);
573 if (tevent_req_is_nterror(req, &status)) {
574 state->cli->raw_status = status;
575 tevent_req_received(req);
579 state->cli->raw_status = NT_STATUS_OK;
580 tevent_req_received(req);
584 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
586 TALLOC_CTX *frame = talloc_stackframe();
587 struct tevent_context *ev;
588 struct tevent_req *req;
589 NTSTATUS status = NT_STATUS_NO_MEMORY;
591 if (smbXcli_conn_has_async_calls(cli->conn)) {
593 * Can't use sync call while an async call is in flight
595 status = NT_STATUS_INVALID_PARAMETER;
598 ev = samba_tevent_context_init(frame);
602 req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
606 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
609 status = cli_smb2_delete_on_close_recv(req);
615 /***************************************************************
616 Small wrapper that allows SMB2 to create a directory
618 ***************************************************************/
620 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
625 if (smbXcli_conn_has_async_calls(cli->conn)) {
627 * Can't use sync call while an async call is in flight
629 return NT_STATUS_INVALID_PARAMETER;
632 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
633 return NT_STATUS_INVALID_PARAMETER;
636 status = cli_smb2_create_fnum(cli,
638 0, /* create_flags */
639 FILE_READ_ATTRIBUTES, /* desired_access */
640 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
641 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
642 FILE_CREATE, /* create_disposition */
643 FILE_DIRECTORY_FILE, /* create_options */
647 if (!NT_STATUS_IS_OK(status)) {
650 return cli_smb2_close_fnum(cli, fnum);
653 /***************************************************************
654 Small wrapper that allows SMB2 to delete a directory
656 ***************************************************************/
658 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
663 if (smbXcli_conn_has_async_calls(cli->conn)) {
665 * Can't use sync call while an async call is in flight
667 return NT_STATUS_INVALID_PARAMETER;
670 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
671 return NT_STATUS_INVALID_PARAMETER;
674 status = cli_smb2_create_fnum(cli,
676 0, /* create_flags */
677 DELETE_ACCESS, /* desired_access */
678 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
679 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
680 FILE_OPEN, /* create_disposition */
681 FILE_DIRECTORY_FILE|FILE_DELETE_ON_CLOSE, /* create_options */
685 if (!NT_STATUS_IS_OK(status)) {
688 return cli_smb2_close_fnum(cli, fnum);
691 /***************************************************************
692 Small wrapper that allows SMB2 to unlink a pathname.
694 ***************************************************************/
696 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
701 if (smbXcli_conn_has_async_calls(cli->conn)) {
703 * Can't use sync call while an async call is in flight
705 return NT_STATUS_INVALID_PARAMETER;
708 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
709 return NT_STATUS_INVALID_PARAMETER;
712 status = cli_smb2_create_fnum(cli,
714 0, /* create_flags */
715 DELETE_ACCESS, /* desired_access */
716 FILE_ATTRIBUTE_NORMAL, /* file attributes */
717 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
718 FILE_OPEN, /* create_disposition */
719 FILE_DELETE_ON_CLOSE, /* create_options */
723 if (!NT_STATUS_IS_OK(status)) {
726 return cli_smb2_close_fnum(cli, fnum);
729 /***************************************************************
730 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
731 ***************************************************************/
733 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
734 uint32_t dir_data_length,
735 struct file_info *finfo,
736 uint32_t *next_offset)
742 if (dir_data_length < 4) {
743 return NT_STATUS_INFO_LENGTH_MISMATCH;
746 *next_offset = IVAL(dir_data, 0);
748 if (*next_offset > dir_data_length) {
749 return NT_STATUS_INFO_LENGTH_MISMATCH;
752 if (*next_offset != 0) {
753 /* Ensure we only read what in this record. */
754 dir_data_length = *next_offset;
757 if (dir_data_length < 105) {
758 return NT_STATUS_INFO_LENGTH_MISMATCH;
761 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
762 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
763 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
764 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
765 finfo->mode = CVAL(dir_data + 56, 0);
766 namelen = IVAL(dir_data + 60,0);
767 if (namelen > (dir_data_length - 104)) {
768 return NT_STATUS_INFO_LENGTH_MISMATCH;
770 slen = CVAL(dir_data + 68, 0);
772 return NT_STATUS_INFO_LENGTH_MISMATCH;
774 ret = pull_string_talloc(finfo,
776 FLAGS2_UNICODE_STRINGS,
781 if (ret == (size_t)-1) {
782 /* Bad conversion. */
783 return NT_STATUS_INVALID_NETWORK_RESPONSE;
786 ret = pull_string_talloc(finfo,
788 FLAGS2_UNICODE_STRINGS,
793 if (ret == (size_t)-1) {
794 /* Bad conversion. */
795 return NT_STATUS_INVALID_NETWORK_RESPONSE;
800 /*******************************************************************
801 Given a filename - get its directory name
802 ********************************************************************/
804 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
812 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
815 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
826 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
829 (*parent)[len] = '\0';
837 /***************************************************************
838 Wrapper that allows SMB2 to list a directory.
840 ***************************************************************/
842 NTSTATUS cli_smb2_list(struct cli_state *cli,
843 const char *pathname,
845 NTSTATUS (*fn)(const char *,
852 uint16_t fnum = 0xffff;
853 char *parent_dir = NULL;
854 const char *mask = NULL;
855 struct smb2_hnd *ph = NULL;
856 bool processed_file = false;
857 TALLOC_CTX *frame = talloc_stackframe();
858 TALLOC_CTX *subframe = NULL;
861 if (smbXcli_conn_has_async_calls(cli->conn)) {
863 * Can't use sync call while an async call is in flight
865 status = NT_STATUS_INVALID_PARAMETER;
869 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
870 status = NT_STATUS_INVALID_PARAMETER;
874 /* Get the directory name. */
875 if (!windows_parent_dirname(frame,
879 status = NT_STATUS_NO_MEMORY;
883 mask_has_wild = ms_has_wild(mask);
885 status = cli_smb2_create_fnum(cli,
887 0, /* create_flags */
888 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
889 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
890 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
891 FILE_OPEN, /* create_disposition */
892 FILE_DIRECTORY_FILE, /* create_options */
896 if (!NT_STATUS_IS_OK(status)) {
900 status = map_fnum_to_smb2_handle(cli,
903 if (!NT_STATUS_IS_OK(status)) {
908 uint8_t *dir_data = NULL;
909 uint32_t dir_data_length = 0;
910 uint32_t next_offset = 0;
911 subframe = talloc_stackframe();
913 status = smb2cli_query_directory(cli->conn,
917 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
928 if (!NT_STATUS_IS_OK(status)) {
929 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
936 struct file_info *finfo = talloc_zero(subframe,
940 status = NT_STATUS_NO_MEMORY;
944 status = parse_finfo_id_both_directory_info(dir_data,
949 if (!NT_STATUS_IS_OK(status)) {
953 if (dir_check_ftype((uint32_t)finfo->mode,
954 (uint32_t)attribute)) {
956 * Only process if attributes match.
957 * On SMB1 server does this, so on
958 * SMB2 we need to emulate in the
961 * https://bugzilla.samba.org/show_bug.cgi?id=10260
963 processed_file = true;
965 status = fn(cli->dfs_mountpoint,
970 if (!NT_STATUS_IS_OK(status)) {
977 /* Move to next entry. */
979 dir_data += next_offset;
980 dir_data_length -= next_offset;
982 } while (next_offset != 0);
984 TALLOC_FREE(subframe);
986 if (!mask_has_wild) {
988 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
989 * when handed a non-wildcard path. Do it
990 * for the server (with a non-wildcard path
991 * there should only ever be one file returned.
993 status = STATUS_NO_MORE_FILES;
997 } while (NT_STATUS_IS_OK(status));
999 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1000 status = NT_STATUS_OK;
1003 if (NT_STATUS_IS_OK(status) && !processed_file) {
1005 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1006 * if no files match. Emulate this in the client.
1008 status = NT_STATUS_NO_SUCH_FILE;
1013 if (fnum != 0xffff) {
1014 cli_smb2_close_fnum(cli, fnum);
1017 cli->raw_status = status;
1019 TALLOC_FREE(subframe);
1024 /***************************************************************
1025 Wrapper that allows SMB2 to query a path info (basic level).
1027 ***************************************************************/
1029 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1031 SMB_STRUCT_STAT *sbuf,
1032 uint32_t *attributes)
1035 struct smb_create_returns cr;
1036 uint16_t fnum = 0xffff;
1037 size_t namelen = strlen(name);
1039 if (smbXcli_conn_has_async_calls(cli->conn)) {
1041 * Can't use sync call while an async call is in flight
1043 return NT_STATUS_INVALID_PARAMETER;
1046 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1047 return NT_STATUS_INVALID_PARAMETER;
1050 /* SMB2 is pickier about pathnames. Ensure it doesn't
1052 if (namelen > 0 && name[namelen-1] == '\\') {
1053 char *modname = talloc_strdup(talloc_tos(), name);
1054 modname[namelen-1] = '\0';
1058 /* This is commonly used as a 'cd'. Try qpathinfo on
1059 a directory handle first. */
1061 status = cli_smb2_create_fnum(cli,
1063 0, /* create_flags */
1064 FILE_READ_ATTRIBUTES, /* desired_access */
1065 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1066 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1067 FILE_OPEN, /* create_disposition */
1068 FILE_DIRECTORY_FILE, /* create_options */
1072 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1073 /* Maybe a file ? */
1074 status = cli_smb2_create_fnum(cli,
1076 0, /* create_flags */
1077 FILE_READ_ATTRIBUTES, /* desired_access */
1078 0, /* file attributes */
1079 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1080 FILE_OPEN, /* create_disposition */
1081 0, /* create_options */
1086 if (!NT_STATUS_IS_OK(status)) {
1090 status = cli_smb2_close_fnum(cli, fnum);
1094 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1095 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1096 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1097 sbuf->st_ex_size = cr.end_of_file;
1098 *attributes = cr.file_attributes;
1103 /***************************************************************
1104 Wrapper that allows SMB2 to check if a path is a directory.
1106 ***************************************************************/
1108 NTSTATUS cli_smb2_chkpath(struct cli_state *cli,
1112 uint16_t fnum = 0xffff;
1114 if (smbXcli_conn_has_async_calls(cli->conn)) {
1116 * Can't use sync call while an async call is in flight
1118 return NT_STATUS_INVALID_PARAMETER;
1121 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1122 return NT_STATUS_INVALID_PARAMETER;
1125 /* Ensure this is a directory. */
1126 status = cli_smb2_create_fnum(cli,
1128 0, /* create_flags */
1129 FILE_READ_ATTRIBUTES, /* desired_access */
1130 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1131 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1132 FILE_OPEN, /* create_disposition */
1133 FILE_DIRECTORY_FILE, /* create_options */
1137 if (!NT_STATUS_IS_OK(status)) {
1141 return cli_smb2_close_fnum(cli, fnum);
1144 /***************************************************************
1145 Helper function for pathname operations.
1146 ***************************************************************/
1148 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1150 uint32_t desired_access,
1154 size_t namelen = strlen(name);
1155 TALLOC_CTX *frame = talloc_stackframe();
1157 /* SMB2 is pickier about pathnames. Ensure it doesn't
1159 if (namelen > 0 && name[namelen-1] == '\\') {
1160 char *modname = talloc_strdup(frame, name);
1161 if (modname == NULL) {
1162 status = NT_STATUS_NO_MEMORY;
1165 modname[namelen-1] = '\0';
1169 /* Try to open a file handle first. */
1170 status = cli_smb2_create_fnum(cli,
1172 0, /* create_flags */
1174 0, /* file attributes */
1175 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1176 FILE_OPEN, /* create_disposition */
1177 0, /* create_options */
1181 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1182 status = cli_smb2_create_fnum(cli,
1184 0, /* create_flags */
1186 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1187 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1188 FILE_OPEN, /* create_disposition */
1189 FILE_DIRECTORY_FILE, /* create_options */
1200 /***************************************************************
1201 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1203 ***************************************************************/
1205 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1210 DATA_BLOB outbuf = data_blob_null;
1211 uint16_t fnum = 0xffff;
1212 struct smb2_hnd *ph = NULL;
1213 uint32_t altnamelen = 0;
1214 TALLOC_CTX *frame = talloc_stackframe();
1216 if (smbXcli_conn_has_async_calls(cli->conn)) {
1218 * Can't use sync call while an async call is in flight
1220 status = NT_STATUS_INVALID_PARAMETER;
1224 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1225 status = NT_STATUS_INVALID_PARAMETER;
1229 status = get_fnum_from_path(cli,
1231 FILE_READ_ATTRIBUTES,
1234 if (!NT_STATUS_IS_OK(status)) {
1238 status = map_fnum_to_smb2_handle(cli,
1241 if (!NT_STATUS_IS_OK(status)) {
1245 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1246 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1248 status = smb2cli_query_info(cli->conn,
1252 1, /* in_info_type */
1253 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1254 0xFFFF, /* in_max_output_length */
1255 NULL, /* in_input_buffer */
1256 0, /* in_additional_info */
1263 if (!NT_STATUS_IS_OK(status)) {
1267 /* Parse the reply. */
1268 if (outbuf.length < 4) {
1269 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1273 altnamelen = IVAL(outbuf.data, 0);
1274 if (altnamelen > outbuf.length - 4) {
1275 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1279 if (altnamelen > 0) {
1281 char *short_name = NULL;
1282 ret = pull_string_talloc(frame,
1284 FLAGS2_UNICODE_STRINGS,
1289 if (ret == (size_t)-1) {
1290 /* Bad conversion. */
1291 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1295 fstrcpy(alt_name, short_name);
1300 status = NT_STATUS_OK;
1304 if (fnum != 0xffff) {
1305 cli_smb2_close_fnum(cli, fnum);
1308 cli->raw_status = status;
1315 /***************************************************************
1316 Wrapper that allows SMB2 to query a fnum info (basic level).
1318 ***************************************************************/
1320 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1324 struct timespec *create_time,
1325 struct timespec *access_time,
1326 struct timespec *write_time,
1327 struct timespec *change_time,
1331 DATA_BLOB outbuf = data_blob_null;
1332 struct smb2_hnd *ph = NULL;
1333 TALLOC_CTX *frame = talloc_stackframe();
1335 if (smbXcli_conn_has_async_calls(cli->conn)) {
1337 * Can't use sync call while an async call is in flight
1339 status = NT_STATUS_INVALID_PARAMETER;
1343 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1344 status = NT_STATUS_INVALID_PARAMETER;
1348 status = map_fnum_to_smb2_handle(cli,
1351 if (!NT_STATUS_IS_OK(status)) {
1355 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1356 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1358 status = smb2cli_query_info(cli->conn,
1362 1, /* in_info_type */
1363 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1364 0xFFFF, /* in_max_output_length */
1365 NULL, /* in_input_buffer */
1366 0, /* in_additional_info */
1372 if (!NT_STATUS_IS_OK(status)) {
1376 /* Parse the reply. */
1377 if (outbuf.length < 0x60) {
1378 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1383 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1386 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1389 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1392 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1395 uint32_t attr = IVAL(outbuf.data, 0x20);
1396 *mode = (uint16_t)attr;
1399 uint64_t file_size = BVAL(outbuf.data, 0x30);
1400 *size = (off_t)file_size;
1403 uint64_t file_index = BVAL(outbuf.data, 0x40);
1404 *ino = (SMB_INO_T)file_index;
1409 cli->raw_status = status;
1415 /***************************************************************
1416 Wrapper that allows SMB2 to query an fnum.
1417 Implement on top of cli_smb2_qfileinfo_basic().
1419 ***************************************************************/
1421 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1425 time_t *change_time,
1426 time_t *access_time,
1429 struct timespec access_time_ts;
1430 struct timespec write_time_ts;
1431 struct timespec change_time_ts;
1432 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1442 cli->raw_status = status;
1444 if (!NT_STATUS_IS_OK(status)) {
1449 *change_time = change_time_ts.tv_sec;
1452 *access_time = access_time_ts.tv_sec;
1455 *write_time = write_time_ts.tv_sec;
1457 return NT_STATUS_OK;
1460 /***************************************************************
1461 Wrapper that allows SMB2 to get pathname attributes.
1463 ***************************************************************/
1465 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1472 uint16_t fnum = 0xffff;
1473 struct smb2_hnd *ph = NULL;
1474 TALLOC_CTX *frame = talloc_stackframe();
1476 if (smbXcli_conn_has_async_calls(cli->conn)) {
1478 * Can't use sync call while an async call is in flight
1480 status = NT_STATUS_INVALID_PARAMETER;
1484 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1485 status = NT_STATUS_INVALID_PARAMETER;
1489 status = get_fnum_from_path(cli,
1491 FILE_READ_ATTRIBUTES,
1494 if (!NT_STATUS_IS_OK(status)) {
1498 status = map_fnum_to_smb2_handle(cli,
1501 if (!NT_STATUS_IS_OK(status)) {
1504 status = cli_smb2_getattrE(cli,
1511 if (!NT_STATUS_IS_OK(status)) {
1517 if (fnum != 0xffff) {
1518 cli_smb2_close_fnum(cli, fnum);
1521 cli->raw_status = status;
1527 /***************************************************************
1528 Wrapper that allows SMB2 to query a pathname info (basic level).
1529 Implement on top of cli_smb2_qfileinfo_basic().
1531 ***************************************************************/
1533 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1535 struct timespec *create_time,
1536 struct timespec *access_time,
1537 struct timespec *write_time,
1538 struct timespec *change_time,
1544 struct smb2_hnd *ph = NULL;
1545 uint16_t fnum = 0xffff;
1546 TALLOC_CTX *frame = talloc_stackframe();
1548 if (smbXcli_conn_has_async_calls(cli->conn)) {
1550 * Can't use sync call while an async call is in flight
1552 status = NT_STATUS_INVALID_PARAMETER;
1556 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1557 status = NT_STATUS_INVALID_PARAMETER;
1561 status = get_fnum_from_path(cli,
1563 FILE_READ_ATTRIBUTES,
1566 if (!NT_STATUS_IS_OK(status)) {
1570 status = map_fnum_to_smb2_handle(cli,
1573 if (!NT_STATUS_IS_OK(status)) {
1577 status = cli_smb2_qfileinfo_basic(cli,
1589 if (fnum != 0xffff) {
1590 cli_smb2_close_fnum(cli, fnum);
1593 cli->raw_status = status;
1599 /***************************************************************
1600 Wrapper that allows SMB2 to query pathname streams.
1602 ***************************************************************/
1604 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1606 TALLOC_CTX *mem_ctx,
1607 unsigned int *pnum_streams,
1608 struct stream_struct **pstreams)
1611 struct smb2_hnd *ph = NULL;
1612 uint16_t fnum = 0xffff;
1613 DATA_BLOB outbuf = data_blob_null;
1614 TALLOC_CTX *frame = talloc_stackframe();
1616 if (smbXcli_conn_has_async_calls(cli->conn)) {
1618 * Can't use sync call while an async call is in flight
1620 status = NT_STATUS_INVALID_PARAMETER;
1624 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1625 status = NT_STATUS_INVALID_PARAMETER;
1629 status = get_fnum_from_path(cli,
1631 FILE_READ_ATTRIBUTES,
1634 if (!NT_STATUS_IS_OK(status)) {
1638 status = map_fnum_to_smb2_handle(cli,
1641 if (!NT_STATUS_IS_OK(status)) {
1645 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1646 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1648 status = smb2cli_query_info(cli->conn,
1652 1, /* in_info_type */
1653 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1654 0xFFFF, /* in_max_output_length */
1655 NULL, /* in_input_buffer */
1656 0, /* in_additional_info */
1663 if (!NT_STATUS_IS_OK(status)) {
1667 /* Parse the reply. */
1668 if (!parse_streams_blob(mem_ctx,
1673 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1679 if (fnum != 0xffff) {
1680 cli_smb2_close_fnum(cli, fnum);
1683 cli->raw_status = status;
1689 /***************************************************************
1690 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
1693 ***************************************************************/
1695 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
1697 uint8_t in_info_type,
1698 uint8_t in_file_info_class,
1699 const DATA_BLOB *p_in_data)
1702 uint16_t fnum = 0xffff;
1703 struct smb2_hnd *ph = NULL;
1704 TALLOC_CTX *frame = talloc_stackframe();
1706 if (smbXcli_conn_has_async_calls(cli->conn)) {
1708 * Can't use sync call while an async call is in flight
1710 status = NT_STATUS_INVALID_PARAMETER;
1714 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1715 status = NT_STATUS_INVALID_PARAMETER;
1719 status = get_fnum_from_path(cli,
1721 FILE_WRITE_ATTRIBUTES,
1724 if (!NT_STATUS_IS_OK(status)) {
1728 status = map_fnum_to_smb2_handle(cli,
1731 if (!NT_STATUS_IS_OK(status)) {
1735 status = smb2cli_set_info(cli->conn,
1741 p_in_data, /* in_input_buffer */
1742 0, /* in_additional_info */
1747 if (fnum != 0xffff) {
1748 cli_smb2_close_fnum(cli, fnum);
1751 cli->raw_status = status;
1758 /***************************************************************
1759 Wrapper that allows SMB2 to set pathname attributes.
1761 ***************************************************************/
1763 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1768 uint8_t inbuf_store[40];
1769 DATA_BLOB inbuf = data_blob_null;
1771 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1772 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1774 inbuf.data = inbuf_store;
1775 inbuf.length = sizeof(inbuf_store);
1776 data_blob_clear(&inbuf);
1779 * SMB1 uses attr == 0 to clear all attributes
1780 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
1781 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
1782 * request attribute change.
1784 * SMB2 uses exactly the reverse. Unfortunately as the
1785 * cli_setatr() ABI is exposed inside libsmbclient,
1786 * we must make the SMB2 cli_smb2_setatr() call
1787 * export the same ABI as the SMB1 cli_setatr()
1788 * which calls it. This means reversing the sense
1789 * of the requested attr argument if it's zero
1790 * or FILE_ATTRIBUTE_NORMAL.
1792 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
1796 attr = FILE_ATTRIBUTE_NORMAL;
1797 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
1801 SSVAL(inbuf.data, 32, attr);
1803 put_long_date((char *)inbuf.data + 16,mtime);
1805 /* Set all the other times to -1. */
1806 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1807 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1808 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1810 return cli_smb2_setpathinfo(cli,
1812 1, /* in_info_type */
1813 /* in_file_info_class */
1814 SMB_FILE_BASIC_INFORMATION - 1000,
1819 /***************************************************************
1820 Wrapper that allows SMB2 to set file handle times.
1822 ***************************************************************/
1824 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1831 struct smb2_hnd *ph = NULL;
1832 uint8_t inbuf_store[40];
1833 DATA_BLOB inbuf = data_blob_null;
1835 if (smbXcli_conn_has_async_calls(cli->conn)) {
1837 * Can't use sync call while an async call is in flight
1839 return NT_STATUS_INVALID_PARAMETER;
1842 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1843 return NT_STATUS_INVALID_PARAMETER;
1846 status = map_fnum_to_smb2_handle(cli,
1849 if (!NT_STATUS_IS_OK(status)) {
1853 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1854 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1856 inbuf.data = inbuf_store;
1857 inbuf.length = sizeof(inbuf_store);
1858 data_blob_clear(&inbuf);
1860 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1861 if (change_time != 0) {
1862 put_long_date((char *)inbuf.data + 24, change_time);
1864 if (access_time != 0) {
1865 put_long_date((char *)inbuf.data + 8, access_time);
1867 if (write_time != 0) {
1868 put_long_date((char *)inbuf.data + 16, write_time);
1871 cli->raw_status = smb2cli_set_info(cli->conn,
1875 1, /* in_info_type */
1876 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1877 &inbuf, /* in_input_buffer */
1878 0, /* in_additional_info */
1882 return cli->raw_status;
1885 /***************************************************************
1886 Wrapper that allows SMB2 to query disk attributes (size).
1888 ***************************************************************/
1890 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
1891 uint64_t *bsize, uint64_t *total, uint64_t *avail)
1894 uint16_t fnum = 0xffff;
1895 DATA_BLOB outbuf = data_blob_null;
1896 struct smb2_hnd *ph = NULL;
1897 uint32_t sectors_per_unit = 0;
1898 uint32_t bytes_per_sector = 0;
1899 uint64_t total_size = 0;
1900 uint64_t size_free = 0;
1901 TALLOC_CTX *frame = talloc_stackframe();
1903 if (smbXcli_conn_has_async_calls(cli->conn)) {
1905 * Can't use sync call while an async call is in flight
1907 status = NT_STATUS_INVALID_PARAMETER;
1911 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1912 status = NT_STATUS_INVALID_PARAMETER;
1916 /* First open the top level directory. */
1917 status = cli_smb2_create_fnum(cli,
1919 0, /* create_flags */
1920 FILE_READ_ATTRIBUTES, /* desired_access */
1921 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1922 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1923 FILE_OPEN, /* create_disposition */
1924 FILE_DIRECTORY_FILE, /* create_options */
1928 if (!NT_STATUS_IS_OK(status)) {
1932 status = map_fnum_to_smb2_handle(cli,
1935 if (!NT_STATUS_IS_OK(status)) {
1939 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1940 level 3 (SMB_FS_SIZE_INFORMATION). */
1942 status = smb2cli_query_info(cli->conn,
1946 2, /* in_info_type */
1947 3, /* in_file_info_class */
1948 0xFFFF, /* in_max_output_length */
1949 NULL, /* in_input_buffer */
1950 0, /* in_additional_info */
1956 if (!NT_STATUS_IS_OK(status)) {
1960 /* Parse the reply. */
1961 if (outbuf.length != 24) {
1962 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1966 total_size = BVAL(outbuf.data, 0);
1967 size_free = BVAL(outbuf.data, 8);
1968 sectors_per_unit = IVAL(outbuf.data, 16);
1969 bytes_per_sector = IVAL(outbuf.data, 20);
1972 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
1975 *total = total_size;
1981 status = NT_STATUS_OK;
1985 if (fnum != 0xffff) {
1986 cli_smb2_close_fnum(cli, fnum);
1989 cli->raw_status = status;
1995 /***************************************************************
1996 Wrapper that allows SMB2 to query file system attributes.
1998 ***************************************************************/
2000 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2003 uint16_t fnum = 0xffff;
2004 DATA_BLOB outbuf = data_blob_null;
2005 struct smb2_hnd *ph = NULL;
2006 TALLOC_CTX *frame = talloc_stackframe();
2008 if (smbXcli_conn_has_async_calls(cli->conn)) {
2010 * Can't use sync call while an async call is in flight
2012 status = NT_STATUS_INVALID_PARAMETER;
2016 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2017 status = NT_STATUS_INVALID_PARAMETER;
2021 /* First open the top level directory. */
2023 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2024 FILE_READ_ATTRIBUTES, /* desired_access */
2025 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2026 FILE_SHARE_READ | FILE_SHARE_WRITE |
2027 FILE_SHARE_DELETE, /* share_access */
2028 FILE_OPEN, /* create_disposition */
2029 FILE_DIRECTORY_FILE, /* create_options */
2033 if (!NT_STATUS_IS_OK(status)) {
2037 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2038 if (!NT_STATUS_IS_OK(status)) {
2042 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2043 cli->smb2.tcon, 2, /* in_info_type */
2044 5, /* in_file_info_class */
2045 0xFFFF, /* in_max_output_length */
2046 NULL, /* in_input_buffer */
2047 0, /* in_additional_info */
2049 ph->fid_persistent, ph->fid_volatile, frame,
2051 if (!NT_STATUS_IS_OK(status)) {
2055 if (outbuf.length < 12) {
2056 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2060 *fs_attr = IVAL(outbuf.data, 0);
2064 if (fnum != 0xffff) {
2065 cli_smb2_close_fnum(cli, fnum);
2068 cli->raw_status = status;
2074 /***************************************************************
2075 Wrapper that allows SMB2 to query a security descriptor.
2077 ***************************************************************/
2079 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2082 TALLOC_CTX *mem_ctx,
2083 struct security_descriptor **ppsd)
2086 DATA_BLOB outbuf = data_blob_null;
2087 struct smb2_hnd *ph = NULL;
2088 struct security_descriptor *lsd = NULL;
2089 TALLOC_CTX *frame = talloc_stackframe();
2091 if (smbXcli_conn_has_async_calls(cli->conn)) {
2093 * Can't use sync call while an async call is in flight
2095 status = NT_STATUS_INVALID_PARAMETER;
2099 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2100 status = NT_STATUS_INVALID_PARAMETER;
2104 status = map_fnum_to_smb2_handle(cli,
2107 if (!NT_STATUS_IS_OK(status)) {
2111 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2113 status = smb2cli_query_info(cli->conn,
2117 3, /* in_info_type */
2118 0, /* in_file_info_class */
2119 0xFFFF, /* in_max_output_length */
2120 NULL, /* in_input_buffer */
2121 sec_info, /* in_additional_info */
2128 if (!NT_STATUS_IS_OK(status)) {
2132 /* Parse the reply. */
2133 status = unmarshall_sec_desc(mem_ctx,
2138 if (!NT_STATUS_IS_OK(status)) {
2150 cli->raw_status = status;
2156 /***************************************************************
2157 Wrapper that allows SMB2 to set a security descriptor.
2159 ***************************************************************/
2161 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
2164 const struct security_descriptor *sd)
2167 DATA_BLOB inbuf = data_blob_null;
2168 struct smb2_hnd *ph = NULL;
2169 TALLOC_CTX *frame = talloc_stackframe();
2171 if (smbXcli_conn_has_async_calls(cli->conn)) {
2173 * Can't use sync call while an async call is in flight
2175 status = NT_STATUS_INVALID_PARAMETER;
2179 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2180 status = NT_STATUS_INVALID_PARAMETER;
2184 status = map_fnum_to_smb2_handle(cli,
2187 if (!NT_STATUS_IS_OK(status)) {
2191 status = marshall_sec_desc(frame,
2196 if (!NT_STATUS_IS_OK(status)) {
2200 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2202 status = smb2cli_set_info(cli->conn,
2206 3, /* in_info_type */
2207 0, /* in_file_info_class */
2208 &inbuf, /* in_input_buffer */
2209 sec_info, /* in_additional_info */
2215 cli->raw_status = status;
2221 /***************************************************************
2222 Wrapper that allows SMB2 to rename a file.
2224 ***************************************************************/
2226 NTSTATUS cli_smb2_rename(struct cli_state *cli,
2227 const char *fname_src,
2228 const char *fname_dst,
2232 DATA_BLOB inbuf = data_blob_null;
2233 uint16_t fnum = 0xffff;
2234 struct smb2_hnd *ph = NULL;
2235 smb_ucs2_t *converted_str = NULL;
2236 size_t converted_size_bytes = 0;
2238 TALLOC_CTX *frame = talloc_stackframe();
2240 if (smbXcli_conn_has_async_calls(cli->conn)) {
2242 * Can't use sync call while an async call is in flight
2244 status = NT_STATUS_INVALID_PARAMETER;
2248 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2249 status = NT_STATUS_INVALID_PARAMETER;
2253 status = get_fnum_from_path(cli,
2258 if (!NT_STATUS_IS_OK(status)) {
2262 status = map_fnum_to_smb2_handle(cli,
2265 if (!NT_STATUS_IS_OK(status)) {
2269 /* SMB2 is pickier about pathnames. Ensure it doesn't
2271 if (*fname_dst == '\\') {
2275 /* SMB2 is pickier about pathnames. Ensure it doesn't
2277 namelen = strlen(fname_dst);
2278 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2279 char *modname = talloc_strdup(frame, fname_dst);
2280 modname[namelen-1] = '\0';
2281 fname_dst = modname;
2284 if (!push_ucs2_talloc(frame,
2287 &converted_size_bytes)) {
2288 status = NT_STATUS_INVALID_PARAMETER;
2292 /* W2K8 insists the dest name is not null
2293 terminated. Remove the last 2 zero bytes
2294 and reduce the name length. */
2296 if (converted_size_bytes < 2) {
2297 status = NT_STATUS_INVALID_PARAMETER;
2300 converted_size_bytes -= 2;
2302 inbuf = data_blob_talloc_zero(frame,
2303 20 + converted_size_bytes);
2304 if (inbuf.data == NULL) {
2305 status = NT_STATUS_NO_MEMORY;
2310 SCVAL(inbuf.data, 0, 1);
2313 SIVAL(inbuf.data, 16, converted_size_bytes);
2314 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2316 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2317 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2319 status = smb2cli_set_info(cli->conn,
2323 1, /* in_info_type */
2324 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2325 &inbuf, /* in_input_buffer */
2326 0, /* in_additional_info */
2332 if (fnum != 0xffff) {
2333 cli_smb2_close_fnum(cli, fnum);
2336 cli->raw_status = status;
2342 /***************************************************************
2343 Wrapper that allows SMB2 to set an EA on a fnum.
2345 ***************************************************************/
2347 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2349 const char *ea_name,
2354 DATA_BLOB inbuf = data_blob_null;
2356 char *ea_name_ascii = NULL;
2358 struct smb2_hnd *ph = NULL;
2359 TALLOC_CTX *frame = talloc_stackframe();
2361 if (smbXcli_conn_has_async_calls(cli->conn)) {
2363 * Can't use sync call while an async call is in flight
2365 status = NT_STATUS_INVALID_PARAMETER;
2369 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2370 status = NT_STATUS_INVALID_PARAMETER;
2374 status = map_fnum_to_smb2_handle(cli,
2377 if (!NT_STATUS_IS_OK(status)) {
2381 /* Marshall the SMB2 EA data. */
2382 if (ea_len > 0xFFFF) {
2383 status = NT_STATUS_INVALID_PARAMETER;
2387 if (!push_ascii_talloc(frame,
2391 status = NT_STATUS_INVALID_PARAMETER;
2395 if (namelen < 2 || namelen > 0xFF) {
2396 status = NT_STATUS_INVALID_PARAMETER;
2400 bloblen = 8 + ea_len + namelen;
2401 /* Round up to a 4 byte boundary. */
2402 bloblen = ((bloblen + 3)&~3);
2404 inbuf = data_blob_talloc_zero(frame, bloblen);
2405 if (inbuf.data == NULL) {
2406 status = NT_STATUS_NO_MEMORY;
2409 /* namelen doesn't include the NULL byte. */
2410 SCVAL(inbuf.data, 5, namelen - 1);
2411 SSVAL(inbuf.data, 6, ea_len);
2412 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2413 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2415 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2416 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2418 status = smb2cli_set_info(cli->conn,
2422 1, /* in_info_type */
2423 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2424 &inbuf, /* in_input_buffer */
2425 0, /* in_additional_info */
2431 cli->raw_status = status;
2437 /***************************************************************
2438 Wrapper that allows SMB2 to set an EA on a pathname.
2440 ***************************************************************/
2442 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2444 const char *ea_name,
2449 uint16_t fnum = 0xffff;
2451 if (smbXcli_conn_has_async_calls(cli->conn)) {
2453 * Can't use sync call while an async call is in flight
2455 status = NT_STATUS_INVALID_PARAMETER;
2459 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2460 status = NT_STATUS_INVALID_PARAMETER;
2464 status = get_fnum_from_path(cli,
2469 if (!NT_STATUS_IS_OK(status)) {
2473 status = cli_set_ea_fnum(cli,
2478 if (!NT_STATUS_IS_OK(status)) {
2484 if (fnum != 0xffff) {
2485 cli_smb2_close_fnum(cli, fnum);
2488 cli->raw_status = status;
2493 /***************************************************************
2494 Wrapper that allows SMB2 to get an EA list on a pathname.
2496 ***************************************************************/
2498 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2502 struct ea_struct **pea_array)
2505 uint16_t fnum = 0xffff;
2506 DATA_BLOB outbuf = data_blob_null;
2507 struct smb2_hnd *ph = NULL;
2508 struct ea_list *ea_list = NULL;
2509 struct ea_list *eal = NULL;
2510 size_t ea_count = 0;
2511 TALLOC_CTX *frame = talloc_stackframe();
2516 if (smbXcli_conn_has_async_calls(cli->conn)) {
2518 * Can't use sync call while an async call is in flight
2520 status = NT_STATUS_INVALID_PARAMETER;
2524 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2525 status = NT_STATUS_INVALID_PARAMETER;
2529 status = get_fnum_from_path(cli,
2534 if (!NT_STATUS_IS_OK(status)) {
2538 status = map_fnum_to_smb2_handle(cli,
2541 if (!NT_STATUS_IS_OK(status)) {
2545 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2546 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2548 status = smb2cli_query_info(cli->conn,
2552 1, /* in_info_type */
2553 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2554 0xFFFF, /* in_max_output_length */
2555 NULL, /* in_input_buffer */
2556 0, /* in_additional_info */
2563 if (!NT_STATUS_IS_OK(status)) {
2567 /* Parse the reply. */
2568 ea_list = read_nttrans_ea_list(ctx,
2569 (const char *)outbuf.data,
2571 if (ea_list == NULL) {
2572 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2576 /* Convert to an array. */
2577 for (eal = ea_list; eal; eal = eal->next) {
2582 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2583 if (*pea_array == NULL) {
2584 status = NT_STATUS_NO_MEMORY;
2588 for (eal = ea_list; eal; eal = eal->next) {
2589 (*pea_array)[ea_count++] = eal->ea;
2591 *pnum_eas = ea_count;
2596 if (fnum != 0xffff) {
2597 cli_smb2_close_fnum(cli, fnum);
2600 cli->raw_status = status;
2606 /***************************************************************
2607 Wrapper that allows SMB2 to get user quota.
2609 ***************************************************************/
2611 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
2613 SMB_NTQUOTA_STRUCT *pqt)
2616 DATA_BLOB inbuf = data_blob_null;
2617 DATA_BLOB outbuf = data_blob_null;
2618 struct smb2_hnd *ph = NULL;
2619 TALLOC_CTX *frame = talloc_stackframe();
2621 unsigned int offset;
2624 if (smbXcli_conn_has_async_calls(cli->conn)) {
2626 * Can't use sync call while an async call is in flight
2628 status = NT_STATUS_INVALID_PARAMETER;
2632 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2633 status = NT_STATUS_INVALID_PARAMETER;
2637 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2638 if (!NT_STATUS_IS_OK(status)) {
2642 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
2644 inbuf = data_blob_talloc_zero(frame, 24 + sid_len);
2645 if (inbuf.data == NULL) {
2646 status = NT_STATUS_NO_MEMORY;
2652 SCVAL(buf, 0, 1); /* ReturnSingle */
2653 SCVAL(buf, 1, 0); /* RestartScan */
2654 SSVAL(buf, 2, 0); /* Reserved */
2655 if (8 + sid_len < 8) {
2656 status = NT_STATUS_INVALID_PARAMETER;
2659 SIVAL(buf, 4, 8 + sid_len); /* SidListLength */
2660 SIVAL(buf, 8, 0); /* StartSidLength */
2661 SIVAL(buf, 12, 0); /* StartSidOffset */
2662 SIVAL(buf, 16, 0); /* NextEntryOffset */
2663 SIVAL(buf, 20, sid_len); /* SidLength */
2664 sid_linearize(buf + 24, sid_len, &pqt->sid);
2666 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2667 cli->smb2.tcon, 4, /* in_info_type */
2668 0, /* in_file_info_class */
2669 0xFFFF, /* in_max_output_length */
2670 &inbuf, /* in_input_buffer */
2671 0, /* in_additional_info */
2673 ph->fid_persistent, ph->fid_volatile, frame,
2676 if (!NT_STATUS_IS_OK(status)) {
2680 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
2682 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2683 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
2687 cli->raw_status = status;
2693 /***************************************************************
2694 Wrapper that allows SMB2 to list user quota.
2696 ***************************************************************/
2698 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
2699 TALLOC_CTX *mem_ctx,
2701 SMB_NTQUOTA_LIST **pqt_list,
2705 DATA_BLOB inbuf = data_blob_null;
2706 DATA_BLOB outbuf = data_blob_null;
2707 struct smb2_hnd *ph = NULL;
2708 TALLOC_CTX *frame = talloc_stackframe();
2711 if (smbXcli_conn_has_async_calls(cli->conn)) {
2713 * Can't use sync call while an async call is in flight
2715 status = NT_STATUS_INVALID_PARAMETER;
2719 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2720 status = NT_STATUS_INVALID_PARAMETER;
2724 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2725 if (!NT_STATUS_IS_OK(status)) {
2729 inbuf = data_blob_talloc_zero(frame, 16);
2730 if (inbuf.data == NULL) {
2731 status = NT_STATUS_NO_MEMORY;
2737 SCVAL(buf, 0, 0); /* ReturnSingle */
2738 SCVAL(buf, 1, first ? 1 : 0); /* RestartScan */
2739 SSVAL(buf, 2, 0); /* Reserved */
2740 SIVAL(buf, 4, 0); /* SidListLength */
2741 SIVAL(buf, 8, 0); /* StartSidLength */
2742 SIVAL(buf, 12, 0); /* StartSidOffset */
2744 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2745 cli->smb2.tcon, 4, /* in_info_type */
2746 0, /* in_file_info_class */
2747 0xFFFF, /* in_max_output_length */
2748 &inbuf, /* in_input_buffer */
2749 0, /* in_additional_info */
2751 ph->fid_persistent, ph->fid_volatile, frame,
2754 if (!NT_STATUS_IS_OK(status)) {
2758 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
2762 cli->raw_status = status;
2768 /***************************************************************
2769 Wrapper that allows SMB2 to get file system quota.
2771 ***************************************************************/
2773 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
2775 SMB_NTQUOTA_STRUCT *pqt)
2778 DATA_BLOB outbuf = data_blob_null;
2779 struct smb2_hnd *ph = NULL;
2780 TALLOC_CTX *frame = talloc_stackframe();
2782 if (smbXcli_conn_has_async_calls(cli->conn)) {
2784 * Can't use sync call while an async call is in flight
2786 status = NT_STATUS_INVALID_PARAMETER;
2790 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2791 status = NT_STATUS_INVALID_PARAMETER;
2795 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2796 if (!NT_STATUS_IS_OK(status)) {
2800 status = smb2cli_query_info(
2801 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
2802 2, /* in_info_type */
2803 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
2804 0xFFFF, /* in_max_output_length */
2805 NULL, /* in_input_buffer */
2806 0, /* in_additional_info */
2808 ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
2810 if (!NT_STATUS_IS_OK(status)) {
2814 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
2817 cli->raw_status = status;
2823 /***************************************************************
2824 Wrapper that allows SMB2 to set user quota.
2826 ***************************************************************/
2828 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
2830 SMB_NTQUOTA_LIST *qtl)
2833 DATA_BLOB inbuf = data_blob_null;
2834 struct smb2_hnd *ph = NULL;
2835 TALLOC_CTX *frame = talloc_stackframe();
2837 if (smbXcli_conn_has_async_calls(cli->conn)) {
2839 * Can't use sync call while an async call is in flight
2841 status = NT_STATUS_INVALID_PARAMETER;
2845 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2846 status = NT_STATUS_INVALID_PARAMETER;
2850 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2851 if (!NT_STATUS_IS_OK(status)) {
2855 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
2856 if (!NT_STATUS_IS_OK(status)) {
2860 status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
2861 cli->smb2.tcon, 4, /* in_info_type */
2862 0, /* in_file_info_class */
2863 &inbuf, /* in_input_buffer */
2864 0, /* in_additional_info */
2865 ph->fid_persistent, ph->fid_volatile);
2868 cli->raw_status = status;
2875 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
2877 SMB_NTQUOTA_STRUCT *pqt)
2880 DATA_BLOB inbuf = data_blob_null;
2881 struct smb2_hnd *ph = NULL;
2882 TALLOC_CTX *frame = talloc_stackframe();
2884 if (smbXcli_conn_has_async_calls(cli->conn)) {
2886 * Can't use sync call while an async call is in flight
2888 status = NT_STATUS_INVALID_PARAMETER;
2892 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2893 status = NT_STATUS_INVALID_PARAMETER;
2897 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2898 if (!NT_STATUS_IS_OK(status)) {
2902 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
2903 if (!NT_STATUS_IS_OK(status)) {
2907 status = smb2cli_set_info(
2908 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
2909 2, /* in_info_type */
2910 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
2911 &inbuf, /* in_input_buffer */
2912 0, /* in_additional_info */
2913 ph->fid_persistent, ph->fid_volatile);
2915 cli->raw_status = status;
2921 struct cli_smb2_read_state {
2922 struct tevent_context *ev;
2923 struct cli_state *cli;
2924 struct smb2_hnd *ph;
2925 uint64_t start_offset;
2931 static void cli_smb2_read_done(struct tevent_req *subreq);
2933 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
2934 struct tevent_context *ev,
2935 struct cli_state *cli,
2941 struct tevent_req *req, *subreq;
2942 struct cli_smb2_read_state *state;
2944 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
2950 state->start_offset = (uint64_t)offset;
2951 state->size = (uint32_t)size;
2952 state->received = 0;
2955 status = map_fnum_to_smb2_handle(cli,
2958 if (tevent_req_nterror(req, status)) {
2959 return tevent_req_post(req, ev);
2962 subreq = smb2cli_read_send(state,
2965 state->cli->timeout,
2966 state->cli->smb2.session,
2967 state->cli->smb2.tcon,
2969 state->start_offset,
2970 state->ph->fid_persistent,
2971 state->ph->fid_volatile,
2972 0, /* minimum_count */
2973 0); /* remaining_bytes */
2975 if (tevent_req_nomem(subreq, req)) {
2976 return tevent_req_post(req, ev);
2978 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
2982 static void cli_smb2_read_done(struct tevent_req *subreq)
2984 struct tevent_req *req = tevent_req_callback_data(
2985 subreq, struct tevent_req);
2986 struct cli_smb2_read_state *state = tevent_req_data(
2987 req, struct cli_smb2_read_state);
2990 status = smb2cli_read_recv(subreq, state,
2991 &state->buf, &state->received);
2992 if (tevent_req_nterror(req, status)) {
2996 if (state->received > state->size) {
2997 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3001 tevent_req_done(req);
3004 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
3009 struct cli_smb2_read_state *state = tevent_req_data(
3010 req, struct cli_smb2_read_state);
3012 if (tevent_req_is_nterror(req, &status)) {
3013 state->cli->raw_status = status;
3017 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3018 * better make sure that you copy it away before you talloc_free(req).
3019 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3021 *received = (ssize_t)state->received;
3022 *rcvbuf = state->buf;
3023 state->cli->raw_status = NT_STATUS_OK;
3024 return NT_STATUS_OK;
3027 struct cli_smb2_write_state {
3028 struct tevent_context *ev;
3029 struct cli_state *cli;
3030 struct smb2_hnd *ph;
3038 static void cli_smb2_write_written(struct tevent_req *req);
3040 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
3041 struct tevent_context *ev,
3042 struct cli_state *cli,
3050 struct tevent_req *req, *subreq = NULL;
3051 struct cli_smb2_write_state *state = NULL;
3053 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
3059 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3060 state->flags = (uint32_t)mode;
3062 state->offset = (uint64_t)offset;
3063 state->size = (uint32_t)size;
3066 status = map_fnum_to_smb2_handle(cli,
3069 if (tevent_req_nterror(req, status)) {
3070 return tevent_req_post(req, ev);
3073 subreq = smb2cli_write_send(state,
3076 state->cli->timeout,
3077 state->cli->smb2.session,
3078 state->cli->smb2.tcon,
3081 state->ph->fid_persistent,
3082 state->ph->fid_volatile,
3083 0, /* remaining_bytes */
3084 state->flags, /* flags */
3087 if (tevent_req_nomem(subreq, req)) {
3088 return tevent_req_post(req, ev);
3090 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
3094 static void cli_smb2_write_written(struct tevent_req *subreq)
3096 struct tevent_req *req = tevent_req_callback_data(
3097 subreq, struct tevent_req);
3098 struct cli_smb2_write_state *state = tevent_req_data(
3099 req, struct cli_smb2_write_state);
3103 status = smb2cli_write_recv(subreq, &written);
3104 TALLOC_FREE(subreq);
3105 if (tevent_req_nterror(req, status)) {
3109 state->written = written;
3111 tevent_req_done(req);
3114 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
3117 struct cli_smb2_write_state *state = tevent_req_data(
3118 req, struct cli_smb2_write_state);
3121 if (tevent_req_is_nterror(req, &status)) {
3122 state->cli->raw_status = status;
3123 tevent_req_received(req);
3127 if (pwritten != NULL) {
3128 *pwritten = (size_t)state->written;
3130 state->cli->raw_status = NT_STATUS_OK;
3131 tevent_req_received(req);
3132 return NT_STATUS_OK;
3135 /***************************************************************
3136 Wrapper that allows SMB2 async write using an fnum.
3137 This is mostly cut-and-paste from Volker's code inside
3138 source3/libsmb/clireadwrite.c, adapted for SMB2.
3140 Done this way so I can reuse all the logic inside cli_push()
3142 ***************************************************************/
3144 struct cli_smb2_writeall_state {
3145 struct tevent_context *ev;
3146 struct cli_state *cli;
3147 struct smb2_hnd *ph;
3155 static void cli_smb2_writeall_written(struct tevent_req *req);
3157 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
3158 struct tevent_context *ev,
3159 struct cli_state *cli,
3167 struct tevent_req *req, *subreq = NULL;
3168 struct cli_smb2_writeall_state *state = NULL;
3173 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
3179 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3180 state->flags = (uint32_t)mode;
3182 state->offset = (uint64_t)offset;
3183 state->size = (uint32_t)size;
3186 status = map_fnum_to_smb2_handle(cli,
3189 if (tevent_req_nterror(req, status)) {
3190 return tevent_req_post(req, ev);
3193 to_write = state->size;
3194 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3195 to_write = MIN(max_size, to_write);
3196 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3198 to_write = MIN(max_size, to_write);
3201 subreq = smb2cli_write_send(state,
3204 state->cli->timeout,
3205 state->cli->smb2.session,
3206 state->cli->smb2.tcon,
3209 state->ph->fid_persistent,
3210 state->ph->fid_volatile,
3211 0, /* remaining_bytes */
3212 state->flags, /* flags */
3213 state->buf + state->written);
3215 if (tevent_req_nomem(subreq, req)) {
3216 return tevent_req_post(req, ev);
3218 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3222 static void cli_smb2_writeall_written(struct tevent_req *subreq)
3224 struct tevent_req *req = tevent_req_callback_data(
3225 subreq, struct tevent_req);
3226 struct cli_smb2_writeall_state *state = tevent_req_data(
3227 req, struct cli_smb2_writeall_state);
3229 uint32_t written, to_write;
3233 status = smb2cli_write_recv(subreq, &written);
3234 TALLOC_FREE(subreq);
3235 if (tevent_req_nterror(req, status)) {
3239 state->written += written;
3241 if (state->written > state->size) {
3242 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3246 to_write = state->size - state->written;
3248 if (to_write == 0) {
3249 tevent_req_done(req);
3253 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3254 to_write = MIN(max_size, to_write);
3255 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3257 to_write = MIN(max_size, to_write);
3260 subreq = smb2cli_write_send(state,
3263 state->cli->timeout,
3264 state->cli->smb2.session,
3265 state->cli->smb2.tcon,
3267 state->offset + state->written,
3268 state->ph->fid_persistent,
3269 state->ph->fid_volatile,
3270 0, /* remaining_bytes */
3271 state->flags, /* flags */
3272 state->buf + state->written);
3274 if (tevent_req_nomem(subreq, req)) {
3277 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3280 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
3283 struct cli_smb2_writeall_state *state = tevent_req_data(
3284 req, struct cli_smb2_writeall_state);
3287 if (tevent_req_is_nterror(req, &status)) {
3288 state->cli->raw_status = status;
3291 if (pwritten != NULL) {
3292 *pwritten = (size_t)state->written;
3294 state->cli->raw_status = NT_STATUS_OK;
3295 return NT_STATUS_OK;
3298 struct cli_smb2_splice_state {
3299 struct tevent_context *ev;
3300 struct cli_state *cli;
3301 struct smb2_hnd *src_ph;
3302 struct smb2_hnd *dst_ph;
3303 int (*splice_cb)(off_t n, void *priv);
3310 struct req_resume_key_rsp resume_rsp;
3311 struct srv_copychunk_copy cc_copy;
3314 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3315 struct tevent_req *req);
3317 static void cli_splice_copychunk_done(struct tevent_req *subreq)
3319 struct tevent_req *req = tevent_req_callback_data(
3320 subreq, struct tevent_req);
3321 struct cli_smb2_splice_state *state =
3322 tevent_req_data(req,
3323 struct cli_smb2_splice_state);
3324 struct smbXcli_conn *conn = state->cli->conn;
3325 DATA_BLOB out_input_buffer = data_blob_null;
3326 DATA_BLOB out_output_buffer = data_blob_null;
3327 struct srv_copychunk_rsp cc_copy_rsp;
3328 enum ndr_err_code ndr_ret;
3331 status = smb2cli_ioctl_recv(subreq, state,
3333 &out_output_buffer);
3334 TALLOC_FREE(subreq);
3335 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
3336 state->resized) && tevent_req_nterror(req, status)) {
3340 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
3341 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
3342 if (ndr_ret != NDR_ERR_SUCCESS) {
3343 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3344 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3348 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
3349 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
3350 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
3351 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
3352 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
3353 tevent_req_nterror(req, status)) {
3357 state->resized = true;
3358 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
3359 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
3361 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3362 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3363 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
3364 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3367 state->src_offset += cc_copy_rsp.total_bytes_written;
3368 state->dst_offset += cc_copy_rsp.total_bytes_written;
3369 state->written += cc_copy_rsp.total_bytes_written;
3370 if (!state->splice_cb(state->written, state->priv)) {
3371 tevent_req_nterror(req, NT_STATUS_CANCELLED);
3376 cli_splice_copychunk_send(state, req);
3379 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3380 struct tevent_req *req)
3382 struct tevent_req *subreq;
3383 enum ndr_err_code ndr_ret;
3384 struct smbXcli_conn *conn = state->cli->conn;
3385 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
3386 off_t src_offset = state->src_offset;
3387 off_t dst_offset = state->dst_offset;
3388 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
3389 state->size - state->written);
3390 DATA_BLOB in_input_buffer = data_blob_null;
3391 DATA_BLOB in_output_buffer = data_blob_null;
3393 if (state->size - state->written == 0) {
3394 tevent_req_done(req);
3398 cc_copy->chunk_count = 0;
3400 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
3401 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
3402 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
3403 smb2cli_conn_cc_chunk_len(conn));
3404 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
3405 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3408 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
3409 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
3410 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
3411 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3414 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3415 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3416 cc_copy->chunk_count++;
3419 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
3420 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
3421 if (ndr_ret != NDR_ERR_SUCCESS) {
3422 DEBUG(0, ("failed to marshall copy chunk req\n"));
3423 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3427 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
3428 state->cli->timeout,
3429 state->cli->smb2.session,
3430 state->cli->smb2.tcon,
3431 state->dst_ph->fid_persistent, /* in_fid_persistent */
3432 state->dst_ph->fid_volatile, /* in_fid_volatile */
3433 FSCTL_SRV_COPYCHUNK_WRITE,
3434 0, /* in_max_input_length */
3436 12, /* in_max_output_length */
3438 SMB2_IOCTL_FLAG_IS_FSCTL);
3439 if (tevent_req_nomem(subreq, req)) {
3442 tevent_req_set_callback(subreq,
3443 cli_splice_copychunk_done,
3447 static void cli_splice_key_done(struct tevent_req *subreq)
3449 struct tevent_req *req = tevent_req_callback_data(
3450 subreq, struct tevent_req);
3451 struct cli_smb2_splice_state *state =
3452 tevent_req_data(req,
3453 struct cli_smb2_splice_state);
3454 enum ndr_err_code ndr_ret;
3457 DATA_BLOB out_input_buffer = data_blob_null;
3458 DATA_BLOB out_output_buffer = data_blob_null;
3460 status = smb2cli_ioctl_recv(subreq, state,
3462 &out_output_buffer);
3463 TALLOC_FREE(subreq);
3464 if (tevent_req_nterror(req, status)) {
3468 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
3469 state, &state->resume_rsp,
3470 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
3471 if (ndr_ret != NDR_ERR_SUCCESS) {
3472 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3473 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3477 memcpy(&state->cc_copy.source_key,
3478 &state->resume_rsp.resume_key,
3479 sizeof state->resume_rsp.resume_key);
3481 cli_splice_copychunk_send(state, req);
3484 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
3485 struct tevent_context *ev,
3486 struct cli_state *cli,
3487 uint16_t src_fnum, uint16_t dst_fnum,
3488 off_t size, off_t src_offset, off_t dst_offset,
3489 int (*splice_cb)(off_t n, void *priv),
3492 struct tevent_req *req;
3493 struct tevent_req *subreq;
3494 struct cli_smb2_splice_state *state;
3496 DATA_BLOB in_input_buffer = data_blob_null;
3497 DATA_BLOB in_output_buffer = data_blob_null;
3499 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
3505 state->splice_cb = splice_cb;
3509 state->src_offset = src_offset;
3510 state->dst_offset = dst_offset;
3511 state->cc_copy.chunks = talloc_array(state,
3512 struct srv_copychunk,
3513 smb2cli_conn_cc_max_chunks(cli->conn));
3514 if (state->cc_copy.chunks == NULL) {
3518 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
3519 if (tevent_req_nterror(req, status))
3520 return tevent_req_post(req, ev);
3522 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
3523 if (tevent_req_nterror(req, status))
3524 return tevent_req_post(req, ev);
3526 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
3530 state->src_ph->fid_persistent, /* in_fid_persistent */
3531 state->src_ph->fid_volatile, /* in_fid_volatile */
3532 FSCTL_SRV_REQUEST_RESUME_KEY,
3533 0, /* in_max_input_length */
3535 32, /* in_max_output_length */
3537 SMB2_IOCTL_FLAG_IS_FSCTL);
3538 if (tevent_req_nomem(subreq, req)) {
3541 tevent_req_set_callback(subreq,
3542 cli_splice_key_done,
3548 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
3550 struct cli_smb2_splice_state *state = tevent_req_data(
3551 req, struct cli_smb2_splice_state);
3554 if (tevent_req_is_nterror(req, &status)) {
3555 state->cli->raw_status = status;
3556 tevent_req_received(req);
3559 if (written != NULL) {
3560 *written = state->written;
3562 state->cli->raw_status = NT_STATUS_OK;
3563 tevent_req_received(req);
3564 return NT_STATUS_OK;
3567 /***************************************************************
3568 SMB2 enum shadow copy data.
3569 ***************************************************************/
3571 struct cli_smb2_shadow_copy_data_fnum_state {
3572 struct cli_state *cli;
3574 struct smb2_hnd *ph;
3575 DATA_BLOB out_input_buffer;
3576 DATA_BLOB out_output_buffer;
3579 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
3581 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
3582 TALLOC_CTX *mem_ctx,
3583 struct tevent_context *ev,
3584 struct cli_state *cli,
3588 struct tevent_req *req, *subreq;
3589 struct cli_smb2_shadow_copy_data_fnum_state *state;
3592 req = tevent_req_create(mem_ctx, &state,
3593 struct cli_smb2_shadow_copy_data_fnum_state);
3598 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3599 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3600 return tevent_req_post(req, ev);
3606 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
3607 if (tevent_req_nterror(req, status)) {
3608 return tevent_req_post(req, ev);
3612 * TODO. Under SMB2 we should send a zero max_output_length
3613 * ioctl to get the required size, then send another ioctl
3614 * to get the data, but the current SMB1 implementation just
3615 * does one roundtrip with a 64K buffer size. Do the same
3619 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
3620 state->cli->timeout,
3621 state->cli->smb2.session,
3622 state->cli->smb2.tcon,
3623 state->ph->fid_persistent, /* in_fid_persistent */
3624 state->ph->fid_volatile, /* in_fid_volatile */
3625 FSCTL_GET_SHADOW_COPY_DATA,
3626 0, /* in_max_input_length */
3627 NULL, /* in_input_buffer */
3629 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
3630 NULL, /* in_output_buffer */
3631 SMB2_IOCTL_FLAG_IS_FSCTL);
3633 if (tevent_req_nomem(subreq, req)) {
3634 return tevent_req_post(req, ev);
3636 tevent_req_set_callback(subreq,
3637 cli_smb2_shadow_copy_data_fnum_done,
3643 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
3645 struct tevent_req *req = tevent_req_callback_data(
3646 subreq, struct tevent_req);
3647 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3648 req, struct cli_smb2_shadow_copy_data_fnum_state);
3651 status = smb2cli_ioctl_recv(subreq, state,
3652 &state->out_input_buffer,
3653 &state->out_output_buffer);
3654 TALLOC_FREE(subreq);
3655 if (tevent_req_nterror(req, status)) {
3658 tevent_req_done(req);
3661 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
3662 TALLOC_CTX *mem_ctx,
3667 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3668 req, struct cli_smb2_shadow_copy_data_fnum_state);
3669 char **names = NULL;
3670 uint32_t num_names = 0;
3671 uint32_t num_names_returned = 0;
3672 uint32_t dlength = 0;
3674 uint8_t *endp = NULL;
3677 if (tevent_req_is_nterror(req, &status)) {
3681 if (state->out_output_buffer.length < 16) {
3682 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3685 num_names = IVAL(state->out_output_buffer.data, 0);
3686 num_names_returned = IVAL(state->out_output_buffer.data, 4);
3687 dlength = IVAL(state->out_output_buffer.data, 8);
3689 if (num_names > 0x7FFFFFFF) {
3690 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3693 if (get_names == false) {
3694 *pnum_names = (int)num_names;
3695 return NT_STATUS_OK;
3697 if (num_names != num_names_returned) {
3698 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3700 if (dlength + 12 < 12) {
3701 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3704 * NB. The below is an allowable return if there are
3705 * more snapshots than the buffer size we told the
3706 * server we can receive. We currently don't support
3709 if (dlength + 12 > state->out_output_buffer.length) {
3710 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3712 if (state->out_output_buffer.length +
3713 (2 * sizeof(SHADOW_COPY_LABEL)) <
3714 state->out_output_buffer.length) {
3715 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3718 names = talloc_array(mem_ctx, char *, num_names_returned);
3719 if (names == NULL) {
3720 return NT_STATUS_NO_MEMORY;
3723 endp = state->out_output_buffer.data +
3724 state->out_output_buffer.length;
3726 for (i=0; i<num_names_returned; i++) {
3729 size_t converted_size;
3731 src = state->out_output_buffer.data + 12 +
3732 (i * 2 * sizeof(SHADOW_COPY_LABEL));
3734 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
3735 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3737 ret = convert_string_talloc(
3738 names, CH_UTF16LE, CH_UNIX,
3739 src, 2 * sizeof(SHADOW_COPY_LABEL),
3740 &names[i], &converted_size);
3743 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3746 *pnum_names = num_names;
3748 return NT_STATUS_OK;
3751 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
3752 struct cli_state *cli,
3758 TALLOC_CTX *frame = talloc_stackframe();
3759 struct tevent_context *ev;
3760 struct tevent_req *req;
3761 NTSTATUS status = NT_STATUS_NO_MEMORY;
3763 if (smbXcli_conn_has_async_calls(cli->conn)) {
3765 * Can't use sync call while an async call is in flight
3767 status = NT_STATUS_INVALID_PARAMETER;
3770 ev = samba_tevent_context_init(frame);
3774 req = cli_smb2_shadow_copy_data_fnum_send(frame,
3782 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3785 status = cli_smb2_shadow_copy_data_fnum_recv(req,
3791 cli->raw_status = status;
3797 /***************************************************************
3798 Wrapper that allows SMB2 to truncate a file.
3800 ***************************************************************/
3802 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
3807 DATA_BLOB inbuf = data_blob_null;
3808 struct smb2_hnd *ph = NULL;
3809 TALLOC_CTX *frame = talloc_stackframe();
3811 if (smbXcli_conn_has_async_calls(cli->conn)) {
3813 * Can't use sync call while an async call is in flight
3815 status = NT_STATUS_INVALID_PARAMETER;
3819 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3820 status = NT_STATUS_INVALID_PARAMETER;
3824 status = map_fnum_to_smb2_handle(cli,
3827 if (!NT_STATUS_IS_OK(status)) {
3831 inbuf = data_blob_talloc_zero(frame, 8);
3832 if (inbuf.data == NULL) {
3833 status = NT_STATUS_NO_MEMORY;
3837 SBVAL(inbuf.data, 0, newsize);
3839 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3840 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
3842 status = smb2cli_set_info(cli->conn,
3846 1, /* in_info_type */
3847 /* in_file_info_class */
3848 SMB_FILE_END_OF_FILE_INFORMATION - 1000,
3849 &inbuf, /* in_input_buffer */
3850 0, /* in_additional_info */
3856 cli->raw_status = status;
3862 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
3863 uint32_t buffer_size, uint32_t completion_filter,
3864 bool recursive, TALLOC_CTX *mem_ctx,
3865 struct notify_change **pchanges,
3866 uint32_t *pnum_changes)
3869 struct smb2_hnd *ph = NULL;
3870 TALLOC_CTX *frame = talloc_stackframe();
3873 struct notify_change *changes = NULL;
3874 size_t num_changes = 0;
3876 if (smbXcli_conn_has_async_calls(cli->conn)) {
3878 * Can't use sync call while an async call is in flight
3880 status = NT_STATUS_INVALID_PARAMETER;
3884 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3885 status = NT_STATUS_INVALID_PARAMETER;
3889 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
3890 if (!NT_STATUS_IS_OK(status)) {
3894 status = smb2cli_notify(cli->conn, cli->timeout,
3895 cli->smb2.session, cli->smb2.tcon,
3897 ph->fid_persistent, ph->fid_volatile,
3898 completion_filter, recursive,
3899 frame, &base, &len);
3903 while (len - ofs >= 12) {
3904 struct notify_change *tmp;
3905 struct notify_change *c;
3906 uint32_t next_ofs = IVAL(base, ofs);
3907 uint32_t file_name_length = IVAL(base, ofs+8);
3911 tmp = talloc_realloc(frame, changes, struct notify_change,
3914 status = NT_STATUS_NO_MEMORY;
3918 c = &changes[num_changes];
3921 if (smb_buffer_oob(len, ofs, next_ofs) ||
3922 smb_buffer_oob(len, ofs+12, file_name_length)) {
3923 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3927 c->action = IVAL(base, ofs+4);
3929 ok = convert_string_talloc(changes, CH_UTF16LE, CH_UNIX,
3930 base + ofs + 12, file_name_length,
3931 &c->name, &namelen);
3933 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3937 if (next_ofs == 0) {
3943 *pchanges = talloc_move(mem_ctx, &changes);
3944 *pnum_changes = num_changes;
3945 status = NT_STATUS_OK;
3948 cli->raw_status = status;