2 Unix SMB/CIFS implementation.
4 Copyright (C) Jeremy Allison 2013
5 Copyright (C) Volker Lendecke 2013
6 Copyright (C) Stefan Metzmacher 2013
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This code is a thin wrapper around the existing
24 cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c,
25 but allows the handles to be mapped to uint16_t fnums,
26 which are easier for smbclient to use.
31 #include "async_smb.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "cli_smb2_fnum.h"
36 #include "../libcli/smb/smb2_create_blob.h"
37 #include "libsmb/proto.h"
38 #include "lib/util/tevent_ntstatus.h"
39 #include "../libcli/security/security.h"
40 #include "../librpc/gen_ndr/ndr_security.h"
41 #include "lib/util_ea.h"
42 #include "librpc/gen_ndr/ndr_ioctl.h"
44 #include "librpc/gen_ndr/ndr_quota.h"
47 uint64_t fid_persistent;
48 uint64_t fid_volatile;
52 * Handle mapping code.
55 /***************************************************************
56 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
57 Ensures handle is owned by cli struct.
58 ***************************************************************/
60 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
61 const struct smb2_hnd *ph, /* In */
62 uint16_t *pfnum) /* Out */
65 struct idr_context *idp = cli->smb2.open_handles;
66 struct smb2_hnd *owned_h = talloc_memdup(cli,
68 sizeof(struct smb2_hnd));
70 if (owned_h == NULL) {
71 return NT_STATUS_NO_MEMORY;
76 cli->smb2.open_handles = idr_init(cli);
77 if (cli->smb2.open_handles == NULL) {
79 return NT_STATUS_NO_MEMORY;
81 idp = cli->smb2.open_handles;
84 ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
87 return NT_STATUS_NO_MEMORY;
90 *pfnum = (uint16_t)ret;
94 /***************************************************************
95 Return the smb2_hnd pointer associated with the given fnum.
96 ***************************************************************/
98 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
99 uint16_t fnum, /* In */
100 struct smb2_hnd **pph) /* Out */
102 struct idr_context *idp = cli->smb2.open_handles;
105 return NT_STATUS_INVALID_PARAMETER;
107 *pph = (struct smb2_hnd *)idr_find(idp, fnum);
109 return NT_STATUS_INVALID_HANDLE;
114 /***************************************************************
115 Delete the fnum to smb2_hnd mapping. Zeros out handle on
117 ***************************************************************/
119 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
120 struct smb2_hnd **pph, /* In */
121 uint16_t fnum) /* In */
123 struct idr_context *idp = cli->smb2.open_handles;
127 return NT_STATUS_INVALID_PARAMETER;
130 ph = (struct smb2_hnd *)idr_find(idp, fnum);
132 return NT_STATUS_INVALID_PARAMETER;
134 idr_remove(idp, fnum);
139 /***************************************************************
141 ***************************************************************/
143 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
145 if (create_flags & REQUEST_BATCH_OPLOCK) {
146 return SMB2_OPLOCK_LEVEL_BATCH;
147 } else if (create_flags & REQUEST_OPLOCK) {
148 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
151 /* create_flags doesn't do a level2 request. */
152 return SMB2_OPLOCK_LEVEL_NONE;
155 /***************************************************************
156 Small wrapper that allows SMB2 create to return a uint16_t fnum.
157 ***************************************************************/
159 struct cli_smb2_create_fnum_state {
160 struct cli_state *cli;
161 struct smb_create_returns cr;
163 struct tevent_req *subreq;
166 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
167 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
169 struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
170 struct tevent_context *ev,
171 struct cli_state *cli,
173 uint32_t create_flags,
174 uint32_t impersonation_level,
175 uint32_t desired_access,
176 uint32_t file_attributes,
177 uint32_t share_access,
178 uint32_t create_disposition,
179 uint32_t create_options)
181 struct tevent_req *req, *subreq;
182 struct cli_smb2_create_fnum_state *state;
183 size_t fname_len = 0;
184 const char *startp = NULL;
185 const char *endp = NULL;
186 time_t tstamp = (time_t)0;
187 struct smb2_create_blobs *cblobs = NULL;
189 req = tevent_req_create(mem_ctx, &state,
190 struct cli_smb2_create_fnum_state);
196 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
197 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
198 return tevent_req_post(req, ev);
201 if (cli->backup_intent) {
202 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
205 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
206 fname_len = strlen(fname);
207 if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
208 size_t len_before_gmt = startp - fname;
209 size_t len_after_gmt = fname + fname_len - endp;
214 char *new_fname = talloc_array(state, char,
215 len_before_gmt + len_after_gmt + 1);
217 if (tevent_req_nomem(new_fname, req)) {
218 return tevent_req_post(req, ev);
221 memcpy(new_fname, fname, len_before_gmt);
222 memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
224 fname_len = len_before_gmt + len_after_gmt;
226 unix_to_nt_time(&ntt, tstamp);
227 twrp_blob = data_blob_const((const void *)&ntt, 8);
229 cblobs = talloc_zero(state, struct smb2_create_blobs);
230 if (tevent_req_nomem(cblobs, req)) {
231 return tevent_req_post(req, ev);
234 status = smb2_create_blob_add(state, cblobs,
235 SMB2_CREATE_TAG_TWRP, twrp_blob);
236 if (!NT_STATUS_IS_OK(status)) {
237 tevent_req_nterror(req, status);
238 return tevent_req_post(req, ev);
242 /* SMB2 is pickier about pathnames. Ensure it doesn't
244 if (*fname == '\\') {
249 /* Or end in a '\' */
250 if (fname_len > 0 && fname[fname_len-1] == '\\') {
251 char *new_fname = talloc_strdup(state, fname);
252 if (tevent_req_nomem(new_fname, req)) {
253 return tevent_req_post(req, ev);
255 new_fname[fname_len-1] = '\0';
259 subreq = smb2cli_create_send(state, ev,
265 flags_to_smb2_oplock(create_flags),
273 if (tevent_req_nomem(subreq, req)) {
274 return tevent_req_post(req, ev);
276 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
278 state->subreq = subreq;
279 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
284 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
286 struct tevent_req *req = tevent_req_callback_data(
287 subreq, struct tevent_req);
288 struct cli_smb2_create_fnum_state *state = tevent_req_data(
289 req, struct cli_smb2_create_fnum_state);
293 status = smb2cli_create_recv(subreq, &h.fid_persistent,
294 &h.fid_volatile, &state->cr, NULL, NULL);
296 if (tevent_req_nterror(req, status)) {
300 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
301 if (tevent_req_nterror(req, status)) {
304 tevent_req_done(req);
307 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
309 struct cli_smb2_create_fnum_state *state = tevent_req_data(
310 req, struct cli_smb2_create_fnum_state);
311 return tevent_req_cancel(state->subreq);
314 NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum,
315 struct smb_create_returns *cr)
317 struct cli_smb2_create_fnum_state *state = tevent_req_data(
318 req, struct cli_smb2_create_fnum_state);
321 if (tevent_req_is_nterror(req, &status)) {
322 state->cli->raw_status = status;
326 *pfnum = state->fnum;
331 state->cli->raw_status = NT_STATUS_OK;
335 NTSTATUS cli_smb2_create_fnum(struct cli_state *cli,
337 uint32_t create_flags,
338 uint32_t desired_access,
339 uint32_t file_attributes,
340 uint32_t share_access,
341 uint32_t create_disposition,
342 uint32_t create_options,
344 struct smb_create_returns *cr)
346 TALLOC_CTX *frame = talloc_stackframe();
347 struct tevent_context *ev;
348 struct tevent_req *req;
349 uint32_t impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
350 NTSTATUS status = NT_STATUS_NO_MEMORY;
352 if (smbXcli_conn_has_async_calls(cli->conn)) {
354 * Can't use sync call while an async call is in flight
356 status = NT_STATUS_INVALID_PARAMETER;
359 ev = samba_tevent_context_init(frame);
363 req = cli_smb2_create_fnum_send(frame, ev, cli, fname, create_flags,
365 desired_access, file_attributes,
366 share_access, create_disposition,
371 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
374 status = cli_smb2_create_fnum_recv(req, pfid, cr);
380 /***************************************************************
381 Small wrapper that allows SMB2 close to use a uint16_t fnum.
382 ***************************************************************/
384 struct cli_smb2_close_fnum_state {
385 struct cli_state *cli;
390 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
392 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
393 struct tevent_context *ev,
394 struct cli_state *cli,
397 struct tevent_req *req, *subreq;
398 struct cli_smb2_close_fnum_state *state;
401 req = tevent_req_create(mem_ctx, &state,
402 struct cli_smb2_close_fnum_state);
409 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
410 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
411 return tevent_req_post(req, ev);
414 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
415 if (tevent_req_nterror(req, status)) {
416 return tevent_req_post(req, ev);
419 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
420 cli->smb2.session, cli->smb2.tcon,
421 0, state->ph->fid_persistent,
422 state->ph->fid_volatile);
423 if (tevent_req_nomem(subreq, req)) {
424 return tevent_req_post(req, ev);
426 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
430 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
432 struct tevent_req *req = tevent_req_callback_data(
433 subreq, struct tevent_req);
434 struct cli_smb2_close_fnum_state *state = tevent_req_data(
435 req, struct cli_smb2_close_fnum_state);
438 status = smb2cli_close_recv(subreq);
439 if (tevent_req_nterror(req, status)) {
443 /* Delete the fnum -> handle mapping. */
444 status = delete_smb2_handle_mapping(state->cli, &state->ph,
446 if (tevent_req_nterror(req, status)) {
449 tevent_req_done(req);
452 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
454 struct cli_smb2_close_fnum_state *state = tevent_req_data(
455 req, struct cli_smb2_close_fnum_state);
456 NTSTATUS status = NT_STATUS_OK;
458 if (tevent_req_is_nterror(req, &status)) {
459 state->cli->raw_status = status;
461 tevent_req_received(req);
465 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
467 TALLOC_CTX *frame = talloc_stackframe();
468 struct tevent_context *ev;
469 struct tevent_req *req;
470 NTSTATUS status = NT_STATUS_NO_MEMORY;
472 if (smbXcli_conn_has_async_calls(cli->conn)) {
474 * Can't use sync call while an async call is in flight
476 status = NT_STATUS_INVALID_PARAMETER;
479 ev = samba_tevent_context_init(frame);
483 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
487 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
490 status = cli_smb2_close_fnum_recv(req);
496 struct cli_smb2_delete_on_close_state {
497 struct cli_state *cli;
504 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
506 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
507 struct tevent_context *ev,
508 struct cli_state *cli,
512 struct tevent_req *req = NULL;
513 struct cli_smb2_delete_on_close_state *state = NULL;
514 struct tevent_req *subreq = NULL;
515 uint8_t in_info_type;
516 uint8_t in_file_info_class;
519 req = tevent_req_create(mem_ctx, &state,
520 struct cli_smb2_delete_on_close_state);
527 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
528 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
529 return tevent_req_post(req, ev);
532 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
533 if (tevent_req_nterror(req, status)) {
534 return tevent_req_post(req, ev);
538 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
539 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
542 in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
543 /* Setup data array. */
544 SCVAL(&state->data[0], 0, flag ? 1 : 0);
545 state->inbuf.data = &state->data[0];
546 state->inbuf.length = 1;
548 subreq = smb2cli_set_info_send(state, ev,
555 &state->inbuf, /* in_input_buffer */
556 0, /* in_additional_info */
557 state->ph->fid_persistent,
558 state->ph->fid_volatile);
559 if (tevent_req_nomem(subreq, req)) {
560 return tevent_req_post(req, ev);
562 tevent_req_set_callback(subreq,
563 cli_smb2_delete_on_close_done,
568 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
570 NTSTATUS status = smb2cli_set_info_recv(subreq);
571 tevent_req_simple_finish_ntstatus(subreq, status);
574 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
576 struct cli_smb2_delete_on_close_state *state =
578 struct cli_smb2_delete_on_close_state);
581 if (tevent_req_is_nterror(req, &status)) {
582 state->cli->raw_status = status;
583 tevent_req_received(req);
587 state->cli->raw_status = NT_STATUS_OK;
588 tevent_req_received(req);
592 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
594 TALLOC_CTX *frame = talloc_stackframe();
595 struct tevent_context *ev;
596 struct tevent_req *req;
597 NTSTATUS status = NT_STATUS_NO_MEMORY;
599 if (smbXcli_conn_has_async_calls(cli->conn)) {
601 * Can't use sync call while an async call is in flight
603 status = NT_STATUS_INVALID_PARAMETER;
606 ev = samba_tevent_context_init(frame);
610 req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
614 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
617 status = cli_smb2_delete_on_close_recv(req);
623 /***************************************************************
624 Small wrapper that allows SMB2 to create a directory
626 ***************************************************************/
628 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
633 if (smbXcli_conn_has_async_calls(cli->conn)) {
635 * Can't use sync call while an async call is in flight
637 return NT_STATUS_INVALID_PARAMETER;
640 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
641 return NT_STATUS_INVALID_PARAMETER;
644 status = cli_smb2_create_fnum(cli,
646 0, /* create_flags */
647 FILE_READ_ATTRIBUTES, /* desired_access */
648 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
649 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
650 FILE_CREATE, /* create_disposition */
651 FILE_DIRECTORY_FILE, /* create_options */
655 if (!NT_STATUS_IS_OK(status)) {
658 return cli_smb2_close_fnum(cli, fnum);
661 /***************************************************************
662 Small wrapper that allows SMB2 to delete a directory
664 ***************************************************************/
666 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
671 if (smbXcli_conn_has_async_calls(cli->conn)) {
673 * Can't use sync call while an async call is in flight
675 return NT_STATUS_INVALID_PARAMETER;
678 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
679 return NT_STATUS_INVALID_PARAMETER;
682 status = cli_smb2_create_fnum(cli,
684 0, /* create_flags */
685 DELETE_ACCESS, /* desired_access */
686 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
687 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
688 FILE_OPEN, /* create_disposition */
689 FILE_DIRECTORY_FILE, /* create_options */
693 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
695 * Naive option to match our SMB1 code. Assume the
696 * symlink path that tripped us up was the last
697 * component and try again. Eventually we will have to
698 * deal with the returned path unprocessed component. JRA.
700 status = cli_smb2_create_fnum(cli,
702 0, /* create_flags */
703 DELETE_ACCESS, /* desired_access */
704 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
705 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
706 FILE_OPEN, /* create_disposition */
708 FILE_DELETE_ON_CLOSE|
709 FILE_OPEN_REPARSE_POINT, /* create_options */
714 if (!NT_STATUS_IS_OK(status)) {
718 status = cli_smb2_delete_on_close(cli, fnum, true);
719 if (!NT_STATUS_IS_OK(status)) {
720 cli_smb2_close_fnum(cli, fnum);
724 return cli_smb2_close_fnum(cli, fnum);
727 /***************************************************************
728 Small wrapper that allows SMB2 to unlink a pathname.
730 ***************************************************************/
732 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
737 if (smbXcli_conn_has_async_calls(cli->conn)) {
739 * Can't use sync call while an async call is in flight
741 return NT_STATUS_INVALID_PARAMETER;
744 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
745 return NT_STATUS_INVALID_PARAMETER;
748 status = cli_smb2_create_fnum(cli,
750 0, /* create_flags */
751 DELETE_ACCESS, /* desired_access */
752 FILE_ATTRIBUTE_NORMAL, /* file attributes */
753 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
754 FILE_OPEN, /* create_disposition */
755 FILE_DELETE_ON_CLOSE, /* create_options */
759 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
761 * Naive option to match our SMB1 code. Assume the
762 * symlink path that tripped us up was the last
763 * component and try again. Eventually we will have to
764 * deal with the returned path unprocessed component. JRA.
766 status = cli_smb2_create_fnum(cli,
768 0, /* create_flags */
769 DELETE_ACCESS, /* desired_access */
770 FILE_ATTRIBUTE_NORMAL, /* file attributes */
771 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
772 FILE_OPEN, /* create_disposition */
773 FILE_DELETE_ON_CLOSE|
774 FILE_OPEN_REPARSE_POINT, /* create_options */
779 if (!NT_STATUS_IS_OK(status)) {
782 return cli_smb2_close_fnum(cli, fnum);
785 /***************************************************************
786 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
787 ***************************************************************/
789 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
790 uint32_t dir_data_length,
791 struct file_info *finfo,
792 uint32_t *next_offset)
798 if (dir_data_length < 4) {
799 return NT_STATUS_INFO_LENGTH_MISMATCH;
802 *next_offset = IVAL(dir_data, 0);
804 if (*next_offset > dir_data_length) {
805 return NT_STATUS_INFO_LENGTH_MISMATCH;
808 if (*next_offset != 0) {
809 /* Ensure we only read what in this record. */
810 dir_data_length = *next_offset;
813 if (dir_data_length < 105) {
814 return NT_STATUS_INFO_LENGTH_MISMATCH;
817 finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
818 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
819 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
820 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
821 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
822 finfo->mode = CVAL(dir_data + 56, 0);
823 namelen = IVAL(dir_data + 60,0);
824 if (namelen > (dir_data_length - 104)) {
825 return NT_STATUS_INFO_LENGTH_MISMATCH;
827 slen = CVAL(dir_data + 68, 0);
829 return NT_STATUS_INFO_LENGTH_MISMATCH;
831 ret = pull_string_talloc(finfo,
833 FLAGS2_UNICODE_STRINGS,
838 if (ret == (size_t)-1) {
839 /* Bad conversion. */
840 return NT_STATUS_INVALID_NETWORK_RESPONSE;
843 ret = pull_string_talloc(finfo,
845 FLAGS2_UNICODE_STRINGS,
850 if (ret == (size_t)-1) {
851 /* Bad conversion. */
852 return NT_STATUS_INVALID_NETWORK_RESPONSE;
857 /*******************************************************************
858 Given a filename - get its directory name
859 ********************************************************************/
861 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
869 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
872 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
883 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
886 (*parent)[len] = '\0';
894 /***************************************************************
895 Wrapper that allows SMB2 to list a directory.
897 ***************************************************************/
899 NTSTATUS cli_smb2_list(struct cli_state *cli,
900 const char *pathname,
902 NTSTATUS (*fn)(const char *,
909 uint16_t fnum = 0xffff;
910 char *parent_dir = NULL;
911 const char *mask = NULL;
912 struct smb2_hnd *ph = NULL;
913 bool processed_file = false;
914 TALLOC_CTX *frame = talloc_stackframe();
915 TALLOC_CTX *subframe = NULL;
917 uint32_t max_trans = smb2cli_conn_max_trans_size(cli->conn);
919 if (smbXcli_conn_has_async_calls(cli->conn)) {
921 * Can't use sync call while an async call is in flight
923 status = NT_STATUS_INVALID_PARAMETER;
927 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
928 status = NT_STATUS_INVALID_PARAMETER;
932 /* Get the directory name. */
933 if (!windows_parent_dirname(frame,
937 status = NT_STATUS_NO_MEMORY;
941 mask_has_wild = ms_has_wild(mask);
943 status = cli_smb2_create_fnum(cli,
945 0, /* create_flags */
946 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
947 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
948 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
949 FILE_OPEN, /* create_disposition */
950 FILE_DIRECTORY_FILE, /* create_options */
954 if (!NT_STATUS_IS_OK(status)) {
958 status = map_fnum_to_smb2_handle(cli,
961 if (!NT_STATUS_IS_OK(status)) {
966 uint8_t *dir_data = NULL;
967 uint32_t dir_data_length = 0;
968 uint32_t next_offset = 0;
969 subframe = talloc_stackframe();
971 status = smb2cli_query_directory(cli->conn,
975 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
986 if (!NT_STATUS_IS_OK(status)) {
987 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
994 struct file_info *finfo = talloc_zero(subframe,
998 status = NT_STATUS_NO_MEMORY;
1002 status = parse_finfo_id_both_directory_info(dir_data,
1007 if (!NT_STATUS_IS_OK(status)) {
1011 if (dir_check_ftype((uint32_t)finfo->mode,
1012 (uint32_t)attribute)) {
1014 * Only process if attributes match.
1015 * On SMB1 server does this, so on
1016 * SMB2 we need to emulate in the
1019 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1021 processed_file = true;
1023 status = fn(cli->dfs_mountpoint,
1028 if (!NT_STATUS_IS_OK(status)) {
1035 /* Move to next entry. */
1037 dir_data += next_offset;
1038 dir_data_length -= next_offset;
1040 } while (next_offset != 0);
1042 TALLOC_FREE(subframe);
1044 if (!mask_has_wild) {
1046 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1047 * when handed a non-wildcard path. Do it
1048 * for the server (with a non-wildcard path
1049 * there should only ever be one file returned.
1051 status = STATUS_NO_MORE_FILES;
1055 } while (NT_STATUS_IS_OK(status));
1057 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1058 status = NT_STATUS_OK;
1061 if (NT_STATUS_IS_OK(status) && !processed_file) {
1063 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1064 * if no files match. Emulate this in the client.
1066 status = NT_STATUS_NO_SUCH_FILE;
1071 if (fnum != 0xffff) {
1072 cli_smb2_close_fnum(cli, fnum);
1075 cli->raw_status = status;
1077 TALLOC_FREE(subframe);
1082 /***************************************************************
1083 Wrapper that allows SMB2 to query a path info (basic level).
1085 ***************************************************************/
1087 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1089 SMB_STRUCT_STAT *sbuf,
1090 uint32_t *attributes)
1093 struct smb_create_returns cr;
1094 uint16_t fnum = 0xffff;
1095 size_t namelen = strlen(name);
1097 if (smbXcli_conn_has_async_calls(cli->conn)) {
1099 * Can't use sync call while an async call is in flight
1101 return NT_STATUS_INVALID_PARAMETER;
1104 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1105 return NT_STATUS_INVALID_PARAMETER;
1108 /* SMB2 is pickier about pathnames. Ensure it doesn't
1110 if (namelen > 0 && name[namelen-1] == '\\') {
1111 char *modname = talloc_strdup(talloc_tos(), name);
1112 modname[namelen-1] = '\0';
1116 /* This is commonly used as a 'cd'. Try qpathinfo on
1117 a directory handle first. */
1119 status = cli_smb2_create_fnum(cli,
1121 0, /* create_flags */
1122 FILE_READ_ATTRIBUTES, /* desired_access */
1123 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1124 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1125 FILE_OPEN, /* create_disposition */
1126 FILE_DIRECTORY_FILE, /* create_options */
1130 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1131 /* Maybe a file ? */
1132 status = cli_smb2_create_fnum(cli,
1134 0, /* create_flags */
1135 FILE_READ_ATTRIBUTES, /* desired_access */
1136 0, /* file attributes */
1137 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1138 FILE_OPEN, /* create_disposition */
1139 0, /* create_options */
1144 if (!NT_STATUS_IS_OK(status)) {
1148 status = cli_smb2_close_fnum(cli, fnum);
1152 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1153 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1154 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1155 sbuf->st_ex_size = cr.end_of_file;
1156 *attributes = cr.file_attributes;
1161 /***************************************************************
1162 Wrapper that allows SMB2 to check if a path is a directory.
1164 ***************************************************************/
1166 NTSTATUS cli_smb2_chkpath(struct cli_state *cli,
1170 uint16_t fnum = 0xffff;
1172 if (smbXcli_conn_has_async_calls(cli->conn)) {
1174 * Can't use sync call while an async call is in flight
1176 return NT_STATUS_INVALID_PARAMETER;
1179 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1180 return NT_STATUS_INVALID_PARAMETER;
1183 /* Ensure this is a directory. */
1184 status = cli_smb2_create_fnum(cli,
1186 0, /* create_flags */
1187 FILE_READ_ATTRIBUTES, /* desired_access */
1188 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1189 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1190 FILE_OPEN, /* create_disposition */
1191 FILE_DIRECTORY_FILE, /* create_options */
1195 if (!NT_STATUS_IS_OK(status)) {
1199 return cli_smb2_close_fnum(cli, fnum);
1202 /***************************************************************
1203 Helper function for pathname operations.
1204 ***************************************************************/
1206 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1208 uint32_t desired_access,
1212 size_t namelen = strlen(name);
1213 TALLOC_CTX *frame = talloc_stackframe();
1214 uint32_t create_options = 0;
1216 /* SMB2 is pickier about pathnames. Ensure it doesn't
1218 if (namelen > 0 && name[namelen-1] == '\\') {
1219 char *modname = talloc_strdup(frame, name);
1220 if (modname == NULL) {
1221 status = NT_STATUS_NO_MEMORY;
1224 modname[namelen-1] = '\0';
1228 /* Try to open a file handle first. */
1229 status = cli_smb2_create_fnum(cli,
1231 0, /* create_flags */
1233 0, /* file attributes */
1234 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1235 FILE_OPEN, /* create_disposition */
1240 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1242 * Naive option to match our SMB1 code. Assume the
1243 * symlink path that tripped us up was the last
1244 * component and try again. Eventually we will have to
1245 * deal with the returned path unprocessed component. JRA.
1247 create_options |= FILE_OPEN_REPARSE_POINT;
1248 status = cli_smb2_create_fnum(cli,
1250 0, /* create_flags */
1252 0, /* file attributes */
1253 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1254 FILE_OPEN, /* create_disposition */
1260 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1261 create_options |= FILE_DIRECTORY_FILE;
1262 status = cli_smb2_create_fnum(cli,
1264 0, /* create_flags */
1266 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1267 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1268 FILE_OPEN, /* create_disposition */
1269 FILE_DIRECTORY_FILE, /* create_options */
1280 /***************************************************************
1281 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1283 ***************************************************************/
1285 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1290 DATA_BLOB outbuf = data_blob_null;
1291 uint16_t fnum = 0xffff;
1292 struct smb2_hnd *ph = NULL;
1293 uint32_t altnamelen = 0;
1294 TALLOC_CTX *frame = talloc_stackframe();
1296 if (smbXcli_conn_has_async_calls(cli->conn)) {
1298 * Can't use sync call while an async call is in flight
1300 status = NT_STATUS_INVALID_PARAMETER;
1304 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1305 status = NT_STATUS_INVALID_PARAMETER;
1309 status = get_fnum_from_path(cli,
1311 FILE_READ_ATTRIBUTES,
1314 if (!NT_STATUS_IS_OK(status)) {
1318 status = map_fnum_to_smb2_handle(cli,
1321 if (!NT_STATUS_IS_OK(status)) {
1325 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1326 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1328 status = smb2cli_query_info(cli->conn,
1332 1, /* in_info_type */
1333 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1334 0xFFFF, /* in_max_output_length */
1335 NULL, /* in_input_buffer */
1336 0, /* in_additional_info */
1343 if (!NT_STATUS_IS_OK(status)) {
1347 /* Parse the reply. */
1348 if (outbuf.length < 4) {
1349 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1353 altnamelen = IVAL(outbuf.data, 0);
1354 if (altnamelen > outbuf.length - 4) {
1355 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1359 if (altnamelen > 0) {
1361 char *short_name = NULL;
1362 ret = pull_string_talloc(frame,
1364 FLAGS2_UNICODE_STRINGS,
1369 if (ret == (size_t)-1) {
1370 /* Bad conversion. */
1371 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1375 fstrcpy(alt_name, short_name);
1380 status = NT_STATUS_OK;
1384 if (fnum != 0xffff) {
1385 cli_smb2_close_fnum(cli, fnum);
1388 cli->raw_status = status;
1395 /***************************************************************
1396 Wrapper that allows SMB2 to query a fnum info (basic level).
1398 ***************************************************************/
1400 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1404 struct timespec *create_time,
1405 struct timespec *access_time,
1406 struct timespec *write_time,
1407 struct timespec *change_time,
1411 DATA_BLOB outbuf = data_blob_null;
1412 struct smb2_hnd *ph = NULL;
1413 TALLOC_CTX *frame = talloc_stackframe();
1415 if (smbXcli_conn_has_async_calls(cli->conn)) {
1417 * Can't use sync call while an async call is in flight
1419 status = NT_STATUS_INVALID_PARAMETER;
1423 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1424 status = NT_STATUS_INVALID_PARAMETER;
1428 status = map_fnum_to_smb2_handle(cli,
1431 if (!NT_STATUS_IS_OK(status)) {
1435 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1436 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1438 status = smb2cli_query_info(cli->conn,
1442 1, /* in_info_type */
1443 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1444 0xFFFF, /* in_max_output_length */
1445 NULL, /* in_input_buffer */
1446 0, /* in_additional_info */
1452 if (!NT_STATUS_IS_OK(status)) {
1456 /* Parse the reply. */
1457 if (outbuf.length < 0x60) {
1458 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1463 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1466 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1469 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1472 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1475 uint32_t attr = IVAL(outbuf.data, 0x20);
1476 *mode = (uint16_t)attr;
1479 uint64_t file_size = BVAL(outbuf.data, 0x30);
1480 *size = (off_t)file_size;
1483 uint64_t file_index = BVAL(outbuf.data, 0x40);
1484 *ino = (SMB_INO_T)file_index;
1489 cli->raw_status = status;
1495 /***************************************************************
1496 Wrapper that allows SMB2 to query an fnum.
1497 Implement on top of cli_smb2_qfileinfo_basic().
1499 ***************************************************************/
1501 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1505 time_t *change_time,
1506 time_t *access_time,
1509 struct timespec access_time_ts;
1510 struct timespec write_time_ts;
1511 struct timespec change_time_ts;
1512 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1522 cli->raw_status = status;
1524 if (!NT_STATUS_IS_OK(status)) {
1529 *change_time = change_time_ts.tv_sec;
1532 *access_time = access_time_ts.tv_sec;
1535 *write_time = write_time_ts.tv_sec;
1537 return NT_STATUS_OK;
1540 /***************************************************************
1541 Wrapper that allows SMB2 to get pathname attributes.
1543 ***************************************************************/
1545 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1552 uint16_t fnum = 0xffff;
1553 struct smb2_hnd *ph = NULL;
1554 TALLOC_CTX *frame = talloc_stackframe();
1556 if (smbXcli_conn_has_async_calls(cli->conn)) {
1558 * Can't use sync call while an async call is in flight
1560 status = NT_STATUS_INVALID_PARAMETER;
1564 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1565 status = NT_STATUS_INVALID_PARAMETER;
1569 status = get_fnum_from_path(cli,
1571 FILE_READ_ATTRIBUTES,
1574 if (!NT_STATUS_IS_OK(status)) {
1578 status = map_fnum_to_smb2_handle(cli,
1581 if (!NT_STATUS_IS_OK(status)) {
1584 status = cli_smb2_getattrE(cli,
1591 if (!NT_STATUS_IS_OK(status)) {
1597 if (fnum != 0xffff) {
1598 cli_smb2_close_fnum(cli, fnum);
1601 cli->raw_status = status;
1607 /***************************************************************
1608 Wrapper that allows SMB2 to query a pathname info (basic level).
1609 Implement on top of cli_smb2_qfileinfo_basic().
1611 ***************************************************************/
1613 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1615 struct timespec *create_time,
1616 struct timespec *access_time,
1617 struct timespec *write_time,
1618 struct timespec *change_time,
1624 struct smb2_hnd *ph = NULL;
1625 uint16_t fnum = 0xffff;
1626 TALLOC_CTX *frame = talloc_stackframe();
1628 if (smbXcli_conn_has_async_calls(cli->conn)) {
1630 * Can't use sync call while an async call is in flight
1632 status = NT_STATUS_INVALID_PARAMETER;
1636 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1637 status = NT_STATUS_INVALID_PARAMETER;
1641 status = get_fnum_from_path(cli,
1643 FILE_READ_ATTRIBUTES,
1646 if (!NT_STATUS_IS_OK(status)) {
1650 status = map_fnum_to_smb2_handle(cli,
1653 if (!NT_STATUS_IS_OK(status)) {
1657 status = cli_smb2_qfileinfo_basic(cli,
1669 if (fnum != 0xffff) {
1670 cli_smb2_close_fnum(cli, fnum);
1673 cli->raw_status = status;
1679 /***************************************************************
1680 Wrapper that allows SMB2 to query pathname streams.
1682 ***************************************************************/
1684 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1686 TALLOC_CTX *mem_ctx,
1687 unsigned int *pnum_streams,
1688 struct stream_struct **pstreams)
1691 struct smb2_hnd *ph = NULL;
1692 uint16_t fnum = 0xffff;
1693 DATA_BLOB outbuf = data_blob_null;
1694 TALLOC_CTX *frame = talloc_stackframe();
1696 if (smbXcli_conn_has_async_calls(cli->conn)) {
1698 * Can't use sync call while an async call is in flight
1700 status = NT_STATUS_INVALID_PARAMETER;
1704 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1705 status = NT_STATUS_INVALID_PARAMETER;
1709 status = get_fnum_from_path(cli,
1711 FILE_READ_ATTRIBUTES,
1714 if (!NT_STATUS_IS_OK(status)) {
1718 status = map_fnum_to_smb2_handle(cli,
1721 if (!NT_STATUS_IS_OK(status)) {
1725 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1726 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1728 status = smb2cli_query_info(cli->conn,
1732 1, /* in_info_type */
1733 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1734 0xFFFF, /* in_max_output_length */
1735 NULL, /* in_input_buffer */
1736 0, /* in_additional_info */
1743 if (!NT_STATUS_IS_OK(status)) {
1747 /* Parse the reply. */
1748 if (!parse_streams_blob(mem_ctx,
1753 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1759 if (fnum != 0xffff) {
1760 cli_smb2_close_fnum(cli, fnum);
1763 cli->raw_status = status;
1769 /***************************************************************
1770 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
1773 ***************************************************************/
1775 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
1777 uint8_t in_info_type,
1778 uint8_t in_file_info_class,
1779 const DATA_BLOB *p_in_data)
1782 uint16_t fnum = 0xffff;
1783 struct smb2_hnd *ph = NULL;
1784 TALLOC_CTX *frame = talloc_stackframe();
1786 if (smbXcli_conn_has_async_calls(cli->conn)) {
1788 * Can't use sync call while an async call is in flight
1790 status = NT_STATUS_INVALID_PARAMETER;
1794 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1795 status = NT_STATUS_INVALID_PARAMETER;
1799 status = get_fnum_from_path(cli,
1801 FILE_WRITE_ATTRIBUTES,
1804 if (!NT_STATUS_IS_OK(status)) {
1808 status = map_fnum_to_smb2_handle(cli,
1811 if (!NT_STATUS_IS_OK(status)) {
1815 status = smb2cli_set_info(cli->conn,
1821 p_in_data, /* in_input_buffer */
1822 0, /* in_additional_info */
1827 if (fnum != 0xffff) {
1828 cli_smb2_close_fnum(cli, fnum);
1831 cli->raw_status = status;
1838 /***************************************************************
1839 Wrapper that allows SMB2 to set pathname attributes.
1841 ***************************************************************/
1843 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1848 uint8_t inbuf_store[40];
1849 DATA_BLOB inbuf = data_blob_null;
1851 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1852 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1854 inbuf.data = inbuf_store;
1855 inbuf.length = sizeof(inbuf_store);
1856 data_blob_clear(&inbuf);
1859 * SMB1 uses attr == 0 to clear all attributes
1860 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
1861 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
1862 * request attribute change.
1864 * SMB2 uses exactly the reverse. Unfortunately as the
1865 * cli_setatr() ABI is exposed inside libsmbclient,
1866 * we must make the SMB2 cli_smb2_setatr() call
1867 * export the same ABI as the SMB1 cli_setatr()
1868 * which calls it. This means reversing the sense
1869 * of the requested attr argument if it's zero
1870 * or FILE_ATTRIBUTE_NORMAL.
1872 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
1876 attr = FILE_ATTRIBUTE_NORMAL;
1877 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
1881 SSVAL(inbuf.data, 32, attr);
1883 put_long_date((char *)inbuf.data + 16,mtime);
1885 /* Set all the other times to -1. */
1886 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1887 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1888 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1890 return cli_smb2_setpathinfo(cli,
1892 1, /* in_info_type */
1893 /* in_file_info_class */
1894 SMB_FILE_BASIC_INFORMATION - 1000,
1899 /***************************************************************
1900 Wrapper that allows SMB2 to set file handle times.
1902 ***************************************************************/
1904 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1911 struct smb2_hnd *ph = NULL;
1912 uint8_t inbuf_store[40];
1913 DATA_BLOB inbuf = data_blob_null;
1915 if (smbXcli_conn_has_async_calls(cli->conn)) {
1917 * Can't use sync call while an async call is in flight
1919 return NT_STATUS_INVALID_PARAMETER;
1922 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1923 return NT_STATUS_INVALID_PARAMETER;
1926 status = map_fnum_to_smb2_handle(cli,
1929 if (!NT_STATUS_IS_OK(status)) {
1933 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1934 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1936 inbuf.data = inbuf_store;
1937 inbuf.length = sizeof(inbuf_store);
1938 data_blob_clear(&inbuf);
1940 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1941 if (change_time != 0) {
1942 put_long_date((char *)inbuf.data + 24, change_time);
1944 if (access_time != 0) {
1945 put_long_date((char *)inbuf.data + 8, access_time);
1947 if (write_time != 0) {
1948 put_long_date((char *)inbuf.data + 16, write_time);
1951 cli->raw_status = smb2cli_set_info(cli->conn,
1955 1, /* in_info_type */
1956 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1957 &inbuf, /* in_input_buffer */
1958 0, /* in_additional_info */
1962 return cli->raw_status;
1965 /***************************************************************
1966 Wrapper that allows SMB2 to query disk attributes (size).
1968 ***************************************************************/
1970 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
1971 uint64_t *bsize, uint64_t *total, uint64_t *avail)
1974 uint16_t fnum = 0xffff;
1975 DATA_BLOB outbuf = data_blob_null;
1976 struct smb2_hnd *ph = NULL;
1977 uint32_t sectors_per_unit = 0;
1978 uint32_t bytes_per_sector = 0;
1979 uint64_t total_size = 0;
1980 uint64_t size_free = 0;
1981 TALLOC_CTX *frame = talloc_stackframe();
1983 if (smbXcli_conn_has_async_calls(cli->conn)) {
1985 * Can't use sync call while an async call is in flight
1987 status = NT_STATUS_INVALID_PARAMETER;
1991 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1992 status = NT_STATUS_INVALID_PARAMETER;
1996 /* First open the top level directory. */
1997 status = cli_smb2_create_fnum(cli,
1999 0, /* create_flags */
2000 FILE_READ_ATTRIBUTES, /* desired_access */
2001 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2002 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2003 FILE_OPEN, /* create_disposition */
2004 FILE_DIRECTORY_FILE, /* create_options */
2008 if (!NT_STATUS_IS_OK(status)) {
2012 status = map_fnum_to_smb2_handle(cli,
2015 if (!NT_STATUS_IS_OK(status)) {
2019 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2020 level 3 (SMB_FS_SIZE_INFORMATION). */
2022 status = smb2cli_query_info(cli->conn,
2026 2, /* in_info_type */
2027 3, /* in_file_info_class */
2028 0xFFFF, /* in_max_output_length */
2029 NULL, /* in_input_buffer */
2030 0, /* in_additional_info */
2036 if (!NT_STATUS_IS_OK(status)) {
2040 /* Parse the reply. */
2041 if (outbuf.length != 24) {
2042 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2046 total_size = BVAL(outbuf.data, 0);
2047 size_free = BVAL(outbuf.data, 8);
2048 sectors_per_unit = IVAL(outbuf.data, 16);
2049 bytes_per_sector = IVAL(outbuf.data, 20);
2052 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2055 *total = total_size;
2061 status = NT_STATUS_OK;
2065 if (fnum != 0xffff) {
2066 cli_smb2_close_fnum(cli, fnum);
2069 cli->raw_status = status;
2075 /***************************************************************
2076 Wrapper that allows SMB2 to query file system sizes.
2078 ***************************************************************/
2080 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2081 uint64_t *total_allocation_units,
2082 uint64_t *caller_allocation_units,
2083 uint64_t *actual_allocation_units,
2084 uint64_t *sectors_per_allocation_unit,
2085 uint64_t *bytes_per_sector)
2088 uint16_t fnum = 0xffff;
2089 DATA_BLOB outbuf = data_blob_null;
2090 struct smb2_hnd *ph = NULL;
2091 TALLOC_CTX *frame = talloc_stackframe();
2093 if (smbXcli_conn_has_async_calls(cli->conn)) {
2095 * Can't use sync call while an async call is in flight
2097 status = NT_STATUS_INVALID_PARAMETER;
2101 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2102 status = NT_STATUS_INVALID_PARAMETER;
2106 /* First open the top level directory. */
2108 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2109 FILE_READ_ATTRIBUTES, /* desired_access */
2110 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2111 FILE_SHARE_READ | FILE_SHARE_WRITE |
2112 FILE_SHARE_DELETE, /* share_access */
2113 FILE_OPEN, /* create_disposition */
2114 FILE_DIRECTORY_FILE, /* create_options */
2118 if (!NT_STATUS_IS_OK(status)) {
2122 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2123 if (!NT_STATUS_IS_OK(status)) {
2127 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2128 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2130 status = smb2cli_query_info(cli->conn,
2134 SMB2_GETINFO_FS, /* in_info_type */
2135 /* in_file_info_class */
2136 SMB_FS_FULL_SIZE_INFORMATION - 1000,
2137 0xFFFF, /* in_max_output_length */
2138 NULL, /* in_input_buffer */
2139 0, /* in_additional_info */
2145 if (!NT_STATUS_IS_OK(status)) {
2149 if (outbuf.length < 32) {
2150 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2154 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2155 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2156 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2157 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2158 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2162 if (fnum != 0xffff) {
2163 cli_smb2_close_fnum(cli, fnum);
2166 cli->raw_status = status;
2172 /***************************************************************
2173 Wrapper that allows SMB2 to query file system attributes.
2175 ***************************************************************/
2177 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2180 uint16_t fnum = 0xffff;
2181 DATA_BLOB outbuf = data_blob_null;
2182 struct smb2_hnd *ph = NULL;
2183 TALLOC_CTX *frame = talloc_stackframe();
2185 if (smbXcli_conn_has_async_calls(cli->conn)) {
2187 * Can't use sync call while an async call is in flight
2189 status = NT_STATUS_INVALID_PARAMETER;
2193 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2194 status = NT_STATUS_INVALID_PARAMETER;
2198 /* First open the top level directory. */
2200 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2201 FILE_READ_ATTRIBUTES, /* desired_access */
2202 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2203 FILE_SHARE_READ | FILE_SHARE_WRITE |
2204 FILE_SHARE_DELETE, /* share_access */
2205 FILE_OPEN, /* create_disposition */
2206 FILE_DIRECTORY_FILE, /* create_options */
2210 if (!NT_STATUS_IS_OK(status)) {
2214 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2215 if (!NT_STATUS_IS_OK(status)) {
2219 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2220 cli->smb2.tcon, 2, /* in_info_type */
2221 5, /* in_file_info_class */
2222 0xFFFF, /* in_max_output_length */
2223 NULL, /* in_input_buffer */
2224 0, /* in_additional_info */
2226 ph->fid_persistent, ph->fid_volatile, frame,
2228 if (!NT_STATUS_IS_OK(status)) {
2232 if (outbuf.length < 12) {
2233 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2237 *fs_attr = IVAL(outbuf.data, 0);
2241 if (fnum != 0xffff) {
2242 cli_smb2_close_fnum(cli, fnum);
2245 cli->raw_status = status;
2251 /***************************************************************
2252 Wrapper that allows SMB2 to query file system volume info.
2254 ***************************************************************/
2256 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2257 TALLOC_CTX *mem_ctx,
2258 char **_volume_name,
2259 uint32_t *pserial_number,
2263 uint16_t fnum = 0xffff;
2264 DATA_BLOB outbuf = data_blob_null;
2265 struct smb2_hnd *ph = NULL;
2267 char *volume_name = NULL;
2268 TALLOC_CTX *frame = talloc_stackframe();
2270 if (smbXcli_conn_has_async_calls(cli->conn)) {
2272 * Can't use sync call while an async call is in flight
2274 status = NT_STATUS_INVALID_PARAMETER;
2278 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2279 status = NT_STATUS_INVALID_PARAMETER;
2283 /* First open the top level directory. */
2285 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2286 FILE_READ_ATTRIBUTES, /* desired_access */
2287 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2288 FILE_SHARE_READ | FILE_SHARE_WRITE |
2289 FILE_SHARE_DELETE, /* share_access */
2290 FILE_OPEN, /* create_disposition */
2291 FILE_DIRECTORY_FILE, /* create_options */
2295 if (!NT_STATUS_IS_OK(status)) {
2299 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2300 if (!NT_STATUS_IS_OK(status)) {
2304 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2305 level 1 (SMB_FS_VOLUME_INFORMATION). */
2307 status = smb2cli_query_info(cli->conn,
2311 SMB2_GETINFO_FS, /* in_info_type */
2312 /* in_file_info_class */
2313 SMB_FS_VOLUME_INFORMATION - 1000,
2314 0xFFFF, /* in_max_output_length */
2315 NULL, /* in_input_buffer */
2316 0, /* in_additional_info */
2322 if (!NT_STATUS_IS_OK(status)) {
2326 if (outbuf.length < 24) {
2327 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2333 ts = interpret_long_date((char *)outbuf.data);
2336 if (pserial_number) {
2337 *pserial_number = IVAL(outbuf.data,8);
2339 nlen = IVAL(outbuf.data,12);
2340 if (nlen + 18 < 18) {
2342 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2346 * The next check is safe as we know outbuf.length >= 24
2349 if (nlen > (outbuf.length - 18)) {
2350 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2354 clistr_pull_talloc(mem_ctx,
2355 (const char *)outbuf.data,
2361 if (volume_name == NULL) {
2362 status = map_nt_error_from_unix(errno);
2366 *_volume_name = volume_name;
2370 if (fnum != 0xffff) {
2371 cli_smb2_close_fnum(cli, fnum);
2374 cli->raw_status = status;
2381 /***************************************************************
2382 Wrapper that allows SMB2 to query a security descriptor.
2384 ***************************************************************/
2386 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2389 TALLOC_CTX *mem_ctx,
2390 struct security_descriptor **ppsd)
2393 DATA_BLOB outbuf = data_blob_null;
2394 struct smb2_hnd *ph = NULL;
2395 struct security_descriptor *lsd = NULL;
2396 TALLOC_CTX *frame = talloc_stackframe();
2398 if (smbXcli_conn_has_async_calls(cli->conn)) {
2400 * Can't use sync call while an async call is in flight
2402 status = NT_STATUS_INVALID_PARAMETER;
2406 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2407 status = NT_STATUS_INVALID_PARAMETER;
2411 status = map_fnum_to_smb2_handle(cli,
2414 if (!NT_STATUS_IS_OK(status)) {
2418 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2420 status = smb2cli_query_info(cli->conn,
2424 3, /* in_info_type */
2425 0, /* in_file_info_class */
2426 0xFFFF, /* in_max_output_length */
2427 NULL, /* in_input_buffer */
2428 sec_info, /* in_additional_info */
2435 if (!NT_STATUS_IS_OK(status)) {
2439 /* Parse the reply. */
2440 status = unmarshall_sec_desc(mem_ctx,
2445 if (!NT_STATUS_IS_OK(status)) {
2457 cli->raw_status = status;
2463 /***************************************************************
2464 Wrapper that allows SMB2 to set a security descriptor.
2466 ***************************************************************/
2468 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
2471 const struct security_descriptor *sd)
2474 DATA_BLOB inbuf = data_blob_null;
2475 struct smb2_hnd *ph = NULL;
2476 TALLOC_CTX *frame = talloc_stackframe();
2478 if (smbXcli_conn_has_async_calls(cli->conn)) {
2480 * Can't use sync call while an async call is in flight
2482 status = NT_STATUS_INVALID_PARAMETER;
2486 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2487 status = NT_STATUS_INVALID_PARAMETER;
2491 status = map_fnum_to_smb2_handle(cli,
2494 if (!NT_STATUS_IS_OK(status)) {
2498 status = marshall_sec_desc(frame,
2503 if (!NT_STATUS_IS_OK(status)) {
2507 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2509 status = smb2cli_set_info(cli->conn,
2513 3, /* in_info_type */
2514 0, /* in_file_info_class */
2515 &inbuf, /* in_input_buffer */
2516 sec_info, /* in_additional_info */
2522 cli->raw_status = status;
2528 /***************************************************************
2529 Wrapper that allows SMB2 to rename a file.
2531 ***************************************************************/
2533 NTSTATUS cli_smb2_rename(struct cli_state *cli,
2534 const char *fname_src,
2535 const char *fname_dst,
2539 DATA_BLOB inbuf = data_blob_null;
2540 uint16_t fnum = 0xffff;
2541 struct smb2_hnd *ph = NULL;
2542 smb_ucs2_t *converted_str = NULL;
2543 size_t converted_size_bytes = 0;
2545 TALLOC_CTX *frame = talloc_stackframe();
2547 if (smbXcli_conn_has_async_calls(cli->conn)) {
2549 * Can't use sync call while an async call is in flight
2551 status = NT_STATUS_INVALID_PARAMETER;
2555 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2556 status = NT_STATUS_INVALID_PARAMETER;
2560 status = get_fnum_from_path(cli,
2565 if (!NT_STATUS_IS_OK(status)) {
2569 status = map_fnum_to_smb2_handle(cli,
2572 if (!NT_STATUS_IS_OK(status)) {
2576 /* SMB2 is pickier about pathnames. Ensure it doesn't
2578 if (*fname_dst == '\\') {
2582 /* SMB2 is pickier about pathnames. Ensure it doesn't
2584 namelen = strlen(fname_dst);
2585 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2586 char *modname = talloc_strdup(frame, fname_dst);
2587 modname[namelen-1] = '\0';
2588 fname_dst = modname;
2591 if (!push_ucs2_talloc(frame,
2594 &converted_size_bytes)) {
2595 status = NT_STATUS_INVALID_PARAMETER;
2599 /* W2K8 insists the dest name is not null
2600 terminated. Remove the last 2 zero bytes
2601 and reduce the name length. */
2603 if (converted_size_bytes < 2) {
2604 status = NT_STATUS_INVALID_PARAMETER;
2607 converted_size_bytes -= 2;
2609 inbuf = data_blob_talloc_zero(frame,
2610 20 + converted_size_bytes);
2611 if (inbuf.data == NULL) {
2612 status = NT_STATUS_NO_MEMORY;
2617 SCVAL(inbuf.data, 0, 1);
2620 SIVAL(inbuf.data, 16, converted_size_bytes);
2621 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2623 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2624 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2626 status = smb2cli_set_info(cli->conn,
2630 1, /* in_info_type */
2631 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2632 &inbuf, /* in_input_buffer */
2633 0, /* in_additional_info */
2639 if (fnum != 0xffff) {
2640 cli_smb2_close_fnum(cli, fnum);
2643 cli->raw_status = status;
2649 /***************************************************************
2650 Wrapper that allows SMB2 to set an EA on a fnum.
2652 ***************************************************************/
2654 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2656 const char *ea_name,
2661 DATA_BLOB inbuf = data_blob_null;
2663 char *ea_name_ascii = NULL;
2665 struct smb2_hnd *ph = NULL;
2666 TALLOC_CTX *frame = talloc_stackframe();
2668 if (smbXcli_conn_has_async_calls(cli->conn)) {
2670 * Can't use sync call while an async call is in flight
2672 status = NT_STATUS_INVALID_PARAMETER;
2676 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2677 status = NT_STATUS_INVALID_PARAMETER;
2681 status = map_fnum_to_smb2_handle(cli,
2684 if (!NT_STATUS_IS_OK(status)) {
2688 /* Marshall the SMB2 EA data. */
2689 if (ea_len > 0xFFFF) {
2690 status = NT_STATUS_INVALID_PARAMETER;
2694 if (!push_ascii_talloc(frame,
2698 status = NT_STATUS_INVALID_PARAMETER;
2702 if (namelen < 2 || namelen > 0xFF) {
2703 status = NT_STATUS_INVALID_PARAMETER;
2707 bloblen = 8 + ea_len + namelen;
2708 /* Round up to a 4 byte boundary. */
2709 bloblen = ((bloblen + 3)&~3);
2711 inbuf = data_blob_talloc_zero(frame, bloblen);
2712 if (inbuf.data == NULL) {
2713 status = NT_STATUS_NO_MEMORY;
2716 /* namelen doesn't include the NULL byte. */
2717 SCVAL(inbuf.data, 5, namelen - 1);
2718 SSVAL(inbuf.data, 6, ea_len);
2719 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2720 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2722 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2723 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2725 status = smb2cli_set_info(cli->conn,
2729 1, /* in_info_type */
2730 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2731 &inbuf, /* in_input_buffer */
2732 0, /* in_additional_info */
2738 cli->raw_status = status;
2744 /***************************************************************
2745 Wrapper that allows SMB2 to set an EA on a pathname.
2747 ***************************************************************/
2749 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2751 const char *ea_name,
2756 uint16_t fnum = 0xffff;
2758 if (smbXcli_conn_has_async_calls(cli->conn)) {
2760 * Can't use sync call while an async call is in flight
2762 status = NT_STATUS_INVALID_PARAMETER;
2766 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2767 status = NT_STATUS_INVALID_PARAMETER;
2771 status = get_fnum_from_path(cli,
2776 if (!NT_STATUS_IS_OK(status)) {
2780 status = cli_set_ea_fnum(cli,
2785 if (!NT_STATUS_IS_OK(status)) {
2791 if (fnum != 0xffff) {
2792 cli_smb2_close_fnum(cli, fnum);
2795 cli->raw_status = status;
2800 /***************************************************************
2801 Wrapper that allows SMB2 to get an EA list on a pathname.
2803 ***************************************************************/
2805 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2809 struct ea_struct **pea_array)
2812 uint16_t fnum = 0xffff;
2813 DATA_BLOB outbuf = data_blob_null;
2814 struct smb2_hnd *ph = NULL;
2815 struct ea_list *ea_list = NULL;
2816 struct ea_list *eal = NULL;
2817 size_t ea_count = 0;
2818 TALLOC_CTX *frame = talloc_stackframe();
2823 if (smbXcli_conn_has_async_calls(cli->conn)) {
2825 * Can't use sync call while an async call is in flight
2827 status = NT_STATUS_INVALID_PARAMETER;
2831 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2832 status = NT_STATUS_INVALID_PARAMETER;
2836 status = get_fnum_from_path(cli,
2841 if (!NT_STATUS_IS_OK(status)) {
2845 status = map_fnum_to_smb2_handle(cli,
2848 if (!NT_STATUS_IS_OK(status)) {
2852 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2853 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2855 status = smb2cli_query_info(cli->conn,
2859 1, /* in_info_type */
2860 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2861 0xFFFF, /* in_max_output_length */
2862 NULL, /* in_input_buffer */
2863 0, /* in_additional_info */
2870 if (!NT_STATUS_IS_OK(status)) {
2874 /* Parse the reply. */
2875 ea_list = read_nttrans_ea_list(ctx,
2876 (const char *)outbuf.data,
2878 if (ea_list == NULL) {
2879 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2883 /* Convert to an array. */
2884 for (eal = ea_list; eal; eal = eal->next) {
2889 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2890 if (*pea_array == NULL) {
2891 status = NT_STATUS_NO_MEMORY;
2895 for (eal = ea_list; eal; eal = eal->next) {
2896 (*pea_array)[ea_count++] = eal->ea;
2898 *pnum_eas = ea_count;
2903 if (fnum != 0xffff) {
2904 cli_smb2_close_fnum(cli, fnum);
2907 cli->raw_status = status;
2913 /***************************************************************
2914 Wrapper that allows SMB2 to get user quota.
2916 ***************************************************************/
2918 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
2920 SMB_NTQUOTA_STRUCT *pqt)
2923 DATA_BLOB inbuf = data_blob_null;
2924 DATA_BLOB info_blob = data_blob_null;
2925 DATA_BLOB outbuf = data_blob_null;
2926 struct smb2_hnd *ph = NULL;
2927 TALLOC_CTX *frame = talloc_stackframe();
2929 unsigned int offset;
2930 struct smb2_query_quota_info query = {0};
2931 struct file_get_quota_info info = {0};
2932 enum ndr_err_code err;
2933 struct ndr_push *ndr_push = NULL;
2935 if (smbXcli_conn_has_async_calls(cli->conn)) {
2937 * Can't use sync call while an async call is in flight
2939 status = NT_STATUS_INVALID_PARAMETER;
2943 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2944 status = NT_STATUS_INVALID_PARAMETER;
2948 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2949 if (!NT_STATUS_IS_OK(status)) {
2953 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
2955 query.return_single = 1;
2957 info.next_entry_offset = 0;
2958 info.sid_length = sid_len;
2959 info.sid = pqt->sid;
2961 err = ndr_push_struct_blob(
2965 (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
2967 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
2968 status = NT_STATUS_INTERNAL_ERROR;
2972 query.sid_list_length = info_blob.length;
2973 ndr_push = ndr_push_init_ctx(frame);
2975 status = NT_STATUS_NO_MEMORY;
2979 err = ndr_push_smb2_query_quota_info(ndr_push,
2980 NDR_SCALARS | NDR_BUFFERS,
2983 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
2984 status = NT_STATUS_INTERNAL_ERROR;
2988 err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
2991 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
2992 status = NT_STATUS_INTERNAL_ERROR;
2995 inbuf.data = ndr_push->data;
2996 inbuf.length = ndr_push->offset;
2998 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2999 cli->smb2.tcon, 4, /* in_info_type */
3000 0, /* in_file_info_class */
3001 0xFFFF, /* in_max_output_length */
3002 &inbuf, /* in_input_buffer */
3003 0, /* in_additional_info */
3005 ph->fid_persistent, ph->fid_volatile, frame,
3008 if (!NT_STATUS_IS_OK(status)) {
3012 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3014 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3015 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3019 cli->raw_status = status;
3025 /***************************************************************
3026 Wrapper that allows SMB2 to list user quota.
3028 ***************************************************************/
3030 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3031 TALLOC_CTX *mem_ctx,
3033 SMB_NTQUOTA_LIST **pqt_list,
3037 DATA_BLOB inbuf = data_blob_null;
3038 DATA_BLOB outbuf = data_blob_null;
3039 struct smb2_hnd *ph = NULL;
3040 TALLOC_CTX *frame = talloc_stackframe();
3041 struct smb2_query_quota_info info = {0};
3042 enum ndr_err_code err;
3044 if (smbXcli_conn_has_async_calls(cli->conn)) {
3046 * Can't use sync call while an async call is in flight
3048 status = NT_STATUS_INVALID_PARAMETER;
3052 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3053 status = NT_STATUS_INVALID_PARAMETER;
3057 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3058 if (!NT_STATUS_IS_OK(status)) {
3063 info.restart_scan = first ? 1 : 0;
3065 err = ndr_push_struct_blob(
3069 (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3071 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3072 status = NT_STATUS_INTERNAL_ERROR;
3076 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
3077 cli->smb2.tcon, 4, /* in_info_type */
3078 0, /* in_file_info_class */
3079 0xFFFF, /* in_max_output_length */
3080 &inbuf, /* in_input_buffer */
3081 0, /* in_additional_info */
3083 ph->fid_persistent, ph->fid_volatile, frame,
3087 * safeguard against panic from calling parse_user_quota_list with
3090 if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3091 status = NT_STATUS_NO_MORE_ENTRIES;
3094 if (!NT_STATUS_IS_OK(status)) {
3098 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3102 cli->raw_status = status;
3108 /***************************************************************
3109 Wrapper that allows SMB2 to get file system quota.
3111 ***************************************************************/
3113 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3115 SMB_NTQUOTA_STRUCT *pqt)
3118 DATA_BLOB outbuf = data_blob_null;
3119 struct smb2_hnd *ph = NULL;
3120 TALLOC_CTX *frame = talloc_stackframe();
3122 if (smbXcli_conn_has_async_calls(cli->conn)) {
3124 * Can't use sync call while an async call is in flight
3126 status = NT_STATUS_INVALID_PARAMETER;
3130 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3131 status = NT_STATUS_INVALID_PARAMETER;
3135 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3136 if (!NT_STATUS_IS_OK(status)) {
3140 status = smb2cli_query_info(
3141 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3142 2, /* in_info_type */
3143 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3144 0xFFFF, /* in_max_output_length */
3145 NULL, /* in_input_buffer */
3146 0, /* in_additional_info */
3148 ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
3150 if (!NT_STATUS_IS_OK(status)) {
3154 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3157 cli->raw_status = status;
3163 /***************************************************************
3164 Wrapper that allows SMB2 to set user quota.
3166 ***************************************************************/
3168 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3170 SMB_NTQUOTA_LIST *qtl)
3173 DATA_BLOB inbuf = data_blob_null;
3174 struct smb2_hnd *ph = NULL;
3175 TALLOC_CTX *frame = talloc_stackframe();
3177 if (smbXcli_conn_has_async_calls(cli->conn)) {
3179 * Can't use sync call while an async call is in flight
3181 status = NT_STATUS_INVALID_PARAMETER;
3185 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3186 status = NT_STATUS_INVALID_PARAMETER;
3190 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3191 if (!NT_STATUS_IS_OK(status)) {
3195 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3196 if (!NT_STATUS_IS_OK(status)) {
3200 status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
3201 cli->smb2.tcon, 4, /* in_info_type */
3202 0, /* in_file_info_class */
3203 &inbuf, /* in_input_buffer */
3204 0, /* in_additional_info */
3205 ph->fid_persistent, ph->fid_volatile);
3208 cli->raw_status = status;
3215 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3217 SMB_NTQUOTA_STRUCT *pqt)
3220 DATA_BLOB inbuf = data_blob_null;
3221 struct smb2_hnd *ph = NULL;
3222 TALLOC_CTX *frame = talloc_stackframe();
3224 if (smbXcli_conn_has_async_calls(cli->conn)) {
3226 * Can't use sync call while an async call is in flight
3228 status = NT_STATUS_INVALID_PARAMETER;
3232 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3233 status = NT_STATUS_INVALID_PARAMETER;
3237 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3238 if (!NT_STATUS_IS_OK(status)) {
3242 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3243 if (!NT_STATUS_IS_OK(status)) {
3247 status = smb2cli_set_info(
3248 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3249 2, /* in_info_type */
3250 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3251 &inbuf, /* in_input_buffer */
3252 0, /* in_additional_info */
3253 ph->fid_persistent, ph->fid_volatile);
3255 cli->raw_status = status;
3261 struct cli_smb2_read_state {
3262 struct tevent_context *ev;
3263 struct cli_state *cli;
3264 struct smb2_hnd *ph;
3265 uint64_t start_offset;
3271 static void cli_smb2_read_done(struct tevent_req *subreq);
3273 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3274 struct tevent_context *ev,
3275 struct cli_state *cli,
3281 struct tevent_req *req, *subreq;
3282 struct cli_smb2_read_state *state;
3284 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3290 state->start_offset = (uint64_t)offset;
3291 state->size = (uint32_t)size;
3292 state->received = 0;
3295 status = map_fnum_to_smb2_handle(cli,
3298 if (tevent_req_nterror(req, status)) {
3299 return tevent_req_post(req, ev);
3302 subreq = smb2cli_read_send(state,
3305 state->cli->timeout,
3306 state->cli->smb2.session,
3307 state->cli->smb2.tcon,
3309 state->start_offset,
3310 state->ph->fid_persistent,
3311 state->ph->fid_volatile,
3312 0, /* minimum_count */
3313 0); /* remaining_bytes */
3315 if (tevent_req_nomem(subreq, req)) {
3316 return tevent_req_post(req, ev);
3318 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3322 static void cli_smb2_read_done(struct tevent_req *subreq)
3324 struct tevent_req *req = tevent_req_callback_data(
3325 subreq, struct tevent_req);
3326 struct cli_smb2_read_state *state = tevent_req_data(
3327 req, struct cli_smb2_read_state);
3330 status = smb2cli_read_recv(subreq, state,
3331 &state->buf, &state->received);
3332 if (tevent_req_nterror(req, status)) {
3336 if (state->received > state->size) {
3337 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3341 tevent_req_done(req);
3344 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
3349 struct cli_smb2_read_state *state = tevent_req_data(
3350 req, struct cli_smb2_read_state);
3352 if (tevent_req_is_nterror(req, &status)) {
3353 state->cli->raw_status = status;
3357 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3358 * better make sure that you copy it away before you talloc_free(req).
3359 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3361 *received = (ssize_t)state->received;
3362 *rcvbuf = state->buf;
3363 state->cli->raw_status = NT_STATUS_OK;
3364 return NT_STATUS_OK;
3367 struct cli_smb2_write_state {
3368 struct tevent_context *ev;
3369 struct cli_state *cli;
3370 struct smb2_hnd *ph;
3378 static void cli_smb2_write_written(struct tevent_req *req);
3380 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
3381 struct tevent_context *ev,
3382 struct cli_state *cli,
3390 struct tevent_req *req, *subreq = NULL;
3391 struct cli_smb2_write_state *state = NULL;
3393 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
3399 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3400 state->flags = (uint32_t)mode;
3402 state->offset = (uint64_t)offset;
3403 state->size = (uint32_t)size;
3406 status = map_fnum_to_smb2_handle(cli,
3409 if (tevent_req_nterror(req, status)) {
3410 return tevent_req_post(req, ev);
3413 subreq = smb2cli_write_send(state,
3416 state->cli->timeout,
3417 state->cli->smb2.session,
3418 state->cli->smb2.tcon,
3421 state->ph->fid_persistent,
3422 state->ph->fid_volatile,
3423 0, /* remaining_bytes */
3424 state->flags, /* flags */
3427 if (tevent_req_nomem(subreq, req)) {
3428 return tevent_req_post(req, ev);
3430 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
3434 static void cli_smb2_write_written(struct tevent_req *subreq)
3436 struct tevent_req *req = tevent_req_callback_data(
3437 subreq, struct tevent_req);
3438 struct cli_smb2_write_state *state = tevent_req_data(
3439 req, struct cli_smb2_write_state);
3443 status = smb2cli_write_recv(subreq, &written);
3444 TALLOC_FREE(subreq);
3445 if (tevent_req_nterror(req, status)) {
3449 state->written = written;
3451 tevent_req_done(req);
3454 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
3457 struct cli_smb2_write_state *state = tevent_req_data(
3458 req, struct cli_smb2_write_state);
3461 if (tevent_req_is_nterror(req, &status)) {
3462 state->cli->raw_status = status;
3463 tevent_req_received(req);
3467 if (pwritten != NULL) {
3468 *pwritten = (size_t)state->written;
3470 state->cli->raw_status = NT_STATUS_OK;
3471 tevent_req_received(req);
3472 return NT_STATUS_OK;
3475 /***************************************************************
3476 Wrapper that allows SMB2 async write using an fnum.
3477 This is mostly cut-and-paste from Volker's code inside
3478 source3/libsmb/clireadwrite.c, adapted for SMB2.
3480 Done this way so I can reuse all the logic inside cli_push()
3482 ***************************************************************/
3484 struct cli_smb2_writeall_state {
3485 struct tevent_context *ev;
3486 struct cli_state *cli;
3487 struct smb2_hnd *ph;
3495 static void cli_smb2_writeall_written(struct tevent_req *req);
3497 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
3498 struct tevent_context *ev,
3499 struct cli_state *cli,
3507 struct tevent_req *req, *subreq = NULL;
3508 struct cli_smb2_writeall_state *state = NULL;
3513 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
3519 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3520 state->flags = (uint32_t)mode;
3522 state->offset = (uint64_t)offset;
3523 state->size = (uint32_t)size;
3526 status = map_fnum_to_smb2_handle(cli,
3529 if (tevent_req_nterror(req, status)) {
3530 return tevent_req_post(req, ev);
3533 to_write = state->size;
3534 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3535 to_write = MIN(max_size, to_write);
3536 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3538 to_write = MIN(max_size, to_write);
3541 subreq = smb2cli_write_send(state,
3544 state->cli->timeout,
3545 state->cli->smb2.session,
3546 state->cli->smb2.tcon,
3549 state->ph->fid_persistent,
3550 state->ph->fid_volatile,
3551 0, /* remaining_bytes */
3552 state->flags, /* flags */
3553 state->buf + state->written);
3555 if (tevent_req_nomem(subreq, req)) {
3556 return tevent_req_post(req, ev);
3558 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3562 static void cli_smb2_writeall_written(struct tevent_req *subreq)
3564 struct tevent_req *req = tevent_req_callback_data(
3565 subreq, struct tevent_req);
3566 struct cli_smb2_writeall_state *state = tevent_req_data(
3567 req, struct cli_smb2_writeall_state);
3569 uint32_t written, to_write;
3573 status = smb2cli_write_recv(subreq, &written);
3574 TALLOC_FREE(subreq);
3575 if (tevent_req_nterror(req, status)) {
3579 state->written += written;
3581 if (state->written > state->size) {
3582 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3586 to_write = state->size - state->written;
3588 if (to_write == 0) {
3589 tevent_req_done(req);
3593 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3594 to_write = MIN(max_size, to_write);
3595 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3597 to_write = MIN(max_size, to_write);
3600 subreq = smb2cli_write_send(state,
3603 state->cli->timeout,
3604 state->cli->smb2.session,
3605 state->cli->smb2.tcon,
3607 state->offset + state->written,
3608 state->ph->fid_persistent,
3609 state->ph->fid_volatile,
3610 0, /* remaining_bytes */
3611 state->flags, /* flags */
3612 state->buf + state->written);
3614 if (tevent_req_nomem(subreq, req)) {
3617 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3620 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
3623 struct cli_smb2_writeall_state *state = tevent_req_data(
3624 req, struct cli_smb2_writeall_state);
3627 if (tevent_req_is_nterror(req, &status)) {
3628 state->cli->raw_status = status;
3631 if (pwritten != NULL) {
3632 *pwritten = (size_t)state->written;
3634 state->cli->raw_status = NT_STATUS_OK;
3635 return NT_STATUS_OK;
3638 struct cli_smb2_splice_state {
3639 struct tevent_context *ev;
3640 struct cli_state *cli;
3641 struct smb2_hnd *src_ph;
3642 struct smb2_hnd *dst_ph;
3643 int (*splice_cb)(off_t n, void *priv);
3650 struct req_resume_key_rsp resume_rsp;
3651 struct srv_copychunk_copy cc_copy;
3654 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3655 struct tevent_req *req);
3657 static void cli_splice_copychunk_done(struct tevent_req *subreq)
3659 struct tevent_req *req = tevent_req_callback_data(
3660 subreq, struct tevent_req);
3661 struct cli_smb2_splice_state *state =
3662 tevent_req_data(req,
3663 struct cli_smb2_splice_state);
3664 struct smbXcli_conn *conn = state->cli->conn;
3665 DATA_BLOB out_input_buffer = data_blob_null;
3666 DATA_BLOB out_output_buffer = data_blob_null;
3667 struct srv_copychunk_rsp cc_copy_rsp;
3668 enum ndr_err_code ndr_ret;
3671 status = smb2cli_ioctl_recv(subreq, state,
3673 &out_output_buffer);
3674 TALLOC_FREE(subreq);
3675 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
3676 state->resized) && tevent_req_nterror(req, status)) {
3680 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
3681 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
3682 if (ndr_ret != NDR_ERR_SUCCESS) {
3683 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3684 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3688 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
3689 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
3690 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
3691 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
3692 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
3693 tevent_req_nterror(req, status)) {
3697 state->resized = true;
3698 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
3699 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
3701 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3702 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3703 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
3704 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3707 state->src_offset += cc_copy_rsp.total_bytes_written;
3708 state->dst_offset += cc_copy_rsp.total_bytes_written;
3709 state->written += cc_copy_rsp.total_bytes_written;
3710 if (!state->splice_cb(state->written, state->priv)) {
3711 tevent_req_nterror(req, NT_STATUS_CANCELLED);
3716 cli_splice_copychunk_send(state, req);
3719 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3720 struct tevent_req *req)
3722 struct tevent_req *subreq;
3723 enum ndr_err_code ndr_ret;
3724 struct smbXcli_conn *conn = state->cli->conn;
3725 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
3726 off_t src_offset = state->src_offset;
3727 off_t dst_offset = state->dst_offset;
3728 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
3729 state->size - state->written);
3730 DATA_BLOB in_input_buffer = data_blob_null;
3731 DATA_BLOB in_output_buffer = data_blob_null;
3733 if (state->size - state->written == 0) {
3734 tevent_req_done(req);
3738 cc_copy->chunk_count = 0;
3740 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
3741 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
3742 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
3743 smb2cli_conn_cc_chunk_len(conn));
3744 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
3745 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3748 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
3749 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
3750 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
3751 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3754 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3755 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3756 cc_copy->chunk_count++;
3759 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
3760 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
3761 if (ndr_ret != NDR_ERR_SUCCESS) {
3762 DEBUG(0, ("failed to marshall copy chunk req\n"));
3763 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3767 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
3768 state->cli->timeout,
3769 state->cli->smb2.session,
3770 state->cli->smb2.tcon,
3771 state->dst_ph->fid_persistent, /* in_fid_persistent */
3772 state->dst_ph->fid_volatile, /* in_fid_volatile */
3773 FSCTL_SRV_COPYCHUNK_WRITE,
3774 0, /* in_max_input_length */
3776 12, /* in_max_output_length */
3778 SMB2_IOCTL_FLAG_IS_FSCTL);
3779 if (tevent_req_nomem(subreq, req)) {
3782 tevent_req_set_callback(subreq,
3783 cli_splice_copychunk_done,
3787 static void cli_splice_key_done(struct tevent_req *subreq)
3789 struct tevent_req *req = tevent_req_callback_data(
3790 subreq, struct tevent_req);
3791 struct cli_smb2_splice_state *state =
3792 tevent_req_data(req,
3793 struct cli_smb2_splice_state);
3794 enum ndr_err_code ndr_ret;
3797 DATA_BLOB out_input_buffer = data_blob_null;
3798 DATA_BLOB out_output_buffer = data_blob_null;
3800 status = smb2cli_ioctl_recv(subreq, state,
3802 &out_output_buffer);
3803 TALLOC_FREE(subreq);
3804 if (tevent_req_nterror(req, status)) {
3808 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
3809 state, &state->resume_rsp,
3810 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
3811 if (ndr_ret != NDR_ERR_SUCCESS) {
3812 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3813 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3817 memcpy(&state->cc_copy.source_key,
3818 &state->resume_rsp.resume_key,
3819 sizeof state->resume_rsp.resume_key);
3821 cli_splice_copychunk_send(state, req);
3824 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
3825 struct tevent_context *ev,
3826 struct cli_state *cli,
3827 uint16_t src_fnum, uint16_t dst_fnum,
3828 off_t size, off_t src_offset, off_t dst_offset,
3829 int (*splice_cb)(off_t n, void *priv),
3832 struct tevent_req *req;
3833 struct tevent_req *subreq;
3834 struct cli_smb2_splice_state *state;
3836 DATA_BLOB in_input_buffer = data_blob_null;
3837 DATA_BLOB in_output_buffer = data_blob_null;
3839 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
3845 state->splice_cb = splice_cb;
3849 state->src_offset = src_offset;
3850 state->dst_offset = dst_offset;
3851 state->cc_copy.chunks = talloc_array(state,
3852 struct srv_copychunk,
3853 smb2cli_conn_cc_max_chunks(cli->conn));
3854 if (state->cc_copy.chunks == NULL) {
3858 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
3859 if (tevent_req_nterror(req, status))
3860 return tevent_req_post(req, ev);
3862 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
3863 if (tevent_req_nterror(req, status))
3864 return tevent_req_post(req, ev);
3866 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
3870 state->src_ph->fid_persistent, /* in_fid_persistent */
3871 state->src_ph->fid_volatile, /* in_fid_volatile */
3872 FSCTL_SRV_REQUEST_RESUME_KEY,
3873 0, /* in_max_input_length */
3875 32, /* in_max_output_length */
3877 SMB2_IOCTL_FLAG_IS_FSCTL);
3878 if (tevent_req_nomem(subreq, req)) {
3881 tevent_req_set_callback(subreq,
3882 cli_splice_key_done,
3888 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
3890 struct cli_smb2_splice_state *state = tevent_req_data(
3891 req, struct cli_smb2_splice_state);
3894 if (tevent_req_is_nterror(req, &status)) {
3895 state->cli->raw_status = status;
3896 tevent_req_received(req);
3899 if (written != NULL) {
3900 *written = state->written;
3902 state->cli->raw_status = NT_STATUS_OK;
3903 tevent_req_received(req);
3904 return NT_STATUS_OK;
3907 /***************************************************************
3908 SMB2 enum shadow copy data.
3909 ***************************************************************/
3911 struct cli_smb2_shadow_copy_data_fnum_state {
3912 struct cli_state *cli;
3914 struct smb2_hnd *ph;
3915 DATA_BLOB out_input_buffer;
3916 DATA_BLOB out_output_buffer;
3919 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
3921 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
3922 TALLOC_CTX *mem_ctx,
3923 struct tevent_context *ev,
3924 struct cli_state *cli,
3928 struct tevent_req *req, *subreq;
3929 struct cli_smb2_shadow_copy_data_fnum_state *state;
3932 req = tevent_req_create(mem_ctx, &state,
3933 struct cli_smb2_shadow_copy_data_fnum_state);
3938 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3939 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3940 return tevent_req_post(req, ev);
3946 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
3947 if (tevent_req_nterror(req, status)) {
3948 return tevent_req_post(req, ev);
3952 * TODO. Under SMB2 we should send a zero max_output_length
3953 * ioctl to get the required size, then send another ioctl
3954 * to get the data, but the current SMB1 implementation just
3955 * does one roundtrip with a 64K buffer size. Do the same
3959 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
3960 state->cli->timeout,
3961 state->cli->smb2.session,
3962 state->cli->smb2.tcon,
3963 state->ph->fid_persistent, /* in_fid_persistent */
3964 state->ph->fid_volatile, /* in_fid_volatile */
3965 FSCTL_GET_SHADOW_COPY_DATA,
3966 0, /* in_max_input_length */
3967 NULL, /* in_input_buffer */
3969 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
3970 NULL, /* in_output_buffer */
3971 SMB2_IOCTL_FLAG_IS_FSCTL);
3973 if (tevent_req_nomem(subreq, req)) {
3974 return tevent_req_post(req, ev);
3976 tevent_req_set_callback(subreq,
3977 cli_smb2_shadow_copy_data_fnum_done,
3983 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
3985 struct tevent_req *req = tevent_req_callback_data(
3986 subreq, struct tevent_req);
3987 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3988 req, struct cli_smb2_shadow_copy_data_fnum_state);
3991 status = smb2cli_ioctl_recv(subreq, state,
3992 &state->out_input_buffer,
3993 &state->out_output_buffer);
3994 TALLOC_FREE(subreq);
3995 if (tevent_req_nterror(req, status)) {
3998 tevent_req_done(req);
4001 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4002 TALLOC_CTX *mem_ctx,
4007 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4008 req, struct cli_smb2_shadow_copy_data_fnum_state);
4009 char **names = NULL;
4010 uint32_t num_names = 0;
4011 uint32_t num_names_returned = 0;
4012 uint32_t dlength = 0;
4014 uint8_t *endp = NULL;
4017 if (tevent_req_is_nterror(req, &status)) {
4021 if (state->out_output_buffer.length < 16) {
4022 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4025 num_names = IVAL(state->out_output_buffer.data, 0);
4026 num_names_returned = IVAL(state->out_output_buffer.data, 4);
4027 dlength = IVAL(state->out_output_buffer.data, 8);
4029 if (num_names > 0x7FFFFFFF) {
4030 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4033 if (get_names == false) {
4034 *pnum_names = (int)num_names;
4035 return NT_STATUS_OK;
4037 if (num_names != num_names_returned) {
4038 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4040 if (dlength + 12 < 12) {
4041 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4044 * NB. The below is an allowable return if there are
4045 * more snapshots than the buffer size we told the
4046 * server we can receive. We currently don't support
4049 if (dlength + 12 > state->out_output_buffer.length) {
4050 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4052 if (state->out_output_buffer.length +
4053 (2 * sizeof(SHADOW_COPY_LABEL)) <
4054 state->out_output_buffer.length) {
4055 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4058 names = talloc_array(mem_ctx, char *, num_names_returned);
4059 if (names == NULL) {
4060 return NT_STATUS_NO_MEMORY;
4063 endp = state->out_output_buffer.data +
4064 state->out_output_buffer.length;
4066 for (i=0; i<num_names_returned; i++) {
4069 size_t converted_size;
4071 src = state->out_output_buffer.data + 12 +
4072 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4074 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4075 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4077 ret = convert_string_talloc(
4078 names, CH_UTF16LE, CH_UNIX,
4079 src, 2 * sizeof(SHADOW_COPY_LABEL),
4080 &names[i], &converted_size);
4083 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4086 *pnum_names = num_names;
4088 return NT_STATUS_OK;
4091 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4092 struct cli_state *cli,
4098 TALLOC_CTX *frame = talloc_stackframe();
4099 struct tevent_context *ev;
4100 struct tevent_req *req;
4101 NTSTATUS status = NT_STATUS_NO_MEMORY;
4103 if (smbXcli_conn_has_async_calls(cli->conn)) {
4105 * Can't use sync call while an async call is in flight
4107 status = NT_STATUS_INVALID_PARAMETER;
4110 ev = samba_tevent_context_init(frame);
4114 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4122 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4125 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4131 cli->raw_status = status;
4137 /***************************************************************
4138 Wrapper that allows SMB2 to truncate a file.
4140 ***************************************************************/
4142 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4147 DATA_BLOB inbuf = data_blob_null;
4148 struct smb2_hnd *ph = NULL;
4149 TALLOC_CTX *frame = talloc_stackframe();
4151 if (smbXcli_conn_has_async_calls(cli->conn)) {
4153 * Can't use sync call while an async call is in flight
4155 status = NT_STATUS_INVALID_PARAMETER;
4159 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4160 status = NT_STATUS_INVALID_PARAMETER;
4164 status = map_fnum_to_smb2_handle(cli,
4167 if (!NT_STATUS_IS_OK(status)) {
4171 inbuf = data_blob_talloc_zero(frame, 8);
4172 if (inbuf.data == NULL) {
4173 status = NT_STATUS_NO_MEMORY;
4177 SBVAL(inbuf.data, 0, newsize);
4179 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4180 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4182 status = smb2cli_set_info(cli->conn,
4186 1, /* in_info_type */
4187 /* in_file_info_class */
4188 SMB_FILE_END_OF_FILE_INFORMATION - 1000,
4189 &inbuf, /* in_input_buffer */
4190 0, /* in_additional_info */
4196 cli->raw_status = status;
4202 struct cli_smb2_notify_state {
4203 struct tevent_req *subreq;
4204 struct notify_change *changes;
4208 static void cli_smb2_notify_done(struct tevent_req *subreq);
4209 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4211 struct tevent_req *cli_smb2_notify_send(
4212 TALLOC_CTX *mem_ctx,
4213 struct tevent_context *ev,
4214 struct cli_state *cli,
4216 uint32_t buffer_size,
4217 uint32_t completion_filter,
4220 struct tevent_req *req = NULL;
4221 struct cli_smb2_notify_state *state = NULL;
4222 struct smb2_hnd *ph = NULL;
4225 req = tevent_req_create(mem_ctx, &state,
4226 struct cli_smb2_notify_state);
4231 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4232 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4233 return tevent_req_post(req, ev);
4236 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4237 if (tevent_req_nterror(req, status)) {
4238 return tevent_req_post(req, ev);
4241 state->subreq = smb2cli_notify_send(
4253 if (tevent_req_nomem(state->subreq, req)) {
4254 return tevent_req_post(req, ev);
4256 tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4257 tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4261 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4263 struct cli_smb2_notify_state *state = tevent_req_data(
4264 req, struct cli_smb2_notify_state);
4267 ok = tevent_req_cancel(state->subreq);
4271 static void cli_smb2_notify_done(struct tevent_req *subreq)
4273 struct tevent_req *req = tevent_req_callback_data(
4274 subreq, struct tevent_req);
4275 struct cli_smb2_notify_state *state = tevent_req_data(
4276 req, struct cli_smb2_notify_state);
4282 status = smb2cli_notify_recv(subreq, state, &base, &len);
4283 TALLOC_FREE(subreq);
4285 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4286 tevent_req_done(req);
4289 if (tevent_req_nterror(req, status)) {
4295 while (len - ofs >= 12) {
4296 struct notify_change *tmp;
4297 struct notify_change *c;
4298 uint32_t next_ofs = IVAL(base, ofs);
4299 uint32_t file_name_length = IVAL(base, ofs+8);
4303 tmp = talloc_realloc(
4306 struct notify_change,
4307 state->num_changes + 1);
4308 if (tevent_req_nomem(tmp, req)) {
4311 state->changes = tmp;
4312 c = &state->changes[state->num_changes];
4313 state->num_changes += 1;
4315 if (smb_buffer_oob(len, ofs, next_ofs) ||
4316 smb_buffer_oob(len, ofs+12, file_name_length)) {
4318 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4322 c->action = IVAL(base, ofs+4);
4324 ok = convert_string_talloc(
4334 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4338 if (next_ofs == 0) {
4344 tevent_req_done(req);
4347 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
4348 TALLOC_CTX *mem_ctx,
4349 struct notify_change **pchanges,
4350 uint32_t *pnum_changes)
4352 struct cli_smb2_notify_state *state = tevent_req_data(
4353 req, struct cli_smb2_notify_state);
4356 if (tevent_req_is_nterror(req, &status)) {
4359 *pchanges = talloc_move(mem_ctx, &state->changes);
4360 *pnum_changes = state->num_changes;
4361 return NT_STATUS_OK;
4364 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
4365 uint32_t buffer_size, uint32_t completion_filter,
4366 bool recursive, TALLOC_CTX *mem_ctx,
4367 struct notify_change **pchanges,
4368 uint32_t *pnum_changes)
4370 TALLOC_CTX *frame = talloc_stackframe();
4371 struct tevent_context *ev;
4372 struct tevent_req *req;
4373 NTSTATUS status = NT_STATUS_NO_MEMORY;
4375 if (smbXcli_conn_has_async_calls(cli->conn)) {
4377 * Can't use sync call while an async call is in flight
4379 status = NT_STATUS_INVALID_PARAMETER;
4382 ev = samba_tevent_context_init(frame);
4386 req = cli_smb2_notify_send(
4397 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4400 status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
4406 struct cli_smb2_set_reparse_point_fnum_state {
4407 struct cli_state *cli;
4409 struct smb2_hnd *ph;
4410 DATA_BLOB input_buffer;
4413 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
4415 struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
4416 TALLOC_CTX *mem_ctx,
4417 struct tevent_context *ev,
4418 struct cli_state *cli,
4422 struct tevent_req *req, *subreq;
4423 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
4426 req = tevent_req_create(mem_ctx, &state,
4427 struct cli_smb2_set_reparse_point_fnum_state);
4432 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4433 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4434 return tevent_req_post(req, ev);
4440 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4441 if (tevent_req_nterror(req, status)) {
4442 return tevent_req_post(req, ev);
4445 state->input_buffer = data_blob_talloc(state,
4448 if (state->input_buffer.data == NULL) {
4449 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4450 return tevent_req_post(req, ev);
4453 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4454 state->cli->timeout,
4455 state->cli->smb2.session,
4456 state->cli->smb2.tcon,
4457 state->ph->fid_persistent, /* in_fid_persistent */
4458 state->ph->fid_volatile, /* in_fid_volatile */
4459 FSCTL_SET_REPARSE_POINT,
4460 0, /* in_max_input_length */
4461 &state->input_buffer ,
4464 SMB2_IOCTL_FLAG_IS_FSCTL);
4466 if (tevent_req_nomem(subreq, req)) {
4467 return tevent_req_post(req, ev);
4469 tevent_req_set_callback(subreq,
4470 cli_smb2_set_reparse_point_fnum_done,
4476 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
4478 struct tevent_req *req = tevent_req_callback_data(
4479 subreq, struct tevent_req);
4480 struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
4481 req, struct cli_smb2_set_reparse_point_fnum_state);
4484 status = smb2cli_ioctl_recv(subreq, state,
4487 TALLOC_FREE(subreq);
4488 if (tevent_req_nterror(req, status)) {
4491 tevent_req_done(req);
4494 NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
4496 return tevent_req_simple_recv_ntstatus(req);
4499 struct cli_smb2_get_reparse_point_fnum_state {
4500 struct cli_state *cli;
4502 struct smb2_hnd *ph;
4503 DATA_BLOB output_buffer;
4506 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
4508 struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
4509 TALLOC_CTX *mem_ctx,
4510 struct tevent_context *ev,
4511 struct cli_state *cli,
4514 struct tevent_req *req, *subreq;
4515 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
4518 req = tevent_req_create(mem_ctx, &state,
4519 struct cli_smb2_get_reparse_point_fnum_state);
4524 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4525 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4526 return tevent_req_post(req, ev);
4532 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4533 if (tevent_req_nterror(req, status)) {
4534 return tevent_req_post(req, ev);
4537 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4538 state->cli->timeout,
4539 state->cli->smb2.session,
4540 state->cli->smb2.tcon,
4541 state->ph->fid_persistent, /* in_fid_persistent */
4542 state->ph->fid_volatile, /* in_fid_volatile */
4543 FSCTL_GET_REPARSE_POINT,
4544 0, /* in_max_input_length */
4548 SMB2_IOCTL_FLAG_IS_FSCTL);
4550 if (tevent_req_nomem(subreq, req)) {
4551 return tevent_req_post(req, ev);
4553 tevent_req_set_callback(subreq,
4554 cli_smb2_get_reparse_point_fnum_done,
4560 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
4562 struct tevent_req *req = tevent_req_callback_data(
4563 subreq, struct tevent_req);
4564 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
4565 req, struct cli_smb2_get_reparse_point_fnum_state);
4568 status = smb2cli_ioctl_recv(subreq, state,
4570 &state->output_buffer);
4571 TALLOC_FREE(subreq);
4572 if (tevent_req_nterror(req, status)) {
4573 state->cli->raw_status = status;
4576 tevent_req_done(req);
4579 NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
4580 TALLOC_CTX *mem_ctx,
4583 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
4584 req, struct cli_smb2_get_reparse_point_fnum_state);
4586 if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
4587 tevent_req_received(req);
4588 return state->cli->raw_status;
4590 *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
4591 if (output->data == NULL) {
4592 tevent_req_received(req);
4593 return NT_STATUS_NO_MEMORY;
4595 tevent_req_received(req);
4596 return NT_STATUS_OK;