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(
171 struct tevent_context *ev,
172 struct cli_state *cli,
174 uint32_t create_flags,
175 uint32_t impersonation_level,
176 uint32_t desired_access,
177 uint32_t file_attributes,
178 uint32_t share_access,
179 uint32_t create_disposition,
180 uint32_t create_options)
182 struct tevent_req *req, *subreq;
183 struct cli_smb2_create_fnum_state *state;
184 size_t fname_len = 0;
185 const char *startp = NULL;
186 const char *endp = NULL;
187 time_t tstamp = (time_t)0;
188 struct smb2_create_blobs *cblobs = NULL;
190 req = tevent_req_create(mem_ctx, &state,
191 struct cli_smb2_create_fnum_state);
197 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
198 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
199 return tevent_req_post(req, ev);
202 if (cli->backup_intent) {
203 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
206 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
207 fname_len = strlen(fname);
208 if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
209 size_t len_before_gmt = startp - fname;
210 size_t len_after_gmt = fname + fname_len - endp;
215 char *new_fname = talloc_array(state, char,
216 len_before_gmt + len_after_gmt + 1);
218 if (tevent_req_nomem(new_fname, req)) {
219 return tevent_req_post(req, ev);
222 memcpy(new_fname, fname, len_before_gmt);
223 memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
225 fname_len = len_before_gmt + len_after_gmt;
227 unix_to_nt_time(&ntt, tstamp);
228 twrp_blob = data_blob_const((const void *)&ntt, 8);
230 cblobs = talloc_zero(state, struct smb2_create_blobs);
231 if (tevent_req_nomem(cblobs, req)) {
232 return tevent_req_post(req, ev);
235 status = smb2_create_blob_add(state, cblobs,
236 SMB2_CREATE_TAG_TWRP, twrp_blob);
237 if (!NT_STATUS_IS_OK(status)) {
238 tevent_req_nterror(req, status);
239 return tevent_req_post(req, ev);
243 /* SMB2 is pickier about pathnames. Ensure it doesn't
245 if (*fname == '\\') {
250 /* Or end in a '\' */
251 if (fname_len > 0 && fname[fname_len-1] == '\\') {
252 char *new_fname = talloc_strdup(state, fname);
253 if (tevent_req_nomem(new_fname, req)) {
254 return tevent_req_post(req, ev);
256 new_fname[fname_len-1] = '\0';
260 subreq = smb2cli_create_send(state, ev,
266 flags_to_smb2_oplock(create_flags),
274 if (tevent_req_nomem(subreq, req)) {
275 return tevent_req_post(req, ev);
277 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
279 state->subreq = subreq;
280 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
285 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
287 struct tevent_req *req = tevent_req_callback_data(
288 subreq, struct tevent_req);
289 struct cli_smb2_create_fnum_state *state = tevent_req_data(
290 req, struct cli_smb2_create_fnum_state);
294 status = smb2cli_create_recv(subreq, &h.fid_persistent,
295 &h.fid_volatile, &state->cr, NULL, NULL);
297 if (tevent_req_nterror(req, status)) {
301 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
302 if (tevent_req_nterror(req, status)) {
305 tevent_req_done(req);
308 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
310 struct cli_smb2_create_fnum_state *state = tevent_req_data(
311 req, struct cli_smb2_create_fnum_state);
312 return tevent_req_cancel(state->subreq);
315 NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum,
316 struct smb_create_returns *cr)
318 struct cli_smb2_create_fnum_state *state = tevent_req_data(
319 req, struct cli_smb2_create_fnum_state);
322 if (tevent_req_is_nterror(req, &status)) {
323 state->cli->raw_status = status;
327 *pfnum = state->fnum;
332 state->cli->raw_status = NT_STATUS_OK;
336 NTSTATUS cli_smb2_create_fnum(
337 struct cli_state *cli,
339 uint32_t create_flags,
340 uint32_t impersonation_level,
341 uint32_t desired_access,
342 uint32_t file_attributes,
343 uint32_t share_access,
344 uint32_t create_disposition,
345 uint32_t create_options,
347 struct smb_create_returns *cr)
349 TALLOC_CTX *frame = talloc_stackframe();
350 struct tevent_context *ev;
351 struct tevent_req *req;
352 NTSTATUS status = NT_STATUS_NO_MEMORY;
354 if (smbXcli_conn_has_async_calls(cli->conn)) {
356 * Can't use sync call while an async call is in flight
358 status = NT_STATUS_INVALID_PARAMETER;
361 ev = samba_tevent_context_init(frame);
365 req = cli_smb2_create_fnum_send(
380 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
383 status = cli_smb2_create_fnum_recv(req, pfid, cr);
389 /***************************************************************
390 Small wrapper that allows SMB2 close to use a uint16_t fnum.
391 ***************************************************************/
393 struct cli_smb2_close_fnum_state {
394 struct cli_state *cli;
399 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
401 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
402 struct tevent_context *ev,
403 struct cli_state *cli,
406 struct tevent_req *req, *subreq;
407 struct cli_smb2_close_fnum_state *state;
410 req = tevent_req_create(mem_ctx, &state,
411 struct cli_smb2_close_fnum_state);
418 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
419 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
420 return tevent_req_post(req, ev);
423 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
424 if (tevent_req_nterror(req, status)) {
425 return tevent_req_post(req, ev);
428 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
429 cli->smb2.session, cli->smb2.tcon,
430 0, state->ph->fid_persistent,
431 state->ph->fid_volatile);
432 if (tevent_req_nomem(subreq, req)) {
433 return tevent_req_post(req, ev);
435 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
439 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
441 struct tevent_req *req = tevent_req_callback_data(
442 subreq, struct tevent_req);
443 struct cli_smb2_close_fnum_state *state = tevent_req_data(
444 req, struct cli_smb2_close_fnum_state);
447 status = smb2cli_close_recv(subreq);
448 if (tevent_req_nterror(req, status)) {
452 /* Delete the fnum -> handle mapping. */
453 status = delete_smb2_handle_mapping(state->cli, &state->ph,
455 if (tevent_req_nterror(req, status)) {
458 tevent_req_done(req);
461 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
463 struct cli_smb2_close_fnum_state *state = tevent_req_data(
464 req, struct cli_smb2_close_fnum_state);
465 NTSTATUS status = NT_STATUS_OK;
467 if (tevent_req_is_nterror(req, &status)) {
468 state->cli->raw_status = status;
470 tevent_req_received(req);
474 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
476 TALLOC_CTX *frame = talloc_stackframe();
477 struct tevent_context *ev;
478 struct tevent_req *req;
479 NTSTATUS status = NT_STATUS_NO_MEMORY;
481 if (smbXcli_conn_has_async_calls(cli->conn)) {
483 * Can't use sync call while an async call is in flight
485 status = NT_STATUS_INVALID_PARAMETER;
488 ev = samba_tevent_context_init(frame);
492 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
496 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
499 status = cli_smb2_close_fnum_recv(req);
505 struct cli_smb2_delete_on_close_state {
506 struct cli_state *cli;
513 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
515 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
516 struct tevent_context *ev,
517 struct cli_state *cli,
521 struct tevent_req *req = NULL;
522 struct cli_smb2_delete_on_close_state *state = NULL;
523 struct tevent_req *subreq = NULL;
524 uint8_t in_info_type;
525 uint8_t in_file_info_class;
528 req = tevent_req_create(mem_ctx, &state,
529 struct cli_smb2_delete_on_close_state);
536 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
537 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
538 return tevent_req_post(req, ev);
541 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
542 if (tevent_req_nterror(req, status)) {
543 return tevent_req_post(req, ev);
547 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
548 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
551 in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
552 /* Setup data array. */
553 SCVAL(&state->data[0], 0, flag ? 1 : 0);
554 state->inbuf.data = &state->data[0];
555 state->inbuf.length = 1;
557 subreq = smb2cli_set_info_send(state, ev,
564 &state->inbuf, /* in_input_buffer */
565 0, /* in_additional_info */
566 state->ph->fid_persistent,
567 state->ph->fid_volatile);
568 if (tevent_req_nomem(subreq, req)) {
569 return tevent_req_post(req, ev);
571 tevent_req_set_callback(subreq,
572 cli_smb2_delete_on_close_done,
577 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
579 NTSTATUS status = smb2cli_set_info_recv(subreq);
580 tevent_req_simple_finish_ntstatus(subreq, status);
583 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
585 struct cli_smb2_delete_on_close_state *state =
587 struct cli_smb2_delete_on_close_state);
590 if (tevent_req_is_nterror(req, &status)) {
591 state->cli->raw_status = status;
592 tevent_req_received(req);
596 state->cli->raw_status = NT_STATUS_OK;
597 tevent_req_received(req);
601 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
603 TALLOC_CTX *frame = talloc_stackframe();
604 struct tevent_context *ev;
605 struct tevent_req *req;
606 NTSTATUS status = NT_STATUS_NO_MEMORY;
608 if (smbXcli_conn_has_async_calls(cli->conn)) {
610 * Can't use sync call while an async call is in flight
612 status = NT_STATUS_INVALID_PARAMETER;
615 ev = samba_tevent_context_init(frame);
619 req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
623 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
626 status = cli_smb2_delete_on_close_recv(req);
632 /***************************************************************
633 Small wrapper that allows SMB2 to create a directory
635 ***************************************************************/
637 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
642 if (smbXcli_conn_has_async_calls(cli->conn)) {
644 * Can't use sync call while an async call is in flight
646 return NT_STATUS_INVALID_PARAMETER;
649 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
650 return NT_STATUS_INVALID_PARAMETER;
653 status = cli_smb2_create_fnum(cli,
655 0, /* create_flags */
656 SMB2_IMPERSONATION_IMPERSONATION,
657 FILE_READ_ATTRIBUTES, /* desired_access */
658 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
659 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
660 FILE_CREATE, /* create_disposition */
661 FILE_DIRECTORY_FILE, /* create_options */
665 if (!NT_STATUS_IS_OK(status)) {
668 return cli_smb2_close_fnum(cli, fnum);
671 /***************************************************************
672 Small wrapper that allows SMB2 to delete a directory
674 ***************************************************************/
676 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
681 if (smbXcli_conn_has_async_calls(cli->conn)) {
683 * Can't use sync call while an async call is in flight
685 return NT_STATUS_INVALID_PARAMETER;
688 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
689 return NT_STATUS_INVALID_PARAMETER;
692 status = cli_smb2_create_fnum(cli,
694 0, /* create_flags */
695 SMB2_IMPERSONATION_IMPERSONATION,
696 DELETE_ACCESS, /* desired_access */
697 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
698 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
699 FILE_OPEN, /* create_disposition */
700 FILE_DIRECTORY_FILE, /* create_options */
704 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
706 * Naive option to match our SMB1 code. Assume the
707 * symlink path that tripped us up was the last
708 * component and try again. Eventually we will have to
709 * deal with the returned path unprocessed component. JRA.
711 status = cli_smb2_create_fnum(cli,
713 0, /* create_flags */
714 SMB2_IMPERSONATION_IMPERSONATION,
715 DELETE_ACCESS, /* desired_access */
716 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
717 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
718 FILE_OPEN, /* create_disposition */
720 FILE_DELETE_ON_CLOSE|
721 FILE_OPEN_REPARSE_POINT, /* create_options */
726 if (!NT_STATUS_IS_OK(status)) {
730 status = cli_smb2_delete_on_close(cli, fnum, true);
731 if (!NT_STATUS_IS_OK(status)) {
732 cli_smb2_close_fnum(cli, fnum);
736 return cli_smb2_close_fnum(cli, fnum);
739 /***************************************************************
740 Small wrapper that allows SMB2 to unlink a pathname.
742 ***************************************************************/
744 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
749 if (smbXcli_conn_has_async_calls(cli->conn)) {
751 * Can't use sync call while an async call is in flight
753 return NT_STATUS_INVALID_PARAMETER;
756 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
757 return NT_STATUS_INVALID_PARAMETER;
760 status = cli_smb2_create_fnum(cli,
762 0, /* create_flags */
763 SMB2_IMPERSONATION_IMPERSONATION,
764 DELETE_ACCESS, /* desired_access */
765 FILE_ATTRIBUTE_NORMAL, /* file attributes */
766 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
767 FILE_OPEN, /* create_disposition */
768 FILE_DELETE_ON_CLOSE, /* create_options */
772 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
774 * Naive option to match our SMB1 code. Assume the
775 * symlink path that tripped us up was the last
776 * component and try again. Eventually we will have to
777 * deal with the returned path unprocessed component. JRA.
779 status = cli_smb2_create_fnum(cli,
781 0, /* create_flags */
782 SMB2_IMPERSONATION_IMPERSONATION,
783 DELETE_ACCESS, /* desired_access */
784 FILE_ATTRIBUTE_NORMAL, /* file attributes */
785 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
786 FILE_OPEN, /* create_disposition */
787 FILE_DELETE_ON_CLOSE|
788 FILE_OPEN_REPARSE_POINT, /* create_options */
793 if (!NT_STATUS_IS_OK(status)) {
796 return cli_smb2_close_fnum(cli, fnum);
799 /***************************************************************
800 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
801 ***************************************************************/
803 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
804 uint32_t dir_data_length,
805 struct file_info *finfo,
806 uint32_t *next_offset)
812 if (dir_data_length < 4) {
813 return NT_STATUS_INFO_LENGTH_MISMATCH;
816 *next_offset = IVAL(dir_data, 0);
818 if (*next_offset > dir_data_length) {
819 return NT_STATUS_INFO_LENGTH_MISMATCH;
822 if (*next_offset != 0) {
823 /* Ensure we only read what in this record. */
824 dir_data_length = *next_offset;
827 if (dir_data_length < 105) {
828 return NT_STATUS_INFO_LENGTH_MISMATCH;
831 finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
832 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
833 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
834 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
835 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
836 finfo->allocated_size = IVAL2_TO_SMB_BIG_UINT(dir_data + 48, 0);
837 finfo->mode = CVAL(dir_data + 56, 0);
838 finfo->ino = IVAL2_TO_SMB_BIG_UINT(dir_data + 96, 0);
839 namelen = IVAL(dir_data + 60,0);
840 if (namelen > (dir_data_length - 104)) {
841 return NT_STATUS_INFO_LENGTH_MISMATCH;
843 slen = CVAL(dir_data + 68, 0);
845 return NT_STATUS_INFO_LENGTH_MISMATCH;
847 ret = pull_string_talloc(finfo,
849 FLAGS2_UNICODE_STRINGS,
854 if (ret == (size_t)-1) {
855 /* Bad conversion. */
856 return NT_STATUS_INVALID_NETWORK_RESPONSE;
859 ret = pull_string_talloc(finfo,
861 FLAGS2_UNICODE_STRINGS,
866 if (ret == (size_t)-1) {
867 /* Bad conversion. */
868 return NT_STATUS_INVALID_NETWORK_RESPONSE;
873 /*******************************************************************
874 Given a filename - get its directory name
875 ********************************************************************/
877 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
885 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
888 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
899 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
902 (*parent)[len] = '\0';
910 /***************************************************************
911 Wrapper that allows SMB2 to list a directory.
913 ***************************************************************/
915 NTSTATUS cli_smb2_list(struct cli_state *cli,
916 const char *pathname,
918 NTSTATUS (*fn)(const char *,
925 uint16_t fnum = 0xffff;
926 char *parent_dir = NULL;
927 const char *mask = NULL;
928 struct smb2_hnd *ph = NULL;
929 bool processed_file = false;
930 TALLOC_CTX *frame = talloc_stackframe();
931 TALLOC_CTX *subframe = NULL;
934 uint32_t max_avail_len;
937 if (smbXcli_conn_has_async_calls(cli->conn)) {
939 * Can't use sync call while an async call is in flight
941 status = NT_STATUS_INVALID_PARAMETER;
945 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
946 status = NT_STATUS_INVALID_PARAMETER;
950 /* Get the directory name. */
951 if (!windows_parent_dirname(frame,
955 status = NT_STATUS_NO_MEMORY;
959 mask_has_wild = ms_has_wild(mask);
961 status = cli_smb2_create_fnum(cli,
963 0, /* create_flags */
964 SMB2_IMPERSONATION_IMPERSONATION,
965 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
966 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
967 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
968 FILE_OPEN, /* create_disposition */
969 FILE_DIRECTORY_FILE, /* create_options */
973 if (!NT_STATUS_IS_OK(status)) {
977 status = map_fnum_to_smb2_handle(cli,
980 if (!NT_STATUS_IS_OK(status)) {
985 * ideally, use the max transaction size, but don't send a request
986 * bigger than we have credits available for
988 max_trans = smb2cli_conn_max_trans_size(cli->conn);
989 ok = smb2cli_conn_req_possible(cli->conn, &max_avail_len);
991 max_trans = MIN(max_trans, max_avail_len);
995 uint8_t *dir_data = NULL;
996 uint32_t dir_data_length = 0;
997 uint32_t next_offset = 0;
998 subframe = talloc_stackframe();
1000 status = smb2cli_query_directory(cli->conn,
1004 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
1015 if (!NT_STATUS_IS_OK(status)) {
1016 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1023 struct file_info *finfo = talloc_zero(subframe,
1026 if (finfo == NULL) {
1027 status = NT_STATUS_NO_MEMORY;
1031 status = parse_finfo_id_both_directory_info(dir_data,
1036 if (!NT_STATUS_IS_OK(status)) {
1040 if (dir_check_ftype((uint32_t)finfo->mode,
1041 (uint32_t)attribute)) {
1043 * Only process if attributes match.
1044 * On SMB1 server does this, so on
1045 * SMB2 we need to emulate in the
1048 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1050 processed_file = true;
1052 status = fn(cli->dfs_mountpoint,
1057 if (!NT_STATUS_IS_OK(status)) {
1064 /* Move to next entry. */
1066 dir_data += next_offset;
1067 dir_data_length -= next_offset;
1069 } while (next_offset != 0);
1071 TALLOC_FREE(subframe);
1073 if (!mask_has_wild) {
1075 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1076 * when handed a non-wildcard path. Do it
1077 * for the server (with a non-wildcard path
1078 * there should only ever be one file returned.
1080 status = STATUS_NO_MORE_FILES;
1084 } while (NT_STATUS_IS_OK(status));
1086 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1087 status = NT_STATUS_OK;
1090 if (NT_STATUS_IS_OK(status) && !processed_file) {
1092 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1093 * if no files match. Emulate this in the client.
1095 status = NT_STATUS_NO_SUCH_FILE;
1100 if (fnum != 0xffff) {
1101 cli_smb2_close_fnum(cli, fnum);
1104 cli->raw_status = status;
1106 TALLOC_FREE(subframe);
1111 /***************************************************************
1112 Wrapper that allows SMB2 to query a path info (basic level).
1114 ***************************************************************/
1116 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1118 SMB_STRUCT_STAT *sbuf,
1119 uint32_t *attributes)
1122 struct smb_create_returns cr;
1123 uint16_t fnum = 0xffff;
1124 size_t namelen = strlen(name);
1126 if (smbXcli_conn_has_async_calls(cli->conn)) {
1128 * Can't use sync call while an async call is in flight
1130 return NT_STATUS_INVALID_PARAMETER;
1133 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1134 return NT_STATUS_INVALID_PARAMETER;
1137 /* SMB2 is pickier about pathnames. Ensure it doesn't
1139 if (namelen > 0 && name[namelen-1] == '\\') {
1140 char *modname = talloc_strdup(talloc_tos(), name);
1141 modname[namelen-1] = '\0';
1145 /* This is commonly used as a 'cd'. Try qpathinfo on
1146 a directory handle first. */
1148 status = cli_smb2_create_fnum(cli,
1150 0, /* create_flags */
1151 SMB2_IMPERSONATION_IMPERSONATION,
1152 FILE_READ_ATTRIBUTES, /* desired_access */
1153 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1154 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1155 FILE_OPEN, /* create_disposition */
1156 FILE_DIRECTORY_FILE, /* create_options */
1160 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1161 /* Maybe a file ? */
1162 status = cli_smb2_create_fnum(cli,
1164 0, /* create_flags */
1165 SMB2_IMPERSONATION_IMPERSONATION,
1166 FILE_READ_ATTRIBUTES, /* desired_access */
1167 0, /* file attributes */
1168 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1169 FILE_OPEN, /* create_disposition */
1170 0, /* create_options */
1175 if (!NT_STATUS_IS_OK(status)) {
1179 status = cli_smb2_close_fnum(cli, fnum);
1183 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1184 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1185 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1186 sbuf->st_ex_size = cr.end_of_file;
1187 *attributes = cr.file_attributes;
1192 /***************************************************************
1193 Wrapper that allows SMB2 to check if a path is a directory.
1195 ***************************************************************/
1197 NTSTATUS cli_smb2_chkpath(struct cli_state *cli,
1201 uint16_t fnum = 0xffff;
1203 if (smbXcli_conn_has_async_calls(cli->conn)) {
1205 * Can't use sync call while an async call is in flight
1207 return NT_STATUS_INVALID_PARAMETER;
1210 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1211 return NT_STATUS_INVALID_PARAMETER;
1214 /* Ensure this is a directory. */
1215 status = cli_smb2_create_fnum(cli,
1217 0, /* create_flags */
1218 SMB2_IMPERSONATION_IMPERSONATION,
1219 FILE_READ_ATTRIBUTES, /* desired_access */
1220 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1221 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1222 FILE_OPEN, /* create_disposition */
1223 FILE_DIRECTORY_FILE, /* create_options */
1227 if (!NT_STATUS_IS_OK(status)) {
1231 return cli_smb2_close_fnum(cli, fnum);
1234 /***************************************************************
1235 Helper function for pathname operations.
1236 ***************************************************************/
1238 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1240 uint32_t desired_access,
1244 size_t namelen = strlen(name);
1245 TALLOC_CTX *frame = talloc_stackframe();
1246 uint32_t create_options = 0;
1248 /* SMB2 is pickier about pathnames. Ensure it doesn't
1250 if (namelen > 0 && name[namelen-1] == '\\') {
1251 char *modname = talloc_strdup(frame, name);
1252 if (modname == NULL) {
1253 status = NT_STATUS_NO_MEMORY;
1256 modname[namelen-1] = '\0';
1260 /* Try to open a file handle first. */
1261 status = cli_smb2_create_fnum(cli,
1263 0, /* create_flags */
1264 SMB2_IMPERSONATION_IMPERSONATION,
1266 0, /* file attributes */
1267 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1268 FILE_OPEN, /* create_disposition */
1273 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1275 * Naive option to match our SMB1 code. Assume the
1276 * symlink path that tripped us up was the last
1277 * component and try again. Eventually we will have to
1278 * deal with the returned path unprocessed component. JRA.
1280 create_options |= FILE_OPEN_REPARSE_POINT;
1281 status = cli_smb2_create_fnum(cli,
1283 0, /* create_flags */
1284 SMB2_IMPERSONATION_IMPERSONATION,
1286 0, /* file attributes */
1287 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1288 FILE_OPEN, /* create_disposition */
1294 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1295 create_options |= FILE_DIRECTORY_FILE;
1296 status = cli_smb2_create_fnum(cli,
1298 0, /* create_flags */
1299 SMB2_IMPERSONATION_IMPERSONATION,
1301 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1302 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1303 FILE_OPEN, /* create_disposition */
1304 FILE_DIRECTORY_FILE, /* create_options */
1315 /***************************************************************
1316 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1318 ***************************************************************/
1320 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1325 DATA_BLOB outbuf = data_blob_null;
1326 uint16_t fnum = 0xffff;
1327 struct smb2_hnd *ph = NULL;
1328 uint32_t altnamelen = 0;
1329 TALLOC_CTX *frame = talloc_stackframe();
1331 if (smbXcli_conn_has_async_calls(cli->conn)) {
1333 * Can't use sync call while an async call is in flight
1335 status = NT_STATUS_INVALID_PARAMETER;
1339 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1340 status = NT_STATUS_INVALID_PARAMETER;
1344 status = get_fnum_from_path(cli,
1346 FILE_READ_ATTRIBUTES,
1349 if (!NT_STATUS_IS_OK(status)) {
1353 status = map_fnum_to_smb2_handle(cli,
1356 if (!NT_STATUS_IS_OK(status)) {
1360 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1361 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1363 status = smb2cli_query_info(cli->conn,
1367 1, /* in_info_type */
1368 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1369 0xFFFF, /* in_max_output_length */
1370 NULL, /* in_input_buffer */
1371 0, /* in_additional_info */
1378 if (!NT_STATUS_IS_OK(status)) {
1382 /* Parse the reply. */
1383 if (outbuf.length < 4) {
1384 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1388 altnamelen = IVAL(outbuf.data, 0);
1389 if (altnamelen > outbuf.length - 4) {
1390 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1394 if (altnamelen > 0) {
1396 char *short_name = NULL;
1397 ret = pull_string_talloc(frame,
1399 FLAGS2_UNICODE_STRINGS,
1404 if (ret == (size_t)-1) {
1405 /* Bad conversion. */
1406 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1410 fstrcpy(alt_name, short_name);
1415 status = NT_STATUS_OK;
1419 if (fnum != 0xffff) {
1420 cli_smb2_close_fnum(cli, fnum);
1423 cli->raw_status = status;
1430 /***************************************************************
1431 Wrapper that allows SMB2 to query a fnum info (basic level).
1433 ***************************************************************/
1435 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1439 struct timespec *create_time,
1440 struct timespec *access_time,
1441 struct timespec *write_time,
1442 struct timespec *change_time,
1446 DATA_BLOB outbuf = data_blob_null;
1447 struct smb2_hnd *ph = NULL;
1448 TALLOC_CTX *frame = talloc_stackframe();
1450 if (smbXcli_conn_has_async_calls(cli->conn)) {
1452 * Can't use sync call while an async call is in flight
1454 status = NT_STATUS_INVALID_PARAMETER;
1458 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1459 status = NT_STATUS_INVALID_PARAMETER;
1463 status = map_fnum_to_smb2_handle(cli,
1466 if (!NT_STATUS_IS_OK(status)) {
1470 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1471 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1473 status = smb2cli_query_info(cli->conn,
1477 1, /* in_info_type */
1478 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1479 0xFFFF, /* in_max_output_length */
1480 NULL, /* in_input_buffer */
1481 0, /* in_additional_info */
1487 if (!NT_STATUS_IS_OK(status)) {
1491 /* Parse the reply. */
1492 if (outbuf.length < 0x60) {
1493 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1498 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1501 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1504 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1507 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1510 uint32_t attr = IVAL(outbuf.data, 0x20);
1511 *mode = (uint16_t)attr;
1514 uint64_t file_size = BVAL(outbuf.data, 0x30);
1515 *size = (off_t)file_size;
1518 uint64_t file_index = BVAL(outbuf.data, 0x40);
1519 *ino = (SMB_INO_T)file_index;
1524 cli->raw_status = status;
1530 /***************************************************************
1531 Wrapper that allows SMB2 to query an fnum.
1532 Implement on top of cli_smb2_qfileinfo_basic().
1534 ***************************************************************/
1536 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1540 time_t *change_time,
1541 time_t *access_time,
1544 struct timespec access_time_ts;
1545 struct timespec write_time_ts;
1546 struct timespec change_time_ts;
1547 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1557 cli->raw_status = status;
1559 if (!NT_STATUS_IS_OK(status)) {
1564 *change_time = change_time_ts.tv_sec;
1567 *access_time = access_time_ts.tv_sec;
1570 *write_time = write_time_ts.tv_sec;
1572 return NT_STATUS_OK;
1575 /***************************************************************
1576 Wrapper that allows SMB2 to get pathname attributes.
1578 ***************************************************************/
1580 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1587 uint16_t fnum = 0xffff;
1588 struct smb2_hnd *ph = NULL;
1589 TALLOC_CTX *frame = talloc_stackframe();
1591 if (smbXcli_conn_has_async_calls(cli->conn)) {
1593 * Can't use sync call while an async call is in flight
1595 status = NT_STATUS_INVALID_PARAMETER;
1599 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1600 status = NT_STATUS_INVALID_PARAMETER;
1604 status = get_fnum_from_path(cli,
1606 FILE_READ_ATTRIBUTES,
1609 if (!NT_STATUS_IS_OK(status)) {
1613 status = map_fnum_to_smb2_handle(cli,
1616 if (!NT_STATUS_IS_OK(status)) {
1619 status = cli_smb2_getattrE(cli,
1626 if (!NT_STATUS_IS_OK(status)) {
1632 if (fnum != 0xffff) {
1633 cli_smb2_close_fnum(cli, fnum);
1636 cli->raw_status = status;
1642 /***************************************************************
1643 Wrapper that allows SMB2 to query a pathname info (basic level).
1644 Implement on top of cli_smb2_qfileinfo_basic().
1646 ***************************************************************/
1648 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1650 struct timespec *create_time,
1651 struct timespec *access_time,
1652 struct timespec *write_time,
1653 struct timespec *change_time,
1659 struct smb2_hnd *ph = NULL;
1660 uint16_t fnum = 0xffff;
1661 TALLOC_CTX *frame = talloc_stackframe();
1663 if (smbXcli_conn_has_async_calls(cli->conn)) {
1665 * Can't use sync call while an async call is in flight
1667 status = NT_STATUS_INVALID_PARAMETER;
1671 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1672 status = NT_STATUS_INVALID_PARAMETER;
1676 status = get_fnum_from_path(cli,
1678 FILE_READ_ATTRIBUTES,
1681 if (!NT_STATUS_IS_OK(status)) {
1685 status = map_fnum_to_smb2_handle(cli,
1688 if (!NT_STATUS_IS_OK(status)) {
1692 status = cli_smb2_qfileinfo_basic(cli,
1704 if (fnum != 0xffff) {
1705 cli_smb2_close_fnum(cli, fnum);
1708 cli->raw_status = status;
1714 /***************************************************************
1715 Wrapper that allows SMB2 to query pathname streams.
1717 ***************************************************************/
1719 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1721 TALLOC_CTX *mem_ctx,
1722 unsigned int *pnum_streams,
1723 struct stream_struct **pstreams)
1726 struct smb2_hnd *ph = NULL;
1727 uint16_t fnum = 0xffff;
1728 DATA_BLOB outbuf = data_blob_null;
1729 TALLOC_CTX *frame = talloc_stackframe();
1731 if (smbXcli_conn_has_async_calls(cli->conn)) {
1733 * Can't use sync call while an async call is in flight
1735 status = NT_STATUS_INVALID_PARAMETER;
1739 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1740 status = NT_STATUS_INVALID_PARAMETER;
1744 status = get_fnum_from_path(cli,
1746 FILE_READ_ATTRIBUTES,
1749 if (!NT_STATUS_IS_OK(status)) {
1753 status = map_fnum_to_smb2_handle(cli,
1756 if (!NT_STATUS_IS_OK(status)) {
1760 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1761 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1763 status = smb2cli_query_info(cli->conn,
1767 1, /* in_info_type */
1768 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1769 0xFFFF, /* in_max_output_length */
1770 NULL, /* in_input_buffer */
1771 0, /* in_additional_info */
1778 if (!NT_STATUS_IS_OK(status)) {
1782 /* Parse the reply. */
1783 if (!parse_streams_blob(mem_ctx,
1788 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1794 if (fnum != 0xffff) {
1795 cli_smb2_close_fnum(cli, fnum);
1798 cli->raw_status = status;
1804 /***************************************************************
1805 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
1808 ***************************************************************/
1810 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
1812 uint8_t in_info_type,
1813 uint8_t in_file_info_class,
1814 const DATA_BLOB *p_in_data)
1817 uint16_t fnum = 0xffff;
1818 struct smb2_hnd *ph = NULL;
1819 TALLOC_CTX *frame = talloc_stackframe();
1821 if (smbXcli_conn_has_async_calls(cli->conn)) {
1823 * Can't use sync call while an async call is in flight
1825 status = NT_STATUS_INVALID_PARAMETER;
1829 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1830 status = NT_STATUS_INVALID_PARAMETER;
1834 status = get_fnum_from_path(cli,
1836 FILE_WRITE_ATTRIBUTES,
1839 if (!NT_STATUS_IS_OK(status)) {
1843 status = map_fnum_to_smb2_handle(cli,
1846 if (!NT_STATUS_IS_OK(status)) {
1850 status = smb2cli_set_info(cli->conn,
1856 p_in_data, /* in_input_buffer */
1857 0, /* in_additional_info */
1862 if (fnum != 0xffff) {
1863 cli_smb2_close_fnum(cli, fnum);
1866 cli->raw_status = status;
1873 /***************************************************************
1874 Wrapper that allows SMB2 to set pathname attributes.
1876 ***************************************************************/
1878 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1883 uint8_t inbuf_store[40];
1884 DATA_BLOB inbuf = data_blob_null;
1886 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1887 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1889 inbuf.data = inbuf_store;
1890 inbuf.length = sizeof(inbuf_store);
1891 data_blob_clear(&inbuf);
1894 * SMB1 uses attr == 0 to clear all attributes
1895 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
1896 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
1897 * request attribute change.
1899 * SMB2 uses exactly the reverse. Unfortunately as the
1900 * cli_setatr() ABI is exposed inside libsmbclient,
1901 * we must make the SMB2 cli_smb2_setatr() call
1902 * export the same ABI as the SMB1 cli_setatr()
1903 * which calls it. This means reversing the sense
1904 * of the requested attr argument if it's zero
1905 * or FILE_ATTRIBUTE_NORMAL.
1907 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
1911 attr = FILE_ATTRIBUTE_NORMAL;
1912 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
1916 SSVAL(inbuf.data, 32, attr);
1918 put_long_date((char *)inbuf.data + 16,mtime);
1920 /* Set all the other times to -1. */
1921 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1922 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1923 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1925 return cli_smb2_setpathinfo(cli,
1927 1, /* in_info_type */
1928 /* in_file_info_class */
1929 SMB_FILE_BASIC_INFORMATION - 1000,
1934 /***************************************************************
1935 Wrapper that allows SMB2 to set file handle times.
1937 ***************************************************************/
1939 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1946 struct smb2_hnd *ph = NULL;
1947 uint8_t inbuf_store[40];
1948 DATA_BLOB inbuf = data_blob_null;
1950 if (smbXcli_conn_has_async_calls(cli->conn)) {
1952 * Can't use sync call while an async call is in flight
1954 return NT_STATUS_INVALID_PARAMETER;
1957 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1958 return NT_STATUS_INVALID_PARAMETER;
1961 status = map_fnum_to_smb2_handle(cli,
1964 if (!NT_STATUS_IS_OK(status)) {
1968 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1969 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1971 inbuf.data = inbuf_store;
1972 inbuf.length = sizeof(inbuf_store);
1973 data_blob_clear(&inbuf);
1975 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1976 if (change_time != 0) {
1977 put_long_date((char *)inbuf.data + 24, change_time);
1979 if (access_time != 0) {
1980 put_long_date((char *)inbuf.data + 8, access_time);
1982 if (write_time != 0) {
1983 put_long_date((char *)inbuf.data + 16, write_time);
1986 cli->raw_status = smb2cli_set_info(cli->conn,
1990 1, /* in_info_type */
1991 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1992 &inbuf, /* in_input_buffer */
1993 0, /* in_additional_info */
1997 return cli->raw_status;
2000 /***************************************************************
2001 Wrapper that allows SMB2 to query disk attributes (size).
2003 ***************************************************************/
2005 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2006 uint64_t *bsize, uint64_t *total, uint64_t *avail)
2009 uint16_t fnum = 0xffff;
2010 DATA_BLOB outbuf = data_blob_null;
2011 struct smb2_hnd *ph = NULL;
2012 uint32_t sectors_per_unit = 0;
2013 uint32_t bytes_per_sector = 0;
2014 uint64_t total_size = 0;
2015 uint64_t size_free = 0;
2016 TALLOC_CTX *frame = talloc_stackframe();
2018 if (smbXcli_conn_has_async_calls(cli->conn)) {
2020 * Can't use sync call while an async call is in flight
2022 status = NT_STATUS_INVALID_PARAMETER;
2026 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2027 status = NT_STATUS_INVALID_PARAMETER;
2031 /* First open the top level directory. */
2032 status = cli_smb2_create_fnum(cli,
2034 0, /* create_flags */
2035 SMB2_IMPERSONATION_IMPERSONATION,
2036 FILE_READ_ATTRIBUTES, /* desired_access */
2037 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2038 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2039 FILE_OPEN, /* create_disposition */
2040 FILE_DIRECTORY_FILE, /* create_options */
2044 if (!NT_STATUS_IS_OK(status)) {
2048 status = map_fnum_to_smb2_handle(cli,
2051 if (!NT_STATUS_IS_OK(status)) {
2055 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2056 level 3 (SMB_FS_SIZE_INFORMATION). */
2058 status = smb2cli_query_info(cli->conn,
2062 2, /* in_info_type */
2063 3, /* in_file_info_class */
2064 0xFFFF, /* in_max_output_length */
2065 NULL, /* in_input_buffer */
2066 0, /* in_additional_info */
2072 if (!NT_STATUS_IS_OK(status)) {
2076 /* Parse the reply. */
2077 if (outbuf.length != 24) {
2078 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2082 total_size = BVAL(outbuf.data, 0);
2083 size_free = BVAL(outbuf.data, 8);
2084 sectors_per_unit = IVAL(outbuf.data, 16);
2085 bytes_per_sector = IVAL(outbuf.data, 20);
2088 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2091 *total = total_size;
2097 status = NT_STATUS_OK;
2101 if (fnum != 0xffff) {
2102 cli_smb2_close_fnum(cli, fnum);
2105 cli->raw_status = status;
2111 /***************************************************************
2112 Wrapper that allows SMB2 to query file system sizes.
2114 ***************************************************************/
2116 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2117 uint64_t *total_allocation_units,
2118 uint64_t *caller_allocation_units,
2119 uint64_t *actual_allocation_units,
2120 uint64_t *sectors_per_allocation_unit,
2121 uint64_t *bytes_per_sector)
2124 uint16_t fnum = 0xffff;
2125 DATA_BLOB outbuf = data_blob_null;
2126 struct smb2_hnd *ph = NULL;
2127 TALLOC_CTX *frame = talloc_stackframe();
2129 if (smbXcli_conn_has_async_calls(cli->conn)) {
2131 * Can't use sync call while an async call is in flight
2133 status = NT_STATUS_INVALID_PARAMETER;
2137 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2138 status = NT_STATUS_INVALID_PARAMETER;
2142 /* First open the top level directory. */
2144 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2145 SMB2_IMPERSONATION_IMPERSONATION,
2146 FILE_READ_ATTRIBUTES, /* desired_access */
2147 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2148 FILE_SHARE_READ | FILE_SHARE_WRITE |
2149 FILE_SHARE_DELETE, /* share_access */
2150 FILE_OPEN, /* create_disposition */
2151 FILE_DIRECTORY_FILE, /* create_options */
2155 if (!NT_STATUS_IS_OK(status)) {
2159 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2160 if (!NT_STATUS_IS_OK(status)) {
2164 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2165 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2167 status = smb2cli_query_info(cli->conn,
2171 SMB2_GETINFO_FS, /* in_info_type */
2172 /* in_file_info_class */
2173 SMB_FS_FULL_SIZE_INFORMATION - 1000,
2174 0xFFFF, /* in_max_output_length */
2175 NULL, /* in_input_buffer */
2176 0, /* in_additional_info */
2182 if (!NT_STATUS_IS_OK(status)) {
2186 if (outbuf.length < 32) {
2187 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2191 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2192 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2193 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2194 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2195 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2199 if (fnum != 0xffff) {
2200 cli_smb2_close_fnum(cli, fnum);
2203 cli->raw_status = status;
2209 /***************************************************************
2210 Wrapper that allows SMB2 to query file system attributes.
2212 ***************************************************************/
2214 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2217 uint16_t fnum = 0xffff;
2218 DATA_BLOB outbuf = data_blob_null;
2219 struct smb2_hnd *ph = NULL;
2220 TALLOC_CTX *frame = talloc_stackframe();
2222 if (smbXcli_conn_has_async_calls(cli->conn)) {
2224 * Can't use sync call while an async call is in flight
2226 status = NT_STATUS_INVALID_PARAMETER;
2230 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2231 status = NT_STATUS_INVALID_PARAMETER;
2235 /* First open the top level directory. */
2237 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2238 SMB2_IMPERSONATION_IMPERSONATION,
2239 FILE_READ_ATTRIBUTES, /* desired_access */
2240 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2241 FILE_SHARE_READ | FILE_SHARE_WRITE |
2242 FILE_SHARE_DELETE, /* share_access */
2243 FILE_OPEN, /* create_disposition */
2244 FILE_DIRECTORY_FILE, /* create_options */
2248 if (!NT_STATUS_IS_OK(status)) {
2252 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2253 if (!NT_STATUS_IS_OK(status)) {
2257 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2258 cli->smb2.tcon, 2, /* in_info_type */
2259 5, /* in_file_info_class */
2260 0xFFFF, /* in_max_output_length */
2261 NULL, /* in_input_buffer */
2262 0, /* in_additional_info */
2264 ph->fid_persistent, ph->fid_volatile, frame,
2266 if (!NT_STATUS_IS_OK(status)) {
2270 if (outbuf.length < 12) {
2271 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2275 *fs_attr = IVAL(outbuf.data, 0);
2279 if (fnum != 0xffff) {
2280 cli_smb2_close_fnum(cli, fnum);
2283 cli->raw_status = status;
2289 /***************************************************************
2290 Wrapper that allows SMB2 to query file system volume info.
2292 ***************************************************************/
2294 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2295 TALLOC_CTX *mem_ctx,
2296 char **_volume_name,
2297 uint32_t *pserial_number,
2301 uint16_t fnum = 0xffff;
2302 DATA_BLOB outbuf = data_blob_null;
2303 struct smb2_hnd *ph = NULL;
2305 char *volume_name = NULL;
2306 TALLOC_CTX *frame = talloc_stackframe();
2308 if (smbXcli_conn_has_async_calls(cli->conn)) {
2310 * Can't use sync call while an async call is in flight
2312 status = NT_STATUS_INVALID_PARAMETER;
2316 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2317 status = NT_STATUS_INVALID_PARAMETER;
2321 /* First open the top level directory. */
2323 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2324 SMB2_IMPERSONATION_IMPERSONATION,
2325 FILE_READ_ATTRIBUTES, /* desired_access */
2326 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2327 FILE_SHARE_READ | FILE_SHARE_WRITE |
2328 FILE_SHARE_DELETE, /* share_access */
2329 FILE_OPEN, /* create_disposition */
2330 FILE_DIRECTORY_FILE, /* create_options */
2334 if (!NT_STATUS_IS_OK(status)) {
2338 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2339 if (!NT_STATUS_IS_OK(status)) {
2343 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2344 level 1 (SMB_FS_VOLUME_INFORMATION). */
2346 status = smb2cli_query_info(cli->conn,
2350 SMB2_GETINFO_FS, /* in_info_type */
2351 /* in_file_info_class */
2352 SMB_FS_VOLUME_INFORMATION - 1000,
2353 0xFFFF, /* in_max_output_length */
2354 NULL, /* in_input_buffer */
2355 0, /* in_additional_info */
2361 if (!NT_STATUS_IS_OK(status)) {
2365 if (outbuf.length < 24) {
2366 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2372 ts = interpret_long_date((char *)outbuf.data);
2375 if (pserial_number) {
2376 *pserial_number = IVAL(outbuf.data,8);
2378 nlen = IVAL(outbuf.data,12);
2379 if (nlen + 18 < 18) {
2381 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2385 * The next check is safe as we know outbuf.length >= 24
2388 if (nlen > (outbuf.length - 18)) {
2389 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2393 clistr_pull_talloc(mem_ctx,
2394 (const char *)outbuf.data,
2400 if (volume_name == NULL) {
2401 status = map_nt_error_from_unix(errno);
2405 *_volume_name = volume_name;
2409 if (fnum != 0xffff) {
2410 cli_smb2_close_fnum(cli, fnum);
2413 cli->raw_status = status;
2420 /***************************************************************
2421 Wrapper that allows SMB2 to query a security descriptor.
2423 ***************************************************************/
2425 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2428 TALLOC_CTX *mem_ctx,
2429 struct security_descriptor **ppsd)
2432 DATA_BLOB outbuf = data_blob_null;
2433 struct smb2_hnd *ph = NULL;
2434 struct security_descriptor *lsd = NULL;
2435 TALLOC_CTX *frame = talloc_stackframe();
2437 if (smbXcli_conn_has_async_calls(cli->conn)) {
2439 * Can't use sync call while an async call is in flight
2441 status = NT_STATUS_INVALID_PARAMETER;
2445 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2446 status = NT_STATUS_INVALID_PARAMETER;
2450 status = map_fnum_to_smb2_handle(cli,
2453 if (!NT_STATUS_IS_OK(status)) {
2457 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2459 status = smb2cli_query_info(cli->conn,
2463 3, /* in_info_type */
2464 0, /* in_file_info_class */
2465 0xFFFF, /* in_max_output_length */
2466 NULL, /* in_input_buffer */
2467 sec_info, /* in_additional_info */
2474 if (!NT_STATUS_IS_OK(status)) {
2478 /* Parse the reply. */
2479 status = unmarshall_sec_desc(mem_ctx,
2484 if (!NT_STATUS_IS_OK(status)) {
2496 cli->raw_status = status;
2502 /***************************************************************
2503 Wrapper that allows SMB2 to set a security descriptor.
2505 ***************************************************************/
2507 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
2510 const struct security_descriptor *sd)
2513 DATA_BLOB inbuf = data_blob_null;
2514 struct smb2_hnd *ph = NULL;
2515 TALLOC_CTX *frame = talloc_stackframe();
2517 if (smbXcli_conn_has_async_calls(cli->conn)) {
2519 * Can't use sync call while an async call is in flight
2521 status = NT_STATUS_INVALID_PARAMETER;
2525 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2526 status = NT_STATUS_INVALID_PARAMETER;
2530 status = map_fnum_to_smb2_handle(cli,
2533 if (!NT_STATUS_IS_OK(status)) {
2537 status = marshall_sec_desc(frame,
2542 if (!NT_STATUS_IS_OK(status)) {
2546 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2548 status = smb2cli_set_info(cli->conn,
2552 3, /* in_info_type */
2553 0, /* in_file_info_class */
2554 &inbuf, /* in_input_buffer */
2555 sec_info, /* in_additional_info */
2561 cli->raw_status = status;
2567 /***************************************************************
2568 Wrapper that allows SMB2 to rename a file.
2570 ***************************************************************/
2572 NTSTATUS cli_smb2_rename(struct cli_state *cli,
2573 const char *fname_src,
2574 const char *fname_dst,
2578 DATA_BLOB inbuf = data_blob_null;
2579 uint16_t fnum = 0xffff;
2580 struct smb2_hnd *ph = NULL;
2581 smb_ucs2_t *converted_str = NULL;
2582 size_t converted_size_bytes = 0;
2584 TALLOC_CTX *frame = talloc_stackframe();
2586 if (smbXcli_conn_has_async_calls(cli->conn)) {
2588 * Can't use sync call while an async call is in flight
2590 status = NT_STATUS_INVALID_PARAMETER;
2594 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2595 status = NT_STATUS_INVALID_PARAMETER;
2599 status = get_fnum_from_path(cli,
2604 if (!NT_STATUS_IS_OK(status)) {
2608 status = map_fnum_to_smb2_handle(cli,
2611 if (!NT_STATUS_IS_OK(status)) {
2615 /* SMB2 is pickier about pathnames. Ensure it doesn't
2617 if (*fname_dst == '\\') {
2621 /* SMB2 is pickier about pathnames. Ensure it doesn't
2623 namelen = strlen(fname_dst);
2624 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2625 char *modname = talloc_strdup(frame, fname_dst);
2626 modname[namelen-1] = '\0';
2627 fname_dst = modname;
2630 if (!push_ucs2_talloc(frame,
2633 &converted_size_bytes)) {
2634 status = NT_STATUS_INVALID_PARAMETER;
2638 /* W2K8 insists the dest name is not null
2639 terminated. Remove the last 2 zero bytes
2640 and reduce the name length. */
2642 if (converted_size_bytes < 2) {
2643 status = NT_STATUS_INVALID_PARAMETER;
2646 converted_size_bytes -= 2;
2648 inbuf = data_blob_talloc_zero(frame,
2649 20 + converted_size_bytes);
2650 if (inbuf.data == NULL) {
2651 status = NT_STATUS_NO_MEMORY;
2656 SCVAL(inbuf.data, 0, 1);
2659 SIVAL(inbuf.data, 16, converted_size_bytes);
2660 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2662 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2663 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2665 status = smb2cli_set_info(cli->conn,
2669 1, /* in_info_type */
2670 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2671 &inbuf, /* in_input_buffer */
2672 0, /* in_additional_info */
2678 if (fnum != 0xffff) {
2679 cli_smb2_close_fnum(cli, fnum);
2682 cli->raw_status = status;
2688 /***************************************************************
2689 Wrapper that allows SMB2 to set an EA on a fnum.
2691 ***************************************************************/
2693 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2695 const char *ea_name,
2700 DATA_BLOB inbuf = data_blob_null;
2702 char *ea_name_ascii = NULL;
2704 struct smb2_hnd *ph = NULL;
2705 TALLOC_CTX *frame = talloc_stackframe();
2707 if (smbXcli_conn_has_async_calls(cli->conn)) {
2709 * Can't use sync call while an async call is in flight
2711 status = NT_STATUS_INVALID_PARAMETER;
2715 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2716 status = NT_STATUS_INVALID_PARAMETER;
2720 status = map_fnum_to_smb2_handle(cli,
2723 if (!NT_STATUS_IS_OK(status)) {
2727 /* Marshall the SMB2 EA data. */
2728 if (ea_len > 0xFFFF) {
2729 status = NT_STATUS_INVALID_PARAMETER;
2733 if (!push_ascii_talloc(frame,
2737 status = NT_STATUS_INVALID_PARAMETER;
2741 if (namelen < 2 || namelen > 0xFF) {
2742 status = NT_STATUS_INVALID_PARAMETER;
2746 bloblen = 8 + ea_len + namelen;
2747 /* Round up to a 4 byte boundary. */
2748 bloblen = ((bloblen + 3)&~3);
2750 inbuf = data_blob_talloc_zero(frame, bloblen);
2751 if (inbuf.data == NULL) {
2752 status = NT_STATUS_NO_MEMORY;
2755 /* namelen doesn't include the NULL byte. */
2756 SCVAL(inbuf.data, 5, namelen - 1);
2757 SSVAL(inbuf.data, 6, ea_len);
2758 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2759 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2761 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2762 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2764 status = smb2cli_set_info(cli->conn,
2768 1, /* in_info_type */
2769 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2770 &inbuf, /* in_input_buffer */
2771 0, /* in_additional_info */
2777 cli->raw_status = status;
2783 /***************************************************************
2784 Wrapper that allows SMB2 to set an EA on a pathname.
2786 ***************************************************************/
2788 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2790 const char *ea_name,
2795 uint16_t fnum = 0xffff;
2797 if (smbXcli_conn_has_async_calls(cli->conn)) {
2799 * Can't use sync call while an async call is in flight
2801 status = NT_STATUS_INVALID_PARAMETER;
2805 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2806 status = NT_STATUS_INVALID_PARAMETER;
2810 status = get_fnum_from_path(cli,
2815 if (!NT_STATUS_IS_OK(status)) {
2819 status = cli_set_ea_fnum(cli,
2824 if (!NT_STATUS_IS_OK(status)) {
2830 if (fnum != 0xffff) {
2831 cli_smb2_close_fnum(cli, fnum);
2834 cli->raw_status = status;
2839 /***************************************************************
2840 Wrapper that allows SMB2 to get an EA list on a pathname.
2842 ***************************************************************/
2844 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2848 struct ea_struct **pea_array)
2851 uint16_t fnum = 0xffff;
2852 DATA_BLOB outbuf = data_blob_null;
2853 struct smb2_hnd *ph = NULL;
2854 struct ea_list *ea_list = NULL;
2855 struct ea_list *eal = NULL;
2856 size_t ea_count = 0;
2857 TALLOC_CTX *frame = talloc_stackframe();
2862 if (smbXcli_conn_has_async_calls(cli->conn)) {
2864 * Can't use sync call while an async call is in flight
2866 status = NT_STATUS_INVALID_PARAMETER;
2870 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2871 status = NT_STATUS_INVALID_PARAMETER;
2875 status = get_fnum_from_path(cli,
2880 if (!NT_STATUS_IS_OK(status)) {
2884 status = map_fnum_to_smb2_handle(cli,
2887 if (!NT_STATUS_IS_OK(status)) {
2891 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2892 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2894 status = smb2cli_query_info(cli->conn,
2898 1, /* in_info_type */
2899 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2900 0xFFFF, /* in_max_output_length */
2901 NULL, /* in_input_buffer */
2902 0, /* in_additional_info */
2909 if (!NT_STATUS_IS_OK(status)) {
2913 /* Parse the reply. */
2914 ea_list = read_nttrans_ea_list(ctx,
2915 (const char *)outbuf.data,
2917 if (ea_list == NULL) {
2918 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2922 /* Convert to an array. */
2923 for (eal = ea_list; eal; eal = eal->next) {
2928 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2929 if (*pea_array == NULL) {
2930 status = NT_STATUS_NO_MEMORY;
2934 for (eal = ea_list; eal; eal = eal->next) {
2935 (*pea_array)[ea_count++] = eal->ea;
2937 *pnum_eas = ea_count;
2942 if (fnum != 0xffff) {
2943 cli_smb2_close_fnum(cli, fnum);
2946 cli->raw_status = status;
2952 /***************************************************************
2953 Wrapper that allows SMB2 to get user quota.
2955 ***************************************************************/
2957 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
2959 SMB_NTQUOTA_STRUCT *pqt)
2962 DATA_BLOB inbuf = data_blob_null;
2963 DATA_BLOB info_blob = data_blob_null;
2964 DATA_BLOB outbuf = data_blob_null;
2965 struct smb2_hnd *ph = NULL;
2966 TALLOC_CTX *frame = talloc_stackframe();
2968 unsigned int offset;
2969 struct smb2_query_quota_info query = {0};
2970 struct file_get_quota_info info = {0};
2971 enum ndr_err_code err;
2972 struct ndr_push *ndr_push = NULL;
2974 if (smbXcli_conn_has_async_calls(cli->conn)) {
2976 * Can't use sync call while an async call is in flight
2978 status = NT_STATUS_INVALID_PARAMETER;
2982 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2983 status = NT_STATUS_INVALID_PARAMETER;
2987 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2988 if (!NT_STATUS_IS_OK(status)) {
2992 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
2994 query.return_single = 1;
2996 info.next_entry_offset = 0;
2997 info.sid_length = sid_len;
2998 info.sid = pqt->sid;
3000 err = ndr_push_struct_blob(
3004 (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
3006 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3007 status = NT_STATUS_INTERNAL_ERROR;
3011 query.sid_list_length = info_blob.length;
3012 ndr_push = ndr_push_init_ctx(frame);
3014 status = NT_STATUS_NO_MEMORY;
3018 err = ndr_push_smb2_query_quota_info(ndr_push,
3019 NDR_SCALARS | NDR_BUFFERS,
3022 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3023 status = NT_STATUS_INTERNAL_ERROR;
3027 err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3030 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3031 status = NT_STATUS_INTERNAL_ERROR;
3034 inbuf.data = ndr_push->data;
3035 inbuf.length = ndr_push->offset;
3037 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
3038 cli->smb2.tcon, 4, /* in_info_type */
3039 0, /* in_file_info_class */
3040 0xFFFF, /* in_max_output_length */
3041 &inbuf, /* in_input_buffer */
3042 0, /* in_additional_info */
3044 ph->fid_persistent, ph->fid_volatile, frame,
3047 if (!NT_STATUS_IS_OK(status)) {
3051 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3053 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3054 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3058 cli->raw_status = status;
3064 /***************************************************************
3065 Wrapper that allows SMB2 to list user quota.
3067 ***************************************************************/
3069 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3070 TALLOC_CTX *mem_ctx,
3072 SMB_NTQUOTA_LIST **pqt_list,
3076 DATA_BLOB inbuf = data_blob_null;
3077 DATA_BLOB outbuf = data_blob_null;
3078 struct smb2_hnd *ph = NULL;
3079 TALLOC_CTX *frame = talloc_stackframe();
3080 struct smb2_query_quota_info info = {0};
3081 enum ndr_err_code err;
3083 if (smbXcli_conn_has_async_calls(cli->conn)) {
3085 * Can't use sync call while an async call is in flight
3087 status = NT_STATUS_INVALID_PARAMETER;
3091 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3092 status = NT_STATUS_INVALID_PARAMETER;
3096 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3097 if (!NT_STATUS_IS_OK(status)) {
3102 info.restart_scan = first ? 1 : 0;
3104 err = ndr_push_struct_blob(
3108 (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3110 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3111 status = NT_STATUS_INTERNAL_ERROR;
3115 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
3116 cli->smb2.tcon, 4, /* in_info_type */
3117 0, /* in_file_info_class */
3118 0xFFFF, /* in_max_output_length */
3119 &inbuf, /* in_input_buffer */
3120 0, /* in_additional_info */
3122 ph->fid_persistent, ph->fid_volatile, frame,
3126 * safeguard against panic from calling parse_user_quota_list with
3129 if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3130 status = NT_STATUS_NO_MORE_ENTRIES;
3133 if (!NT_STATUS_IS_OK(status)) {
3137 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3141 cli->raw_status = status;
3147 /***************************************************************
3148 Wrapper that allows SMB2 to get file system quota.
3150 ***************************************************************/
3152 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3154 SMB_NTQUOTA_STRUCT *pqt)
3157 DATA_BLOB outbuf = data_blob_null;
3158 struct smb2_hnd *ph = NULL;
3159 TALLOC_CTX *frame = talloc_stackframe();
3161 if (smbXcli_conn_has_async_calls(cli->conn)) {
3163 * Can't use sync call while an async call is in flight
3165 status = NT_STATUS_INVALID_PARAMETER;
3169 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3170 status = NT_STATUS_INVALID_PARAMETER;
3174 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3175 if (!NT_STATUS_IS_OK(status)) {
3179 status = smb2cli_query_info(
3180 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3181 2, /* in_info_type */
3182 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3183 0xFFFF, /* in_max_output_length */
3184 NULL, /* in_input_buffer */
3185 0, /* in_additional_info */
3187 ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
3189 if (!NT_STATUS_IS_OK(status)) {
3193 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3196 cli->raw_status = status;
3202 /***************************************************************
3203 Wrapper that allows SMB2 to set user quota.
3205 ***************************************************************/
3207 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3209 SMB_NTQUOTA_LIST *qtl)
3212 DATA_BLOB inbuf = data_blob_null;
3213 struct smb2_hnd *ph = NULL;
3214 TALLOC_CTX *frame = talloc_stackframe();
3216 if (smbXcli_conn_has_async_calls(cli->conn)) {
3218 * Can't use sync call while an async call is in flight
3220 status = NT_STATUS_INVALID_PARAMETER;
3224 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3225 status = NT_STATUS_INVALID_PARAMETER;
3229 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3230 if (!NT_STATUS_IS_OK(status)) {
3234 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3235 if (!NT_STATUS_IS_OK(status)) {
3239 status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
3240 cli->smb2.tcon, 4, /* in_info_type */
3241 0, /* in_file_info_class */
3242 &inbuf, /* in_input_buffer */
3243 0, /* in_additional_info */
3244 ph->fid_persistent, ph->fid_volatile);
3247 cli->raw_status = status;
3254 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3256 SMB_NTQUOTA_STRUCT *pqt)
3259 DATA_BLOB inbuf = data_blob_null;
3260 struct smb2_hnd *ph = NULL;
3261 TALLOC_CTX *frame = talloc_stackframe();
3263 if (smbXcli_conn_has_async_calls(cli->conn)) {
3265 * Can't use sync call while an async call is in flight
3267 status = NT_STATUS_INVALID_PARAMETER;
3271 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3272 status = NT_STATUS_INVALID_PARAMETER;
3276 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3277 if (!NT_STATUS_IS_OK(status)) {
3281 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3282 if (!NT_STATUS_IS_OK(status)) {
3286 status = smb2cli_set_info(
3287 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3288 2, /* in_info_type */
3289 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3290 &inbuf, /* in_input_buffer */
3291 0, /* in_additional_info */
3292 ph->fid_persistent, ph->fid_volatile);
3294 cli->raw_status = status;
3300 struct cli_smb2_read_state {
3301 struct tevent_context *ev;
3302 struct cli_state *cli;
3303 struct smb2_hnd *ph;
3304 uint64_t start_offset;
3310 static void cli_smb2_read_done(struct tevent_req *subreq);
3312 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3313 struct tevent_context *ev,
3314 struct cli_state *cli,
3320 struct tevent_req *req, *subreq;
3321 struct cli_smb2_read_state *state;
3323 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3329 state->start_offset = (uint64_t)offset;
3330 state->size = (uint32_t)size;
3331 state->received = 0;
3334 status = map_fnum_to_smb2_handle(cli,
3337 if (tevent_req_nterror(req, status)) {
3338 return tevent_req_post(req, ev);
3341 subreq = smb2cli_read_send(state,
3344 state->cli->timeout,
3345 state->cli->smb2.session,
3346 state->cli->smb2.tcon,
3348 state->start_offset,
3349 state->ph->fid_persistent,
3350 state->ph->fid_volatile,
3351 0, /* minimum_count */
3352 0); /* remaining_bytes */
3354 if (tevent_req_nomem(subreq, req)) {
3355 return tevent_req_post(req, ev);
3357 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3361 static void cli_smb2_read_done(struct tevent_req *subreq)
3363 struct tevent_req *req = tevent_req_callback_data(
3364 subreq, struct tevent_req);
3365 struct cli_smb2_read_state *state = tevent_req_data(
3366 req, struct cli_smb2_read_state);
3369 status = smb2cli_read_recv(subreq, state,
3370 &state->buf, &state->received);
3371 if (tevent_req_nterror(req, status)) {
3375 if (state->received > state->size) {
3376 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3380 tevent_req_done(req);
3383 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
3388 struct cli_smb2_read_state *state = tevent_req_data(
3389 req, struct cli_smb2_read_state);
3391 if (tevent_req_is_nterror(req, &status)) {
3392 state->cli->raw_status = status;
3396 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3397 * better make sure that you copy it away before you talloc_free(req).
3398 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3400 *received = (ssize_t)state->received;
3401 *rcvbuf = state->buf;
3402 state->cli->raw_status = NT_STATUS_OK;
3403 return NT_STATUS_OK;
3406 struct cli_smb2_write_state {
3407 struct tevent_context *ev;
3408 struct cli_state *cli;
3409 struct smb2_hnd *ph;
3417 static void cli_smb2_write_written(struct tevent_req *req);
3419 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
3420 struct tevent_context *ev,
3421 struct cli_state *cli,
3429 struct tevent_req *req, *subreq = NULL;
3430 struct cli_smb2_write_state *state = NULL;
3432 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
3438 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3439 state->flags = (uint32_t)mode;
3441 state->offset = (uint64_t)offset;
3442 state->size = (uint32_t)size;
3445 status = map_fnum_to_smb2_handle(cli,
3448 if (tevent_req_nterror(req, status)) {
3449 return tevent_req_post(req, ev);
3452 subreq = smb2cli_write_send(state,
3455 state->cli->timeout,
3456 state->cli->smb2.session,
3457 state->cli->smb2.tcon,
3460 state->ph->fid_persistent,
3461 state->ph->fid_volatile,
3462 0, /* remaining_bytes */
3463 state->flags, /* flags */
3466 if (tevent_req_nomem(subreq, req)) {
3467 return tevent_req_post(req, ev);
3469 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
3473 static void cli_smb2_write_written(struct tevent_req *subreq)
3475 struct tevent_req *req = tevent_req_callback_data(
3476 subreq, struct tevent_req);
3477 struct cli_smb2_write_state *state = tevent_req_data(
3478 req, struct cli_smb2_write_state);
3482 status = smb2cli_write_recv(subreq, &written);
3483 TALLOC_FREE(subreq);
3484 if (tevent_req_nterror(req, status)) {
3488 state->written = written;
3490 tevent_req_done(req);
3493 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
3496 struct cli_smb2_write_state *state = tevent_req_data(
3497 req, struct cli_smb2_write_state);
3500 if (tevent_req_is_nterror(req, &status)) {
3501 state->cli->raw_status = status;
3502 tevent_req_received(req);
3506 if (pwritten != NULL) {
3507 *pwritten = (size_t)state->written;
3509 state->cli->raw_status = NT_STATUS_OK;
3510 tevent_req_received(req);
3511 return NT_STATUS_OK;
3514 /***************************************************************
3515 Wrapper that allows SMB2 async write using an fnum.
3516 This is mostly cut-and-paste from Volker's code inside
3517 source3/libsmb/clireadwrite.c, adapted for SMB2.
3519 Done this way so I can reuse all the logic inside cli_push()
3521 ***************************************************************/
3523 struct cli_smb2_writeall_state {
3524 struct tevent_context *ev;
3525 struct cli_state *cli;
3526 struct smb2_hnd *ph;
3534 static void cli_smb2_writeall_written(struct tevent_req *req);
3536 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
3537 struct tevent_context *ev,
3538 struct cli_state *cli,
3546 struct tevent_req *req, *subreq = NULL;
3547 struct cli_smb2_writeall_state *state = NULL;
3552 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
3558 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3559 state->flags = (uint32_t)mode;
3561 state->offset = (uint64_t)offset;
3562 state->size = (uint32_t)size;
3565 status = map_fnum_to_smb2_handle(cli,
3568 if (tevent_req_nterror(req, status)) {
3569 return tevent_req_post(req, ev);
3572 to_write = state->size;
3573 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3574 to_write = MIN(max_size, to_write);
3575 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3577 to_write = MIN(max_size, to_write);
3580 subreq = smb2cli_write_send(state,
3583 state->cli->timeout,
3584 state->cli->smb2.session,
3585 state->cli->smb2.tcon,
3588 state->ph->fid_persistent,
3589 state->ph->fid_volatile,
3590 0, /* remaining_bytes */
3591 state->flags, /* flags */
3592 state->buf + state->written);
3594 if (tevent_req_nomem(subreq, req)) {
3595 return tevent_req_post(req, ev);
3597 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3601 static void cli_smb2_writeall_written(struct tevent_req *subreq)
3603 struct tevent_req *req = tevent_req_callback_data(
3604 subreq, struct tevent_req);
3605 struct cli_smb2_writeall_state *state = tevent_req_data(
3606 req, struct cli_smb2_writeall_state);
3608 uint32_t written, to_write;
3612 status = smb2cli_write_recv(subreq, &written);
3613 TALLOC_FREE(subreq);
3614 if (tevent_req_nterror(req, status)) {
3618 state->written += written;
3620 if (state->written > state->size) {
3621 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3625 to_write = state->size - state->written;
3627 if (to_write == 0) {
3628 tevent_req_done(req);
3632 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3633 to_write = MIN(max_size, to_write);
3634 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3636 to_write = MIN(max_size, to_write);
3639 subreq = smb2cli_write_send(state,
3642 state->cli->timeout,
3643 state->cli->smb2.session,
3644 state->cli->smb2.tcon,
3646 state->offset + state->written,
3647 state->ph->fid_persistent,
3648 state->ph->fid_volatile,
3649 0, /* remaining_bytes */
3650 state->flags, /* flags */
3651 state->buf + state->written);
3653 if (tevent_req_nomem(subreq, req)) {
3656 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3659 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
3662 struct cli_smb2_writeall_state *state = tevent_req_data(
3663 req, struct cli_smb2_writeall_state);
3666 if (tevent_req_is_nterror(req, &status)) {
3667 state->cli->raw_status = status;
3670 if (pwritten != NULL) {
3671 *pwritten = (size_t)state->written;
3673 state->cli->raw_status = NT_STATUS_OK;
3674 return NT_STATUS_OK;
3677 struct cli_smb2_splice_state {
3678 struct tevent_context *ev;
3679 struct cli_state *cli;
3680 struct smb2_hnd *src_ph;
3681 struct smb2_hnd *dst_ph;
3682 int (*splice_cb)(off_t n, void *priv);
3689 struct req_resume_key_rsp resume_rsp;
3690 struct srv_copychunk_copy cc_copy;
3693 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3694 struct tevent_req *req);
3696 static void cli_splice_copychunk_done(struct tevent_req *subreq)
3698 struct tevent_req *req = tevent_req_callback_data(
3699 subreq, struct tevent_req);
3700 struct cli_smb2_splice_state *state =
3701 tevent_req_data(req,
3702 struct cli_smb2_splice_state);
3703 struct smbXcli_conn *conn = state->cli->conn;
3704 DATA_BLOB out_input_buffer = data_blob_null;
3705 DATA_BLOB out_output_buffer = data_blob_null;
3706 struct srv_copychunk_rsp cc_copy_rsp;
3707 enum ndr_err_code ndr_ret;
3710 status = smb2cli_ioctl_recv(subreq, state,
3712 &out_output_buffer);
3713 TALLOC_FREE(subreq);
3714 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
3715 state->resized) && tevent_req_nterror(req, status)) {
3719 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
3720 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
3721 if (ndr_ret != NDR_ERR_SUCCESS) {
3722 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3723 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3727 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
3728 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
3729 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
3730 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
3731 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
3732 tevent_req_nterror(req, status)) {
3736 state->resized = true;
3737 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
3738 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
3740 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3741 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3742 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
3743 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3746 state->src_offset += cc_copy_rsp.total_bytes_written;
3747 state->dst_offset += cc_copy_rsp.total_bytes_written;
3748 state->written += cc_copy_rsp.total_bytes_written;
3749 if (!state->splice_cb(state->written, state->priv)) {
3750 tevent_req_nterror(req, NT_STATUS_CANCELLED);
3755 cli_splice_copychunk_send(state, req);
3758 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3759 struct tevent_req *req)
3761 struct tevent_req *subreq;
3762 enum ndr_err_code ndr_ret;
3763 struct smbXcli_conn *conn = state->cli->conn;
3764 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
3765 off_t src_offset = state->src_offset;
3766 off_t dst_offset = state->dst_offset;
3767 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
3768 state->size - state->written);
3769 DATA_BLOB in_input_buffer = data_blob_null;
3770 DATA_BLOB in_output_buffer = data_blob_null;
3772 if (state->size - state->written == 0) {
3773 tevent_req_done(req);
3777 cc_copy->chunk_count = 0;
3779 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
3780 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
3781 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
3782 smb2cli_conn_cc_chunk_len(conn));
3783 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
3784 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3787 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
3788 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
3789 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
3790 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3793 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3794 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3795 cc_copy->chunk_count++;
3798 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
3799 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
3800 if (ndr_ret != NDR_ERR_SUCCESS) {
3801 DEBUG(0, ("failed to marshall copy chunk req\n"));
3802 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3806 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
3807 state->cli->timeout,
3808 state->cli->smb2.session,
3809 state->cli->smb2.tcon,
3810 state->dst_ph->fid_persistent, /* in_fid_persistent */
3811 state->dst_ph->fid_volatile, /* in_fid_volatile */
3812 FSCTL_SRV_COPYCHUNK_WRITE,
3813 0, /* in_max_input_length */
3815 12, /* in_max_output_length */
3817 SMB2_IOCTL_FLAG_IS_FSCTL);
3818 if (tevent_req_nomem(subreq, req)) {
3821 tevent_req_set_callback(subreq,
3822 cli_splice_copychunk_done,
3826 static void cli_splice_key_done(struct tevent_req *subreq)
3828 struct tevent_req *req = tevent_req_callback_data(
3829 subreq, struct tevent_req);
3830 struct cli_smb2_splice_state *state =
3831 tevent_req_data(req,
3832 struct cli_smb2_splice_state);
3833 enum ndr_err_code ndr_ret;
3836 DATA_BLOB out_input_buffer = data_blob_null;
3837 DATA_BLOB out_output_buffer = data_blob_null;
3839 status = smb2cli_ioctl_recv(subreq, state,
3841 &out_output_buffer);
3842 TALLOC_FREE(subreq);
3843 if (tevent_req_nterror(req, status)) {
3847 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
3848 state, &state->resume_rsp,
3849 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
3850 if (ndr_ret != NDR_ERR_SUCCESS) {
3851 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3852 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3856 memcpy(&state->cc_copy.source_key,
3857 &state->resume_rsp.resume_key,
3858 sizeof state->resume_rsp.resume_key);
3860 cli_splice_copychunk_send(state, req);
3863 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
3864 struct tevent_context *ev,
3865 struct cli_state *cli,
3866 uint16_t src_fnum, uint16_t dst_fnum,
3867 off_t size, off_t src_offset, off_t dst_offset,
3868 int (*splice_cb)(off_t n, void *priv),
3871 struct tevent_req *req;
3872 struct tevent_req *subreq;
3873 struct cli_smb2_splice_state *state;
3875 DATA_BLOB in_input_buffer = data_blob_null;
3876 DATA_BLOB in_output_buffer = data_blob_null;
3878 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
3884 state->splice_cb = splice_cb;
3888 state->src_offset = src_offset;
3889 state->dst_offset = dst_offset;
3890 state->cc_copy.chunks = talloc_array(state,
3891 struct srv_copychunk,
3892 smb2cli_conn_cc_max_chunks(cli->conn));
3893 if (state->cc_copy.chunks == NULL) {
3897 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
3898 if (tevent_req_nterror(req, status))
3899 return tevent_req_post(req, ev);
3901 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
3902 if (tevent_req_nterror(req, status))
3903 return tevent_req_post(req, ev);
3905 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
3909 state->src_ph->fid_persistent, /* in_fid_persistent */
3910 state->src_ph->fid_volatile, /* in_fid_volatile */
3911 FSCTL_SRV_REQUEST_RESUME_KEY,
3912 0, /* in_max_input_length */
3914 32, /* in_max_output_length */
3916 SMB2_IOCTL_FLAG_IS_FSCTL);
3917 if (tevent_req_nomem(subreq, req)) {
3920 tevent_req_set_callback(subreq,
3921 cli_splice_key_done,
3927 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
3929 struct cli_smb2_splice_state *state = tevent_req_data(
3930 req, struct cli_smb2_splice_state);
3933 if (tevent_req_is_nterror(req, &status)) {
3934 state->cli->raw_status = status;
3935 tevent_req_received(req);
3938 if (written != NULL) {
3939 *written = state->written;
3941 state->cli->raw_status = NT_STATUS_OK;
3942 tevent_req_received(req);
3943 return NT_STATUS_OK;
3946 /***************************************************************
3947 SMB2 enum shadow copy data.
3948 ***************************************************************/
3950 struct cli_smb2_shadow_copy_data_fnum_state {
3951 struct cli_state *cli;
3953 struct smb2_hnd *ph;
3954 DATA_BLOB out_input_buffer;
3955 DATA_BLOB out_output_buffer;
3958 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
3960 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
3961 TALLOC_CTX *mem_ctx,
3962 struct tevent_context *ev,
3963 struct cli_state *cli,
3967 struct tevent_req *req, *subreq;
3968 struct cli_smb2_shadow_copy_data_fnum_state *state;
3971 req = tevent_req_create(mem_ctx, &state,
3972 struct cli_smb2_shadow_copy_data_fnum_state);
3977 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3978 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3979 return tevent_req_post(req, ev);
3985 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
3986 if (tevent_req_nterror(req, status)) {
3987 return tevent_req_post(req, ev);
3991 * TODO. Under SMB2 we should send a zero max_output_length
3992 * ioctl to get the required size, then send another ioctl
3993 * to get the data, but the current SMB1 implementation just
3994 * does one roundtrip with a 64K buffer size. Do the same
3998 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
3999 state->cli->timeout,
4000 state->cli->smb2.session,
4001 state->cli->smb2.tcon,
4002 state->ph->fid_persistent, /* in_fid_persistent */
4003 state->ph->fid_volatile, /* in_fid_volatile */
4004 FSCTL_GET_SHADOW_COPY_DATA,
4005 0, /* in_max_input_length */
4006 NULL, /* in_input_buffer */
4008 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
4009 NULL, /* in_output_buffer */
4010 SMB2_IOCTL_FLAG_IS_FSCTL);
4012 if (tevent_req_nomem(subreq, req)) {
4013 return tevent_req_post(req, ev);
4015 tevent_req_set_callback(subreq,
4016 cli_smb2_shadow_copy_data_fnum_done,
4022 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4024 struct tevent_req *req = tevent_req_callback_data(
4025 subreq, struct tevent_req);
4026 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4027 req, struct cli_smb2_shadow_copy_data_fnum_state);
4030 status = smb2cli_ioctl_recv(subreq, state,
4031 &state->out_input_buffer,
4032 &state->out_output_buffer);
4033 TALLOC_FREE(subreq);
4034 if (tevent_req_nterror(req, status)) {
4037 tevent_req_done(req);
4040 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4041 TALLOC_CTX *mem_ctx,
4046 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4047 req, struct cli_smb2_shadow_copy_data_fnum_state);
4048 char **names = NULL;
4049 uint32_t num_names = 0;
4050 uint32_t num_names_returned = 0;
4051 uint32_t dlength = 0;
4053 uint8_t *endp = NULL;
4056 if (tevent_req_is_nterror(req, &status)) {
4060 if (state->out_output_buffer.length < 16) {
4061 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4064 num_names = IVAL(state->out_output_buffer.data, 0);
4065 num_names_returned = IVAL(state->out_output_buffer.data, 4);
4066 dlength = IVAL(state->out_output_buffer.data, 8);
4068 if (num_names > 0x7FFFFFFF) {
4069 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4072 if (get_names == false) {
4073 *pnum_names = (int)num_names;
4074 return NT_STATUS_OK;
4076 if (num_names != num_names_returned) {
4077 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4079 if (dlength + 12 < 12) {
4080 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4083 * NB. The below is an allowable return if there are
4084 * more snapshots than the buffer size we told the
4085 * server we can receive. We currently don't support
4088 if (dlength + 12 > state->out_output_buffer.length) {
4089 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4091 if (state->out_output_buffer.length +
4092 (2 * sizeof(SHADOW_COPY_LABEL)) <
4093 state->out_output_buffer.length) {
4094 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4097 names = talloc_array(mem_ctx, char *, num_names_returned);
4098 if (names == NULL) {
4099 return NT_STATUS_NO_MEMORY;
4102 endp = state->out_output_buffer.data +
4103 state->out_output_buffer.length;
4105 for (i=0; i<num_names_returned; i++) {
4108 size_t converted_size;
4110 src = state->out_output_buffer.data + 12 +
4111 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4113 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4114 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4116 ret = convert_string_talloc(
4117 names, CH_UTF16LE, CH_UNIX,
4118 src, 2 * sizeof(SHADOW_COPY_LABEL),
4119 &names[i], &converted_size);
4122 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4125 *pnum_names = num_names;
4127 return NT_STATUS_OK;
4130 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4131 struct cli_state *cli,
4137 TALLOC_CTX *frame = talloc_stackframe();
4138 struct tevent_context *ev;
4139 struct tevent_req *req;
4140 NTSTATUS status = NT_STATUS_NO_MEMORY;
4142 if (smbXcli_conn_has_async_calls(cli->conn)) {
4144 * Can't use sync call while an async call is in flight
4146 status = NT_STATUS_INVALID_PARAMETER;
4149 ev = samba_tevent_context_init(frame);
4153 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4161 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4164 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4170 cli->raw_status = status;
4176 /***************************************************************
4177 Wrapper that allows SMB2 to truncate a file.
4179 ***************************************************************/
4181 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4186 DATA_BLOB inbuf = data_blob_null;
4187 struct smb2_hnd *ph = NULL;
4188 TALLOC_CTX *frame = talloc_stackframe();
4190 if (smbXcli_conn_has_async_calls(cli->conn)) {
4192 * Can't use sync call while an async call is in flight
4194 status = NT_STATUS_INVALID_PARAMETER;
4198 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4199 status = NT_STATUS_INVALID_PARAMETER;
4203 status = map_fnum_to_smb2_handle(cli,
4206 if (!NT_STATUS_IS_OK(status)) {
4210 inbuf = data_blob_talloc_zero(frame, 8);
4211 if (inbuf.data == NULL) {
4212 status = NT_STATUS_NO_MEMORY;
4216 SBVAL(inbuf.data, 0, newsize);
4218 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4219 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4221 status = smb2cli_set_info(cli->conn,
4225 1, /* in_info_type */
4226 /* in_file_info_class */
4227 SMB_FILE_END_OF_FILE_INFORMATION - 1000,
4228 &inbuf, /* in_input_buffer */
4229 0, /* in_additional_info */
4235 cli->raw_status = status;
4241 struct cli_smb2_notify_state {
4242 struct tevent_req *subreq;
4243 struct notify_change *changes;
4247 static void cli_smb2_notify_done(struct tevent_req *subreq);
4248 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4250 struct tevent_req *cli_smb2_notify_send(
4251 TALLOC_CTX *mem_ctx,
4252 struct tevent_context *ev,
4253 struct cli_state *cli,
4255 uint32_t buffer_size,
4256 uint32_t completion_filter,
4259 struct tevent_req *req = NULL;
4260 struct cli_smb2_notify_state *state = NULL;
4261 struct smb2_hnd *ph = NULL;
4264 req = tevent_req_create(mem_ctx, &state,
4265 struct cli_smb2_notify_state);
4270 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4271 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4272 return tevent_req_post(req, ev);
4275 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4276 if (tevent_req_nterror(req, status)) {
4277 return tevent_req_post(req, ev);
4280 state->subreq = smb2cli_notify_send(
4292 if (tevent_req_nomem(state->subreq, req)) {
4293 return tevent_req_post(req, ev);
4295 tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4296 tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4300 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4302 struct cli_smb2_notify_state *state = tevent_req_data(
4303 req, struct cli_smb2_notify_state);
4306 ok = tevent_req_cancel(state->subreq);
4310 static void cli_smb2_notify_done(struct tevent_req *subreq)
4312 struct tevent_req *req = tevent_req_callback_data(
4313 subreq, struct tevent_req);
4314 struct cli_smb2_notify_state *state = tevent_req_data(
4315 req, struct cli_smb2_notify_state);
4321 status = smb2cli_notify_recv(subreq, state, &base, &len);
4322 TALLOC_FREE(subreq);
4324 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4325 tevent_req_done(req);
4328 if (tevent_req_nterror(req, status)) {
4334 while (len - ofs >= 12) {
4335 struct notify_change *tmp;
4336 struct notify_change *c;
4337 uint32_t next_ofs = IVAL(base, ofs);
4338 uint32_t file_name_length = IVAL(base, ofs+8);
4342 tmp = talloc_realloc(
4345 struct notify_change,
4346 state->num_changes + 1);
4347 if (tevent_req_nomem(tmp, req)) {
4350 state->changes = tmp;
4351 c = &state->changes[state->num_changes];
4352 state->num_changes += 1;
4354 if (smb_buffer_oob(len, ofs, next_ofs) ||
4355 smb_buffer_oob(len, ofs+12, file_name_length)) {
4357 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4361 c->action = IVAL(base, ofs+4);
4363 ok = convert_string_talloc(
4373 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4377 if (next_ofs == 0) {
4383 tevent_req_done(req);
4386 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
4387 TALLOC_CTX *mem_ctx,
4388 struct notify_change **pchanges,
4389 uint32_t *pnum_changes)
4391 struct cli_smb2_notify_state *state = tevent_req_data(
4392 req, struct cli_smb2_notify_state);
4395 if (tevent_req_is_nterror(req, &status)) {
4398 *pchanges = talloc_move(mem_ctx, &state->changes);
4399 *pnum_changes = state->num_changes;
4400 return NT_STATUS_OK;
4403 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
4404 uint32_t buffer_size, uint32_t completion_filter,
4405 bool recursive, TALLOC_CTX *mem_ctx,
4406 struct notify_change **pchanges,
4407 uint32_t *pnum_changes)
4409 TALLOC_CTX *frame = talloc_stackframe();
4410 struct tevent_context *ev;
4411 struct tevent_req *req;
4412 NTSTATUS status = NT_STATUS_NO_MEMORY;
4414 if (smbXcli_conn_has_async_calls(cli->conn)) {
4416 * Can't use sync call while an async call is in flight
4418 status = NT_STATUS_INVALID_PARAMETER;
4421 ev = samba_tevent_context_init(frame);
4425 req = cli_smb2_notify_send(
4436 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4439 status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
4445 struct cli_smb2_set_reparse_point_fnum_state {
4446 struct cli_state *cli;
4448 struct smb2_hnd *ph;
4449 DATA_BLOB input_buffer;
4452 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
4454 struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
4455 TALLOC_CTX *mem_ctx,
4456 struct tevent_context *ev,
4457 struct cli_state *cli,
4461 struct tevent_req *req, *subreq;
4462 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
4465 req = tevent_req_create(mem_ctx, &state,
4466 struct cli_smb2_set_reparse_point_fnum_state);
4471 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4472 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4473 return tevent_req_post(req, ev);
4479 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4480 if (tevent_req_nterror(req, status)) {
4481 return tevent_req_post(req, ev);
4484 state->input_buffer = data_blob_talloc(state,
4487 if (state->input_buffer.data == NULL) {
4488 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4489 return tevent_req_post(req, ev);
4492 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4493 state->cli->timeout,
4494 state->cli->smb2.session,
4495 state->cli->smb2.tcon,
4496 state->ph->fid_persistent, /* in_fid_persistent */
4497 state->ph->fid_volatile, /* in_fid_volatile */
4498 FSCTL_SET_REPARSE_POINT,
4499 0, /* in_max_input_length */
4500 &state->input_buffer ,
4503 SMB2_IOCTL_FLAG_IS_FSCTL);
4505 if (tevent_req_nomem(subreq, req)) {
4506 return tevent_req_post(req, ev);
4508 tevent_req_set_callback(subreq,
4509 cli_smb2_set_reparse_point_fnum_done,
4515 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
4517 struct tevent_req *req = tevent_req_callback_data(
4518 subreq, struct tevent_req);
4519 struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
4520 req, struct cli_smb2_set_reparse_point_fnum_state);
4523 status = smb2cli_ioctl_recv(subreq, state,
4526 TALLOC_FREE(subreq);
4527 if (tevent_req_nterror(req, status)) {
4530 tevent_req_done(req);
4533 NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
4535 return tevent_req_simple_recv_ntstatus(req);
4538 struct cli_smb2_get_reparse_point_fnum_state {
4539 struct cli_state *cli;
4541 struct smb2_hnd *ph;
4542 DATA_BLOB output_buffer;
4545 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
4547 struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
4548 TALLOC_CTX *mem_ctx,
4549 struct tevent_context *ev,
4550 struct cli_state *cli,
4553 struct tevent_req *req, *subreq;
4554 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
4557 req = tevent_req_create(mem_ctx, &state,
4558 struct cli_smb2_get_reparse_point_fnum_state);
4563 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4564 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4565 return tevent_req_post(req, ev);
4571 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4572 if (tevent_req_nterror(req, status)) {
4573 return tevent_req_post(req, ev);
4576 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4577 state->cli->timeout,
4578 state->cli->smb2.session,
4579 state->cli->smb2.tcon,
4580 state->ph->fid_persistent, /* in_fid_persistent */
4581 state->ph->fid_volatile, /* in_fid_volatile */
4582 FSCTL_GET_REPARSE_POINT,
4583 0, /* in_max_input_length */
4587 SMB2_IOCTL_FLAG_IS_FSCTL);
4589 if (tevent_req_nomem(subreq, req)) {
4590 return tevent_req_post(req, ev);
4592 tevent_req_set_callback(subreq,
4593 cli_smb2_get_reparse_point_fnum_done,
4599 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
4601 struct tevent_req *req = tevent_req_callback_data(
4602 subreq, struct tevent_req);
4603 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
4604 req, struct cli_smb2_get_reparse_point_fnum_state);
4607 status = smb2cli_ioctl_recv(subreq, state,
4609 &state->output_buffer);
4610 TALLOC_FREE(subreq);
4611 if (tevent_req_nterror(req, status)) {
4612 state->cli->raw_status = status;
4615 tevent_req_done(req);
4618 NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
4619 TALLOC_CTX *mem_ctx,
4622 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
4623 req, struct cli_smb2_get_reparse_point_fnum_state);
4625 if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
4626 tevent_req_received(req);
4627 return state->cli->raw_status;
4629 *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
4630 if (output->data == NULL) {
4631 tevent_req_received(req);
4632 return NT_STATUS_NO_MEMORY;
4634 tevent_req_received(req);
4635 return NT_STATUS_OK;