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 sizes.
1998 ***************************************************************/
2000 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2001 uint64_t *total_allocation_units,
2002 uint64_t *caller_allocation_units,
2003 uint64_t *actual_allocation_units,
2004 uint64_t *sectors_per_allocation_unit,
2005 uint64_t *bytes_per_sector)
2008 uint16_t fnum = 0xffff;
2009 DATA_BLOB outbuf = data_blob_null;
2010 struct smb2_hnd *ph = NULL;
2011 TALLOC_CTX *frame = talloc_stackframe();
2013 if (smbXcli_conn_has_async_calls(cli->conn)) {
2015 * Can't use sync call while an async call is in flight
2017 status = NT_STATUS_INVALID_PARAMETER;
2021 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2022 status = NT_STATUS_INVALID_PARAMETER;
2026 /* First open the top level directory. */
2028 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2029 FILE_READ_ATTRIBUTES, /* desired_access */
2030 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2031 FILE_SHARE_READ | FILE_SHARE_WRITE |
2032 FILE_SHARE_DELETE, /* share_access */
2033 FILE_OPEN, /* create_disposition */
2034 FILE_DIRECTORY_FILE, /* create_options */
2038 if (!NT_STATUS_IS_OK(status)) {
2042 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2043 if (!NT_STATUS_IS_OK(status)) {
2047 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2048 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2050 status = smb2cli_query_info(cli->conn,
2054 SMB2_GETINFO_FS, /* in_info_type */
2055 /* in_file_info_class */
2056 SMB_FS_FULL_SIZE_INFORMATION - 1000,
2057 0xFFFF, /* in_max_output_length */
2058 NULL, /* in_input_buffer */
2059 0, /* in_additional_info */
2065 if (!NT_STATUS_IS_OK(status)) {
2069 if (outbuf.length < 32) {
2070 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2074 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2075 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2076 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2077 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2078 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2082 if (fnum != 0xffff) {
2083 cli_smb2_close_fnum(cli, fnum);
2086 cli->raw_status = status;
2092 /***************************************************************
2093 Wrapper that allows SMB2 to query file system attributes.
2095 ***************************************************************/
2097 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2100 uint16_t fnum = 0xffff;
2101 DATA_BLOB outbuf = data_blob_null;
2102 struct smb2_hnd *ph = NULL;
2103 TALLOC_CTX *frame = talloc_stackframe();
2105 if (smbXcli_conn_has_async_calls(cli->conn)) {
2107 * Can't use sync call while an async call is in flight
2109 status = NT_STATUS_INVALID_PARAMETER;
2113 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2114 status = NT_STATUS_INVALID_PARAMETER;
2118 /* First open the top level directory. */
2120 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2121 FILE_READ_ATTRIBUTES, /* desired_access */
2122 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2123 FILE_SHARE_READ | FILE_SHARE_WRITE |
2124 FILE_SHARE_DELETE, /* share_access */
2125 FILE_OPEN, /* create_disposition */
2126 FILE_DIRECTORY_FILE, /* create_options */
2130 if (!NT_STATUS_IS_OK(status)) {
2134 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2135 if (!NT_STATUS_IS_OK(status)) {
2139 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2140 cli->smb2.tcon, 2, /* in_info_type */
2141 5, /* in_file_info_class */
2142 0xFFFF, /* in_max_output_length */
2143 NULL, /* in_input_buffer */
2144 0, /* in_additional_info */
2146 ph->fid_persistent, ph->fid_volatile, frame,
2148 if (!NT_STATUS_IS_OK(status)) {
2152 if (outbuf.length < 12) {
2153 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2157 *fs_attr = IVAL(outbuf.data, 0);
2161 if (fnum != 0xffff) {
2162 cli_smb2_close_fnum(cli, fnum);
2165 cli->raw_status = status;
2171 /***************************************************************
2172 Wrapper that allows SMB2 to query a security descriptor.
2174 ***************************************************************/
2176 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2179 TALLOC_CTX *mem_ctx,
2180 struct security_descriptor **ppsd)
2183 DATA_BLOB outbuf = data_blob_null;
2184 struct smb2_hnd *ph = NULL;
2185 struct security_descriptor *lsd = NULL;
2186 TALLOC_CTX *frame = talloc_stackframe();
2188 if (smbXcli_conn_has_async_calls(cli->conn)) {
2190 * Can't use sync call while an async call is in flight
2192 status = NT_STATUS_INVALID_PARAMETER;
2196 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2197 status = NT_STATUS_INVALID_PARAMETER;
2201 status = map_fnum_to_smb2_handle(cli,
2204 if (!NT_STATUS_IS_OK(status)) {
2208 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2210 status = smb2cli_query_info(cli->conn,
2214 3, /* in_info_type */
2215 0, /* in_file_info_class */
2216 0xFFFF, /* in_max_output_length */
2217 NULL, /* in_input_buffer */
2218 sec_info, /* in_additional_info */
2225 if (!NT_STATUS_IS_OK(status)) {
2229 /* Parse the reply. */
2230 status = unmarshall_sec_desc(mem_ctx,
2235 if (!NT_STATUS_IS_OK(status)) {
2247 cli->raw_status = status;
2253 /***************************************************************
2254 Wrapper that allows SMB2 to set a security descriptor.
2256 ***************************************************************/
2258 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
2261 const struct security_descriptor *sd)
2264 DATA_BLOB inbuf = data_blob_null;
2265 struct smb2_hnd *ph = NULL;
2266 TALLOC_CTX *frame = talloc_stackframe();
2268 if (smbXcli_conn_has_async_calls(cli->conn)) {
2270 * Can't use sync call while an async call is in flight
2272 status = NT_STATUS_INVALID_PARAMETER;
2276 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2277 status = NT_STATUS_INVALID_PARAMETER;
2281 status = map_fnum_to_smb2_handle(cli,
2284 if (!NT_STATUS_IS_OK(status)) {
2288 status = marshall_sec_desc(frame,
2293 if (!NT_STATUS_IS_OK(status)) {
2297 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2299 status = smb2cli_set_info(cli->conn,
2303 3, /* in_info_type */
2304 0, /* in_file_info_class */
2305 &inbuf, /* in_input_buffer */
2306 sec_info, /* in_additional_info */
2312 cli->raw_status = status;
2318 /***************************************************************
2319 Wrapper that allows SMB2 to rename a file.
2321 ***************************************************************/
2323 NTSTATUS cli_smb2_rename(struct cli_state *cli,
2324 const char *fname_src,
2325 const char *fname_dst,
2329 DATA_BLOB inbuf = data_blob_null;
2330 uint16_t fnum = 0xffff;
2331 struct smb2_hnd *ph = NULL;
2332 smb_ucs2_t *converted_str = NULL;
2333 size_t converted_size_bytes = 0;
2335 TALLOC_CTX *frame = talloc_stackframe();
2337 if (smbXcli_conn_has_async_calls(cli->conn)) {
2339 * Can't use sync call while an async call is in flight
2341 status = NT_STATUS_INVALID_PARAMETER;
2345 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2346 status = NT_STATUS_INVALID_PARAMETER;
2350 status = get_fnum_from_path(cli,
2355 if (!NT_STATUS_IS_OK(status)) {
2359 status = map_fnum_to_smb2_handle(cli,
2362 if (!NT_STATUS_IS_OK(status)) {
2366 /* SMB2 is pickier about pathnames. Ensure it doesn't
2368 if (*fname_dst == '\\') {
2372 /* SMB2 is pickier about pathnames. Ensure it doesn't
2374 namelen = strlen(fname_dst);
2375 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2376 char *modname = talloc_strdup(frame, fname_dst);
2377 modname[namelen-1] = '\0';
2378 fname_dst = modname;
2381 if (!push_ucs2_talloc(frame,
2384 &converted_size_bytes)) {
2385 status = NT_STATUS_INVALID_PARAMETER;
2389 /* W2K8 insists the dest name is not null
2390 terminated. Remove the last 2 zero bytes
2391 and reduce the name length. */
2393 if (converted_size_bytes < 2) {
2394 status = NT_STATUS_INVALID_PARAMETER;
2397 converted_size_bytes -= 2;
2399 inbuf = data_blob_talloc_zero(frame,
2400 20 + converted_size_bytes);
2401 if (inbuf.data == NULL) {
2402 status = NT_STATUS_NO_MEMORY;
2407 SCVAL(inbuf.data, 0, 1);
2410 SIVAL(inbuf.data, 16, converted_size_bytes);
2411 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2413 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2414 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2416 status = smb2cli_set_info(cli->conn,
2420 1, /* in_info_type */
2421 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2422 &inbuf, /* in_input_buffer */
2423 0, /* in_additional_info */
2429 if (fnum != 0xffff) {
2430 cli_smb2_close_fnum(cli, fnum);
2433 cli->raw_status = status;
2439 /***************************************************************
2440 Wrapper that allows SMB2 to set an EA on a fnum.
2442 ***************************************************************/
2444 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2446 const char *ea_name,
2451 DATA_BLOB inbuf = data_blob_null;
2453 char *ea_name_ascii = NULL;
2455 struct smb2_hnd *ph = NULL;
2456 TALLOC_CTX *frame = talloc_stackframe();
2458 if (smbXcli_conn_has_async_calls(cli->conn)) {
2460 * Can't use sync call while an async call is in flight
2462 status = NT_STATUS_INVALID_PARAMETER;
2466 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2467 status = NT_STATUS_INVALID_PARAMETER;
2471 status = map_fnum_to_smb2_handle(cli,
2474 if (!NT_STATUS_IS_OK(status)) {
2478 /* Marshall the SMB2 EA data. */
2479 if (ea_len > 0xFFFF) {
2480 status = NT_STATUS_INVALID_PARAMETER;
2484 if (!push_ascii_talloc(frame,
2488 status = NT_STATUS_INVALID_PARAMETER;
2492 if (namelen < 2 || namelen > 0xFF) {
2493 status = NT_STATUS_INVALID_PARAMETER;
2497 bloblen = 8 + ea_len + namelen;
2498 /* Round up to a 4 byte boundary. */
2499 bloblen = ((bloblen + 3)&~3);
2501 inbuf = data_blob_talloc_zero(frame, bloblen);
2502 if (inbuf.data == NULL) {
2503 status = NT_STATUS_NO_MEMORY;
2506 /* namelen doesn't include the NULL byte. */
2507 SCVAL(inbuf.data, 5, namelen - 1);
2508 SSVAL(inbuf.data, 6, ea_len);
2509 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2510 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2512 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2513 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2515 status = smb2cli_set_info(cli->conn,
2519 1, /* in_info_type */
2520 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2521 &inbuf, /* in_input_buffer */
2522 0, /* in_additional_info */
2528 cli->raw_status = status;
2534 /***************************************************************
2535 Wrapper that allows SMB2 to set an EA on a pathname.
2537 ***************************************************************/
2539 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2541 const char *ea_name,
2546 uint16_t fnum = 0xffff;
2548 if (smbXcli_conn_has_async_calls(cli->conn)) {
2550 * Can't use sync call while an async call is in flight
2552 status = NT_STATUS_INVALID_PARAMETER;
2556 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2557 status = NT_STATUS_INVALID_PARAMETER;
2561 status = get_fnum_from_path(cli,
2566 if (!NT_STATUS_IS_OK(status)) {
2570 status = cli_set_ea_fnum(cli,
2575 if (!NT_STATUS_IS_OK(status)) {
2581 if (fnum != 0xffff) {
2582 cli_smb2_close_fnum(cli, fnum);
2585 cli->raw_status = status;
2590 /***************************************************************
2591 Wrapper that allows SMB2 to get an EA list on a pathname.
2593 ***************************************************************/
2595 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2599 struct ea_struct **pea_array)
2602 uint16_t fnum = 0xffff;
2603 DATA_BLOB outbuf = data_blob_null;
2604 struct smb2_hnd *ph = NULL;
2605 struct ea_list *ea_list = NULL;
2606 struct ea_list *eal = NULL;
2607 size_t ea_count = 0;
2608 TALLOC_CTX *frame = talloc_stackframe();
2613 if (smbXcli_conn_has_async_calls(cli->conn)) {
2615 * Can't use sync call while an async call is in flight
2617 status = NT_STATUS_INVALID_PARAMETER;
2621 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2622 status = NT_STATUS_INVALID_PARAMETER;
2626 status = get_fnum_from_path(cli,
2631 if (!NT_STATUS_IS_OK(status)) {
2635 status = map_fnum_to_smb2_handle(cli,
2638 if (!NT_STATUS_IS_OK(status)) {
2642 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2643 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2645 status = smb2cli_query_info(cli->conn,
2649 1, /* in_info_type */
2650 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2651 0xFFFF, /* in_max_output_length */
2652 NULL, /* in_input_buffer */
2653 0, /* in_additional_info */
2660 if (!NT_STATUS_IS_OK(status)) {
2664 /* Parse the reply. */
2665 ea_list = read_nttrans_ea_list(ctx,
2666 (const char *)outbuf.data,
2668 if (ea_list == NULL) {
2669 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2673 /* Convert to an array. */
2674 for (eal = ea_list; eal; eal = eal->next) {
2679 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2680 if (*pea_array == NULL) {
2681 status = NT_STATUS_NO_MEMORY;
2685 for (eal = ea_list; eal; eal = eal->next) {
2686 (*pea_array)[ea_count++] = eal->ea;
2688 *pnum_eas = ea_count;
2693 if (fnum != 0xffff) {
2694 cli_smb2_close_fnum(cli, fnum);
2697 cli->raw_status = status;
2703 /***************************************************************
2704 Wrapper that allows SMB2 to get user quota.
2706 ***************************************************************/
2708 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
2710 SMB_NTQUOTA_STRUCT *pqt)
2713 DATA_BLOB inbuf = data_blob_null;
2714 DATA_BLOB outbuf = data_blob_null;
2715 struct smb2_hnd *ph = NULL;
2716 TALLOC_CTX *frame = talloc_stackframe();
2718 unsigned int offset;
2721 if (smbXcli_conn_has_async_calls(cli->conn)) {
2723 * Can't use sync call while an async call is in flight
2725 status = NT_STATUS_INVALID_PARAMETER;
2729 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2730 status = NT_STATUS_INVALID_PARAMETER;
2734 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2735 if (!NT_STATUS_IS_OK(status)) {
2739 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
2741 inbuf = data_blob_talloc_zero(frame, 24 + sid_len);
2742 if (inbuf.data == NULL) {
2743 status = NT_STATUS_NO_MEMORY;
2749 SCVAL(buf, 0, 1); /* ReturnSingle */
2750 SCVAL(buf, 1, 0); /* RestartScan */
2751 SSVAL(buf, 2, 0); /* Reserved */
2752 if (8 + sid_len < 8) {
2753 status = NT_STATUS_INVALID_PARAMETER;
2756 SIVAL(buf, 4, 8 + sid_len); /* SidListLength */
2757 SIVAL(buf, 8, 0); /* StartSidLength */
2758 SIVAL(buf, 12, 0); /* StartSidOffset */
2759 SIVAL(buf, 16, 0); /* NextEntryOffset */
2760 SIVAL(buf, 20, sid_len); /* SidLength */
2761 sid_linearize(buf + 24, sid_len, &pqt->sid);
2763 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2764 cli->smb2.tcon, 4, /* in_info_type */
2765 0, /* in_file_info_class */
2766 0xFFFF, /* in_max_output_length */
2767 &inbuf, /* in_input_buffer */
2768 0, /* in_additional_info */
2770 ph->fid_persistent, ph->fid_volatile, frame,
2773 if (!NT_STATUS_IS_OK(status)) {
2777 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
2779 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2780 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
2784 cli->raw_status = status;
2790 /***************************************************************
2791 Wrapper that allows SMB2 to list user quota.
2793 ***************************************************************/
2795 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
2796 TALLOC_CTX *mem_ctx,
2798 SMB_NTQUOTA_LIST **pqt_list,
2802 DATA_BLOB inbuf = data_blob_null;
2803 DATA_BLOB outbuf = data_blob_null;
2804 struct smb2_hnd *ph = NULL;
2805 TALLOC_CTX *frame = talloc_stackframe();
2808 if (smbXcli_conn_has_async_calls(cli->conn)) {
2810 * Can't use sync call while an async call is in flight
2812 status = NT_STATUS_INVALID_PARAMETER;
2816 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2817 status = NT_STATUS_INVALID_PARAMETER;
2821 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2822 if (!NT_STATUS_IS_OK(status)) {
2826 inbuf = data_blob_talloc_zero(frame, 16);
2827 if (inbuf.data == NULL) {
2828 status = NT_STATUS_NO_MEMORY;
2834 SCVAL(buf, 0, 0); /* ReturnSingle */
2835 SCVAL(buf, 1, first ? 1 : 0); /* RestartScan */
2836 SSVAL(buf, 2, 0); /* Reserved */
2837 SIVAL(buf, 4, 0); /* SidListLength */
2838 SIVAL(buf, 8, 0); /* StartSidLength */
2839 SIVAL(buf, 12, 0); /* StartSidOffset */
2841 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2842 cli->smb2.tcon, 4, /* in_info_type */
2843 0, /* in_file_info_class */
2844 0xFFFF, /* in_max_output_length */
2845 &inbuf, /* in_input_buffer */
2846 0, /* in_additional_info */
2848 ph->fid_persistent, ph->fid_volatile, frame,
2851 if (!NT_STATUS_IS_OK(status)) {
2855 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
2859 cli->raw_status = status;
2865 /***************************************************************
2866 Wrapper that allows SMB2 to get file system quota.
2868 ***************************************************************/
2870 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
2872 SMB_NTQUOTA_STRUCT *pqt)
2875 DATA_BLOB outbuf = data_blob_null;
2876 struct smb2_hnd *ph = NULL;
2877 TALLOC_CTX *frame = talloc_stackframe();
2879 if (smbXcli_conn_has_async_calls(cli->conn)) {
2881 * Can't use sync call while an async call is in flight
2883 status = NT_STATUS_INVALID_PARAMETER;
2887 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2888 status = NT_STATUS_INVALID_PARAMETER;
2892 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2893 if (!NT_STATUS_IS_OK(status)) {
2897 status = smb2cli_query_info(
2898 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
2899 2, /* in_info_type */
2900 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
2901 0xFFFF, /* in_max_output_length */
2902 NULL, /* in_input_buffer */
2903 0, /* in_additional_info */
2905 ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
2907 if (!NT_STATUS_IS_OK(status)) {
2911 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
2914 cli->raw_status = status;
2920 /***************************************************************
2921 Wrapper that allows SMB2 to set user quota.
2923 ***************************************************************/
2925 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
2927 SMB_NTQUOTA_LIST *qtl)
2930 DATA_BLOB inbuf = data_blob_null;
2931 struct smb2_hnd *ph = NULL;
2932 TALLOC_CTX *frame = talloc_stackframe();
2934 if (smbXcli_conn_has_async_calls(cli->conn)) {
2936 * Can't use sync call while an async call is in flight
2938 status = NT_STATUS_INVALID_PARAMETER;
2942 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2943 status = NT_STATUS_INVALID_PARAMETER;
2947 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2948 if (!NT_STATUS_IS_OK(status)) {
2952 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
2953 if (!NT_STATUS_IS_OK(status)) {
2957 status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
2958 cli->smb2.tcon, 4, /* in_info_type */
2959 0, /* in_file_info_class */
2960 &inbuf, /* in_input_buffer */
2961 0, /* in_additional_info */
2962 ph->fid_persistent, ph->fid_volatile);
2965 cli->raw_status = status;
2972 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
2974 SMB_NTQUOTA_STRUCT *pqt)
2977 DATA_BLOB inbuf = data_blob_null;
2978 struct smb2_hnd *ph = NULL;
2979 TALLOC_CTX *frame = talloc_stackframe();
2981 if (smbXcli_conn_has_async_calls(cli->conn)) {
2983 * Can't use sync call while an async call is in flight
2985 status = NT_STATUS_INVALID_PARAMETER;
2989 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2990 status = NT_STATUS_INVALID_PARAMETER;
2994 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2995 if (!NT_STATUS_IS_OK(status)) {
2999 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3000 if (!NT_STATUS_IS_OK(status)) {
3004 status = smb2cli_set_info(
3005 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3006 2, /* in_info_type */
3007 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3008 &inbuf, /* in_input_buffer */
3009 0, /* in_additional_info */
3010 ph->fid_persistent, ph->fid_volatile);
3012 cli->raw_status = status;
3018 struct cli_smb2_read_state {
3019 struct tevent_context *ev;
3020 struct cli_state *cli;
3021 struct smb2_hnd *ph;
3022 uint64_t start_offset;
3028 static void cli_smb2_read_done(struct tevent_req *subreq);
3030 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3031 struct tevent_context *ev,
3032 struct cli_state *cli,
3038 struct tevent_req *req, *subreq;
3039 struct cli_smb2_read_state *state;
3041 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3047 state->start_offset = (uint64_t)offset;
3048 state->size = (uint32_t)size;
3049 state->received = 0;
3052 status = map_fnum_to_smb2_handle(cli,
3055 if (tevent_req_nterror(req, status)) {
3056 return tevent_req_post(req, ev);
3059 subreq = smb2cli_read_send(state,
3062 state->cli->timeout,
3063 state->cli->smb2.session,
3064 state->cli->smb2.tcon,
3066 state->start_offset,
3067 state->ph->fid_persistent,
3068 state->ph->fid_volatile,
3069 0, /* minimum_count */
3070 0); /* remaining_bytes */
3072 if (tevent_req_nomem(subreq, req)) {
3073 return tevent_req_post(req, ev);
3075 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3079 static void cli_smb2_read_done(struct tevent_req *subreq)
3081 struct tevent_req *req = tevent_req_callback_data(
3082 subreq, struct tevent_req);
3083 struct cli_smb2_read_state *state = tevent_req_data(
3084 req, struct cli_smb2_read_state);
3087 status = smb2cli_read_recv(subreq, state,
3088 &state->buf, &state->received);
3089 if (tevent_req_nterror(req, status)) {
3093 if (state->received > state->size) {
3094 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3098 tevent_req_done(req);
3101 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
3106 struct cli_smb2_read_state *state = tevent_req_data(
3107 req, struct cli_smb2_read_state);
3109 if (tevent_req_is_nterror(req, &status)) {
3110 state->cli->raw_status = status;
3114 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3115 * better make sure that you copy it away before you talloc_free(req).
3116 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3118 *received = (ssize_t)state->received;
3119 *rcvbuf = state->buf;
3120 state->cli->raw_status = NT_STATUS_OK;
3121 return NT_STATUS_OK;
3124 struct cli_smb2_write_state {
3125 struct tevent_context *ev;
3126 struct cli_state *cli;
3127 struct smb2_hnd *ph;
3135 static void cli_smb2_write_written(struct tevent_req *req);
3137 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
3138 struct tevent_context *ev,
3139 struct cli_state *cli,
3147 struct tevent_req *req, *subreq = NULL;
3148 struct cli_smb2_write_state *state = NULL;
3150 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
3156 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3157 state->flags = (uint32_t)mode;
3159 state->offset = (uint64_t)offset;
3160 state->size = (uint32_t)size;
3163 status = map_fnum_to_smb2_handle(cli,
3166 if (tevent_req_nterror(req, status)) {
3167 return tevent_req_post(req, ev);
3170 subreq = smb2cli_write_send(state,
3173 state->cli->timeout,
3174 state->cli->smb2.session,
3175 state->cli->smb2.tcon,
3178 state->ph->fid_persistent,
3179 state->ph->fid_volatile,
3180 0, /* remaining_bytes */
3181 state->flags, /* flags */
3184 if (tevent_req_nomem(subreq, req)) {
3185 return tevent_req_post(req, ev);
3187 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
3191 static void cli_smb2_write_written(struct tevent_req *subreq)
3193 struct tevent_req *req = tevent_req_callback_data(
3194 subreq, struct tevent_req);
3195 struct cli_smb2_write_state *state = tevent_req_data(
3196 req, struct cli_smb2_write_state);
3200 status = smb2cli_write_recv(subreq, &written);
3201 TALLOC_FREE(subreq);
3202 if (tevent_req_nterror(req, status)) {
3206 state->written = written;
3208 tevent_req_done(req);
3211 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
3214 struct cli_smb2_write_state *state = tevent_req_data(
3215 req, struct cli_smb2_write_state);
3218 if (tevent_req_is_nterror(req, &status)) {
3219 state->cli->raw_status = status;
3220 tevent_req_received(req);
3224 if (pwritten != NULL) {
3225 *pwritten = (size_t)state->written;
3227 state->cli->raw_status = NT_STATUS_OK;
3228 tevent_req_received(req);
3229 return NT_STATUS_OK;
3232 /***************************************************************
3233 Wrapper that allows SMB2 async write using an fnum.
3234 This is mostly cut-and-paste from Volker's code inside
3235 source3/libsmb/clireadwrite.c, adapted for SMB2.
3237 Done this way so I can reuse all the logic inside cli_push()
3239 ***************************************************************/
3241 struct cli_smb2_writeall_state {
3242 struct tevent_context *ev;
3243 struct cli_state *cli;
3244 struct smb2_hnd *ph;
3252 static void cli_smb2_writeall_written(struct tevent_req *req);
3254 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
3255 struct tevent_context *ev,
3256 struct cli_state *cli,
3264 struct tevent_req *req, *subreq = NULL;
3265 struct cli_smb2_writeall_state *state = NULL;
3270 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
3276 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3277 state->flags = (uint32_t)mode;
3279 state->offset = (uint64_t)offset;
3280 state->size = (uint32_t)size;
3283 status = map_fnum_to_smb2_handle(cli,
3286 if (tevent_req_nterror(req, status)) {
3287 return tevent_req_post(req, ev);
3290 to_write = state->size;
3291 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3292 to_write = MIN(max_size, to_write);
3293 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3295 to_write = MIN(max_size, to_write);
3298 subreq = smb2cli_write_send(state,
3301 state->cli->timeout,
3302 state->cli->smb2.session,
3303 state->cli->smb2.tcon,
3306 state->ph->fid_persistent,
3307 state->ph->fid_volatile,
3308 0, /* remaining_bytes */
3309 state->flags, /* flags */
3310 state->buf + state->written);
3312 if (tevent_req_nomem(subreq, req)) {
3313 return tevent_req_post(req, ev);
3315 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3319 static void cli_smb2_writeall_written(struct tevent_req *subreq)
3321 struct tevent_req *req = tevent_req_callback_data(
3322 subreq, struct tevent_req);
3323 struct cli_smb2_writeall_state *state = tevent_req_data(
3324 req, struct cli_smb2_writeall_state);
3326 uint32_t written, to_write;
3330 status = smb2cli_write_recv(subreq, &written);
3331 TALLOC_FREE(subreq);
3332 if (tevent_req_nterror(req, status)) {
3336 state->written += written;
3338 if (state->written > state->size) {
3339 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3343 to_write = state->size - state->written;
3345 if (to_write == 0) {
3346 tevent_req_done(req);
3350 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3351 to_write = MIN(max_size, to_write);
3352 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3354 to_write = MIN(max_size, to_write);
3357 subreq = smb2cli_write_send(state,
3360 state->cli->timeout,
3361 state->cli->smb2.session,
3362 state->cli->smb2.tcon,
3364 state->offset + state->written,
3365 state->ph->fid_persistent,
3366 state->ph->fid_volatile,
3367 0, /* remaining_bytes */
3368 state->flags, /* flags */
3369 state->buf + state->written);
3371 if (tevent_req_nomem(subreq, req)) {
3374 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3377 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
3380 struct cli_smb2_writeall_state *state = tevent_req_data(
3381 req, struct cli_smb2_writeall_state);
3384 if (tevent_req_is_nterror(req, &status)) {
3385 state->cli->raw_status = status;
3388 if (pwritten != NULL) {
3389 *pwritten = (size_t)state->written;
3391 state->cli->raw_status = NT_STATUS_OK;
3392 return NT_STATUS_OK;
3395 struct cli_smb2_splice_state {
3396 struct tevent_context *ev;
3397 struct cli_state *cli;
3398 struct smb2_hnd *src_ph;
3399 struct smb2_hnd *dst_ph;
3400 int (*splice_cb)(off_t n, void *priv);
3407 struct req_resume_key_rsp resume_rsp;
3408 struct srv_copychunk_copy cc_copy;
3411 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3412 struct tevent_req *req);
3414 static void cli_splice_copychunk_done(struct tevent_req *subreq)
3416 struct tevent_req *req = tevent_req_callback_data(
3417 subreq, struct tevent_req);
3418 struct cli_smb2_splice_state *state =
3419 tevent_req_data(req,
3420 struct cli_smb2_splice_state);
3421 struct smbXcli_conn *conn = state->cli->conn;
3422 DATA_BLOB out_input_buffer = data_blob_null;
3423 DATA_BLOB out_output_buffer = data_blob_null;
3424 struct srv_copychunk_rsp cc_copy_rsp;
3425 enum ndr_err_code ndr_ret;
3428 status = smb2cli_ioctl_recv(subreq, state,
3430 &out_output_buffer);
3431 TALLOC_FREE(subreq);
3432 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
3433 state->resized) && tevent_req_nterror(req, status)) {
3437 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
3438 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
3439 if (ndr_ret != NDR_ERR_SUCCESS) {
3440 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3441 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3445 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
3446 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
3447 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
3448 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
3449 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
3450 tevent_req_nterror(req, status)) {
3454 state->resized = true;
3455 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
3456 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
3458 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3459 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3460 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
3461 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3464 state->src_offset += cc_copy_rsp.total_bytes_written;
3465 state->dst_offset += cc_copy_rsp.total_bytes_written;
3466 state->written += cc_copy_rsp.total_bytes_written;
3467 if (!state->splice_cb(state->written, state->priv)) {
3468 tevent_req_nterror(req, NT_STATUS_CANCELLED);
3473 cli_splice_copychunk_send(state, req);
3476 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3477 struct tevent_req *req)
3479 struct tevent_req *subreq;
3480 enum ndr_err_code ndr_ret;
3481 struct smbXcli_conn *conn = state->cli->conn;
3482 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
3483 off_t src_offset = state->src_offset;
3484 off_t dst_offset = state->dst_offset;
3485 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
3486 state->size - state->written);
3487 DATA_BLOB in_input_buffer = data_blob_null;
3488 DATA_BLOB in_output_buffer = data_blob_null;
3490 if (state->size - state->written == 0) {
3491 tevent_req_done(req);
3495 cc_copy->chunk_count = 0;
3497 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
3498 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
3499 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
3500 smb2cli_conn_cc_chunk_len(conn));
3501 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
3502 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3505 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
3506 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
3507 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
3508 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3511 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3512 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3513 cc_copy->chunk_count++;
3516 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
3517 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
3518 if (ndr_ret != NDR_ERR_SUCCESS) {
3519 DEBUG(0, ("failed to marshall copy chunk req\n"));
3520 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3524 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
3525 state->cli->timeout,
3526 state->cli->smb2.session,
3527 state->cli->smb2.tcon,
3528 state->dst_ph->fid_persistent, /* in_fid_persistent */
3529 state->dst_ph->fid_volatile, /* in_fid_volatile */
3530 FSCTL_SRV_COPYCHUNK_WRITE,
3531 0, /* in_max_input_length */
3533 12, /* in_max_output_length */
3535 SMB2_IOCTL_FLAG_IS_FSCTL);
3536 if (tevent_req_nomem(subreq, req)) {
3539 tevent_req_set_callback(subreq,
3540 cli_splice_copychunk_done,
3544 static void cli_splice_key_done(struct tevent_req *subreq)
3546 struct tevent_req *req = tevent_req_callback_data(
3547 subreq, struct tevent_req);
3548 struct cli_smb2_splice_state *state =
3549 tevent_req_data(req,
3550 struct cli_smb2_splice_state);
3551 enum ndr_err_code ndr_ret;
3554 DATA_BLOB out_input_buffer = data_blob_null;
3555 DATA_BLOB out_output_buffer = data_blob_null;
3557 status = smb2cli_ioctl_recv(subreq, state,
3559 &out_output_buffer);
3560 TALLOC_FREE(subreq);
3561 if (tevent_req_nterror(req, status)) {
3565 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
3566 state, &state->resume_rsp,
3567 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
3568 if (ndr_ret != NDR_ERR_SUCCESS) {
3569 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3570 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3574 memcpy(&state->cc_copy.source_key,
3575 &state->resume_rsp.resume_key,
3576 sizeof state->resume_rsp.resume_key);
3578 cli_splice_copychunk_send(state, req);
3581 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
3582 struct tevent_context *ev,
3583 struct cli_state *cli,
3584 uint16_t src_fnum, uint16_t dst_fnum,
3585 off_t size, off_t src_offset, off_t dst_offset,
3586 int (*splice_cb)(off_t n, void *priv),
3589 struct tevent_req *req;
3590 struct tevent_req *subreq;
3591 struct cli_smb2_splice_state *state;
3593 DATA_BLOB in_input_buffer = data_blob_null;
3594 DATA_BLOB in_output_buffer = data_blob_null;
3596 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
3602 state->splice_cb = splice_cb;
3606 state->src_offset = src_offset;
3607 state->dst_offset = dst_offset;
3608 state->cc_copy.chunks = talloc_array(state,
3609 struct srv_copychunk,
3610 smb2cli_conn_cc_max_chunks(cli->conn));
3611 if (state->cc_copy.chunks == NULL) {
3615 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
3616 if (tevent_req_nterror(req, status))
3617 return tevent_req_post(req, ev);
3619 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
3620 if (tevent_req_nterror(req, status))
3621 return tevent_req_post(req, ev);
3623 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
3627 state->src_ph->fid_persistent, /* in_fid_persistent */
3628 state->src_ph->fid_volatile, /* in_fid_volatile */
3629 FSCTL_SRV_REQUEST_RESUME_KEY,
3630 0, /* in_max_input_length */
3632 32, /* in_max_output_length */
3634 SMB2_IOCTL_FLAG_IS_FSCTL);
3635 if (tevent_req_nomem(subreq, req)) {
3638 tevent_req_set_callback(subreq,
3639 cli_splice_key_done,
3645 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
3647 struct cli_smb2_splice_state *state = tevent_req_data(
3648 req, struct cli_smb2_splice_state);
3651 if (tevent_req_is_nterror(req, &status)) {
3652 state->cli->raw_status = status;
3653 tevent_req_received(req);
3656 if (written != NULL) {
3657 *written = state->written;
3659 state->cli->raw_status = NT_STATUS_OK;
3660 tevent_req_received(req);
3661 return NT_STATUS_OK;
3664 /***************************************************************
3665 SMB2 enum shadow copy data.
3666 ***************************************************************/
3668 struct cli_smb2_shadow_copy_data_fnum_state {
3669 struct cli_state *cli;
3671 struct smb2_hnd *ph;
3672 DATA_BLOB out_input_buffer;
3673 DATA_BLOB out_output_buffer;
3676 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
3678 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
3679 TALLOC_CTX *mem_ctx,
3680 struct tevent_context *ev,
3681 struct cli_state *cli,
3685 struct tevent_req *req, *subreq;
3686 struct cli_smb2_shadow_copy_data_fnum_state *state;
3689 req = tevent_req_create(mem_ctx, &state,
3690 struct cli_smb2_shadow_copy_data_fnum_state);
3695 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3696 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3697 return tevent_req_post(req, ev);
3703 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
3704 if (tevent_req_nterror(req, status)) {
3705 return tevent_req_post(req, ev);
3709 * TODO. Under SMB2 we should send a zero max_output_length
3710 * ioctl to get the required size, then send another ioctl
3711 * to get the data, but the current SMB1 implementation just
3712 * does one roundtrip with a 64K buffer size. Do the same
3716 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
3717 state->cli->timeout,
3718 state->cli->smb2.session,
3719 state->cli->smb2.tcon,
3720 state->ph->fid_persistent, /* in_fid_persistent */
3721 state->ph->fid_volatile, /* in_fid_volatile */
3722 FSCTL_GET_SHADOW_COPY_DATA,
3723 0, /* in_max_input_length */
3724 NULL, /* in_input_buffer */
3726 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
3727 NULL, /* in_output_buffer */
3728 SMB2_IOCTL_FLAG_IS_FSCTL);
3730 if (tevent_req_nomem(subreq, req)) {
3731 return tevent_req_post(req, ev);
3733 tevent_req_set_callback(subreq,
3734 cli_smb2_shadow_copy_data_fnum_done,
3740 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
3742 struct tevent_req *req = tevent_req_callback_data(
3743 subreq, struct tevent_req);
3744 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3745 req, struct cli_smb2_shadow_copy_data_fnum_state);
3748 status = smb2cli_ioctl_recv(subreq, state,
3749 &state->out_input_buffer,
3750 &state->out_output_buffer);
3751 TALLOC_FREE(subreq);
3752 if (tevent_req_nterror(req, status)) {
3755 tevent_req_done(req);
3758 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
3759 TALLOC_CTX *mem_ctx,
3764 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3765 req, struct cli_smb2_shadow_copy_data_fnum_state);
3766 char **names = NULL;
3767 uint32_t num_names = 0;
3768 uint32_t num_names_returned = 0;
3769 uint32_t dlength = 0;
3771 uint8_t *endp = NULL;
3774 if (tevent_req_is_nterror(req, &status)) {
3778 if (state->out_output_buffer.length < 16) {
3779 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3782 num_names = IVAL(state->out_output_buffer.data, 0);
3783 num_names_returned = IVAL(state->out_output_buffer.data, 4);
3784 dlength = IVAL(state->out_output_buffer.data, 8);
3786 if (num_names > 0x7FFFFFFF) {
3787 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3790 if (get_names == false) {
3791 *pnum_names = (int)num_names;
3792 return NT_STATUS_OK;
3794 if (num_names != num_names_returned) {
3795 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3797 if (dlength + 12 < 12) {
3798 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3801 * NB. The below is an allowable return if there are
3802 * more snapshots than the buffer size we told the
3803 * server we can receive. We currently don't support
3806 if (dlength + 12 > state->out_output_buffer.length) {
3807 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3809 if (state->out_output_buffer.length +
3810 (2 * sizeof(SHADOW_COPY_LABEL)) <
3811 state->out_output_buffer.length) {
3812 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3815 names = talloc_array(mem_ctx, char *, num_names_returned);
3816 if (names == NULL) {
3817 return NT_STATUS_NO_MEMORY;
3820 endp = state->out_output_buffer.data +
3821 state->out_output_buffer.length;
3823 for (i=0; i<num_names_returned; i++) {
3826 size_t converted_size;
3828 src = state->out_output_buffer.data + 12 +
3829 (i * 2 * sizeof(SHADOW_COPY_LABEL));
3831 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
3832 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3834 ret = convert_string_talloc(
3835 names, CH_UTF16LE, CH_UNIX,
3836 src, 2 * sizeof(SHADOW_COPY_LABEL),
3837 &names[i], &converted_size);
3840 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3843 *pnum_names = num_names;
3845 return NT_STATUS_OK;
3848 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
3849 struct cli_state *cli,
3855 TALLOC_CTX *frame = talloc_stackframe();
3856 struct tevent_context *ev;
3857 struct tevent_req *req;
3858 NTSTATUS status = NT_STATUS_NO_MEMORY;
3860 if (smbXcli_conn_has_async_calls(cli->conn)) {
3862 * Can't use sync call while an async call is in flight
3864 status = NT_STATUS_INVALID_PARAMETER;
3867 ev = samba_tevent_context_init(frame);
3871 req = cli_smb2_shadow_copy_data_fnum_send(frame,
3879 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3882 status = cli_smb2_shadow_copy_data_fnum_recv(req,
3888 cli->raw_status = status;
3894 /***************************************************************
3895 Wrapper that allows SMB2 to truncate a file.
3897 ***************************************************************/
3899 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
3904 DATA_BLOB inbuf = data_blob_null;
3905 struct smb2_hnd *ph = NULL;
3906 TALLOC_CTX *frame = talloc_stackframe();
3908 if (smbXcli_conn_has_async_calls(cli->conn)) {
3910 * Can't use sync call while an async call is in flight
3912 status = NT_STATUS_INVALID_PARAMETER;
3916 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3917 status = NT_STATUS_INVALID_PARAMETER;
3921 status = map_fnum_to_smb2_handle(cli,
3924 if (!NT_STATUS_IS_OK(status)) {
3928 inbuf = data_blob_talloc_zero(frame, 8);
3929 if (inbuf.data == NULL) {
3930 status = NT_STATUS_NO_MEMORY;
3934 SBVAL(inbuf.data, 0, newsize);
3936 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3937 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
3939 status = smb2cli_set_info(cli->conn,
3943 1, /* in_info_type */
3944 /* in_file_info_class */
3945 SMB_FILE_END_OF_FILE_INFORMATION - 1000,
3946 &inbuf, /* in_input_buffer */
3947 0, /* in_additional_info */
3953 cli->raw_status = status;
3959 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
3960 uint32_t buffer_size, uint32_t completion_filter,
3961 bool recursive, TALLOC_CTX *mem_ctx,
3962 struct notify_change **pchanges,
3963 uint32_t *pnum_changes)
3966 struct smb2_hnd *ph = NULL;
3967 TALLOC_CTX *frame = talloc_stackframe();
3970 struct notify_change *changes = NULL;
3971 size_t num_changes = 0;
3973 if (smbXcli_conn_has_async_calls(cli->conn)) {
3975 * Can't use sync call while an async call is in flight
3977 status = NT_STATUS_INVALID_PARAMETER;
3981 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3982 status = NT_STATUS_INVALID_PARAMETER;
3986 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
3987 if (!NT_STATUS_IS_OK(status)) {
3991 status = smb2cli_notify(cli->conn, cli->timeout,
3992 cli->smb2.session, cli->smb2.tcon,
3994 ph->fid_persistent, ph->fid_volatile,
3995 completion_filter, recursive,
3996 frame, &base, &len);
4000 while (len - ofs >= 12) {
4001 struct notify_change *tmp;
4002 struct notify_change *c;
4003 uint32_t next_ofs = IVAL(base, ofs);
4004 uint32_t file_name_length = IVAL(base, ofs+8);
4008 tmp = talloc_realloc(frame, changes, struct notify_change,
4011 status = NT_STATUS_NO_MEMORY;
4015 c = &changes[num_changes];
4018 if (smb_buffer_oob(len, ofs, next_ofs) ||
4019 smb_buffer_oob(len, ofs+12, file_name_length)) {
4020 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
4024 c->action = IVAL(base, ofs+4);
4026 ok = convert_string_talloc(changes, CH_UTF16LE, CH_UNIX,
4027 base + ofs + 12, file_name_length,
4028 &c->name, &namelen);
4030 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
4034 if (next_ofs == 0) {
4040 *pchanges = talloc_move(mem_ctx, &changes);
4041 *pnum_changes = num_changes;
4042 status = NT_STATUS_OK;
4045 cli->raw_status = status;