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"
44 #include "librpc/gen_ndr/ndr_quota.h"
47 uint64_t fid_persistent;
48 uint64_t fid_volatile;
52 * Handle mapping code.
55 /***************************************************************
56 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
57 Ensures handle is owned by cli struct.
58 ***************************************************************/
60 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
61 const struct smb2_hnd *ph, /* In */
62 uint16_t *pfnum) /* Out */
65 struct idr_context *idp = cli->smb2.open_handles;
66 struct smb2_hnd *owned_h = talloc_memdup(cli,
68 sizeof(struct smb2_hnd));
70 if (owned_h == NULL) {
71 return NT_STATUS_NO_MEMORY;
76 cli->smb2.open_handles = idr_init(cli);
77 if (cli->smb2.open_handles == NULL) {
79 return NT_STATUS_NO_MEMORY;
81 idp = cli->smb2.open_handles;
84 ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
87 return NT_STATUS_NO_MEMORY;
90 *pfnum = (uint16_t)ret;
94 /***************************************************************
95 Return the smb2_hnd pointer associated with the given fnum.
96 ***************************************************************/
98 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
99 uint16_t fnum, /* In */
100 struct smb2_hnd **pph) /* Out */
102 struct idr_context *idp = cli->smb2.open_handles;
105 return NT_STATUS_INVALID_PARAMETER;
107 *pph = (struct smb2_hnd *)idr_find(idp, fnum);
109 return NT_STATUS_INVALID_HANDLE;
114 /***************************************************************
115 Delete the fnum to smb2_hnd mapping. Zeros out handle on
117 ***************************************************************/
119 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
120 struct smb2_hnd **pph, /* In */
121 uint16_t fnum) /* In */
123 struct idr_context *idp = cli->smb2.open_handles;
127 return NT_STATUS_INVALID_PARAMETER;
130 ph = (struct smb2_hnd *)idr_find(idp, fnum);
132 return NT_STATUS_INVALID_PARAMETER;
134 idr_remove(idp, fnum);
139 /***************************************************************
141 ***************************************************************/
143 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
145 if (create_flags & REQUEST_BATCH_OPLOCK) {
146 return SMB2_OPLOCK_LEVEL_BATCH;
147 } else if (create_flags & REQUEST_OPLOCK) {
148 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
151 /* create_flags doesn't do a level2 request. */
152 return SMB2_OPLOCK_LEVEL_NONE;
155 /***************************************************************
156 Small wrapper that allows SMB2 create to return a uint16_t fnum.
157 ***************************************************************/
159 struct cli_smb2_create_fnum_state {
160 struct cli_state *cli;
161 struct smb_create_returns cr;
163 struct tevent_req *subreq;
166 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
167 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
169 struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
170 struct tevent_context *ev,
171 struct cli_state *cli,
173 uint32_t create_flags,
174 uint32_t desired_access,
175 uint32_t file_attributes,
176 uint32_t share_access,
177 uint32_t create_disposition,
178 uint32_t create_options)
180 struct tevent_req *req, *subreq;
181 struct cli_smb2_create_fnum_state *state;
182 size_t fname_len = 0;
183 const char *startp = NULL;
184 const char *endp = NULL;
185 time_t tstamp = (time_t)0;
186 struct smb2_create_blobs *cblobs = NULL;
188 req = tevent_req_create(mem_ctx, &state,
189 struct cli_smb2_create_fnum_state);
195 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
196 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
197 return tevent_req_post(req, ev);
200 if (cli->backup_intent) {
201 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
204 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
205 fname_len = strlen(fname);
206 if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
207 size_t len_before_gmt = startp - fname;
208 size_t len_after_gmt = fname + fname_len - endp;
213 char *new_fname = talloc_array(state, char,
214 len_before_gmt + len_after_gmt + 1);
216 if (tevent_req_nomem(new_fname, req)) {
217 return tevent_req_post(req, ev);
220 memcpy(new_fname, fname, len_before_gmt);
221 memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
223 fname_len = len_before_gmt + len_after_gmt;
225 unix_to_nt_time(&ntt, tstamp);
226 twrp_blob = data_blob_const((const void *)&ntt, 8);
228 cblobs = talloc_zero(state, struct smb2_create_blobs);
229 if (tevent_req_nomem(cblobs, req)) {
230 return tevent_req_post(req, ev);
233 status = smb2_create_blob_add(state, cblobs,
234 SMB2_CREATE_TAG_TWRP, twrp_blob);
235 if (!NT_STATUS_IS_OK(status)) {
236 tevent_req_nterror(req, status);
237 return tevent_req_post(req, ev);
241 /* SMB2 is pickier about pathnames. Ensure it doesn't
243 if (*fname == '\\') {
248 /* Or end in a '\' */
249 if (fname_len > 0 && fname[fname_len-1] == '\\') {
250 char *new_fname = talloc_strdup(state, fname);
251 if (tevent_req_nomem(new_fname, req)) {
252 return tevent_req_post(req, ev);
254 new_fname[fname_len-1] = '\0';
258 subreq = smb2cli_create_send(state, ev,
264 flags_to_smb2_oplock(create_flags),
265 SMB2_IMPERSONATION_IMPERSONATION,
272 if (tevent_req_nomem(subreq, req)) {
273 return tevent_req_post(req, ev);
275 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
277 state->subreq = subreq;
278 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
283 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
285 struct tevent_req *req = tevent_req_callback_data(
286 subreq, struct tevent_req);
287 struct cli_smb2_create_fnum_state *state = tevent_req_data(
288 req, struct cli_smb2_create_fnum_state);
292 status = smb2cli_create_recv(subreq, &h.fid_persistent,
293 &h.fid_volatile, &state->cr, NULL, NULL);
295 if (tevent_req_nterror(req, status)) {
299 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
300 if (tevent_req_nterror(req, status)) {
303 tevent_req_done(req);
306 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
308 struct cli_smb2_create_fnum_state *state = tevent_req_data(
309 req, struct cli_smb2_create_fnum_state);
310 return tevent_req_cancel(state->subreq);
313 NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum,
314 struct smb_create_returns *cr)
316 struct cli_smb2_create_fnum_state *state = tevent_req_data(
317 req, struct cli_smb2_create_fnum_state);
320 if (tevent_req_is_nterror(req, &status)) {
321 state->cli->raw_status = status;
325 *pfnum = state->fnum;
330 state->cli->raw_status = NT_STATUS_OK;
334 NTSTATUS cli_smb2_create_fnum(struct cli_state *cli,
336 uint32_t create_flags,
337 uint32_t desired_access,
338 uint32_t file_attributes,
339 uint32_t share_access,
340 uint32_t create_disposition,
341 uint32_t create_options,
343 struct smb_create_returns *cr)
345 TALLOC_CTX *frame = talloc_stackframe();
346 struct tevent_context *ev;
347 struct tevent_req *req;
348 NTSTATUS status = NT_STATUS_NO_MEMORY;
350 if (smbXcli_conn_has_async_calls(cli->conn)) {
352 * Can't use sync call while an async call is in flight
354 status = NT_STATUS_INVALID_PARAMETER;
357 ev = samba_tevent_context_init(frame);
361 req = cli_smb2_create_fnum_send(frame, ev, cli, fname, create_flags,
362 desired_access, file_attributes,
363 share_access, create_disposition,
368 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
371 status = cli_smb2_create_fnum_recv(req, pfid, cr);
377 /***************************************************************
378 Small wrapper that allows SMB2 close to use a uint16_t fnum.
379 ***************************************************************/
381 struct cli_smb2_close_fnum_state {
382 struct cli_state *cli;
387 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
389 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
390 struct tevent_context *ev,
391 struct cli_state *cli,
394 struct tevent_req *req, *subreq;
395 struct cli_smb2_close_fnum_state *state;
398 req = tevent_req_create(mem_ctx, &state,
399 struct cli_smb2_close_fnum_state);
406 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
407 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
408 return tevent_req_post(req, ev);
411 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
412 if (tevent_req_nterror(req, status)) {
413 return tevent_req_post(req, ev);
416 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
417 cli->smb2.session, cli->smb2.tcon,
418 0, state->ph->fid_persistent,
419 state->ph->fid_volatile);
420 if (tevent_req_nomem(subreq, req)) {
421 return tevent_req_post(req, ev);
423 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
427 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
429 struct tevent_req *req = tevent_req_callback_data(
430 subreq, struct tevent_req);
431 struct cli_smb2_close_fnum_state *state = tevent_req_data(
432 req, struct cli_smb2_close_fnum_state);
435 status = smb2cli_close_recv(subreq);
436 if (tevent_req_nterror(req, status)) {
440 /* Delete the fnum -> handle mapping. */
441 status = delete_smb2_handle_mapping(state->cli, &state->ph,
443 if (tevent_req_nterror(req, status)) {
446 tevent_req_done(req);
449 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
451 struct cli_smb2_close_fnum_state *state = tevent_req_data(
452 req, struct cli_smb2_close_fnum_state);
453 NTSTATUS status = NT_STATUS_OK;
455 if (tevent_req_is_nterror(req, &status)) {
456 state->cli->raw_status = status;
458 tevent_req_received(req);
462 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
464 TALLOC_CTX *frame = talloc_stackframe();
465 struct tevent_context *ev;
466 struct tevent_req *req;
467 NTSTATUS status = NT_STATUS_NO_MEMORY;
469 if (smbXcli_conn_has_async_calls(cli->conn)) {
471 * Can't use sync call while an async call is in flight
473 status = NT_STATUS_INVALID_PARAMETER;
476 ev = samba_tevent_context_init(frame);
480 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
484 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
487 status = cli_smb2_close_fnum_recv(req);
493 struct cli_smb2_delete_on_close_state {
494 struct cli_state *cli;
501 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
503 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
504 struct tevent_context *ev,
505 struct cli_state *cli,
509 struct tevent_req *req = NULL;
510 struct cli_smb2_delete_on_close_state *state = NULL;
511 struct tevent_req *subreq = NULL;
512 uint8_t in_info_type;
513 uint8_t in_file_info_class;
516 req = tevent_req_create(mem_ctx, &state,
517 struct cli_smb2_delete_on_close_state);
524 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
525 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
526 return tevent_req_post(req, ev);
529 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
530 if (tevent_req_nterror(req, status)) {
531 return tevent_req_post(req, ev);
535 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
536 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
539 in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
540 /* Setup data array. */
541 SCVAL(&state->data[0], 0, flag ? 1 : 0);
542 state->inbuf.data = &state->data[0];
543 state->inbuf.length = 1;
545 subreq = smb2cli_set_info_send(state, ev,
552 &state->inbuf, /* in_input_buffer */
553 0, /* in_additional_info */
554 state->ph->fid_persistent,
555 state->ph->fid_volatile);
556 if (tevent_req_nomem(subreq, req)) {
557 return tevent_req_post(req, ev);
559 tevent_req_set_callback(subreq,
560 cli_smb2_delete_on_close_done,
565 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
567 NTSTATUS status = smb2cli_set_info_recv(subreq);
568 tevent_req_simple_finish_ntstatus(subreq, status);
571 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
573 struct cli_smb2_delete_on_close_state *state =
575 struct cli_smb2_delete_on_close_state);
578 if (tevent_req_is_nterror(req, &status)) {
579 state->cli->raw_status = status;
580 tevent_req_received(req);
584 state->cli->raw_status = NT_STATUS_OK;
585 tevent_req_received(req);
589 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
591 TALLOC_CTX *frame = talloc_stackframe();
592 struct tevent_context *ev;
593 struct tevent_req *req;
594 NTSTATUS status = NT_STATUS_NO_MEMORY;
596 if (smbXcli_conn_has_async_calls(cli->conn)) {
598 * Can't use sync call while an async call is in flight
600 status = NT_STATUS_INVALID_PARAMETER;
603 ev = samba_tevent_context_init(frame);
607 req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
611 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
614 status = cli_smb2_delete_on_close_recv(req);
620 /***************************************************************
621 Small wrapper that allows SMB2 to create a directory
623 ***************************************************************/
625 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
630 if (smbXcli_conn_has_async_calls(cli->conn)) {
632 * Can't use sync call while an async call is in flight
634 return NT_STATUS_INVALID_PARAMETER;
637 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
638 return NT_STATUS_INVALID_PARAMETER;
641 status = cli_smb2_create_fnum(cli,
643 0, /* create_flags */
644 FILE_READ_ATTRIBUTES, /* desired_access */
645 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
646 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
647 FILE_CREATE, /* create_disposition */
648 FILE_DIRECTORY_FILE, /* create_options */
652 if (!NT_STATUS_IS_OK(status)) {
655 return cli_smb2_close_fnum(cli, fnum);
658 /***************************************************************
659 Small wrapper that allows SMB2 to delete a directory
661 ***************************************************************/
663 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
668 if (smbXcli_conn_has_async_calls(cli->conn)) {
670 * Can't use sync call while an async call is in flight
672 return NT_STATUS_INVALID_PARAMETER;
675 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
676 return NT_STATUS_INVALID_PARAMETER;
679 status = cli_smb2_create_fnum(cli,
681 0, /* create_flags */
682 DELETE_ACCESS, /* desired_access */
683 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
684 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
685 FILE_OPEN, /* create_disposition */
686 FILE_DIRECTORY_FILE|FILE_DELETE_ON_CLOSE, /* create_options */
690 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
692 * Naive option to match our SMB1 code. Assume the
693 * symlink path that tripped us up was the last
694 * component and try again. Eventually we will have to
695 * deal with the returned path unprocessed component. JRA.
697 status = cli_smb2_create_fnum(cli,
699 0, /* create_flags */
700 DELETE_ACCESS, /* desired_access */
701 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
702 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
703 FILE_OPEN, /* create_disposition */
705 FILE_DELETE_ON_CLOSE|
706 FILE_OPEN_REPARSE_POINT, /* create_options */
711 if (!NT_STATUS_IS_OK(status)) {
714 return cli_smb2_close_fnum(cli, fnum);
717 /***************************************************************
718 Small wrapper that allows SMB2 to unlink a pathname.
720 ***************************************************************/
722 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
727 if (smbXcli_conn_has_async_calls(cli->conn)) {
729 * Can't use sync call while an async call is in flight
731 return NT_STATUS_INVALID_PARAMETER;
734 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
735 return NT_STATUS_INVALID_PARAMETER;
738 status = cli_smb2_create_fnum(cli,
740 0, /* create_flags */
741 DELETE_ACCESS, /* desired_access */
742 FILE_ATTRIBUTE_NORMAL, /* file attributes */
743 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
744 FILE_OPEN, /* create_disposition */
745 FILE_DELETE_ON_CLOSE, /* create_options */
749 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
751 * Naive option to match our SMB1 code. Assume the
752 * symlink path that tripped us up was the last
753 * component and try again. Eventually we will have to
754 * deal with the returned path unprocessed component. JRA.
756 status = cli_smb2_create_fnum(cli,
758 0, /* create_flags */
759 DELETE_ACCESS, /* desired_access */
760 FILE_ATTRIBUTE_NORMAL, /* file attributes */
761 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
762 FILE_OPEN, /* create_disposition */
763 FILE_DELETE_ON_CLOSE|
764 FILE_OPEN_REPARSE_POINT, /* create_options */
769 if (!NT_STATUS_IS_OK(status)) {
772 return cli_smb2_close_fnum(cli, fnum);
775 /***************************************************************
776 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
777 ***************************************************************/
779 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
780 uint32_t dir_data_length,
781 struct file_info *finfo,
782 uint32_t *next_offset)
788 if (dir_data_length < 4) {
789 return NT_STATUS_INFO_LENGTH_MISMATCH;
792 *next_offset = IVAL(dir_data, 0);
794 if (*next_offset > dir_data_length) {
795 return NT_STATUS_INFO_LENGTH_MISMATCH;
798 if (*next_offset != 0) {
799 /* Ensure we only read what in this record. */
800 dir_data_length = *next_offset;
803 if (dir_data_length < 105) {
804 return NT_STATUS_INFO_LENGTH_MISMATCH;
807 finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
808 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
809 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
810 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
811 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
812 finfo->mode = CVAL(dir_data + 56, 0);
813 namelen = IVAL(dir_data + 60,0);
814 if (namelen > (dir_data_length - 104)) {
815 return NT_STATUS_INFO_LENGTH_MISMATCH;
817 slen = CVAL(dir_data + 68, 0);
819 return NT_STATUS_INFO_LENGTH_MISMATCH;
821 ret = pull_string_talloc(finfo,
823 FLAGS2_UNICODE_STRINGS,
828 if (ret == (size_t)-1) {
829 /* Bad conversion. */
830 return NT_STATUS_INVALID_NETWORK_RESPONSE;
833 ret = pull_string_talloc(finfo,
835 FLAGS2_UNICODE_STRINGS,
840 if (ret == (size_t)-1) {
841 /* Bad conversion. */
842 return NT_STATUS_INVALID_NETWORK_RESPONSE;
847 /*******************************************************************
848 Given a filename - get its directory name
849 ********************************************************************/
851 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
859 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
862 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
873 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
876 (*parent)[len] = '\0';
884 /***************************************************************
885 Wrapper that allows SMB2 to list a directory.
887 ***************************************************************/
889 NTSTATUS cli_smb2_list(struct cli_state *cli,
890 const char *pathname,
892 NTSTATUS (*fn)(const char *,
899 uint16_t fnum = 0xffff;
900 char *parent_dir = NULL;
901 const char *mask = NULL;
902 struct smb2_hnd *ph = NULL;
903 bool processed_file = false;
904 TALLOC_CTX *frame = talloc_stackframe();
905 TALLOC_CTX *subframe = NULL;
907 uint32_t max_trans = smb2cli_conn_max_trans_size(cli->conn);
909 if (smbXcli_conn_has_async_calls(cli->conn)) {
911 * Can't use sync call while an async call is in flight
913 status = NT_STATUS_INVALID_PARAMETER;
917 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
918 status = NT_STATUS_INVALID_PARAMETER;
922 /* Get the directory name. */
923 if (!windows_parent_dirname(frame,
927 status = NT_STATUS_NO_MEMORY;
931 mask_has_wild = ms_has_wild(mask);
933 status = cli_smb2_create_fnum(cli,
935 0, /* create_flags */
936 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
937 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
938 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
939 FILE_OPEN, /* create_disposition */
940 FILE_DIRECTORY_FILE, /* create_options */
944 if (!NT_STATUS_IS_OK(status)) {
948 status = map_fnum_to_smb2_handle(cli,
951 if (!NT_STATUS_IS_OK(status)) {
956 uint8_t *dir_data = NULL;
957 uint32_t dir_data_length = 0;
958 uint32_t next_offset = 0;
959 subframe = talloc_stackframe();
961 status = smb2cli_query_directory(cli->conn,
965 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
976 if (!NT_STATUS_IS_OK(status)) {
977 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
984 struct file_info *finfo = talloc_zero(subframe,
988 status = NT_STATUS_NO_MEMORY;
992 status = parse_finfo_id_both_directory_info(dir_data,
997 if (!NT_STATUS_IS_OK(status)) {
1001 if (dir_check_ftype((uint32_t)finfo->mode,
1002 (uint32_t)attribute)) {
1004 * Only process if attributes match.
1005 * On SMB1 server does this, so on
1006 * SMB2 we need to emulate in the
1009 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1011 processed_file = true;
1013 status = fn(cli->dfs_mountpoint,
1018 if (!NT_STATUS_IS_OK(status)) {
1025 /* Move to next entry. */
1027 dir_data += next_offset;
1028 dir_data_length -= next_offset;
1030 } while (next_offset != 0);
1032 TALLOC_FREE(subframe);
1034 if (!mask_has_wild) {
1036 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1037 * when handed a non-wildcard path. Do it
1038 * for the server (with a non-wildcard path
1039 * there should only ever be one file returned.
1041 status = STATUS_NO_MORE_FILES;
1045 } while (NT_STATUS_IS_OK(status));
1047 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1048 status = NT_STATUS_OK;
1051 if (NT_STATUS_IS_OK(status) && !processed_file) {
1053 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1054 * if no files match. Emulate this in the client.
1056 status = NT_STATUS_NO_SUCH_FILE;
1061 if (fnum != 0xffff) {
1062 cli_smb2_close_fnum(cli, fnum);
1065 cli->raw_status = status;
1067 TALLOC_FREE(subframe);
1072 /***************************************************************
1073 Wrapper that allows SMB2 to query a path info (basic level).
1075 ***************************************************************/
1077 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1079 SMB_STRUCT_STAT *sbuf,
1080 uint32_t *attributes)
1083 struct smb_create_returns cr;
1084 uint16_t fnum = 0xffff;
1085 size_t namelen = strlen(name);
1087 if (smbXcli_conn_has_async_calls(cli->conn)) {
1089 * Can't use sync call while an async call is in flight
1091 return NT_STATUS_INVALID_PARAMETER;
1094 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1095 return NT_STATUS_INVALID_PARAMETER;
1098 /* SMB2 is pickier about pathnames. Ensure it doesn't
1100 if (namelen > 0 && name[namelen-1] == '\\') {
1101 char *modname = talloc_strdup(talloc_tos(), name);
1102 modname[namelen-1] = '\0';
1106 /* This is commonly used as a 'cd'. Try qpathinfo on
1107 a directory handle first. */
1109 status = cli_smb2_create_fnum(cli,
1111 0, /* create_flags */
1112 FILE_READ_ATTRIBUTES, /* desired_access */
1113 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1114 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1115 FILE_OPEN, /* create_disposition */
1116 FILE_DIRECTORY_FILE, /* create_options */
1120 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1121 /* Maybe a file ? */
1122 status = cli_smb2_create_fnum(cli,
1124 0, /* create_flags */
1125 FILE_READ_ATTRIBUTES, /* desired_access */
1126 0, /* file attributes */
1127 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1128 FILE_OPEN, /* create_disposition */
1129 0, /* create_options */
1134 if (!NT_STATUS_IS_OK(status)) {
1138 status = cli_smb2_close_fnum(cli, fnum);
1142 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1143 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1144 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1145 sbuf->st_ex_size = cr.end_of_file;
1146 *attributes = cr.file_attributes;
1151 /***************************************************************
1152 Wrapper that allows SMB2 to check if a path is a directory.
1154 ***************************************************************/
1156 NTSTATUS cli_smb2_chkpath(struct cli_state *cli,
1160 uint16_t fnum = 0xffff;
1162 if (smbXcli_conn_has_async_calls(cli->conn)) {
1164 * Can't use sync call while an async call is in flight
1166 return NT_STATUS_INVALID_PARAMETER;
1169 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1170 return NT_STATUS_INVALID_PARAMETER;
1173 /* Ensure this is a directory. */
1174 status = cli_smb2_create_fnum(cli,
1176 0, /* create_flags */
1177 FILE_READ_ATTRIBUTES, /* desired_access */
1178 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1179 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1180 FILE_OPEN, /* create_disposition */
1181 FILE_DIRECTORY_FILE, /* create_options */
1185 if (!NT_STATUS_IS_OK(status)) {
1189 return cli_smb2_close_fnum(cli, fnum);
1192 /***************************************************************
1193 Helper function for pathname operations.
1194 ***************************************************************/
1196 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1198 uint32_t desired_access,
1202 size_t namelen = strlen(name);
1203 TALLOC_CTX *frame = talloc_stackframe();
1204 uint32_t create_options = 0;
1206 /* SMB2 is pickier about pathnames. Ensure it doesn't
1208 if (namelen > 0 && name[namelen-1] == '\\') {
1209 char *modname = talloc_strdup(frame, name);
1210 if (modname == NULL) {
1211 status = NT_STATUS_NO_MEMORY;
1214 modname[namelen-1] = '\0';
1218 /* Try to open a file handle first. */
1219 status = cli_smb2_create_fnum(cli,
1221 0, /* create_flags */
1223 0, /* file attributes */
1224 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1225 FILE_OPEN, /* create_disposition */
1230 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1232 * Naive option to match our SMB1 code. Assume the
1233 * symlink path that tripped us up was the last
1234 * component and try again. Eventually we will have to
1235 * deal with the returned path unprocessed component. JRA.
1237 create_options |= FILE_OPEN_REPARSE_POINT;
1238 status = cli_smb2_create_fnum(cli,
1240 0, /* create_flags */
1242 0, /* file attributes */
1243 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1244 FILE_OPEN, /* create_disposition */
1250 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1251 create_options |= FILE_DIRECTORY_FILE;
1252 status = cli_smb2_create_fnum(cli,
1254 0, /* create_flags */
1256 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1257 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1258 FILE_OPEN, /* create_disposition */
1259 FILE_DIRECTORY_FILE, /* create_options */
1270 /***************************************************************
1271 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1273 ***************************************************************/
1275 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1280 DATA_BLOB outbuf = data_blob_null;
1281 uint16_t fnum = 0xffff;
1282 struct smb2_hnd *ph = NULL;
1283 uint32_t altnamelen = 0;
1284 TALLOC_CTX *frame = talloc_stackframe();
1286 if (smbXcli_conn_has_async_calls(cli->conn)) {
1288 * Can't use sync call while an async call is in flight
1290 status = NT_STATUS_INVALID_PARAMETER;
1294 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1295 status = NT_STATUS_INVALID_PARAMETER;
1299 status = get_fnum_from_path(cli,
1301 FILE_READ_ATTRIBUTES,
1304 if (!NT_STATUS_IS_OK(status)) {
1308 status = map_fnum_to_smb2_handle(cli,
1311 if (!NT_STATUS_IS_OK(status)) {
1315 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1316 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1318 status = smb2cli_query_info(cli->conn,
1322 1, /* in_info_type */
1323 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1324 0xFFFF, /* in_max_output_length */
1325 NULL, /* in_input_buffer */
1326 0, /* in_additional_info */
1333 if (!NT_STATUS_IS_OK(status)) {
1337 /* Parse the reply. */
1338 if (outbuf.length < 4) {
1339 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1343 altnamelen = IVAL(outbuf.data, 0);
1344 if (altnamelen > outbuf.length - 4) {
1345 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1349 if (altnamelen > 0) {
1351 char *short_name = NULL;
1352 ret = pull_string_talloc(frame,
1354 FLAGS2_UNICODE_STRINGS,
1359 if (ret == (size_t)-1) {
1360 /* Bad conversion. */
1361 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1365 fstrcpy(alt_name, short_name);
1370 status = NT_STATUS_OK;
1374 if (fnum != 0xffff) {
1375 cli_smb2_close_fnum(cli, fnum);
1378 cli->raw_status = status;
1385 /***************************************************************
1386 Wrapper that allows SMB2 to query a fnum info (basic level).
1388 ***************************************************************/
1390 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1394 struct timespec *create_time,
1395 struct timespec *access_time,
1396 struct timespec *write_time,
1397 struct timespec *change_time,
1401 DATA_BLOB outbuf = data_blob_null;
1402 struct smb2_hnd *ph = NULL;
1403 TALLOC_CTX *frame = talloc_stackframe();
1405 if (smbXcli_conn_has_async_calls(cli->conn)) {
1407 * Can't use sync call while an async call is in flight
1409 status = NT_STATUS_INVALID_PARAMETER;
1413 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1414 status = NT_STATUS_INVALID_PARAMETER;
1418 status = map_fnum_to_smb2_handle(cli,
1421 if (!NT_STATUS_IS_OK(status)) {
1425 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1426 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1428 status = smb2cli_query_info(cli->conn,
1432 1, /* in_info_type */
1433 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1434 0xFFFF, /* in_max_output_length */
1435 NULL, /* in_input_buffer */
1436 0, /* in_additional_info */
1442 if (!NT_STATUS_IS_OK(status)) {
1446 /* Parse the reply. */
1447 if (outbuf.length < 0x60) {
1448 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1453 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1456 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1459 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1462 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1465 uint32_t attr = IVAL(outbuf.data, 0x20);
1466 *mode = (uint16_t)attr;
1469 uint64_t file_size = BVAL(outbuf.data, 0x30);
1470 *size = (off_t)file_size;
1473 uint64_t file_index = BVAL(outbuf.data, 0x40);
1474 *ino = (SMB_INO_T)file_index;
1479 cli->raw_status = status;
1485 /***************************************************************
1486 Wrapper that allows SMB2 to query an fnum.
1487 Implement on top of cli_smb2_qfileinfo_basic().
1489 ***************************************************************/
1491 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1495 time_t *change_time,
1496 time_t *access_time,
1499 struct timespec access_time_ts;
1500 struct timespec write_time_ts;
1501 struct timespec change_time_ts;
1502 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1512 cli->raw_status = status;
1514 if (!NT_STATUS_IS_OK(status)) {
1519 *change_time = change_time_ts.tv_sec;
1522 *access_time = access_time_ts.tv_sec;
1525 *write_time = write_time_ts.tv_sec;
1527 return NT_STATUS_OK;
1530 /***************************************************************
1531 Wrapper that allows SMB2 to get pathname attributes.
1533 ***************************************************************/
1535 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1542 uint16_t fnum = 0xffff;
1543 struct smb2_hnd *ph = NULL;
1544 TALLOC_CTX *frame = talloc_stackframe();
1546 if (smbXcli_conn_has_async_calls(cli->conn)) {
1548 * Can't use sync call while an async call is in flight
1550 status = NT_STATUS_INVALID_PARAMETER;
1554 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1555 status = NT_STATUS_INVALID_PARAMETER;
1559 status = get_fnum_from_path(cli,
1561 FILE_READ_ATTRIBUTES,
1564 if (!NT_STATUS_IS_OK(status)) {
1568 status = map_fnum_to_smb2_handle(cli,
1571 if (!NT_STATUS_IS_OK(status)) {
1574 status = cli_smb2_getattrE(cli,
1581 if (!NT_STATUS_IS_OK(status)) {
1587 if (fnum != 0xffff) {
1588 cli_smb2_close_fnum(cli, fnum);
1591 cli->raw_status = status;
1597 /***************************************************************
1598 Wrapper that allows SMB2 to query a pathname info (basic level).
1599 Implement on top of cli_smb2_qfileinfo_basic().
1601 ***************************************************************/
1603 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1605 struct timespec *create_time,
1606 struct timespec *access_time,
1607 struct timespec *write_time,
1608 struct timespec *change_time,
1614 struct smb2_hnd *ph = NULL;
1615 uint16_t fnum = 0xffff;
1616 TALLOC_CTX *frame = talloc_stackframe();
1618 if (smbXcli_conn_has_async_calls(cli->conn)) {
1620 * Can't use sync call while an async call is in flight
1622 status = NT_STATUS_INVALID_PARAMETER;
1626 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1627 status = NT_STATUS_INVALID_PARAMETER;
1631 status = get_fnum_from_path(cli,
1633 FILE_READ_ATTRIBUTES,
1636 if (!NT_STATUS_IS_OK(status)) {
1640 status = map_fnum_to_smb2_handle(cli,
1643 if (!NT_STATUS_IS_OK(status)) {
1647 status = cli_smb2_qfileinfo_basic(cli,
1659 if (fnum != 0xffff) {
1660 cli_smb2_close_fnum(cli, fnum);
1663 cli->raw_status = status;
1669 /***************************************************************
1670 Wrapper that allows SMB2 to query pathname streams.
1672 ***************************************************************/
1674 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1676 TALLOC_CTX *mem_ctx,
1677 unsigned int *pnum_streams,
1678 struct stream_struct **pstreams)
1681 struct smb2_hnd *ph = NULL;
1682 uint16_t fnum = 0xffff;
1683 DATA_BLOB outbuf = data_blob_null;
1684 TALLOC_CTX *frame = talloc_stackframe();
1686 if (smbXcli_conn_has_async_calls(cli->conn)) {
1688 * Can't use sync call while an async call is in flight
1690 status = NT_STATUS_INVALID_PARAMETER;
1694 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1695 status = NT_STATUS_INVALID_PARAMETER;
1699 status = get_fnum_from_path(cli,
1701 FILE_READ_ATTRIBUTES,
1704 if (!NT_STATUS_IS_OK(status)) {
1708 status = map_fnum_to_smb2_handle(cli,
1711 if (!NT_STATUS_IS_OK(status)) {
1715 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1716 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1718 status = smb2cli_query_info(cli->conn,
1722 1, /* in_info_type */
1723 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1724 0xFFFF, /* in_max_output_length */
1725 NULL, /* in_input_buffer */
1726 0, /* in_additional_info */
1733 if (!NT_STATUS_IS_OK(status)) {
1737 /* Parse the reply. */
1738 if (!parse_streams_blob(mem_ctx,
1743 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1749 if (fnum != 0xffff) {
1750 cli_smb2_close_fnum(cli, fnum);
1753 cli->raw_status = status;
1759 /***************************************************************
1760 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
1763 ***************************************************************/
1765 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
1767 uint8_t in_info_type,
1768 uint8_t in_file_info_class,
1769 const DATA_BLOB *p_in_data)
1772 uint16_t fnum = 0xffff;
1773 struct smb2_hnd *ph = NULL;
1774 TALLOC_CTX *frame = talloc_stackframe();
1776 if (smbXcli_conn_has_async_calls(cli->conn)) {
1778 * Can't use sync call while an async call is in flight
1780 status = NT_STATUS_INVALID_PARAMETER;
1784 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1785 status = NT_STATUS_INVALID_PARAMETER;
1789 status = get_fnum_from_path(cli,
1791 FILE_WRITE_ATTRIBUTES,
1794 if (!NT_STATUS_IS_OK(status)) {
1798 status = map_fnum_to_smb2_handle(cli,
1801 if (!NT_STATUS_IS_OK(status)) {
1805 status = smb2cli_set_info(cli->conn,
1811 p_in_data, /* in_input_buffer */
1812 0, /* in_additional_info */
1817 if (fnum != 0xffff) {
1818 cli_smb2_close_fnum(cli, fnum);
1821 cli->raw_status = status;
1828 /***************************************************************
1829 Wrapper that allows SMB2 to set pathname attributes.
1831 ***************************************************************/
1833 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1838 uint8_t inbuf_store[40];
1839 DATA_BLOB inbuf = data_blob_null;
1841 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1842 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1844 inbuf.data = inbuf_store;
1845 inbuf.length = sizeof(inbuf_store);
1846 data_blob_clear(&inbuf);
1849 * SMB1 uses attr == 0 to clear all attributes
1850 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
1851 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
1852 * request attribute change.
1854 * SMB2 uses exactly the reverse. Unfortunately as the
1855 * cli_setatr() ABI is exposed inside libsmbclient,
1856 * we must make the SMB2 cli_smb2_setatr() call
1857 * export the same ABI as the SMB1 cli_setatr()
1858 * which calls it. This means reversing the sense
1859 * of the requested attr argument if it's zero
1860 * or FILE_ATTRIBUTE_NORMAL.
1862 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
1866 attr = FILE_ATTRIBUTE_NORMAL;
1867 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
1871 SSVAL(inbuf.data, 32, attr);
1873 put_long_date((char *)inbuf.data + 16,mtime);
1875 /* Set all the other times to -1. */
1876 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1877 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1878 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1880 return cli_smb2_setpathinfo(cli,
1882 1, /* in_info_type */
1883 /* in_file_info_class */
1884 SMB_FILE_BASIC_INFORMATION - 1000,
1889 /***************************************************************
1890 Wrapper that allows SMB2 to set file handle times.
1892 ***************************************************************/
1894 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1901 struct smb2_hnd *ph = NULL;
1902 uint8_t inbuf_store[40];
1903 DATA_BLOB inbuf = data_blob_null;
1905 if (smbXcli_conn_has_async_calls(cli->conn)) {
1907 * Can't use sync call while an async call is in flight
1909 return NT_STATUS_INVALID_PARAMETER;
1912 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1913 return NT_STATUS_INVALID_PARAMETER;
1916 status = map_fnum_to_smb2_handle(cli,
1919 if (!NT_STATUS_IS_OK(status)) {
1923 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1924 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1926 inbuf.data = inbuf_store;
1927 inbuf.length = sizeof(inbuf_store);
1928 data_blob_clear(&inbuf);
1930 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1931 if (change_time != 0) {
1932 put_long_date((char *)inbuf.data + 24, change_time);
1934 if (access_time != 0) {
1935 put_long_date((char *)inbuf.data + 8, access_time);
1937 if (write_time != 0) {
1938 put_long_date((char *)inbuf.data + 16, write_time);
1941 cli->raw_status = smb2cli_set_info(cli->conn,
1945 1, /* in_info_type */
1946 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1947 &inbuf, /* in_input_buffer */
1948 0, /* in_additional_info */
1952 return cli->raw_status;
1955 /***************************************************************
1956 Wrapper that allows SMB2 to query disk attributes (size).
1958 ***************************************************************/
1960 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
1961 uint64_t *bsize, uint64_t *total, uint64_t *avail)
1964 uint16_t fnum = 0xffff;
1965 DATA_BLOB outbuf = data_blob_null;
1966 struct smb2_hnd *ph = NULL;
1967 uint32_t sectors_per_unit = 0;
1968 uint32_t bytes_per_sector = 0;
1969 uint64_t total_size = 0;
1970 uint64_t size_free = 0;
1971 TALLOC_CTX *frame = talloc_stackframe();
1973 if (smbXcli_conn_has_async_calls(cli->conn)) {
1975 * Can't use sync call while an async call is in flight
1977 status = NT_STATUS_INVALID_PARAMETER;
1981 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1982 status = NT_STATUS_INVALID_PARAMETER;
1986 /* First open the top level directory. */
1987 status = cli_smb2_create_fnum(cli,
1989 0, /* create_flags */
1990 FILE_READ_ATTRIBUTES, /* desired_access */
1991 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1992 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1993 FILE_OPEN, /* create_disposition */
1994 FILE_DIRECTORY_FILE, /* create_options */
1998 if (!NT_STATUS_IS_OK(status)) {
2002 status = map_fnum_to_smb2_handle(cli,
2005 if (!NT_STATUS_IS_OK(status)) {
2009 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2010 level 3 (SMB_FS_SIZE_INFORMATION). */
2012 status = smb2cli_query_info(cli->conn,
2016 2, /* in_info_type */
2017 3, /* in_file_info_class */
2018 0xFFFF, /* in_max_output_length */
2019 NULL, /* in_input_buffer */
2020 0, /* in_additional_info */
2026 if (!NT_STATUS_IS_OK(status)) {
2030 /* Parse the reply. */
2031 if (outbuf.length != 24) {
2032 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2036 total_size = BVAL(outbuf.data, 0);
2037 size_free = BVAL(outbuf.data, 8);
2038 sectors_per_unit = IVAL(outbuf.data, 16);
2039 bytes_per_sector = IVAL(outbuf.data, 20);
2042 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2045 *total = total_size;
2051 status = NT_STATUS_OK;
2055 if (fnum != 0xffff) {
2056 cli_smb2_close_fnum(cli, fnum);
2059 cli->raw_status = status;
2065 /***************************************************************
2066 Wrapper that allows SMB2 to query file system sizes.
2068 ***************************************************************/
2070 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2071 uint64_t *total_allocation_units,
2072 uint64_t *caller_allocation_units,
2073 uint64_t *actual_allocation_units,
2074 uint64_t *sectors_per_allocation_unit,
2075 uint64_t *bytes_per_sector)
2078 uint16_t fnum = 0xffff;
2079 DATA_BLOB outbuf = data_blob_null;
2080 struct smb2_hnd *ph = NULL;
2081 TALLOC_CTX *frame = talloc_stackframe();
2083 if (smbXcli_conn_has_async_calls(cli->conn)) {
2085 * Can't use sync call while an async call is in flight
2087 status = NT_STATUS_INVALID_PARAMETER;
2091 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2092 status = NT_STATUS_INVALID_PARAMETER;
2096 /* First open the top level directory. */
2098 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2099 FILE_READ_ATTRIBUTES, /* desired_access */
2100 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2101 FILE_SHARE_READ | FILE_SHARE_WRITE |
2102 FILE_SHARE_DELETE, /* share_access */
2103 FILE_OPEN, /* create_disposition */
2104 FILE_DIRECTORY_FILE, /* create_options */
2108 if (!NT_STATUS_IS_OK(status)) {
2112 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2113 if (!NT_STATUS_IS_OK(status)) {
2117 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2118 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2120 status = smb2cli_query_info(cli->conn,
2124 SMB2_GETINFO_FS, /* in_info_type */
2125 /* in_file_info_class */
2126 SMB_FS_FULL_SIZE_INFORMATION - 1000,
2127 0xFFFF, /* in_max_output_length */
2128 NULL, /* in_input_buffer */
2129 0, /* in_additional_info */
2135 if (!NT_STATUS_IS_OK(status)) {
2139 if (outbuf.length < 32) {
2140 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2144 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2145 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2146 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2147 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2148 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2152 if (fnum != 0xffff) {
2153 cli_smb2_close_fnum(cli, fnum);
2156 cli->raw_status = status;
2162 /***************************************************************
2163 Wrapper that allows SMB2 to query file system attributes.
2165 ***************************************************************/
2167 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2170 uint16_t fnum = 0xffff;
2171 DATA_BLOB outbuf = data_blob_null;
2172 struct smb2_hnd *ph = NULL;
2173 TALLOC_CTX *frame = talloc_stackframe();
2175 if (smbXcli_conn_has_async_calls(cli->conn)) {
2177 * Can't use sync call while an async call is in flight
2179 status = NT_STATUS_INVALID_PARAMETER;
2183 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2184 status = NT_STATUS_INVALID_PARAMETER;
2188 /* First open the top level directory. */
2190 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2191 FILE_READ_ATTRIBUTES, /* desired_access */
2192 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2193 FILE_SHARE_READ | FILE_SHARE_WRITE |
2194 FILE_SHARE_DELETE, /* share_access */
2195 FILE_OPEN, /* create_disposition */
2196 FILE_DIRECTORY_FILE, /* create_options */
2200 if (!NT_STATUS_IS_OK(status)) {
2204 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2205 if (!NT_STATUS_IS_OK(status)) {
2209 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2210 cli->smb2.tcon, 2, /* in_info_type */
2211 5, /* in_file_info_class */
2212 0xFFFF, /* in_max_output_length */
2213 NULL, /* in_input_buffer */
2214 0, /* in_additional_info */
2216 ph->fid_persistent, ph->fid_volatile, frame,
2218 if (!NT_STATUS_IS_OK(status)) {
2222 if (outbuf.length < 12) {
2223 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2227 *fs_attr = IVAL(outbuf.data, 0);
2231 if (fnum != 0xffff) {
2232 cli_smb2_close_fnum(cli, fnum);
2235 cli->raw_status = status;
2241 /***************************************************************
2242 Wrapper that allows SMB2 to query file system volume info.
2244 ***************************************************************/
2246 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2247 TALLOC_CTX *mem_ctx,
2248 char **_volume_name,
2249 uint32_t *pserial_number,
2253 uint16_t fnum = 0xffff;
2254 DATA_BLOB outbuf = data_blob_null;
2255 struct smb2_hnd *ph = NULL;
2257 char *volume_name = NULL;
2258 TALLOC_CTX *frame = talloc_stackframe();
2260 if (smbXcli_conn_has_async_calls(cli->conn)) {
2262 * Can't use sync call while an async call is in flight
2264 status = NT_STATUS_INVALID_PARAMETER;
2268 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2269 status = NT_STATUS_INVALID_PARAMETER;
2273 /* First open the top level directory. */
2275 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2276 FILE_READ_ATTRIBUTES, /* desired_access */
2277 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2278 FILE_SHARE_READ | FILE_SHARE_WRITE |
2279 FILE_SHARE_DELETE, /* share_access */
2280 FILE_OPEN, /* create_disposition */
2281 FILE_DIRECTORY_FILE, /* create_options */
2285 if (!NT_STATUS_IS_OK(status)) {
2289 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2290 if (!NT_STATUS_IS_OK(status)) {
2294 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2295 level 1 (SMB_FS_VOLUME_INFORMATION). */
2297 status = smb2cli_query_info(cli->conn,
2301 SMB2_GETINFO_FS, /* in_info_type */
2302 /* in_file_info_class */
2303 SMB_FS_VOLUME_INFORMATION - 1000,
2304 0xFFFF, /* in_max_output_length */
2305 NULL, /* in_input_buffer */
2306 0, /* in_additional_info */
2312 if (!NT_STATUS_IS_OK(status)) {
2316 if (outbuf.length < 24) {
2317 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2323 ts = interpret_long_date((char *)outbuf.data);
2326 if (pserial_number) {
2327 *pserial_number = IVAL(outbuf.data,8);
2329 nlen = IVAL(outbuf.data,12);
2330 if (nlen + 18 < 18) {
2332 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2336 * The next check is safe as we know outbuf.length >= 24
2339 if (nlen > (outbuf.length - 18)) {
2340 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2344 clistr_pull_talloc(mem_ctx,
2345 (const char *)outbuf.data,
2351 if (volume_name == NULL) {
2352 status = map_nt_error_from_unix(errno);
2356 *_volume_name = volume_name;
2360 if (fnum != 0xffff) {
2361 cli_smb2_close_fnum(cli, fnum);
2364 cli->raw_status = status;
2371 /***************************************************************
2372 Wrapper that allows SMB2 to query a security descriptor.
2374 ***************************************************************/
2376 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2379 TALLOC_CTX *mem_ctx,
2380 struct security_descriptor **ppsd)
2383 DATA_BLOB outbuf = data_blob_null;
2384 struct smb2_hnd *ph = NULL;
2385 struct security_descriptor *lsd = NULL;
2386 TALLOC_CTX *frame = talloc_stackframe();
2388 if (smbXcli_conn_has_async_calls(cli->conn)) {
2390 * Can't use sync call while an async call is in flight
2392 status = NT_STATUS_INVALID_PARAMETER;
2396 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2397 status = NT_STATUS_INVALID_PARAMETER;
2401 status = map_fnum_to_smb2_handle(cli,
2404 if (!NT_STATUS_IS_OK(status)) {
2408 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2410 status = smb2cli_query_info(cli->conn,
2414 3, /* in_info_type */
2415 0, /* in_file_info_class */
2416 0xFFFF, /* in_max_output_length */
2417 NULL, /* in_input_buffer */
2418 sec_info, /* in_additional_info */
2425 if (!NT_STATUS_IS_OK(status)) {
2429 /* Parse the reply. */
2430 status = unmarshall_sec_desc(mem_ctx,
2435 if (!NT_STATUS_IS_OK(status)) {
2447 cli->raw_status = status;
2453 /***************************************************************
2454 Wrapper that allows SMB2 to set a security descriptor.
2456 ***************************************************************/
2458 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
2461 const struct security_descriptor *sd)
2464 DATA_BLOB inbuf = data_blob_null;
2465 struct smb2_hnd *ph = NULL;
2466 TALLOC_CTX *frame = talloc_stackframe();
2468 if (smbXcli_conn_has_async_calls(cli->conn)) {
2470 * Can't use sync call while an async call is in flight
2472 status = NT_STATUS_INVALID_PARAMETER;
2476 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2477 status = NT_STATUS_INVALID_PARAMETER;
2481 status = map_fnum_to_smb2_handle(cli,
2484 if (!NT_STATUS_IS_OK(status)) {
2488 status = marshall_sec_desc(frame,
2493 if (!NT_STATUS_IS_OK(status)) {
2497 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2499 status = smb2cli_set_info(cli->conn,
2503 3, /* in_info_type */
2504 0, /* in_file_info_class */
2505 &inbuf, /* in_input_buffer */
2506 sec_info, /* in_additional_info */
2512 cli->raw_status = status;
2518 /***************************************************************
2519 Wrapper that allows SMB2 to rename a file.
2521 ***************************************************************/
2523 NTSTATUS cli_smb2_rename(struct cli_state *cli,
2524 const char *fname_src,
2525 const char *fname_dst,
2529 DATA_BLOB inbuf = data_blob_null;
2530 uint16_t fnum = 0xffff;
2531 struct smb2_hnd *ph = NULL;
2532 smb_ucs2_t *converted_str = NULL;
2533 size_t converted_size_bytes = 0;
2535 TALLOC_CTX *frame = talloc_stackframe();
2537 if (smbXcli_conn_has_async_calls(cli->conn)) {
2539 * Can't use sync call while an async call is in flight
2541 status = NT_STATUS_INVALID_PARAMETER;
2545 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2546 status = NT_STATUS_INVALID_PARAMETER;
2550 status = get_fnum_from_path(cli,
2555 if (!NT_STATUS_IS_OK(status)) {
2559 status = map_fnum_to_smb2_handle(cli,
2562 if (!NT_STATUS_IS_OK(status)) {
2566 /* SMB2 is pickier about pathnames. Ensure it doesn't
2568 if (*fname_dst == '\\') {
2572 /* SMB2 is pickier about pathnames. Ensure it doesn't
2574 namelen = strlen(fname_dst);
2575 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2576 char *modname = talloc_strdup(frame, fname_dst);
2577 modname[namelen-1] = '\0';
2578 fname_dst = modname;
2581 if (!push_ucs2_talloc(frame,
2584 &converted_size_bytes)) {
2585 status = NT_STATUS_INVALID_PARAMETER;
2589 /* W2K8 insists the dest name is not null
2590 terminated. Remove the last 2 zero bytes
2591 and reduce the name length. */
2593 if (converted_size_bytes < 2) {
2594 status = NT_STATUS_INVALID_PARAMETER;
2597 converted_size_bytes -= 2;
2599 inbuf = data_blob_talloc_zero(frame,
2600 20 + converted_size_bytes);
2601 if (inbuf.data == NULL) {
2602 status = NT_STATUS_NO_MEMORY;
2607 SCVAL(inbuf.data, 0, 1);
2610 SIVAL(inbuf.data, 16, converted_size_bytes);
2611 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2613 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2614 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2616 status = smb2cli_set_info(cli->conn,
2620 1, /* in_info_type */
2621 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2622 &inbuf, /* in_input_buffer */
2623 0, /* in_additional_info */
2629 if (fnum != 0xffff) {
2630 cli_smb2_close_fnum(cli, fnum);
2633 cli->raw_status = status;
2639 /***************************************************************
2640 Wrapper that allows SMB2 to set an EA on a fnum.
2642 ***************************************************************/
2644 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2646 const char *ea_name,
2651 DATA_BLOB inbuf = data_blob_null;
2653 char *ea_name_ascii = NULL;
2655 struct smb2_hnd *ph = NULL;
2656 TALLOC_CTX *frame = talloc_stackframe();
2658 if (smbXcli_conn_has_async_calls(cli->conn)) {
2660 * Can't use sync call while an async call is in flight
2662 status = NT_STATUS_INVALID_PARAMETER;
2666 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2667 status = NT_STATUS_INVALID_PARAMETER;
2671 status = map_fnum_to_smb2_handle(cli,
2674 if (!NT_STATUS_IS_OK(status)) {
2678 /* Marshall the SMB2 EA data. */
2679 if (ea_len > 0xFFFF) {
2680 status = NT_STATUS_INVALID_PARAMETER;
2684 if (!push_ascii_talloc(frame,
2688 status = NT_STATUS_INVALID_PARAMETER;
2692 if (namelen < 2 || namelen > 0xFF) {
2693 status = NT_STATUS_INVALID_PARAMETER;
2697 bloblen = 8 + ea_len + namelen;
2698 /* Round up to a 4 byte boundary. */
2699 bloblen = ((bloblen + 3)&~3);
2701 inbuf = data_blob_talloc_zero(frame, bloblen);
2702 if (inbuf.data == NULL) {
2703 status = NT_STATUS_NO_MEMORY;
2706 /* namelen doesn't include the NULL byte. */
2707 SCVAL(inbuf.data, 5, namelen - 1);
2708 SSVAL(inbuf.data, 6, ea_len);
2709 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2710 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2712 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2713 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2715 status = smb2cli_set_info(cli->conn,
2719 1, /* in_info_type */
2720 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2721 &inbuf, /* in_input_buffer */
2722 0, /* in_additional_info */
2728 cli->raw_status = status;
2734 /***************************************************************
2735 Wrapper that allows SMB2 to set an EA on a pathname.
2737 ***************************************************************/
2739 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2741 const char *ea_name,
2746 uint16_t fnum = 0xffff;
2748 if (smbXcli_conn_has_async_calls(cli->conn)) {
2750 * Can't use sync call while an async call is in flight
2752 status = NT_STATUS_INVALID_PARAMETER;
2756 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2757 status = NT_STATUS_INVALID_PARAMETER;
2761 status = get_fnum_from_path(cli,
2766 if (!NT_STATUS_IS_OK(status)) {
2770 status = cli_set_ea_fnum(cli,
2775 if (!NT_STATUS_IS_OK(status)) {
2781 if (fnum != 0xffff) {
2782 cli_smb2_close_fnum(cli, fnum);
2785 cli->raw_status = status;
2790 /***************************************************************
2791 Wrapper that allows SMB2 to get an EA list on a pathname.
2793 ***************************************************************/
2795 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2799 struct ea_struct **pea_array)
2802 uint16_t fnum = 0xffff;
2803 DATA_BLOB outbuf = data_blob_null;
2804 struct smb2_hnd *ph = NULL;
2805 struct ea_list *ea_list = NULL;
2806 struct ea_list *eal = NULL;
2807 size_t ea_count = 0;
2808 TALLOC_CTX *frame = talloc_stackframe();
2813 if (smbXcli_conn_has_async_calls(cli->conn)) {
2815 * Can't use sync call while an async call is in flight
2817 status = NT_STATUS_INVALID_PARAMETER;
2821 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2822 status = NT_STATUS_INVALID_PARAMETER;
2826 status = get_fnum_from_path(cli,
2831 if (!NT_STATUS_IS_OK(status)) {
2835 status = map_fnum_to_smb2_handle(cli,
2838 if (!NT_STATUS_IS_OK(status)) {
2842 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2843 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2845 status = smb2cli_query_info(cli->conn,
2849 1, /* in_info_type */
2850 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2851 0xFFFF, /* in_max_output_length */
2852 NULL, /* in_input_buffer */
2853 0, /* in_additional_info */
2860 if (!NT_STATUS_IS_OK(status)) {
2864 /* Parse the reply. */
2865 ea_list = read_nttrans_ea_list(ctx,
2866 (const char *)outbuf.data,
2868 if (ea_list == NULL) {
2869 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2873 /* Convert to an array. */
2874 for (eal = ea_list; eal; eal = eal->next) {
2879 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2880 if (*pea_array == NULL) {
2881 status = NT_STATUS_NO_MEMORY;
2885 for (eal = ea_list; eal; eal = eal->next) {
2886 (*pea_array)[ea_count++] = eal->ea;
2888 *pnum_eas = ea_count;
2893 if (fnum != 0xffff) {
2894 cli_smb2_close_fnum(cli, fnum);
2897 cli->raw_status = status;
2903 /***************************************************************
2904 Wrapper that allows SMB2 to get user quota.
2906 ***************************************************************/
2908 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
2910 SMB_NTQUOTA_STRUCT *pqt)
2913 DATA_BLOB inbuf = data_blob_null;
2914 DATA_BLOB info_blob = data_blob_null;
2915 DATA_BLOB outbuf = data_blob_null;
2916 struct smb2_hnd *ph = NULL;
2917 TALLOC_CTX *frame = talloc_stackframe();
2919 unsigned int offset;
2920 struct smb2_query_quota_info query = {0};
2921 struct file_get_quota_info info = {0};
2922 enum ndr_err_code err;
2923 struct ndr_push *ndr_push = NULL;
2925 if (smbXcli_conn_has_async_calls(cli->conn)) {
2927 * Can't use sync call while an async call is in flight
2929 status = NT_STATUS_INVALID_PARAMETER;
2933 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2934 status = NT_STATUS_INVALID_PARAMETER;
2938 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2939 if (!NT_STATUS_IS_OK(status)) {
2943 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
2945 query.return_single = 1;
2947 status = NT_STATUS_INVALID_PARAMETER;
2951 info.next_entry_offset = 0;
2952 info.sid_length = sid_len;
2953 info.sid = pqt->sid;
2955 err = ndr_push_struct_blob(
2959 (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
2961 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
2962 status = NT_STATUS_INTERNAL_ERROR;
2966 query.sid_list_length = info_blob.length;
2967 ndr_push = ndr_push_init_ctx(frame);
2969 status = NT_STATUS_NO_MEMORY;
2973 err = ndr_push_smb2_query_quota_info(ndr_push,
2974 NDR_SCALARS | NDR_BUFFERS,
2977 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
2978 status = NT_STATUS_INTERNAL_ERROR;
2982 err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
2985 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
2986 status = NT_STATUS_INTERNAL_ERROR;
2989 inbuf.data = ndr_push->data;
2990 inbuf.length = ndr_push->offset;
2992 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2993 cli->smb2.tcon, 4, /* in_info_type */
2994 0, /* in_file_info_class */
2995 0xFFFF, /* in_max_output_length */
2996 &inbuf, /* in_input_buffer */
2997 0, /* in_additional_info */
2999 ph->fid_persistent, ph->fid_volatile, frame,
3002 if (!NT_STATUS_IS_OK(status)) {
3006 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3008 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3009 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3013 cli->raw_status = status;
3019 /***************************************************************
3020 Wrapper that allows SMB2 to list user quota.
3022 ***************************************************************/
3024 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3025 TALLOC_CTX *mem_ctx,
3027 SMB_NTQUOTA_LIST **pqt_list,
3031 DATA_BLOB inbuf = data_blob_null;
3032 DATA_BLOB outbuf = data_blob_null;
3033 struct smb2_hnd *ph = NULL;
3034 TALLOC_CTX *frame = talloc_stackframe();
3035 struct smb2_query_quota_info info = {0};
3036 enum ndr_err_code err;
3038 if (smbXcli_conn_has_async_calls(cli->conn)) {
3040 * Can't use sync call while an async call is in flight
3042 status = NT_STATUS_INVALID_PARAMETER;
3046 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3047 status = NT_STATUS_INVALID_PARAMETER;
3051 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3052 if (!NT_STATUS_IS_OK(status)) {
3057 info.restart_scan = first ? 1 : 0;
3059 err = ndr_push_struct_blob(
3063 (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3065 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3066 status = NT_STATUS_INTERNAL_ERROR;
3070 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
3071 cli->smb2.tcon, 4, /* in_info_type */
3072 0, /* in_file_info_class */
3073 0xFFFF, /* in_max_output_length */
3074 &inbuf, /* in_input_buffer */
3075 0, /* in_additional_info */
3077 ph->fid_persistent, ph->fid_volatile, frame,
3081 * safeguard against panic from calling parse_user_quota_list with
3084 if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3085 status = NT_STATUS_NO_MORE_ENTRIES;
3088 if (!NT_STATUS_IS_OK(status)) {
3092 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3096 cli->raw_status = status;
3102 /***************************************************************
3103 Wrapper that allows SMB2 to get file system quota.
3105 ***************************************************************/
3107 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3109 SMB_NTQUOTA_STRUCT *pqt)
3112 DATA_BLOB outbuf = data_blob_null;
3113 struct smb2_hnd *ph = NULL;
3114 TALLOC_CTX *frame = talloc_stackframe();
3116 if (smbXcli_conn_has_async_calls(cli->conn)) {
3118 * Can't use sync call while an async call is in flight
3120 status = NT_STATUS_INVALID_PARAMETER;
3124 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3125 status = NT_STATUS_INVALID_PARAMETER;
3129 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3130 if (!NT_STATUS_IS_OK(status)) {
3134 status = smb2cli_query_info(
3135 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3136 2, /* in_info_type */
3137 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3138 0xFFFF, /* in_max_output_length */
3139 NULL, /* in_input_buffer */
3140 0, /* in_additional_info */
3142 ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
3144 if (!NT_STATUS_IS_OK(status)) {
3148 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3151 cli->raw_status = status;
3157 /***************************************************************
3158 Wrapper that allows SMB2 to set user quota.
3160 ***************************************************************/
3162 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3164 SMB_NTQUOTA_LIST *qtl)
3167 DATA_BLOB inbuf = data_blob_null;
3168 struct smb2_hnd *ph = NULL;
3169 TALLOC_CTX *frame = talloc_stackframe();
3171 if (smbXcli_conn_has_async_calls(cli->conn)) {
3173 * Can't use sync call while an async call is in flight
3175 status = NT_STATUS_INVALID_PARAMETER;
3179 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3180 status = NT_STATUS_INVALID_PARAMETER;
3184 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3185 if (!NT_STATUS_IS_OK(status)) {
3189 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3190 if (!NT_STATUS_IS_OK(status)) {
3194 status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
3195 cli->smb2.tcon, 4, /* in_info_type */
3196 0, /* in_file_info_class */
3197 &inbuf, /* in_input_buffer */
3198 0, /* in_additional_info */
3199 ph->fid_persistent, ph->fid_volatile);
3202 cli->raw_status = status;
3209 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3211 SMB_NTQUOTA_STRUCT *pqt)
3214 DATA_BLOB inbuf = data_blob_null;
3215 struct smb2_hnd *ph = NULL;
3216 TALLOC_CTX *frame = talloc_stackframe();
3218 if (smbXcli_conn_has_async_calls(cli->conn)) {
3220 * Can't use sync call while an async call is in flight
3222 status = NT_STATUS_INVALID_PARAMETER;
3226 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3227 status = NT_STATUS_INVALID_PARAMETER;
3231 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3232 if (!NT_STATUS_IS_OK(status)) {
3236 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3237 if (!NT_STATUS_IS_OK(status)) {
3241 status = smb2cli_set_info(
3242 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3243 2, /* in_info_type */
3244 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3245 &inbuf, /* in_input_buffer */
3246 0, /* in_additional_info */
3247 ph->fid_persistent, ph->fid_volatile);
3249 cli->raw_status = status;
3255 struct cli_smb2_read_state {
3256 struct tevent_context *ev;
3257 struct cli_state *cli;
3258 struct smb2_hnd *ph;
3259 uint64_t start_offset;
3265 static void cli_smb2_read_done(struct tevent_req *subreq);
3267 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3268 struct tevent_context *ev,
3269 struct cli_state *cli,
3275 struct tevent_req *req, *subreq;
3276 struct cli_smb2_read_state *state;
3278 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3284 state->start_offset = (uint64_t)offset;
3285 state->size = (uint32_t)size;
3286 state->received = 0;
3289 status = map_fnum_to_smb2_handle(cli,
3292 if (tevent_req_nterror(req, status)) {
3293 return tevent_req_post(req, ev);
3296 subreq = smb2cli_read_send(state,
3299 state->cli->timeout,
3300 state->cli->smb2.session,
3301 state->cli->smb2.tcon,
3303 state->start_offset,
3304 state->ph->fid_persistent,
3305 state->ph->fid_volatile,
3306 0, /* minimum_count */
3307 0); /* remaining_bytes */
3309 if (tevent_req_nomem(subreq, req)) {
3310 return tevent_req_post(req, ev);
3312 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3316 static void cli_smb2_read_done(struct tevent_req *subreq)
3318 struct tevent_req *req = tevent_req_callback_data(
3319 subreq, struct tevent_req);
3320 struct cli_smb2_read_state *state = tevent_req_data(
3321 req, struct cli_smb2_read_state);
3324 status = smb2cli_read_recv(subreq, state,
3325 &state->buf, &state->received);
3326 if (tevent_req_nterror(req, status)) {
3330 if (state->received > state->size) {
3331 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3335 tevent_req_done(req);
3338 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
3343 struct cli_smb2_read_state *state = tevent_req_data(
3344 req, struct cli_smb2_read_state);
3346 if (tevent_req_is_nterror(req, &status)) {
3347 state->cli->raw_status = status;
3351 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3352 * better make sure that you copy it away before you talloc_free(req).
3353 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3355 *received = (ssize_t)state->received;
3356 *rcvbuf = state->buf;
3357 state->cli->raw_status = NT_STATUS_OK;
3358 return NT_STATUS_OK;
3361 struct cli_smb2_write_state {
3362 struct tevent_context *ev;
3363 struct cli_state *cli;
3364 struct smb2_hnd *ph;
3372 static void cli_smb2_write_written(struct tevent_req *req);
3374 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
3375 struct tevent_context *ev,
3376 struct cli_state *cli,
3384 struct tevent_req *req, *subreq = NULL;
3385 struct cli_smb2_write_state *state = NULL;
3387 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
3393 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3394 state->flags = (uint32_t)mode;
3396 state->offset = (uint64_t)offset;
3397 state->size = (uint32_t)size;
3400 status = map_fnum_to_smb2_handle(cli,
3403 if (tevent_req_nterror(req, status)) {
3404 return tevent_req_post(req, ev);
3407 subreq = smb2cli_write_send(state,
3410 state->cli->timeout,
3411 state->cli->smb2.session,
3412 state->cli->smb2.tcon,
3415 state->ph->fid_persistent,
3416 state->ph->fid_volatile,
3417 0, /* remaining_bytes */
3418 state->flags, /* flags */
3421 if (tevent_req_nomem(subreq, req)) {
3422 return tevent_req_post(req, ev);
3424 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
3428 static void cli_smb2_write_written(struct tevent_req *subreq)
3430 struct tevent_req *req = tevent_req_callback_data(
3431 subreq, struct tevent_req);
3432 struct cli_smb2_write_state *state = tevent_req_data(
3433 req, struct cli_smb2_write_state);
3437 status = smb2cli_write_recv(subreq, &written);
3438 TALLOC_FREE(subreq);
3439 if (tevent_req_nterror(req, status)) {
3443 state->written = written;
3445 tevent_req_done(req);
3448 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
3451 struct cli_smb2_write_state *state = tevent_req_data(
3452 req, struct cli_smb2_write_state);
3455 if (tevent_req_is_nterror(req, &status)) {
3456 state->cli->raw_status = status;
3457 tevent_req_received(req);
3461 if (pwritten != NULL) {
3462 *pwritten = (size_t)state->written;
3464 state->cli->raw_status = NT_STATUS_OK;
3465 tevent_req_received(req);
3466 return NT_STATUS_OK;
3469 /***************************************************************
3470 Wrapper that allows SMB2 async write using an fnum.
3471 This is mostly cut-and-paste from Volker's code inside
3472 source3/libsmb/clireadwrite.c, adapted for SMB2.
3474 Done this way so I can reuse all the logic inside cli_push()
3476 ***************************************************************/
3478 struct cli_smb2_writeall_state {
3479 struct tevent_context *ev;
3480 struct cli_state *cli;
3481 struct smb2_hnd *ph;
3489 static void cli_smb2_writeall_written(struct tevent_req *req);
3491 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
3492 struct tevent_context *ev,
3493 struct cli_state *cli,
3501 struct tevent_req *req, *subreq = NULL;
3502 struct cli_smb2_writeall_state *state = NULL;
3507 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
3513 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3514 state->flags = (uint32_t)mode;
3516 state->offset = (uint64_t)offset;
3517 state->size = (uint32_t)size;
3520 status = map_fnum_to_smb2_handle(cli,
3523 if (tevent_req_nterror(req, status)) {
3524 return tevent_req_post(req, ev);
3527 to_write = state->size;
3528 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3529 to_write = MIN(max_size, to_write);
3530 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3532 to_write = MIN(max_size, to_write);
3535 subreq = smb2cli_write_send(state,
3538 state->cli->timeout,
3539 state->cli->smb2.session,
3540 state->cli->smb2.tcon,
3543 state->ph->fid_persistent,
3544 state->ph->fid_volatile,
3545 0, /* remaining_bytes */
3546 state->flags, /* flags */
3547 state->buf + state->written);
3549 if (tevent_req_nomem(subreq, req)) {
3550 return tevent_req_post(req, ev);
3552 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3556 static void cli_smb2_writeall_written(struct tevent_req *subreq)
3558 struct tevent_req *req = tevent_req_callback_data(
3559 subreq, struct tevent_req);
3560 struct cli_smb2_writeall_state *state = tevent_req_data(
3561 req, struct cli_smb2_writeall_state);
3563 uint32_t written, to_write;
3567 status = smb2cli_write_recv(subreq, &written);
3568 TALLOC_FREE(subreq);
3569 if (tevent_req_nterror(req, status)) {
3573 state->written += written;
3575 if (state->written > state->size) {
3576 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3580 to_write = state->size - state->written;
3582 if (to_write == 0) {
3583 tevent_req_done(req);
3587 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3588 to_write = MIN(max_size, to_write);
3589 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3591 to_write = MIN(max_size, to_write);
3594 subreq = smb2cli_write_send(state,
3597 state->cli->timeout,
3598 state->cli->smb2.session,
3599 state->cli->smb2.tcon,
3601 state->offset + state->written,
3602 state->ph->fid_persistent,
3603 state->ph->fid_volatile,
3604 0, /* remaining_bytes */
3605 state->flags, /* flags */
3606 state->buf + state->written);
3608 if (tevent_req_nomem(subreq, req)) {
3611 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3614 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
3617 struct cli_smb2_writeall_state *state = tevent_req_data(
3618 req, struct cli_smb2_writeall_state);
3621 if (tevent_req_is_nterror(req, &status)) {
3622 state->cli->raw_status = status;
3625 if (pwritten != NULL) {
3626 *pwritten = (size_t)state->written;
3628 state->cli->raw_status = NT_STATUS_OK;
3629 return NT_STATUS_OK;
3632 struct cli_smb2_splice_state {
3633 struct tevent_context *ev;
3634 struct cli_state *cli;
3635 struct smb2_hnd *src_ph;
3636 struct smb2_hnd *dst_ph;
3637 int (*splice_cb)(off_t n, void *priv);
3644 struct req_resume_key_rsp resume_rsp;
3645 struct srv_copychunk_copy cc_copy;
3648 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3649 struct tevent_req *req);
3651 static void cli_splice_copychunk_done(struct tevent_req *subreq)
3653 struct tevent_req *req = tevent_req_callback_data(
3654 subreq, struct tevent_req);
3655 struct cli_smb2_splice_state *state =
3656 tevent_req_data(req,
3657 struct cli_smb2_splice_state);
3658 struct smbXcli_conn *conn = state->cli->conn;
3659 DATA_BLOB out_input_buffer = data_blob_null;
3660 DATA_BLOB out_output_buffer = data_blob_null;
3661 struct srv_copychunk_rsp cc_copy_rsp;
3662 enum ndr_err_code ndr_ret;
3665 status = smb2cli_ioctl_recv(subreq, state,
3667 &out_output_buffer);
3668 TALLOC_FREE(subreq);
3669 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
3670 state->resized) && tevent_req_nterror(req, status)) {
3674 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
3675 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
3676 if (ndr_ret != NDR_ERR_SUCCESS) {
3677 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3678 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3682 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
3683 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
3684 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
3685 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
3686 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
3687 tevent_req_nterror(req, status)) {
3691 state->resized = true;
3692 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
3693 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
3695 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3696 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3697 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
3698 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3701 state->src_offset += cc_copy_rsp.total_bytes_written;
3702 state->dst_offset += cc_copy_rsp.total_bytes_written;
3703 state->written += cc_copy_rsp.total_bytes_written;
3704 if (!state->splice_cb(state->written, state->priv)) {
3705 tevent_req_nterror(req, NT_STATUS_CANCELLED);
3710 cli_splice_copychunk_send(state, req);
3713 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3714 struct tevent_req *req)
3716 struct tevent_req *subreq;
3717 enum ndr_err_code ndr_ret;
3718 struct smbXcli_conn *conn = state->cli->conn;
3719 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
3720 off_t src_offset = state->src_offset;
3721 off_t dst_offset = state->dst_offset;
3722 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
3723 state->size - state->written);
3724 DATA_BLOB in_input_buffer = data_blob_null;
3725 DATA_BLOB in_output_buffer = data_blob_null;
3727 if (state->size - state->written == 0) {
3728 tevent_req_done(req);
3732 cc_copy->chunk_count = 0;
3734 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
3735 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
3736 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
3737 smb2cli_conn_cc_chunk_len(conn));
3738 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
3739 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3742 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
3743 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
3744 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
3745 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3748 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3749 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3750 cc_copy->chunk_count++;
3753 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
3754 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
3755 if (ndr_ret != NDR_ERR_SUCCESS) {
3756 DEBUG(0, ("failed to marshall copy chunk req\n"));
3757 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3761 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
3762 state->cli->timeout,
3763 state->cli->smb2.session,
3764 state->cli->smb2.tcon,
3765 state->dst_ph->fid_persistent, /* in_fid_persistent */
3766 state->dst_ph->fid_volatile, /* in_fid_volatile */
3767 FSCTL_SRV_COPYCHUNK_WRITE,
3768 0, /* in_max_input_length */
3770 12, /* in_max_output_length */
3772 SMB2_IOCTL_FLAG_IS_FSCTL);
3773 if (tevent_req_nomem(subreq, req)) {
3776 tevent_req_set_callback(subreq,
3777 cli_splice_copychunk_done,
3781 static void cli_splice_key_done(struct tevent_req *subreq)
3783 struct tevent_req *req = tevent_req_callback_data(
3784 subreq, struct tevent_req);
3785 struct cli_smb2_splice_state *state =
3786 tevent_req_data(req,
3787 struct cli_smb2_splice_state);
3788 enum ndr_err_code ndr_ret;
3791 DATA_BLOB out_input_buffer = data_blob_null;
3792 DATA_BLOB out_output_buffer = data_blob_null;
3794 status = smb2cli_ioctl_recv(subreq, state,
3796 &out_output_buffer);
3797 TALLOC_FREE(subreq);
3798 if (tevent_req_nterror(req, status)) {
3802 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
3803 state, &state->resume_rsp,
3804 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
3805 if (ndr_ret != NDR_ERR_SUCCESS) {
3806 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3807 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3811 memcpy(&state->cc_copy.source_key,
3812 &state->resume_rsp.resume_key,
3813 sizeof state->resume_rsp.resume_key);
3815 cli_splice_copychunk_send(state, req);
3818 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
3819 struct tevent_context *ev,
3820 struct cli_state *cli,
3821 uint16_t src_fnum, uint16_t dst_fnum,
3822 off_t size, off_t src_offset, off_t dst_offset,
3823 int (*splice_cb)(off_t n, void *priv),
3826 struct tevent_req *req;
3827 struct tevent_req *subreq;
3828 struct cli_smb2_splice_state *state;
3830 DATA_BLOB in_input_buffer = data_blob_null;
3831 DATA_BLOB in_output_buffer = data_blob_null;
3833 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
3839 state->splice_cb = splice_cb;
3843 state->src_offset = src_offset;
3844 state->dst_offset = dst_offset;
3845 state->cc_copy.chunks = talloc_array(state,
3846 struct srv_copychunk,
3847 smb2cli_conn_cc_max_chunks(cli->conn));
3848 if (state->cc_copy.chunks == NULL) {
3852 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
3853 if (tevent_req_nterror(req, status))
3854 return tevent_req_post(req, ev);
3856 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
3857 if (tevent_req_nterror(req, status))
3858 return tevent_req_post(req, ev);
3860 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
3864 state->src_ph->fid_persistent, /* in_fid_persistent */
3865 state->src_ph->fid_volatile, /* in_fid_volatile */
3866 FSCTL_SRV_REQUEST_RESUME_KEY,
3867 0, /* in_max_input_length */
3869 32, /* in_max_output_length */
3871 SMB2_IOCTL_FLAG_IS_FSCTL);
3872 if (tevent_req_nomem(subreq, req)) {
3875 tevent_req_set_callback(subreq,
3876 cli_splice_key_done,
3882 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
3884 struct cli_smb2_splice_state *state = tevent_req_data(
3885 req, struct cli_smb2_splice_state);
3888 if (tevent_req_is_nterror(req, &status)) {
3889 state->cli->raw_status = status;
3890 tevent_req_received(req);
3893 if (written != NULL) {
3894 *written = state->written;
3896 state->cli->raw_status = NT_STATUS_OK;
3897 tevent_req_received(req);
3898 return NT_STATUS_OK;
3901 /***************************************************************
3902 SMB2 enum shadow copy data.
3903 ***************************************************************/
3905 struct cli_smb2_shadow_copy_data_fnum_state {
3906 struct cli_state *cli;
3908 struct smb2_hnd *ph;
3909 DATA_BLOB out_input_buffer;
3910 DATA_BLOB out_output_buffer;
3913 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
3915 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
3916 TALLOC_CTX *mem_ctx,
3917 struct tevent_context *ev,
3918 struct cli_state *cli,
3922 struct tevent_req *req, *subreq;
3923 struct cli_smb2_shadow_copy_data_fnum_state *state;
3926 req = tevent_req_create(mem_ctx, &state,
3927 struct cli_smb2_shadow_copy_data_fnum_state);
3932 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3933 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3934 return tevent_req_post(req, ev);
3940 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
3941 if (tevent_req_nterror(req, status)) {
3942 return tevent_req_post(req, ev);
3946 * TODO. Under SMB2 we should send a zero max_output_length
3947 * ioctl to get the required size, then send another ioctl
3948 * to get the data, but the current SMB1 implementation just
3949 * does one roundtrip with a 64K buffer size. Do the same
3953 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
3954 state->cli->timeout,
3955 state->cli->smb2.session,
3956 state->cli->smb2.tcon,
3957 state->ph->fid_persistent, /* in_fid_persistent */
3958 state->ph->fid_volatile, /* in_fid_volatile */
3959 FSCTL_GET_SHADOW_COPY_DATA,
3960 0, /* in_max_input_length */
3961 NULL, /* in_input_buffer */
3963 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
3964 NULL, /* in_output_buffer */
3965 SMB2_IOCTL_FLAG_IS_FSCTL);
3967 if (tevent_req_nomem(subreq, req)) {
3968 return tevent_req_post(req, ev);
3970 tevent_req_set_callback(subreq,
3971 cli_smb2_shadow_copy_data_fnum_done,
3977 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
3979 struct tevent_req *req = tevent_req_callback_data(
3980 subreq, struct tevent_req);
3981 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3982 req, struct cli_smb2_shadow_copy_data_fnum_state);
3985 status = smb2cli_ioctl_recv(subreq, state,
3986 &state->out_input_buffer,
3987 &state->out_output_buffer);
3988 TALLOC_FREE(subreq);
3989 if (tevent_req_nterror(req, status)) {
3992 tevent_req_done(req);
3995 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
3996 TALLOC_CTX *mem_ctx,
4001 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4002 req, struct cli_smb2_shadow_copy_data_fnum_state);
4003 char **names = NULL;
4004 uint32_t num_names = 0;
4005 uint32_t num_names_returned = 0;
4006 uint32_t dlength = 0;
4008 uint8_t *endp = NULL;
4011 if (tevent_req_is_nterror(req, &status)) {
4015 if (state->out_output_buffer.length < 16) {
4016 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4019 num_names = IVAL(state->out_output_buffer.data, 0);
4020 num_names_returned = IVAL(state->out_output_buffer.data, 4);
4021 dlength = IVAL(state->out_output_buffer.data, 8);
4023 if (num_names > 0x7FFFFFFF) {
4024 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4027 if (get_names == false) {
4028 *pnum_names = (int)num_names;
4029 return NT_STATUS_OK;
4031 if (num_names != num_names_returned) {
4032 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4034 if (dlength + 12 < 12) {
4035 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4038 * NB. The below is an allowable return if there are
4039 * more snapshots than the buffer size we told the
4040 * server we can receive. We currently don't support
4043 if (dlength + 12 > state->out_output_buffer.length) {
4044 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4046 if (state->out_output_buffer.length +
4047 (2 * sizeof(SHADOW_COPY_LABEL)) <
4048 state->out_output_buffer.length) {
4049 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4052 names = talloc_array(mem_ctx, char *, num_names_returned);
4053 if (names == NULL) {
4054 return NT_STATUS_NO_MEMORY;
4057 endp = state->out_output_buffer.data +
4058 state->out_output_buffer.length;
4060 for (i=0; i<num_names_returned; i++) {
4063 size_t converted_size;
4065 src = state->out_output_buffer.data + 12 +
4066 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4068 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4069 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4071 ret = convert_string_talloc(
4072 names, CH_UTF16LE, CH_UNIX,
4073 src, 2 * sizeof(SHADOW_COPY_LABEL),
4074 &names[i], &converted_size);
4077 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4080 *pnum_names = num_names;
4082 return NT_STATUS_OK;
4085 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4086 struct cli_state *cli,
4092 TALLOC_CTX *frame = talloc_stackframe();
4093 struct tevent_context *ev;
4094 struct tevent_req *req;
4095 NTSTATUS status = NT_STATUS_NO_MEMORY;
4097 if (smbXcli_conn_has_async_calls(cli->conn)) {
4099 * Can't use sync call while an async call is in flight
4101 status = NT_STATUS_INVALID_PARAMETER;
4104 ev = samba_tevent_context_init(frame);
4108 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4116 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4119 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4125 cli->raw_status = status;
4131 /***************************************************************
4132 Wrapper that allows SMB2 to truncate a file.
4134 ***************************************************************/
4136 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4141 DATA_BLOB inbuf = data_blob_null;
4142 struct smb2_hnd *ph = NULL;
4143 TALLOC_CTX *frame = talloc_stackframe();
4145 if (smbXcli_conn_has_async_calls(cli->conn)) {
4147 * Can't use sync call while an async call is in flight
4149 status = NT_STATUS_INVALID_PARAMETER;
4153 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4154 status = NT_STATUS_INVALID_PARAMETER;
4158 status = map_fnum_to_smb2_handle(cli,
4161 if (!NT_STATUS_IS_OK(status)) {
4165 inbuf = data_blob_talloc_zero(frame, 8);
4166 if (inbuf.data == NULL) {
4167 status = NT_STATUS_NO_MEMORY;
4171 SBVAL(inbuf.data, 0, newsize);
4173 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4174 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4176 status = smb2cli_set_info(cli->conn,
4180 1, /* in_info_type */
4181 /* in_file_info_class */
4182 SMB_FILE_END_OF_FILE_INFORMATION - 1000,
4183 &inbuf, /* in_input_buffer */
4184 0, /* in_additional_info */
4190 cli->raw_status = status;
4196 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
4197 uint32_t buffer_size, uint32_t completion_filter,
4198 bool recursive, TALLOC_CTX *mem_ctx,
4199 struct notify_change **pchanges,
4200 uint32_t *pnum_changes)
4203 struct smb2_hnd *ph = NULL;
4204 TALLOC_CTX *frame = talloc_stackframe();
4207 struct notify_change *changes = NULL;
4208 size_t num_changes = 0;
4210 if (smbXcli_conn_has_async_calls(cli->conn)) {
4212 * Can't use sync call while an async call is in flight
4214 status = NT_STATUS_INVALID_PARAMETER;
4218 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4219 status = NT_STATUS_INVALID_PARAMETER;
4223 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4224 if (!NT_STATUS_IS_OK(status)) {
4228 status = smb2cli_notify(cli->conn, cli->timeout,
4229 cli->smb2.session, cli->smb2.tcon,
4231 ph->fid_persistent, ph->fid_volatile,
4232 completion_filter, recursive,
4233 frame, &base, &len);
4235 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4237 status = NT_STATUS_OK;
4240 if (!NT_STATUS_IS_OK(status)) {
4246 while (len - ofs >= 12) {
4247 struct notify_change *tmp;
4248 struct notify_change *c;
4249 uint32_t next_ofs = IVAL(base, ofs);
4250 uint32_t file_name_length = IVAL(base, ofs+8);
4254 tmp = talloc_realloc(frame, changes, struct notify_change,
4257 status = NT_STATUS_NO_MEMORY;
4261 c = &changes[num_changes];
4264 if (smb_buffer_oob(len, ofs, next_ofs) ||
4265 smb_buffer_oob(len, ofs+12, file_name_length)) {
4266 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
4270 c->action = IVAL(base, ofs+4);
4272 ok = convert_string_talloc(changes, CH_UTF16LE, CH_UNIX,
4273 base + ofs + 12, file_name_length,
4274 &c->name, &namelen);
4276 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
4280 if (next_ofs == 0) {
4286 *pchanges = talloc_move(mem_ctx, &changes);
4287 *pnum_changes = num_changes;
4288 status = NT_STATUS_OK;
4291 cli->raw_status = status;
4297 struct cli_smb2_set_reparse_point_fnum_state {
4298 struct cli_state *cli;
4300 struct smb2_hnd *ph;
4301 DATA_BLOB input_buffer;
4304 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
4306 struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
4307 TALLOC_CTX *mem_ctx,
4308 struct tevent_context *ev,
4309 struct cli_state *cli,
4313 struct tevent_req *req, *subreq;
4314 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
4317 req = tevent_req_create(mem_ctx, &state,
4318 struct cli_smb2_set_reparse_point_fnum_state);
4323 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4324 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4325 return tevent_req_post(req, ev);
4331 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4332 if (tevent_req_nterror(req, status)) {
4333 return tevent_req_post(req, ev);
4336 state->input_buffer = data_blob_talloc(state,
4339 if (state->input_buffer.data == NULL) {
4340 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4341 return tevent_req_post(req, ev);
4344 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4345 state->cli->timeout,
4346 state->cli->smb2.session,
4347 state->cli->smb2.tcon,
4348 state->ph->fid_persistent, /* in_fid_persistent */
4349 state->ph->fid_volatile, /* in_fid_volatile */
4350 FSCTL_SET_REPARSE_POINT,
4351 0, /* in_max_input_length */
4352 &state->input_buffer ,
4355 SMB2_IOCTL_FLAG_IS_FSCTL);
4357 if (tevent_req_nomem(subreq, req)) {
4358 return tevent_req_post(req, ev);
4360 tevent_req_set_callback(subreq,
4361 cli_smb2_set_reparse_point_fnum_done,
4367 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
4369 struct tevent_req *req = tevent_req_callback_data(
4370 subreq, struct tevent_req);
4371 struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
4372 req, struct cli_smb2_set_reparse_point_fnum_state);
4375 status = smb2cli_ioctl_recv(subreq, state,
4378 TALLOC_FREE(subreq);
4379 if (tevent_req_nterror(req, status)) {
4382 tevent_req_done(req);
4385 NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
4387 return tevent_req_simple_recv_ntstatus(req);
4390 struct cli_smb2_get_reparse_point_fnum_state {
4391 struct cli_state *cli;
4393 struct smb2_hnd *ph;
4394 DATA_BLOB output_buffer;
4397 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
4399 struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
4400 TALLOC_CTX *mem_ctx,
4401 struct tevent_context *ev,
4402 struct cli_state *cli,
4405 struct tevent_req *req, *subreq;
4406 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
4409 req = tevent_req_create(mem_ctx, &state,
4410 struct cli_smb2_get_reparse_point_fnum_state);
4415 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4416 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4417 return tevent_req_post(req, ev);
4423 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4424 if (tevent_req_nterror(req, status)) {
4425 return tevent_req_post(req, ev);
4428 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4429 state->cli->timeout,
4430 state->cli->smb2.session,
4431 state->cli->smb2.tcon,
4432 state->ph->fid_persistent, /* in_fid_persistent */
4433 state->ph->fid_volatile, /* in_fid_volatile */
4434 FSCTL_GET_REPARSE_POINT,
4435 0, /* in_max_input_length */
4439 SMB2_IOCTL_FLAG_IS_FSCTL);
4441 if (tevent_req_nomem(subreq, req)) {
4442 return tevent_req_post(req, ev);
4444 tevent_req_set_callback(subreq,
4445 cli_smb2_get_reparse_point_fnum_done,
4451 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
4453 struct tevent_req *req = tevent_req_callback_data(
4454 subreq, struct tevent_req);
4455 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
4456 req, struct cli_smb2_get_reparse_point_fnum_state);
4459 status = smb2cli_ioctl_recv(subreq, state,
4461 &state->output_buffer);
4462 TALLOC_FREE(subreq);
4463 if (tevent_req_nterror(req, status)) {
4464 state->cli->raw_status = status;
4467 tevent_req_done(req);
4470 NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
4471 TALLOC_CTX *mem_ctx,
4474 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
4475 req, struct cli_smb2_get_reparse_point_fnum_state);
4477 if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
4478 tevent_req_received(req);
4479 return state->cli->raw_status;
4481 *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
4482 if (output->data == NULL) {
4483 tevent_req_received(req);
4484 return NT_STATUS_NO_MEMORY;
4486 tevent_req_received(req);
4487 return NT_STATUS_OK;