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 smb2_create_blobs cblobs;
162 struct smb_create_returns cr;
164 struct tevent_req *subreq;
167 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
168 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
170 struct tevent_req *cli_smb2_create_fnum_send(
172 struct tevent_context *ev,
173 struct cli_state *cli,
175 uint32_t create_flags,
176 uint32_t impersonation_level,
177 uint32_t desired_access,
178 uint32_t file_attributes,
179 uint32_t share_access,
180 uint32_t create_disposition,
181 uint32_t create_options)
183 struct tevent_req *req, *subreq;
184 struct cli_smb2_create_fnum_state *state;
185 size_t fname_len = 0;
186 const char *startp = NULL;
187 const char *endp = NULL;
188 time_t tstamp = (time_t)0;
190 req = tevent_req_create(mem_ctx, &state,
191 struct cli_smb2_create_fnum_state);
197 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
198 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
199 return tevent_req_post(req, ev);
202 if (cli->backup_intent) {
203 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
206 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
207 fname_len = strlen(fname);
208 if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
209 size_t len_before_gmt = startp - fname;
210 size_t len_after_gmt = fname + fname_len - endp;
215 char *new_fname = talloc_array(state, char,
216 len_before_gmt + len_after_gmt + 1);
218 if (tevent_req_nomem(new_fname, req)) {
219 return tevent_req_post(req, ev);
222 memcpy(new_fname, fname, len_before_gmt);
223 memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
225 fname_len = len_before_gmt + len_after_gmt;
227 unix_to_nt_time(&ntt, tstamp);
228 twrp_blob = data_blob_const((const void *)&ntt, 8);
230 status = smb2_create_blob_add(
233 SMB2_CREATE_TAG_TWRP,
235 if (!NT_STATUS_IS_OK(status)) {
236 tevent_req_nterror(req, status);
237 return tevent_req_post(req, ev);
241 /* SMB2 is pickier about pathnames. Ensure it doesn't
243 if (*fname == '\\') {
248 /* Or end in a '\' */
249 if (fname_len > 0 && fname[fname_len-1] == '\\') {
250 char *new_fname = talloc_strdup(state, fname);
251 if (tevent_req_nomem(new_fname, req)) {
252 return tevent_req_post(req, ev);
254 new_fname[fname_len-1] = '\0';
258 subreq = smb2cli_create_send(state, ev,
264 flags_to_smb2_oplock(create_flags),
272 if (tevent_req_nomem(subreq, req)) {
273 return tevent_req_post(req, ev);
275 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
277 state->subreq = subreq;
278 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
283 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
285 struct tevent_req *req = tevent_req_callback_data(
286 subreq, struct tevent_req);
287 struct cli_smb2_create_fnum_state *state = tevent_req_data(
288 req, struct cli_smb2_create_fnum_state);
292 status = smb2cli_create_recv(subreq, &h.fid_persistent,
293 &h.fid_volatile, &state->cr, NULL, NULL);
295 if (tevent_req_nterror(req, status)) {
299 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
300 if (tevent_req_nterror(req, status)) {
303 tevent_req_done(req);
306 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
308 struct cli_smb2_create_fnum_state *state = tevent_req_data(
309 req, struct cli_smb2_create_fnum_state);
310 return tevent_req_cancel(state->subreq);
313 NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum,
314 struct smb_create_returns *cr)
316 struct cli_smb2_create_fnum_state *state = tevent_req_data(
317 req, struct cli_smb2_create_fnum_state);
320 if (tevent_req_is_nterror(req, &status)) {
321 state->cli->raw_status = status;
325 *pfnum = state->fnum;
330 state->cli->raw_status = NT_STATUS_OK;
334 NTSTATUS cli_smb2_create_fnum(
335 struct cli_state *cli,
337 uint32_t create_flags,
338 uint32_t impersonation_level,
339 uint32_t desired_access,
340 uint32_t file_attributes,
341 uint32_t share_access,
342 uint32_t create_disposition,
343 uint32_t create_options,
345 struct smb_create_returns *cr)
347 TALLOC_CTX *frame = talloc_stackframe();
348 struct tevent_context *ev;
349 struct tevent_req *req;
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(
378 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
381 status = cli_smb2_create_fnum_recv(req, pfid, cr);
387 /***************************************************************
388 Small wrapper that allows SMB2 close to use a uint16_t fnum.
389 ***************************************************************/
391 struct cli_smb2_close_fnum_state {
392 struct cli_state *cli;
397 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
399 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
400 struct tevent_context *ev,
401 struct cli_state *cli,
404 struct tevent_req *req, *subreq;
405 struct cli_smb2_close_fnum_state *state;
408 req = tevent_req_create(mem_ctx, &state,
409 struct cli_smb2_close_fnum_state);
416 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
417 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
418 return tevent_req_post(req, ev);
421 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
422 if (tevent_req_nterror(req, status)) {
423 return tevent_req_post(req, ev);
426 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
427 cli->smb2.session, cli->smb2.tcon,
428 0, state->ph->fid_persistent,
429 state->ph->fid_volatile);
430 if (tevent_req_nomem(subreq, req)) {
431 return tevent_req_post(req, ev);
433 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
437 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
439 struct tevent_req *req = tevent_req_callback_data(
440 subreq, struct tevent_req);
441 struct cli_smb2_close_fnum_state *state = tevent_req_data(
442 req, struct cli_smb2_close_fnum_state);
445 status = smb2cli_close_recv(subreq);
446 if (tevent_req_nterror(req, status)) {
450 /* Delete the fnum -> handle mapping. */
451 status = delete_smb2_handle_mapping(state->cli, &state->ph,
453 if (tevent_req_nterror(req, status)) {
456 tevent_req_done(req);
459 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
461 struct cli_smb2_close_fnum_state *state = tevent_req_data(
462 req, struct cli_smb2_close_fnum_state);
463 NTSTATUS status = NT_STATUS_OK;
465 if (tevent_req_is_nterror(req, &status)) {
466 state->cli->raw_status = status;
468 tevent_req_received(req);
472 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
474 TALLOC_CTX *frame = talloc_stackframe();
475 struct tevent_context *ev;
476 struct tevent_req *req;
477 NTSTATUS status = NT_STATUS_NO_MEMORY;
479 if (smbXcli_conn_has_async_calls(cli->conn)) {
481 * Can't use sync call while an async call is in flight
483 status = NT_STATUS_INVALID_PARAMETER;
486 ev = samba_tevent_context_init(frame);
490 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
494 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
497 status = cli_smb2_close_fnum_recv(req);
503 struct cli_smb2_delete_on_close_state {
504 struct cli_state *cli;
511 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
513 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
514 struct tevent_context *ev,
515 struct cli_state *cli,
519 struct tevent_req *req = NULL;
520 struct cli_smb2_delete_on_close_state *state = NULL;
521 struct tevent_req *subreq = NULL;
522 uint8_t in_info_type;
523 uint8_t in_file_info_class;
526 req = tevent_req_create(mem_ctx, &state,
527 struct cli_smb2_delete_on_close_state);
534 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
535 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
536 return tevent_req_post(req, ev);
539 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
540 if (tevent_req_nterror(req, status)) {
541 return tevent_req_post(req, ev);
545 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
546 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
549 in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
550 /* Setup data array. */
551 SCVAL(&state->data[0], 0, flag ? 1 : 0);
552 state->inbuf.data = &state->data[0];
553 state->inbuf.length = 1;
555 subreq = smb2cli_set_info_send(state, ev,
562 &state->inbuf, /* in_input_buffer */
563 0, /* in_additional_info */
564 state->ph->fid_persistent,
565 state->ph->fid_volatile);
566 if (tevent_req_nomem(subreq, req)) {
567 return tevent_req_post(req, ev);
569 tevent_req_set_callback(subreq,
570 cli_smb2_delete_on_close_done,
575 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
577 NTSTATUS status = smb2cli_set_info_recv(subreq);
578 tevent_req_simple_finish_ntstatus(subreq, status);
581 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
583 struct cli_smb2_delete_on_close_state *state =
585 struct cli_smb2_delete_on_close_state);
588 if (tevent_req_is_nterror(req, &status)) {
589 state->cli->raw_status = status;
590 tevent_req_received(req);
594 state->cli->raw_status = NT_STATUS_OK;
595 tevent_req_received(req);
599 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
601 TALLOC_CTX *frame = talloc_stackframe();
602 struct tevent_context *ev;
603 struct tevent_req *req;
604 NTSTATUS status = NT_STATUS_NO_MEMORY;
606 if (smbXcli_conn_has_async_calls(cli->conn)) {
608 * Can't use sync call while an async call is in flight
610 status = NT_STATUS_INVALID_PARAMETER;
613 ev = samba_tevent_context_init(frame);
617 req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
621 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
624 status = cli_smb2_delete_on_close_recv(req);
630 /***************************************************************
631 Small wrapper that allows SMB2 to create a directory
633 ***************************************************************/
635 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
640 if (smbXcli_conn_has_async_calls(cli->conn)) {
642 * Can't use sync call while an async call is in flight
644 return NT_STATUS_INVALID_PARAMETER;
647 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
648 return NT_STATUS_INVALID_PARAMETER;
651 status = cli_smb2_create_fnum(cli,
653 0, /* create_flags */
654 SMB2_IMPERSONATION_IMPERSONATION,
655 FILE_READ_ATTRIBUTES, /* desired_access */
656 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
657 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
658 FILE_CREATE, /* create_disposition */
659 FILE_DIRECTORY_FILE, /* create_options */
663 if (!NT_STATUS_IS_OK(status)) {
666 return cli_smb2_close_fnum(cli, fnum);
669 /***************************************************************
670 Small wrapper that allows SMB2 to delete a directory
672 ***************************************************************/
674 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
679 if (smbXcli_conn_has_async_calls(cli->conn)) {
681 * Can't use sync call while an async call is in flight
683 return NT_STATUS_INVALID_PARAMETER;
686 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
687 return NT_STATUS_INVALID_PARAMETER;
690 status = cli_smb2_create_fnum(cli,
692 0, /* create_flags */
693 SMB2_IMPERSONATION_IMPERSONATION,
694 DELETE_ACCESS, /* desired_access */
695 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
696 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
697 FILE_OPEN, /* create_disposition */
698 FILE_DIRECTORY_FILE, /* create_options */
702 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
704 * Naive option to match our SMB1 code. Assume the
705 * symlink path that tripped us up was the last
706 * component and try again. Eventually we will have to
707 * deal with the returned path unprocessed component. JRA.
709 status = cli_smb2_create_fnum(cli,
711 0, /* create_flags */
712 SMB2_IMPERSONATION_IMPERSONATION,
713 DELETE_ACCESS, /* desired_access */
714 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
715 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
716 FILE_OPEN, /* create_disposition */
718 FILE_DELETE_ON_CLOSE|
719 FILE_OPEN_REPARSE_POINT, /* create_options */
724 if (!NT_STATUS_IS_OK(status)) {
728 status = cli_smb2_delete_on_close(cli, fnum, true);
729 if (!NT_STATUS_IS_OK(status)) {
730 cli_smb2_close_fnum(cli, fnum);
734 return cli_smb2_close_fnum(cli, fnum);
737 /***************************************************************
738 Small wrapper that allows SMB2 to unlink a pathname.
740 ***************************************************************/
742 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
747 if (smbXcli_conn_has_async_calls(cli->conn)) {
749 * Can't use sync call while an async call is in flight
751 return NT_STATUS_INVALID_PARAMETER;
754 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
755 return NT_STATUS_INVALID_PARAMETER;
758 status = cli_smb2_create_fnum(cli,
760 0, /* create_flags */
761 SMB2_IMPERSONATION_IMPERSONATION,
762 DELETE_ACCESS, /* desired_access */
763 FILE_ATTRIBUTE_NORMAL, /* file attributes */
764 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
765 FILE_OPEN, /* create_disposition */
766 FILE_DELETE_ON_CLOSE, /* create_options */
770 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
772 * Naive option to match our SMB1 code. Assume the
773 * symlink path that tripped us up was the last
774 * component and try again. Eventually we will have to
775 * deal with the returned path unprocessed component. JRA.
777 status = cli_smb2_create_fnum(cli,
779 0, /* create_flags */
780 SMB2_IMPERSONATION_IMPERSONATION,
781 DELETE_ACCESS, /* desired_access */
782 FILE_ATTRIBUTE_NORMAL, /* file attributes */
783 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
784 FILE_OPEN, /* create_disposition */
785 FILE_DELETE_ON_CLOSE|
786 FILE_OPEN_REPARSE_POINT, /* create_options */
791 if (!NT_STATUS_IS_OK(status)) {
794 return cli_smb2_close_fnum(cli, fnum);
797 /***************************************************************
798 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
799 ***************************************************************/
801 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
802 uint32_t dir_data_length,
803 struct file_info *finfo,
804 uint32_t *next_offset)
810 if (dir_data_length < 4) {
811 return NT_STATUS_INFO_LENGTH_MISMATCH;
814 *next_offset = IVAL(dir_data, 0);
816 if (*next_offset > dir_data_length) {
817 return NT_STATUS_INFO_LENGTH_MISMATCH;
820 if (*next_offset != 0) {
821 /* Ensure we only read what in this record. */
822 dir_data_length = *next_offset;
825 if (dir_data_length < 105) {
826 return NT_STATUS_INFO_LENGTH_MISMATCH;
829 finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
830 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
831 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
832 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
833 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
834 finfo->allocated_size = IVAL2_TO_SMB_BIG_UINT(dir_data + 48, 0);
835 finfo->mode = CVAL(dir_data + 56, 0);
836 finfo->ino = IVAL2_TO_SMB_BIG_UINT(dir_data + 96, 0);
837 namelen = IVAL(dir_data + 60,0);
838 if (namelen > (dir_data_length - 104)) {
839 return NT_STATUS_INFO_LENGTH_MISMATCH;
841 slen = CVAL(dir_data + 68, 0);
843 return NT_STATUS_INFO_LENGTH_MISMATCH;
845 ret = pull_string_talloc(finfo,
847 FLAGS2_UNICODE_STRINGS,
852 if (ret == (size_t)-1) {
853 /* Bad conversion. */
854 return NT_STATUS_INVALID_NETWORK_RESPONSE;
857 ret = pull_string_talloc(finfo,
859 FLAGS2_UNICODE_STRINGS,
864 if (ret == (size_t)-1) {
865 /* Bad conversion. */
866 return NT_STATUS_INVALID_NETWORK_RESPONSE;
871 /*******************************************************************
872 Given a filename - get its directory name
873 ********************************************************************/
875 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
883 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
886 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
897 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
900 (*parent)[len] = '\0';
908 /***************************************************************
909 Wrapper that allows SMB2 to list a directory.
911 ***************************************************************/
913 NTSTATUS cli_smb2_list(struct cli_state *cli,
914 const char *pathname,
916 NTSTATUS (*fn)(const char *,
923 uint16_t fnum = 0xffff;
924 char *parent_dir = NULL;
925 const char *mask = NULL;
926 struct smb2_hnd *ph = NULL;
927 bool processed_file = false;
928 TALLOC_CTX *frame = talloc_stackframe();
929 TALLOC_CTX *subframe = NULL;
932 uint32_t max_avail_len;
935 if (smbXcli_conn_has_async_calls(cli->conn)) {
937 * Can't use sync call while an async call is in flight
939 status = NT_STATUS_INVALID_PARAMETER;
943 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
944 status = NT_STATUS_INVALID_PARAMETER;
948 /* Get the directory name. */
949 if (!windows_parent_dirname(frame,
953 status = NT_STATUS_NO_MEMORY;
957 mask_has_wild = ms_has_wild(mask);
959 status = cli_smb2_create_fnum(cli,
961 0, /* create_flags */
962 SMB2_IMPERSONATION_IMPERSONATION,
963 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
964 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
965 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
966 FILE_OPEN, /* create_disposition */
967 FILE_DIRECTORY_FILE, /* create_options */
971 if (!NT_STATUS_IS_OK(status)) {
975 status = map_fnum_to_smb2_handle(cli,
978 if (!NT_STATUS_IS_OK(status)) {
983 * ideally, use the max transaction size, but don't send a request
984 * bigger than we have credits available for
986 max_trans = smb2cli_conn_max_trans_size(cli->conn);
987 ok = smb2cli_conn_req_possible(cli->conn, &max_avail_len);
989 max_trans = MIN(max_trans, max_avail_len);
993 uint8_t *dir_data = NULL;
994 uint32_t dir_data_length = 0;
995 uint32_t next_offset = 0;
996 subframe = talloc_stackframe();
998 status = smb2cli_query_directory(cli->conn,
1002 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
1013 if (!NT_STATUS_IS_OK(status)) {
1014 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1021 struct file_info *finfo = talloc_zero(subframe,
1024 if (finfo == NULL) {
1025 status = NT_STATUS_NO_MEMORY;
1029 status = parse_finfo_id_both_directory_info(dir_data,
1034 if (!NT_STATUS_IS_OK(status)) {
1038 if (dir_check_ftype((uint32_t)finfo->mode,
1039 (uint32_t)attribute)) {
1041 * Only process if attributes match.
1042 * On SMB1 server does this, so on
1043 * SMB2 we need to emulate in the
1046 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1048 processed_file = true;
1050 status = fn(cli->dfs_mountpoint,
1055 if (!NT_STATUS_IS_OK(status)) {
1062 /* Move to next entry. */
1064 dir_data += next_offset;
1065 dir_data_length -= next_offset;
1067 } while (next_offset != 0);
1069 TALLOC_FREE(subframe);
1071 if (!mask_has_wild) {
1073 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1074 * when handed a non-wildcard path. Do it
1075 * for the server (with a non-wildcard path
1076 * there should only ever be one file returned.
1078 status = STATUS_NO_MORE_FILES;
1082 } while (NT_STATUS_IS_OK(status));
1084 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1085 status = NT_STATUS_OK;
1088 if (NT_STATUS_IS_OK(status) && !processed_file) {
1090 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1091 * if no files match. Emulate this in the client.
1093 status = NT_STATUS_NO_SUCH_FILE;
1098 if (fnum != 0xffff) {
1099 cli_smb2_close_fnum(cli, fnum);
1102 cli->raw_status = status;
1104 TALLOC_FREE(subframe);
1109 /***************************************************************
1110 Wrapper that allows SMB2 to query a path info (basic level).
1112 ***************************************************************/
1114 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1116 SMB_STRUCT_STAT *sbuf,
1117 uint32_t *attributes)
1120 struct smb_create_returns cr;
1121 uint16_t fnum = 0xffff;
1122 size_t namelen = strlen(name);
1124 if (smbXcli_conn_has_async_calls(cli->conn)) {
1126 * Can't use sync call while an async call is in flight
1128 return NT_STATUS_INVALID_PARAMETER;
1131 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1132 return NT_STATUS_INVALID_PARAMETER;
1135 /* SMB2 is pickier about pathnames. Ensure it doesn't
1137 if (namelen > 0 && name[namelen-1] == '\\') {
1138 char *modname = talloc_strdup(talloc_tos(), name);
1139 modname[namelen-1] = '\0';
1143 /* This is commonly used as a 'cd'. Try qpathinfo on
1144 a directory handle first. */
1146 status = cli_smb2_create_fnum(cli,
1148 0, /* create_flags */
1149 SMB2_IMPERSONATION_IMPERSONATION,
1150 FILE_READ_ATTRIBUTES, /* desired_access */
1151 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1152 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1153 FILE_OPEN, /* create_disposition */
1154 FILE_DIRECTORY_FILE, /* create_options */
1158 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1159 /* Maybe a file ? */
1160 status = cli_smb2_create_fnum(cli,
1162 0, /* create_flags */
1163 SMB2_IMPERSONATION_IMPERSONATION,
1164 FILE_READ_ATTRIBUTES, /* desired_access */
1165 0, /* file attributes */
1166 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1167 FILE_OPEN, /* create_disposition */
1168 0, /* create_options */
1173 if (!NT_STATUS_IS_OK(status)) {
1177 status = cli_smb2_close_fnum(cli, fnum);
1181 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1182 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1183 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1184 sbuf->st_ex_size = cr.end_of_file;
1185 *attributes = cr.file_attributes;
1190 /***************************************************************
1191 Wrapper that allows SMB2 to check if a path is a directory.
1193 ***************************************************************/
1195 NTSTATUS cli_smb2_chkpath(struct cli_state *cli,
1199 uint16_t fnum = 0xffff;
1201 if (smbXcli_conn_has_async_calls(cli->conn)) {
1203 * Can't use sync call while an async call is in flight
1205 return NT_STATUS_INVALID_PARAMETER;
1208 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1209 return NT_STATUS_INVALID_PARAMETER;
1212 /* Ensure this is a directory. */
1213 status = cli_smb2_create_fnum(cli,
1215 0, /* create_flags */
1216 SMB2_IMPERSONATION_IMPERSONATION,
1217 FILE_READ_ATTRIBUTES, /* desired_access */
1218 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1219 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1220 FILE_OPEN, /* create_disposition */
1221 FILE_DIRECTORY_FILE, /* create_options */
1225 if (!NT_STATUS_IS_OK(status)) {
1229 return cli_smb2_close_fnum(cli, fnum);
1232 /***************************************************************
1233 Helper function for pathname operations.
1234 ***************************************************************/
1236 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1238 uint32_t desired_access,
1242 size_t namelen = strlen(name);
1243 TALLOC_CTX *frame = talloc_stackframe();
1244 uint32_t create_options = 0;
1246 /* SMB2 is pickier about pathnames. Ensure it doesn't
1248 if (namelen > 0 && name[namelen-1] == '\\') {
1249 char *modname = talloc_strdup(frame, name);
1250 if (modname == NULL) {
1251 status = NT_STATUS_NO_MEMORY;
1254 modname[namelen-1] = '\0';
1258 /* Try to open a file handle first. */
1259 status = cli_smb2_create_fnum(cli,
1261 0, /* create_flags */
1262 SMB2_IMPERSONATION_IMPERSONATION,
1264 0, /* file attributes */
1265 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1266 FILE_OPEN, /* create_disposition */
1271 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1273 * Naive option to match our SMB1 code. Assume the
1274 * symlink path that tripped us up was the last
1275 * component and try again. Eventually we will have to
1276 * deal with the returned path unprocessed component. JRA.
1278 create_options |= FILE_OPEN_REPARSE_POINT;
1279 status = cli_smb2_create_fnum(cli,
1281 0, /* create_flags */
1282 SMB2_IMPERSONATION_IMPERSONATION,
1284 0, /* file attributes */
1285 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1286 FILE_OPEN, /* create_disposition */
1292 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1293 create_options |= FILE_DIRECTORY_FILE;
1294 status = cli_smb2_create_fnum(cli,
1296 0, /* create_flags */
1297 SMB2_IMPERSONATION_IMPERSONATION,
1299 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1300 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1301 FILE_OPEN, /* create_disposition */
1302 FILE_DIRECTORY_FILE, /* create_options */
1313 /***************************************************************
1314 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1316 ***************************************************************/
1318 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1323 DATA_BLOB outbuf = data_blob_null;
1324 uint16_t fnum = 0xffff;
1325 struct smb2_hnd *ph = NULL;
1326 uint32_t altnamelen = 0;
1327 TALLOC_CTX *frame = talloc_stackframe();
1329 if (smbXcli_conn_has_async_calls(cli->conn)) {
1331 * Can't use sync call while an async call is in flight
1333 status = NT_STATUS_INVALID_PARAMETER;
1337 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1338 status = NT_STATUS_INVALID_PARAMETER;
1342 status = get_fnum_from_path(cli,
1344 FILE_READ_ATTRIBUTES,
1347 if (!NT_STATUS_IS_OK(status)) {
1351 status = map_fnum_to_smb2_handle(cli,
1354 if (!NT_STATUS_IS_OK(status)) {
1358 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1359 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1361 status = smb2cli_query_info(cli->conn,
1365 1, /* in_info_type */
1366 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1367 0xFFFF, /* in_max_output_length */
1368 NULL, /* in_input_buffer */
1369 0, /* in_additional_info */
1376 if (!NT_STATUS_IS_OK(status)) {
1380 /* Parse the reply. */
1381 if (outbuf.length < 4) {
1382 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1386 altnamelen = IVAL(outbuf.data, 0);
1387 if (altnamelen > outbuf.length - 4) {
1388 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1392 if (altnamelen > 0) {
1394 char *short_name = NULL;
1395 ret = pull_string_talloc(frame,
1397 FLAGS2_UNICODE_STRINGS,
1402 if (ret == (size_t)-1) {
1403 /* Bad conversion. */
1404 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1408 fstrcpy(alt_name, short_name);
1413 status = NT_STATUS_OK;
1417 if (fnum != 0xffff) {
1418 cli_smb2_close_fnum(cli, fnum);
1421 cli->raw_status = status;
1428 /***************************************************************
1429 Wrapper that allows SMB2 to query a fnum info (basic level).
1431 ***************************************************************/
1433 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1437 struct timespec *create_time,
1438 struct timespec *access_time,
1439 struct timespec *write_time,
1440 struct timespec *change_time,
1444 DATA_BLOB outbuf = data_blob_null;
1445 struct smb2_hnd *ph = NULL;
1446 TALLOC_CTX *frame = talloc_stackframe();
1448 if (smbXcli_conn_has_async_calls(cli->conn)) {
1450 * Can't use sync call while an async call is in flight
1452 status = NT_STATUS_INVALID_PARAMETER;
1456 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1457 status = NT_STATUS_INVALID_PARAMETER;
1461 status = map_fnum_to_smb2_handle(cli,
1464 if (!NT_STATUS_IS_OK(status)) {
1468 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1469 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1471 status = smb2cli_query_info(cli->conn,
1475 1, /* in_info_type */
1476 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1477 0xFFFF, /* in_max_output_length */
1478 NULL, /* in_input_buffer */
1479 0, /* in_additional_info */
1485 if (!NT_STATUS_IS_OK(status)) {
1489 /* Parse the reply. */
1490 if (outbuf.length < 0x60) {
1491 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1496 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1499 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1502 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1505 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1508 uint32_t attr = IVAL(outbuf.data, 0x20);
1509 *mode = (uint16_t)attr;
1512 uint64_t file_size = BVAL(outbuf.data, 0x30);
1513 *size = (off_t)file_size;
1516 uint64_t file_index = BVAL(outbuf.data, 0x40);
1517 *ino = (SMB_INO_T)file_index;
1522 cli->raw_status = status;
1528 /***************************************************************
1529 Wrapper that allows SMB2 to query an fnum.
1530 Implement on top of cli_smb2_qfileinfo_basic().
1532 ***************************************************************/
1534 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1538 time_t *change_time,
1539 time_t *access_time,
1542 struct timespec access_time_ts;
1543 struct timespec write_time_ts;
1544 struct timespec change_time_ts;
1545 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1555 cli->raw_status = status;
1557 if (!NT_STATUS_IS_OK(status)) {
1562 *change_time = change_time_ts.tv_sec;
1565 *access_time = access_time_ts.tv_sec;
1568 *write_time = write_time_ts.tv_sec;
1570 return NT_STATUS_OK;
1573 /***************************************************************
1574 Wrapper that allows SMB2 to get pathname attributes.
1576 ***************************************************************/
1578 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1585 uint16_t fnum = 0xffff;
1586 struct smb2_hnd *ph = NULL;
1587 TALLOC_CTX *frame = talloc_stackframe();
1589 if (smbXcli_conn_has_async_calls(cli->conn)) {
1591 * Can't use sync call while an async call is in flight
1593 status = NT_STATUS_INVALID_PARAMETER;
1597 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1598 status = NT_STATUS_INVALID_PARAMETER;
1602 status = get_fnum_from_path(cli,
1604 FILE_READ_ATTRIBUTES,
1607 if (!NT_STATUS_IS_OK(status)) {
1611 status = map_fnum_to_smb2_handle(cli,
1614 if (!NT_STATUS_IS_OK(status)) {
1617 status = cli_smb2_getattrE(cli,
1624 if (!NT_STATUS_IS_OK(status)) {
1630 if (fnum != 0xffff) {
1631 cli_smb2_close_fnum(cli, fnum);
1634 cli->raw_status = status;
1640 /***************************************************************
1641 Wrapper that allows SMB2 to query a pathname info (basic level).
1642 Implement on top of cli_smb2_qfileinfo_basic().
1644 ***************************************************************/
1646 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1648 struct timespec *create_time,
1649 struct timespec *access_time,
1650 struct timespec *write_time,
1651 struct timespec *change_time,
1657 struct smb2_hnd *ph = NULL;
1658 uint16_t fnum = 0xffff;
1659 TALLOC_CTX *frame = talloc_stackframe();
1661 if (smbXcli_conn_has_async_calls(cli->conn)) {
1663 * Can't use sync call while an async call is in flight
1665 status = NT_STATUS_INVALID_PARAMETER;
1669 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1670 status = NT_STATUS_INVALID_PARAMETER;
1674 status = get_fnum_from_path(cli,
1676 FILE_READ_ATTRIBUTES,
1679 if (!NT_STATUS_IS_OK(status)) {
1683 status = map_fnum_to_smb2_handle(cli,
1686 if (!NT_STATUS_IS_OK(status)) {
1690 status = cli_smb2_qfileinfo_basic(cli,
1702 if (fnum != 0xffff) {
1703 cli_smb2_close_fnum(cli, fnum);
1706 cli->raw_status = status;
1712 /***************************************************************
1713 Wrapper that allows SMB2 to query pathname streams.
1715 ***************************************************************/
1717 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1719 TALLOC_CTX *mem_ctx,
1720 unsigned int *pnum_streams,
1721 struct stream_struct **pstreams)
1724 struct smb2_hnd *ph = NULL;
1725 uint16_t fnum = 0xffff;
1726 DATA_BLOB outbuf = data_blob_null;
1727 TALLOC_CTX *frame = talloc_stackframe();
1729 if (smbXcli_conn_has_async_calls(cli->conn)) {
1731 * Can't use sync call while an async call is in flight
1733 status = NT_STATUS_INVALID_PARAMETER;
1737 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1738 status = NT_STATUS_INVALID_PARAMETER;
1742 status = get_fnum_from_path(cli,
1744 FILE_READ_ATTRIBUTES,
1747 if (!NT_STATUS_IS_OK(status)) {
1751 status = map_fnum_to_smb2_handle(cli,
1754 if (!NT_STATUS_IS_OK(status)) {
1758 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1759 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1761 status = smb2cli_query_info(cli->conn,
1765 1, /* in_info_type */
1766 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1767 0xFFFF, /* in_max_output_length */
1768 NULL, /* in_input_buffer */
1769 0, /* in_additional_info */
1776 if (!NT_STATUS_IS_OK(status)) {
1780 /* Parse the reply. */
1781 if (!parse_streams_blob(mem_ctx,
1786 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1792 if (fnum != 0xffff) {
1793 cli_smb2_close_fnum(cli, fnum);
1796 cli->raw_status = status;
1802 /***************************************************************
1803 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
1806 ***************************************************************/
1808 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
1810 uint8_t in_info_type,
1811 uint8_t in_file_info_class,
1812 const DATA_BLOB *p_in_data)
1815 uint16_t fnum = 0xffff;
1816 struct smb2_hnd *ph = NULL;
1817 TALLOC_CTX *frame = talloc_stackframe();
1819 if (smbXcli_conn_has_async_calls(cli->conn)) {
1821 * Can't use sync call while an async call is in flight
1823 status = NT_STATUS_INVALID_PARAMETER;
1827 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1828 status = NT_STATUS_INVALID_PARAMETER;
1832 status = get_fnum_from_path(cli,
1834 FILE_WRITE_ATTRIBUTES,
1837 if (!NT_STATUS_IS_OK(status)) {
1841 status = map_fnum_to_smb2_handle(cli,
1844 if (!NT_STATUS_IS_OK(status)) {
1848 status = smb2cli_set_info(cli->conn,
1854 p_in_data, /* in_input_buffer */
1855 0, /* in_additional_info */
1860 if (fnum != 0xffff) {
1861 cli_smb2_close_fnum(cli, fnum);
1864 cli->raw_status = status;
1871 /***************************************************************
1872 Wrapper that allows SMB2 to set pathname attributes.
1874 ***************************************************************/
1876 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1881 uint8_t inbuf_store[40];
1882 DATA_BLOB inbuf = data_blob_null;
1884 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1885 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1887 inbuf.data = inbuf_store;
1888 inbuf.length = sizeof(inbuf_store);
1889 data_blob_clear(&inbuf);
1892 * SMB1 uses attr == 0 to clear all attributes
1893 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
1894 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
1895 * request attribute change.
1897 * SMB2 uses exactly the reverse. Unfortunately as the
1898 * cli_setatr() ABI is exposed inside libsmbclient,
1899 * we must make the SMB2 cli_smb2_setatr() call
1900 * export the same ABI as the SMB1 cli_setatr()
1901 * which calls it. This means reversing the sense
1902 * of the requested attr argument if it's zero
1903 * or FILE_ATTRIBUTE_NORMAL.
1905 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
1909 attr = FILE_ATTRIBUTE_NORMAL;
1910 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
1914 SSVAL(inbuf.data, 32, attr);
1916 put_long_date((char *)inbuf.data + 16,mtime);
1918 /* Set all the other times to -1. */
1919 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1920 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1921 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1923 return cli_smb2_setpathinfo(cli,
1925 1, /* in_info_type */
1926 /* in_file_info_class */
1927 SMB_FILE_BASIC_INFORMATION - 1000,
1932 /***************************************************************
1933 Wrapper that allows SMB2 to set file handle times.
1935 ***************************************************************/
1937 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1944 struct smb2_hnd *ph = NULL;
1945 uint8_t inbuf_store[40];
1946 DATA_BLOB inbuf = data_blob_null;
1948 if (smbXcli_conn_has_async_calls(cli->conn)) {
1950 * Can't use sync call while an async call is in flight
1952 return NT_STATUS_INVALID_PARAMETER;
1955 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1956 return NT_STATUS_INVALID_PARAMETER;
1959 status = map_fnum_to_smb2_handle(cli,
1962 if (!NT_STATUS_IS_OK(status)) {
1966 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1967 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1969 inbuf.data = inbuf_store;
1970 inbuf.length = sizeof(inbuf_store);
1971 data_blob_clear(&inbuf);
1973 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1974 if (change_time != 0) {
1975 put_long_date((char *)inbuf.data + 24, change_time);
1977 if (access_time != 0) {
1978 put_long_date((char *)inbuf.data + 8, access_time);
1980 if (write_time != 0) {
1981 put_long_date((char *)inbuf.data + 16, write_time);
1984 cli->raw_status = smb2cli_set_info(cli->conn,
1988 1, /* in_info_type */
1989 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1990 &inbuf, /* in_input_buffer */
1991 0, /* in_additional_info */
1995 return cli->raw_status;
1998 /***************************************************************
1999 Wrapper that allows SMB2 to query disk attributes (size).
2001 ***************************************************************/
2003 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2004 uint64_t *bsize, uint64_t *total, uint64_t *avail)
2007 uint16_t fnum = 0xffff;
2008 DATA_BLOB outbuf = data_blob_null;
2009 struct smb2_hnd *ph = NULL;
2010 uint32_t sectors_per_unit = 0;
2011 uint32_t bytes_per_sector = 0;
2012 uint64_t total_size = 0;
2013 uint64_t size_free = 0;
2014 TALLOC_CTX *frame = talloc_stackframe();
2016 if (smbXcli_conn_has_async_calls(cli->conn)) {
2018 * Can't use sync call while an async call is in flight
2020 status = NT_STATUS_INVALID_PARAMETER;
2024 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2025 status = NT_STATUS_INVALID_PARAMETER;
2029 /* First open the top level directory. */
2030 status = cli_smb2_create_fnum(cli,
2032 0, /* create_flags */
2033 SMB2_IMPERSONATION_IMPERSONATION,
2034 FILE_READ_ATTRIBUTES, /* desired_access */
2035 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2036 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2037 FILE_OPEN, /* create_disposition */
2038 FILE_DIRECTORY_FILE, /* create_options */
2042 if (!NT_STATUS_IS_OK(status)) {
2046 status = map_fnum_to_smb2_handle(cli,
2049 if (!NT_STATUS_IS_OK(status)) {
2053 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2054 level 3 (SMB_FS_SIZE_INFORMATION). */
2056 status = smb2cli_query_info(cli->conn,
2060 2, /* in_info_type */
2061 3, /* in_file_info_class */
2062 0xFFFF, /* in_max_output_length */
2063 NULL, /* in_input_buffer */
2064 0, /* in_additional_info */
2070 if (!NT_STATUS_IS_OK(status)) {
2074 /* Parse the reply. */
2075 if (outbuf.length != 24) {
2076 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2080 total_size = BVAL(outbuf.data, 0);
2081 size_free = BVAL(outbuf.data, 8);
2082 sectors_per_unit = IVAL(outbuf.data, 16);
2083 bytes_per_sector = IVAL(outbuf.data, 20);
2086 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2089 *total = total_size;
2095 status = NT_STATUS_OK;
2099 if (fnum != 0xffff) {
2100 cli_smb2_close_fnum(cli, fnum);
2103 cli->raw_status = status;
2109 /***************************************************************
2110 Wrapper that allows SMB2 to query file system sizes.
2112 ***************************************************************/
2114 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2115 uint64_t *total_allocation_units,
2116 uint64_t *caller_allocation_units,
2117 uint64_t *actual_allocation_units,
2118 uint64_t *sectors_per_allocation_unit,
2119 uint64_t *bytes_per_sector)
2122 uint16_t fnum = 0xffff;
2123 DATA_BLOB outbuf = data_blob_null;
2124 struct smb2_hnd *ph = NULL;
2125 TALLOC_CTX *frame = talloc_stackframe();
2127 if (smbXcli_conn_has_async_calls(cli->conn)) {
2129 * Can't use sync call while an async call is in flight
2131 status = NT_STATUS_INVALID_PARAMETER;
2135 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2136 status = NT_STATUS_INVALID_PARAMETER;
2140 /* First open the top level directory. */
2142 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2143 SMB2_IMPERSONATION_IMPERSONATION,
2144 FILE_READ_ATTRIBUTES, /* desired_access */
2145 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2146 FILE_SHARE_READ | FILE_SHARE_WRITE |
2147 FILE_SHARE_DELETE, /* share_access */
2148 FILE_OPEN, /* create_disposition */
2149 FILE_DIRECTORY_FILE, /* create_options */
2153 if (!NT_STATUS_IS_OK(status)) {
2157 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2158 if (!NT_STATUS_IS_OK(status)) {
2162 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2163 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2165 status = smb2cli_query_info(cli->conn,
2169 SMB2_GETINFO_FS, /* in_info_type */
2170 /* in_file_info_class */
2171 SMB_FS_FULL_SIZE_INFORMATION - 1000,
2172 0xFFFF, /* in_max_output_length */
2173 NULL, /* in_input_buffer */
2174 0, /* in_additional_info */
2180 if (!NT_STATUS_IS_OK(status)) {
2184 if (outbuf.length < 32) {
2185 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2189 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2190 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2191 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2192 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2193 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2197 if (fnum != 0xffff) {
2198 cli_smb2_close_fnum(cli, fnum);
2201 cli->raw_status = status;
2207 /***************************************************************
2208 Wrapper that allows SMB2 to query file system attributes.
2210 ***************************************************************/
2212 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2215 uint16_t fnum = 0xffff;
2216 DATA_BLOB outbuf = data_blob_null;
2217 struct smb2_hnd *ph = NULL;
2218 TALLOC_CTX *frame = talloc_stackframe();
2220 if (smbXcli_conn_has_async_calls(cli->conn)) {
2222 * Can't use sync call while an async call is in flight
2224 status = NT_STATUS_INVALID_PARAMETER;
2228 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2229 status = NT_STATUS_INVALID_PARAMETER;
2233 /* First open the top level directory. */
2235 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2236 SMB2_IMPERSONATION_IMPERSONATION,
2237 FILE_READ_ATTRIBUTES, /* desired_access */
2238 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2239 FILE_SHARE_READ | FILE_SHARE_WRITE |
2240 FILE_SHARE_DELETE, /* share_access */
2241 FILE_OPEN, /* create_disposition */
2242 FILE_DIRECTORY_FILE, /* create_options */
2246 if (!NT_STATUS_IS_OK(status)) {
2250 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2251 if (!NT_STATUS_IS_OK(status)) {
2255 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2256 cli->smb2.tcon, 2, /* in_info_type */
2257 5, /* in_file_info_class */
2258 0xFFFF, /* in_max_output_length */
2259 NULL, /* in_input_buffer */
2260 0, /* in_additional_info */
2262 ph->fid_persistent, ph->fid_volatile, frame,
2264 if (!NT_STATUS_IS_OK(status)) {
2268 if (outbuf.length < 12) {
2269 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2273 *fs_attr = IVAL(outbuf.data, 0);
2277 if (fnum != 0xffff) {
2278 cli_smb2_close_fnum(cli, fnum);
2281 cli->raw_status = status;
2287 /***************************************************************
2288 Wrapper that allows SMB2 to query file system volume info.
2290 ***************************************************************/
2292 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2293 TALLOC_CTX *mem_ctx,
2294 char **_volume_name,
2295 uint32_t *pserial_number,
2299 uint16_t fnum = 0xffff;
2300 DATA_BLOB outbuf = data_blob_null;
2301 struct smb2_hnd *ph = NULL;
2303 char *volume_name = NULL;
2304 TALLOC_CTX *frame = talloc_stackframe();
2306 if (smbXcli_conn_has_async_calls(cli->conn)) {
2308 * Can't use sync call while an async call is in flight
2310 status = NT_STATUS_INVALID_PARAMETER;
2314 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2315 status = NT_STATUS_INVALID_PARAMETER;
2319 /* First open the top level directory. */
2321 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2322 SMB2_IMPERSONATION_IMPERSONATION,
2323 FILE_READ_ATTRIBUTES, /* desired_access */
2324 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2325 FILE_SHARE_READ | FILE_SHARE_WRITE |
2326 FILE_SHARE_DELETE, /* share_access */
2327 FILE_OPEN, /* create_disposition */
2328 FILE_DIRECTORY_FILE, /* create_options */
2332 if (!NT_STATUS_IS_OK(status)) {
2336 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2337 if (!NT_STATUS_IS_OK(status)) {
2341 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2342 level 1 (SMB_FS_VOLUME_INFORMATION). */
2344 status = smb2cli_query_info(cli->conn,
2348 SMB2_GETINFO_FS, /* in_info_type */
2349 /* in_file_info_class */
2350 SMB_FS_VOLUME_INFORMATION - 1000,
2351 0xFFFF, /* in_max_output_length */
2352 NULL, /* in_input_buffer */
2353 0, /* in_additional_info */
2359 if (!NT_STATUS_IS_OK(status)) {
2363 if (outbuf.length < 24) {
2364 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2370 ts = interpret_long_date((char *)outbuf.data);
2373 if (pserial_number) {
2374 *pserial_number = IVAL(outbuf.data,8);
2376 nlen = IVAL(outbuf.data,12);
2377 if (nlen + 18 < 18) {
2379 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2383 * The next check is safe as we know outbuf.length >= 24
2386 if (nlen > (outbuf.length - 18)) {
2387 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2391 clistr_pull_talloc(mem_ctx,
2392 (const char *)outbuf.data,
2398 if (volume_name == NULL) {
2399 status = map_nt_error_from_unix(errno);
2403 *_volume_name = volume_name;
2407 if (fnum != 0xffff) {
2408 cli_smb2_close_fnum(cli, fnum);
2411 cli->raw_status = status;
2418 /***************************************************************
2419 Wrapper that allows SMB2 to query a security descriptor.
2421 ***************************************************************/
2423 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2426 TALLOC_CTX *mem_ctx,
2427 struct security_descriptor **ppsd)
2430 DATA_BLOB outbuf = data_blob_null;
2431 struct smb2_hnd *ph = NULL;
2432 struct security_descriptor *lsd = NULL;
2433 TALLOC_CTX *frame = talloc_stackframe();
2435 if (smbXcli_conn_has_async_calls(cli->conn)) {
2437 * Can't use sync call while an async call is in flight
2439 status = NT_STATUS_INVALID_PARAMETER;
2443 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2444 status = NT_STATUS_INVALID_PARAMETER;
2448 status = map_fnum_to_smb2_handle(cli,
2451 if (!NT_STATUS_IS_OK(status)) {
2455 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2457 status = smb2cli_query_info(cli->conn,
2461 3, /* in_info_type */
2462 0, /* in_file_info_class */
2463 0xFFFF, /* in_max_output_length */
2464 NULL, /* in_input_buffer */
2465 sec_info, /* in_additional_info */
2472 if (!NT_STATUS_IS_OK(status)) {
2476 /* Parse the reply. */
2477 status = unmarshall_sec_desc(mem_ctx,
2482 if (!NT_STATUS_IS_OK(status)) {
2494 cli->raw_status = status;
2500 /***************************************************************
2501 Wrapper that allows SMB2 to set a security descriptor.
2503 ***************************************************************/
2505 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
2508 const struct security_descriptor *sd)
2511 DATA_BLOB inbuf = data_blob_null;
2512 struct smb2_hnd *ph = NULL;
2513 TALLOC_CTX *frame = talloc_stackframe();
2515 if (smbXcli_conn_has_async_calls(cli->conn)) {
2517 * Can't use sync call while an async call is in flight
2519 status = NT_STATUS_INVALID_PARAMETER;
2523 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2524 status = NT_STATUS_INVALID_PARAMETER;
2528 status = map_fnum_to_smb2_handle(cli,
2531 if (!NT_STATUS_IS_OK(status)) {
2535 status = marshall_sec_desc(frame,
2540 if (!NT_STATUS_IS_OK(status)) {
2544 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2546 status = smb2cli_set_info(cli->conn,
2550 3, /* in_info_type */
2551 0, /* in_file_info_class */
2552 &inbuf, /* in_input_buffer */
2553 sec_info, /* in_additional_info */
2559 cli->raw_status = status;
2565 /***************************************************************
2566 Wrapper that allows SMB2 to rename a file.
2568 ***************************************************************/
2570 NTSTATUS cli_smb2_rename(struct cli_state *cli,
2571 const char *fname_src,
2572 const char *fname_dst,
2576 DATA_BLOB inbuf = data_blob_null;
2577 uint16_t fnum = 0xffff;
2578 struct smb2_hnd *ph = NULL;
2579 smb_ucs2_t *converted_str = NULL;
2580 size_t converted_size_bytes = 0;
2582 TALLOC_CTX *frame = talloc_stackframe();
2584 if (smbXcli_conn_has_async_calls(cli->conn)) {
2586 * Can't use sync call while an async call is in flight
2588 status = NT_STATUS_INVALID_PARAMETER;
2592 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2593 status = NT_STATUS_INVALID_PARAMETER;
2597 status = get_fnum_from_path(cli,
2602 if (!NT_STATUS_IS_OK(status)) {
2606 status = map_fnum_to_smb2_handle(cli,
2609 if (!NT_STATUS_IS_OK(status)) {
2613 /* SMB2 is pickier about pathnames. Ensure it doesn't
2615 if (*fname_dst == '\\') {
2619 /* SMB2 is pickier about pathnames. Ensure it doesn't
2621 namelen = strlen(fname_dst);
2622 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2623 char *modname = talloc_strdup(frame, fname_dst);
2624 modname[namelen-1] = '\0';
2625 fname_dst = modname;
2628 if (!push_ucs2_talloc(frame,
2631 &converted_size_bytes)) {
2632 status = NT_STATUS_INVALID_PARAMETER;
2636 /* W2K8 insists the dest name is not null
2637 terminated. Remove the last 2 zero bytes
2638 and reduce the name length. */
2640 if (converted_size_bytes < 2) {
2641 status = NT_STATUS_INVALID_PARAMETER;
2644 converted_size_bytes -= 2;
2646 inbuf = data_blob_talloc_zero(frame,
2647 20 + converted_size_bytes);
2648 if (inbuf.data == NULL) {
2649 status = NT_STATUS_NO_MEMORY;
2654 SCVAL(inbuf.data, 0, 1);
2657 SIVAL(inbuf.data, 16, converted_size_bytes);
2658 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2660 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2661 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2663 status = smb2cli_set_info(cli->conn,
2667 1, /* in_info_type */
2668 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2669 &inbuf, /* in_input_buffer */
2670 0, /* in_additional_info */
2676 if (fnum != 0xffff) {
2677 cli_smb2_close_fnum(cli, fnum);
2680 cli->raw_status = status;
2686 /***************************************************************
2687 Wrapper that allows SMB2 to set an EA on a fnum.
2689 ***************************************************************/
2691 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2693 const char *ea_name,
2698 DATA_BLOB inbuf = data_blob_null;
2700 char *ea_name_ascii = NULL;
2702 struct smb2_hnd *ph = NULL;
2703 TALLOC_CTX *frame = talloc_stackframe();
2705 if (smbXcli_conn_has_async_calls(cli->conn)) {
2707 * Can't use sync call while an async call is in flight
2709 status = NT_STATUS_INVALID_PARAMETER;
2713 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2714 status = NT_STATUS_INVALID_PARAMETER;
2718 status = map_fnum_to_smb2_handle(cli,
2721 if (!NT_STATUS_IS_OK(status)) {
2725 /* Marshall the SMB2 EA data. */
2726 if (ea_len > 0xFFFF) {
2727 status = NT_STATUS_INVALID_PARAMETER;
2731 if (!push_ascii_talloc(frame,
2735 status = NT_STATUS_INVALID_PARAMETER;
2739 if (namelen < 2 || namelen > 0xFF) {
2740 status = NT_STATUS_INVALID_PARAMETER;
2744 bloblen = 8 + ea_len + namelen;
2745 /* Round up to a 4 byte boundary. */
2746 bloblen = ((bloblen + 3)&~3);
2748 inbuf = data_blob_talloc_zero(frame, bloblen);
2749 if (inbuf.data == NULL) {
2750 status = NT_STATUS_NO_MEMORY;
2753 /* namelen doesn't include the NULL byte. */
2754 SCVAL(inbuf.data, 5, namelen - 1);
2755 SSVAL(inbuf.data, 6, ea_len);
2756 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2757 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2759 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2760 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2762 status = smb2cli_set_info(cli->conn,
2766 1, /* in_info_type */
2767 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2768 &inbuf, /* in_input_buffer */
2769 0, /* in_additional_info */
2775 cli->raw_status = status;
2781 /***************************************************************
2782 Wrapper that allows SMB2 to set an EA on a pathname.
2784 ***************************************************************/
2786 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2788 const char *ea_name,
2793 uint16_t fnum = 0xffff;
2795 if (smbXcli_conn_has_async_calls(cli->conn)) {
2797 * Can't use sync call while an async call is in flight
2799 status = NT_STATUS_INVALID_PARAMETER;
2803 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2804 status = NT_STATUS_INVALID_PARAMETER;
2808 status = get_fnum_from_path(cli,
2813 if (!NT_STATUS_IS_OK(status)) {
2817 status = cli_set_ea_fnum(cli,
2822 if (!NT_STATUS_IS_OK(status)) {
2828 if (fnum != 0xffff) {
2829 cli_smb2_close_fnum(cli, fnum);
2832 cli->raw_status = status;
2837 /***************************************************************
2838 Wrapper that allows SMB2 to get an EA list on a pathname.
2840 ***************************************************************/
2842 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2846 struct ea_struct **pea_array)
2849 uint16_t fnum = 0xffff;
2850 DATA_BLOB outbuf = data_blob_null;
2851 struct smb2_hnd *ph = NULL;
2852 struct ea_list *ea_list = NULL;
2853 struct ea_list *eal = NULL;
2854 size_t ea_count = 0;
2855 TALLOC_CTX *frame = talloc_stackframe();
2860 if (smbXcli_conn_has_async_calls(cli->conn)) {
2862 * Can't use sync call while an async call is in flight
2864 status = NT_STATUS_INVALID_PARAMETER;
2868 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2869 status = NT_STATUS_INVALID_PARAMETER;
2873 status = get_fnum_from_path(cli,
2878 if (!NT_STATUS_IS_OK(status)) {
2882 status = map_fnum_to_smb2_handle(cli,
2885 if (!NT_STATUS_IS_OK(status)) {
2889 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2890 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2892 status = smb2cli_query_info(cli->conn,
2896 1, /* in_info_type */
2897 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2898 0xFFFF, /* in_max_output_length */
2899 NULL, /* in_input_buffer */
2900 0, /* in_additional_info */
2907 if (!NT_STATUS_IS_OK(status)) {
2911 /* Parse the reply. */
2912 ea_list = read_nttrans_ea_list(ctx,
2913 (const char *)outbuf.data,
2915 if (ea_list == NULL) {
2916 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2920 /* Convert to an array. */
2921 for (eal = ea_list; eal; eal = eal->next) {
2926 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2927 if (*pea_array == NULL) {
2928 status = NT_STATUS_NO_MEMORY;
2932 for (eal = ea_list; eal; eal = eal->next) {
2933 (*pea_array)[ea_count++] = eal->ea;
2935 *pnum_eas = ea_count;
2940 if (fnum != 0xffff) {
2941 cli_smb2_close_fnum(cli, fnum);
2944 cli->raw_status = status;
2950 /***************************************************************
2951 Wrapper that allows SMB2 to get user quota.
2953 ***************************************************************/
2955 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
2957 SMB_NTQUOTA_STRUCT *pqt)
2960 DATA_BLOB inbuf = data_blob_null;
2961 DATA_BLOB info_blob = data_blob_null;
2962 DATA_BLOB outbuf = data_blob_null;
2963 struct smb2_hnd *ph = NULL;
2964 TALLOC_CTX *frame = talloc_stackframe();
2966 unsigned int offset;
2967 struct smb2_query_quota_info query = {0};
2968 struct file_get_quota_info info = {0};
2969 enum ndr_err_code err;
2970 struct ndr_push *ndr_push = NULL;
2972 if (smbXcli_conn_has_async_calls(cli->conn)) {
2974 * Can't use sync call while an async call is in flight
2976 status = NT_STATUS_INVALID_PARAMETER;
2980 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2981 status = NT_STATUS_INVALID_PARAMETER;
2985 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2986 if (!NT_STATUS_IS_OK(status)) {
2990 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
2992 query.return_single = 1;
2994 info.next_entry_offset = 0;
2995 info.sid_length = sid_len;
2996 info.sid = pqt->sid;
2998 err = ndr_push_struct_blob(
3002 (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
3004 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3005 status = NT_STATUS_INTERNAL_ERROR;
3009 query.sid_list_length = info_blob.length;
3010 ndr_push = ndr_push_init_ctx(frame);
3012 status = NT_STATUS_NO_MEMORY;
3016 err = ndr_push_smb2_query_quota_info(ndr_push,
3017 NDR_SCALARS | NDR_BUFFERS,
3020 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3021 status = NT_STATUS_INTERNAL_ERROR;
3025 err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3028 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3029 status = NT_STATUS_INTERNAL_ERROR;
3032 inbuf.data = ndr_push->data;
3033 inbuf.length = ndr_push->offset;
3035 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
3036 cli->smb2.tcon, 4, /* in_info_type */
3037 0, /* in_file_info_class */
3038 0xFFFF, /* in_max_output_length */
3039 &inbuf, /* in_input_buffer */
3040 0, /* in_additional_info */
3042 ph->fid_persistent, ph->fid_volatile, frame,
3045 if (!NT_STATUS_IS_OK(status)) {
3049 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3051 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3052 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3056 cli->raw_status = status;
3062 /***************************************************************
3063 Wrapper that allows SMB2 to list user quota.
3065 ***************************************************************/
3067 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3068 TALLOC_CTX *mem_ctx,
3070 SMB_NTQUOTA_LIST **pqt_list,
3074 DATA_BLOB inbuf = data_blob_null;
3075 DATA_BLOB outbuf = data_blob_null;
3076 struct smb2_hnd *ph = NULL;
3077 TALLOC_CTX *frame = talloc_stackframe();
3078 struct smb2_query_quota_info info = {0};
3079 enum ndr_err_code err;
3081 if (smbXcli_conn_has_async_calls(cli->conn)) {
3083 * Can't use sync call while an async call is in flight
3085 status = NT_STATUS_INVALID_PARAMETER;
3089 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3090 status = NT_STATUS_INVALID_PARAMETER;
3094 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3095 if (!NT_STATUS_IS_OK(status)) {
3100 info.restart_scan = first ? 1 : 0;
3102 err = ndr_push_struct_blob(
3106 (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3108 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3109 status = NT_STATUS_INTERNAL_ERROR;
3113 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
3114 cli->smb2.tcon, 4, /* in_info_type */
3115 0, /* in_file_info_class */
3116 0xFFFF, /* in_max_output_length */
3117 &inbuf, /* in_input_buffer */
3118 0, /* in_additional_info */
3120 ph->fid_persistent, ph->fid_volatile, frame,
3124 * safeguard against panic from calling parse_user_quota_list with
3127 if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3128 status = NT_STATUS_NO_MORE_ENTRIES;
3131 if (!NT_STATUS_IS_OK(status)) {
3135 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3139 cli->raw_status = status;
3145 /***************************************************************
3146 Wrapper that allows SMB2 to get file system quota.
3148 ***************************************************************/
3150 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3152 SMB_NTQUOTA_STRUCT *pqt)
3155 DATA_BLOB outbuf = data_blob_null;
3156 struct smb2_hnd *ph = NULL;
3157 TALLOC_CTX *frame = talloc_stackframe();
3159 if (smbXcli_conn_has_async_calls(cli->conn)) {
3161 * Can't use sync call while an async call is in flight
3163 status = NT_STATUS_INVALID_PARAMETER;
3167 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3168 status = NT_STATUS_INVALID_PARAMETER;
3172 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3173 if (!NT_STATUS_IS_OK(status)) {
3177 status = smb2cli_query_info(
3178 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3179 2, /* in_info_type */
3180 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3181 0xFFFF, /* in_max_output_length */
3182 NULL, /* in_input_buffer */
3183 0, /* in_additional_info */
3185 ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
3187 if (!NT_STATUS_IS_OK(status)) {
3191 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3194 cli->raw_status = status;
3200 /***************************************************************
3201 Wrapper that allows SMB2 to set user quota.
3203 ***************************************************************/
3205 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3207 SMB_NTQUOTA_LIST *qtl)
3210 DATA_BLOB inbuf = data_blob_null;
3211 struct smb2_hnd *ph = NULL;
3212 TALLOC_CTX *frame = talloc_stackframe();
3214 if (smbXcli_conn_has_async_calls(cli->conn)) {
3216 * Can't use sync call while an async call is in flight
3218 status = NT_STATUS_INVALID_PARAMETER;
3222 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3223 status = NT_STATUS_INVALID_PARAMETER;
3227 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3228 if (!NT_STATUS_IS_OK(status)) {
3232 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3233 if (!NT_STATUS_IS_OK(status)) {
3237 status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
3238 cli->smb2.tcon, 4, /* in_info_type */
3239 0, /* in_file_info_class */
3240 &inbuf, /* in_input_buffer */
3241 0, /* in_additional_info */
3242 ph->fid_persistent, ph->fid_volatile);
3245 cli->raw_status = status;
3252 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3254 SMB_NTQUOTA_STRUCT *pqt)
3257 DATA_BLOB inbuf = data_blob_null;
3258 struct smb2_hnd *ph = NULL;
3259 TALLOC_CTX *frame = talloc_stackframe();
3261 if (smbXcli_conn_has_async_calls(cli->conn)) {
3263 * Can't use sync call while an async call is in flight
3265 status = NT_STATUS_INVALID_PARAMETER;
3269 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3270 status = NT_STATUS_INVALID_PARAMETER;
3274 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3275 if (!NT_STATUS_IS_OK(status)) {
3279 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3280 if (!NT_STATUS_IS_OK(status)) {
3284 status = smb2cli_set_info(
3285 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3286 2, /* in_info_type */
3287 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3288 &inbuf, /* in_input_buffer */
3289 0, /* in_additional_info */
3290 ph->fid_persistent, ph->fid_volatile);
3292 cli->raw_status = status;
3298 struct cli_smb2_read_state {
3299 struct tevent_context *ev;
3300 struct cli_state *cli;
3301 struct smb2_hnd *ph;
3302 uint64_t start_offset;
3308 static void cli_smb2_read_done(struct tevent_req *subreq);
3310 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3311 struct tevent_context *ev,
3312 struct cli_state *cli,
3318 struct tevent_req *req, *subreq;
3319 struct cli_smb2_read_state *state;
3321 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3327 state->start_offset = (uint64_t)offset;
3328 state->size = (uint32_t)size;
3329 state->received = 0;
3332 status = map_fnum_to_smb2_handle(cli,
3335 if (tevent_req_nterror(req, status)) {
3336 return tevent_req_post(req, ev);
3339 subreq = smb2cli_read_send(state,
3342 state->cli->timeout,
3343 state->cli->smb2.session,
3344 state->cli->smb2.tcon,
3346 state->start_offset,
3347 state->ph->fid_persistent,
3348 state->ph->fid_volatile,
3349 0, /* minimum_count */
3350 0); /* remaining_bytes */
3352 if (tevent_req_nomem(subreq, req)) {
3353 return tevent_req_post(req, ev);
3355 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3359 static void cli_smb2_read_done(struct tevent_req *subreq)
3361 struct tevent_req *req = tevent_req_callback_data(
3362 subreq, struct tevent_req);
3363 struct cli_smb2_read_state *state = tevent_req_data(
3364 req, struct cli_smb2_read_state);
3367 status = smb2cli_read_recv(subreq, state,
3368 &state->buf, &state->received);
3369 if (tevent_req_nterror(req, status)) {
3373 if (state->received > state->size) {
3374 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3378 tevent_req_done(req);
3381 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
3386 struct cli_smb2_read_state *state = tevent_req_data(
3387 req, struct cli_smb2_read_state);
3389 if (tevent_req_is_nterror(req, &status)) {
3390 state->cli->raw_status = status;
3394 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3395 * better make sure that you copy it away before you talloc_free(req).
3396 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3398 *received = (ssize_t)state->received;
3399 *rcvbuf = state->buf;
3400 state->cli->raw_status = NT_STATUS_OK;
3401 return NT_STATUS_OK;
3404 struct cli_smb2_write_state {
3405 struct tevent_context *ev;
3406 struct cli_state *cli;
3407 struct smb2_hnd *ph;
3415 static void cli_smb2_write_written(struct tevent_req *req);
3417 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
3418 struct tevent_context *ev,
3419 struct cli_state *cli,
3427 struct tevent_req *req, *subreq = NULL;
3428 struct cli_smb2_write_state *state = NULL;
3430 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
3436 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3437 state->flags = (uint32_t)mode;
3439 state->offset = (uint64_t)offset;
3440 state->size = (uint32_t)size;
3443 status = map_fnum_to_smb2_handle(cli,
3446 if (tevent_req_nterror(req, status)) {
3447 return tevent_req_post(req, ev);
3450 subreq = smb2cli_write_send(state,
3453 state->cli->timeout,
3454 state->cli->smb2.session,
3455 state->cli->smb2.tcon,
3458 state->ph->fid_persistent,
3459 state->ph->fid_volatile,
3460 0, /* remaining_bytes */
3461 state->flags, /* flags */
3464 if (tevent_req_nomem(subreq, req)) {
3465 return tevent_req_post(req, ev);
3467 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
3471 static void cli_smb2_write_written(struct tevent_req *subreq)
3473 struct tevent_req *req = tevent_req_callback_data(
3474 subreq, struct tevent_req);
3475 struct cli_smb2_write_state *state = tevent_req_data(
3476 req, struct cli_smb2_write_state);
3480 status = smb2cli_write_recv(subreq, &written);
3481 TALLOC_FREE(subreq);
3482 if (tevent_req_nterror(req, status)) {
3486 state->written = written;
3488 tevent_req_done(req);
3491 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
3494 struct cli_smb2_write_state *state = tevent_req_data(
3495 req, struct cli_smb2_write_state);
3498 if (tevent_req_is_nterror(req, &status)) {
3499 state->cli->raw_status = status;
3500 tevent_req_received(req);
3504 if (pwritten != NULL) {
3505 *pwritten = (size_t)state->written;
3507 state->cli->raw_status = NT_STATUS_OK;
3508 tevent_req_received(req);
3509 return NT_STATUS_OK;
3512 /***************************************************************
3513 Wrapper that allows SMB2 async write using an fnum.
3514 This is mostly cut-and-paste from Volker's code inside
3515 source3/libsmb/clireadwrite.c, adapted for SMB2.
3517 Done this way so I can reuse all the logic inside cli_push()
3519 ***************************************************************/
3521 struct cli_smb2_writeall_state {
3522 struct tevent_context *ev;
3523 struct cli_state *cli;
3524 struct smb2_hnd *ph;
3532 static void cli_smb2_writeall_written(struct tevent_req *req);
3534 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
3535 struct tevent_context *ev,
3536 struct cli_state *cli,
3544 struct tevent_req *req, *subreq = NULL;
3545 struct cli_smb2_writeall_state *state = NULL;
3550 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
3556 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3557 state->flags = (uint32_t)mode;
3559 state->offset = (uint64_t)offset;
3560 state->size = (uint32_t)size;
3563 status = map_fnum_to_smb2_handle(cli,
3566 if (tevent_req_nterror(req, status)) {
3567 return tevent_req_post(req, ev);
3570 to_write = state->size;
3571 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3572 to_write = MIN(max_size, to_write);
3573 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3575 to_write = MIN(max_size, to_write);
3578 subreq = smb2cli_write_send(state,
3581 state->cli->timeout,
3582 state->cli->smb2.session,
3583 state->cli->smb2.tcon,
3586 state->ph->fid_persistent,
3587 state->ph->fid_volatile,
3588 0, /* remaining_bytes */
3589 state->flags, /* flags */
3590 state->buf + state->written);
3592 if (tevent_req_nomem(subreq, req)) {
3593 return tevent_req_post(req, ev);
3595 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3599 static void cli_smb2_writeall_written(struct tevent_req *subreq)
3601 struct tevent_req *req = tevent_req_callback_data(
3602 subreq, struct tevent_req);
3603 struct cli_smb2_writeall_state *state = tevent_req_data(
3604 req, struct cli_smb2_writeall_state);
3606 uint32_t written, to_write;
3610 status = smb2cli_write_recv(subreq, &written);
3611 TALLOC_FREE(subreq);
3612 if (tevent_req_nterror(req, status)) {
3616 state->written += written;
3618 if (state->written > state->size) {
3619 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3623 to_write = state->size - state->written;
3625 if (to_write == 0) {
3626 tevent_req_done(req);
3630 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3631 to_write = MIN(max_size, to_write);
3632 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3634 to_write = MIN(max_size, to_write);
3637 subreq = smb2cli_write_send(state,
3640 state->cli->timeout,
3641 state->cli->smb2.session,
3642 state->cli->smb2.tcon,
3644 state->offset + state->written,
3645 state->ph->fid_persistent,
3646 state->ph->fid_volatile,
3647 0, /* remaining_bytes */
3648 state->flags, /* flags */
3649 state->buf + state->written);
3651 if (tevent_req_nomem(subreq, req)) {
3654 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3657 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
3660 struct cli_smb2_writeall_state *state = tevent_req_data(
3661 req, struct cli_smb2_writeall_state);
3664 if (tevent_req_is_nterror(req, &status)) {
3665 state->cli->raw_status = status;
3668 if (pwritten != NULL) {
3669 *pwritten = (size_t)state->written;
3671 state->cli->raw_status = NT_STATUS_OK;
3672 return NT_STATUS_OK;
3675 struct cli_smb2_splice_state {
3676 struct tevent_context *ev;
3677 struct cli_state *cli;
3678 struct smb2_hnd *src_ph;
3679 struct smb2_hnd *dst_ph;
3680 int (*splice_cb)(off_t n, void *priv);
3687 struct req_resume_key_rsp resume_rsp;
3688 struct srv_copychunk_copy cc_copy;
3691 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3692 struct tevent_req *req);
3694 static void cli_splice_copychunk_done(struct tevent_req *subreq)
3696 struct tevent_req *req = tevent_req_callback_data(
3697 subreq, struct tevent_req);
3698 struct cli_smb2_splice_state *state =
3699 tevent_req_data(req,
3700 struct cli_smb2_splice_state);
3701 struct smbXcli_conn *conn = state->cli->conn;
3702 DATA_BLOB out_input_buffer = data_blob_null;
3703 DATA_BLOB out_output_buffer = data_blob_null;
3704 struct srv_copychunk_rsp cc_copy_rsp;
3705 enum ndr_err_code ndr_ret;
3708 status = smb2cli_ioctl_recv(subreq, state,
3710 &out_output_buffer);
3711 TALLOC_FREE(subreq);
3712 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
3713 state->resized) && tevent_req_nterror(req, status)) {
3717 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
3718 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
3719 if (ndr_ret != NDR_ERR_SUCCESS) {
3720 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3721 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3725 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
3726 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
3727 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
3728 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
3729 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
3730 tevent_req_nterror(req, status)) {
3734 state->resized = true;
3735 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
3736 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
3738 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3739 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3740 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
3741 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3744 state->src_offset += cc_copy_rsp.total_bytes_written;
3745 state->dst_offset += cc_copy_rsp.total_bytes_written;
3746 state->written += cc_copy_rsp.total_bytes_written;
3747 if (!state->splice_cb(state->written, state->priv)) {
3748 tevent_req_nterror(req, NT_STATUS_CANCELLED);
3753 cli_splice_copychunk_send(state, req);
3756 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3757 struct tevent_req *req)
3759 struct tevent_req *subreq;
3760 enum ndr_err_code ndr_ret;
3761 struct smbXcli_conn *conn = state->cli->conn;
3762 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
3763 off_t src_offset = state->src_offset;
3764 off_t dst_offset = state->dst_offset;
3765 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
3766 state->size - state->written);
3767 DATA_BLOB in_input_buffer = data_blob_null;
3768 DATA_BLOB in_output_buffer = data_blob_null;
3770 if (state->size - state->written == 0) {
3771 tevent_req_done(req);
3775 cc_copy->chunk_count = 0;
3777 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
3778 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
3779 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
3780 smb2cli_conn_cc_chunk_len(conn));
3781 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
3782 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3785 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
3786 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
3787 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
3788 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3791 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3792 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3793 cc_copy->chunk_count++;
3796 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
3797 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
3798 if (ndr_ret != NDR_ERR_SUCCESS) {
3799 DEBUG(0, ("failed to marshall copy chunk req\n"));
3800 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3804 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
3805 state->cli->timeout,
3806 state->cli->smb2.session,
3807 state->cli->smb2.tcon,
3808 state->dst_ph->fid_persistent, /* in_fid_persistent */
3809 state->dst_ph->fid_volatile, /* in_fid_volatile */
3810 FSCTL_SRV_COPYCHUNK_WRITE,
3811 0, /* in_max_input_length */
3813 12, /* in_max_output_length */
3815 SMB2_IOCTL_FLAG_IS_FSCTL);
3816 if (tevent_req_nomem(subreq, req)) {
3819 tevent_req_set_callback(subreq,
3820 cli_splice_copychunk_done,
3824 static void cli_splice_key_done(struct tevent_req *subreq)
3826 struct tevent_req *req = tevent_req_callback_data(
3827 subreq, struct tevent_req);
3828 struct cli_smb2_splice_state *state =
3829 tevent_req_data(req,
3830 struct cli_smb2_splice_state);
3831 enum ndr_err_code ndr_ret;
3834 DATA_BLOB out_input_buffer = data_blob_null;
3835 DATA_BLOB out_output_buffer = data_blob_null;
3837 status = smb2cli_ioctl_recv(subreq, state,
3839 &out_output_buffer);
3840 TALLOC_FREE(subreq);
3841 if (tevent_req_nterror(req, status)) {
3845 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
3846 state, &state->resume_rsp,
3847 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
3848 if (ndr_ret != NDR_ERR_SUCCESS) {
3849 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3850 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3854 memcpy(&state->cc_copy.source_key,
3855 &state->resume_rsp.resume_key,
3856 sizeof state->resume_rsp.resume_key);
3858 cli_splice_copychunk_send(state, req);
3861 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
3862 struct tevent_context *ev,
3863 struct cli_state *cli,
3864 uint16_t src_fnum, uint16_t dst_fnum,
3865 off_t size, off_t src_offset, off_t dst_offset,
3866 int (*splice_cb)(off_t n, void *priv),
3869 struct tevent_req *req;
3870 struct tevent_req *subreq;
3871 struct cli_smb2_splice_state *state;
3873 DATA_BLOB in_input_buffer = data_blob_null;
3874 DATA_BLOB in_output_buffer = data_blob_null;
3876 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
3882 state->splice_cb = splice_cb;
3886 state->src_offset = src_offset;
3887 state->dst_offset = dst_offset;
3888 state->cc_copy.chunks = talloc_array(state,
3889 struct srv_copychunk,
3890 smb2cli_conn_cc_max_chunks(cli->conn));
3891 if (state->cc_copy.chunks == NULL) {
3895 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
3896 if (tevent_req_nterror(req, status))
3897 return tevent_req_post(req, ev);
3899 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
3900 if (tevent_req_nterror(req, status))
3901 return tevent_req_post(req, ev);
3903 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
3907 state->src_ph->fid_persistent, /* in_fid_persistent */
3908 state->src_ph->fid_volatile, /* in_fid_volatile */
3909 FSCTL_SRV_REQUEST_RESUME_KEY,
3910 0, /* in_max_input_length */
3912 32, /* in_max_output_length */
3914 SMB2_IOCTL_FLAG_IS_FSCTL);
3915 if (tevent_req_nomem(subreq, req)) {
3918 tevent_req_set_callback(subreq,
3919 cli_splice_key_done,
3925 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
3927 struct cli_smb2_splice_state *state = tevent_req_data(
3928 req, struct cli_smb2_splice_state);
3931 if (tevent_req_is_nterror(req, &status)) {
3932 state->cli->raw_status = status;
3933 tevent_req_received(req);
3936 if (written != NULL) {
3937 *written = state->written;
3939 state->cli->raw_status = NT_STATUS_OK;
3940 tevent_req_received(req);
3941 return NT_STATUS_OK;
3944 /***************************************************************
3945 SMB2 enum shadow copy data.
3946 ***************************************************************/
3948 struct cli_smb2_shadow_copy_data_fnum_state {
3949 struct cli_state *cli;
3951 struct smb2_hnd *ph;
3952 DATA_BLOB out_input_buffer;
3953 DATA_BLOB out_output_buffer;
3956 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
3958 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
3959 TALLOC_CTX *mem_ctx,
3960 struct tevent_context *ev,
3961 struct cli_state *cli,
3965 struct tevent_req *req, *subreq;
3966 struct cli_smb2_shadow_copy_data_fnum_state *state;
3969 req = tevent_req_create(mem_ctx, &state,
3970 struct cli_smb2_shadow_copy_data_fnum_state);
3975 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3976 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3977 return tevent_req_post(req, ev);
3983 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
3984 if (tevent_req_nterror(req, status)) {
3985 return tevent_req_post(req, ev);
3989 * TODO. Under SMB2 we should send a zero max_output_length
3990 * ioctl to get the required size, then send another ioctl
3991 * to get the data, but the current SMB1 implementation just
3992 * does one roundtrip with a 64K buffer size. Do the same
3996 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
3997 state->cli->timeout,
3998 state->cli->smb2.session,
3999 state->cli->smb2.tcon,
4000 state->ph->fid_persistent, /* in_fid_persistent */
4001 state->ph->fid_volatile, /* in_fid_volatile */
4002 FSCTL_GET_SHADOW_COPY_DATA,
4003 0, /* in_max_input_length */
4004 NULL, /* in_input_buffer */
4006 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
4007 NULL, /* in_output_buffer */
4008 SMB2_IOCTL_FLAG_IS_FSCTL);
4010 if (tevent_req_nomem(subreq, req)) {
4011 return tevent_req_post(req, ev);
4013 tevent_req_set_callback(subreq,
4014 cli_smb2_shadow_copy_data_fnum_done,
4020 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4022 struct tevent_req *req = tevent_req_callback_data(
4023 subreq, struct tevent_req);
4024 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4025 req, struct cli_smb2_shadow_copy_data_fnum_state);
4028 status = smb2cli_ioctl_recv(subreq, state,
4029 &state->out_input_buffer,
4030 &state->out_output_buffer);
4031 TALLOC_FREE(subreq);
4032 if (tevent_req_nterror(req, status)) {
4035 tevent_req_done(req);
4038 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4039 TALLOC_CTX *mem_ctx,
4044 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4045 req, struct cli_smb2_shadow_copy_data_fnum_state);
4046 char **names = NULL;
4047 uint32_t num_names = 0;
4048 uint32_t num_names_returned = 0;
4049 uint32_t dlength = 0;
4051 uint8_t *endp = NULL;
4054 if (tevent_req_is_nterror(req, &status)) {
4058 if (state->out_output_buffer.length < 16) {
4059 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4062 num_names = IVAL(state->out_output_buffer.data, 0);
4063 num_names_returned = IVAL(state->out_output_buffer.data, 4);
4064 dlength = IVAL(state->out_output_buffer.data, 8);
4066 if (num_names > 0x7FFFFFFF) {
4067 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4070 if (get_names == false) {
4071 *pnum_names = (int)num_names;
4072 return NT_STATUS_OK;
4074 if (num_names != num_names_returned) {
4075 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4077 if (dlength + 12 < 12) {
4078 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4081 * NB. The below is an allowable return if there are
4082 * more snapshots than the buffer size we told the
4083 * server we can receive. We currently don't support
4086 if (dlength + 12 > state->out_output_buffer.length) {
4087 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4089 if (state->out_output_buffer.length +
4090 (2 * sizeof(SHADOW_COPY_LABEL)) <
4091 state->out_output_buffer.length) {
4092 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4095 names = talloc_array(mem_ctx, char *, num_names_returned);
4096 if (names == NULL) {
4097 return NT_STATUS_NO_MEMORY;
4100 endp = state->out_output_buffer.data +
4101 state->out_output_buffer.length;
4103 for (i=0; i<num_names_returned; i++) {
4106 size_t converted_size;
4108 src = state->out_output_buffer.data + 12 +
4109 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4111 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4112 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4114 ret = convert_string_talloc(
4115 names, CH_UTF16LE, CH_UNIX,
4116 src, 2 * sizeof(SHADOW_COPY_LABEL),
4117 &names[i], &converted_size);
4120 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4123 *pnum_names = num_names;
4125 return NT_STATUS_OK;
4128 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4129 struct cli_state *cli,
4135 TALLOC_CTX *frame = talloc_stackframe();
4136 struct tevent_context *ev;
4137 struct tevent_req *req;
4138 NTSTATUS status = NT_STATUS_NO_MEMORY;
4140 if (smbXcli_conn_has_async_calls(cli->conn)) {
4142 * Can't use sync call while an async call is in flight
4144 status = NT_STATUS_INVALID_PARAMETER;
4147 ev = samba_tevent_context_init(frame);
4151 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4159 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4162 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4168 cli->raw_status = status;
4174 /***************************************************************
4175 Wrapper that allows SMB2 to truncate a file.
4177 ***************************************************************/
4179 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4184 DATA_BLOB inbuf = data_blob_null;
4185 struct smb2_hnd *ph = NULL;
4186 TALLOC_CTX *frame = talloc_stackframe();
4188 if (smbXcli_conn_has_async_calls(cli->conn)) {
4190 * Can't use sync call while an async call is in flight
4192 status = NT_STATUS_INVALID_PARAMETER;
4196 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4197 status = NT_STATUS_INVALID_PARAMETER;
4201 status = map_fnum_to_smb2_handle(cli,
4204 if (!NT_STATUS_IS_OK(status)) {
4208 inbuf = data_blob_talloc_zero(frame, 8);
4209 if (inbuf.data == NULL) {
4210 status = NT_STATUS_NO_MEMORY;
4214 SBVAL(inbuf.data, 0, newsize);
4216 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4217 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4219 status = smb2cli_set_info(cli->conn,
4223 1, /* in_info_type */
4224 /* in_file_info_class */
4225 SMB_FILE_END_OF_FILE_INFORMATION - 1000,
4226 &inbuf, /* in_input_buffer */
4227 0, /* in_additional_info */
4233 cli->raw_status = status;
4239 struct cli_smb2_notify_state {
4240 struct tevent_req *subreq;
4241 struct notify_change *changes;
4245 static void cli_smb2_notify_done(struct tevent_req *subreq);
4246 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4248 struct tevent_req *cli_smb2_notify_send(
4249 TALLOC_CTX *mem_ctx,
4250 struct tevent_context *ev,
4251 struct cli_state *cli,
4253 uint32_t buffer_size,
4254 uint32_t completion_filter,
4257 struct tevent_req *req = NULL;
4258 struct cli_smb2_notify_state *state = NULL;
4259 struct smb2_hnd *ph = NULL;
4262 req = tevent_req_create(mem_ctx, &state,
4263 struct cli_smb2_notify_state);
4268 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4269 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4270 return tevent_req_post(req, ev);
4273 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4274 if (tevent_req_nterror(req, status)) {
4275 return tevent_req_post(req, ev);
4278 state->subreq = smb2cli_notify_send(
4290 if (tevent_req_nomem(state->subreq, req)) {
4291 return tevent_req_post(req, ev);
4293 tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4294 tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4298 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4300 struct cli_smb2_notify_state *state = tevent_req_data(
4301 req, struct cli_smb2_notify_state);
4304 ok = tevent_req_cancel(state->subreq);
4308 static void cli_smb2_notify_done(struct tevent_req *subreq)
4310 struct tevent_req *req = tevent_req_callback_data(
4311 subreq, struct tevent_req);
4312 struct cli_smb2_notify_state *state = tevent_req_data(
4313 req, struct cli_smb2_notify_state);
4319 status = smb2cli_notify_recv(subreq, state, &base, &len);
4320 TALLOC_FREE(subreq);
4322 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4323 tevent_req_done(req);
4326 if (tevent_req_nterror(req, status)) {
4332 while (len - ofs >= 12) {
4333 struct notify_change *tmp;
4334 struct notify_change *c;
4335 uint32_t next_ofs = IVAL(base, ofs);
4336 uint32_t file_name_length = IVAL(base, ofs+8);
4340 tmp = talloc_realloc(
4343 struct notify_change,
4344 state->num_changes + 1);
4345 if (tevent_req_nomem(tmp, req)) {
4348 state->changes = tmp;
4349 c = &state->changes[state->num_changes];
4350 state->num_changes += 1;
4352 if (smb_buffer_oob(len, ofs, next_ofs) ||
4353 smb_buffer_oob(len, ofs+12, file_name_length)) {
4355 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4359 c->action = IVAL(base, ofs+4);
4361 ok = convert_string_talloc(
4371 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4375 if (next_ofs == 0) {
4381 tevent_req_done(req);
4384 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
4385 TALLOC_CTX *mem_ctx,
4386 struct notify_change **pchanges,
4387 uint32_t *pnum_changes)
4389 struct cli_smb2_notify_state *state = tevent_req_data(
4390 req, struct cli_smb2_notify_state);
4393 if (tevent_req_is_nterror(req, &status)) {
4396 *pchanges = talloc_move(mem_ctx, &state->changes);
4397 *pnum_changes = state->num_changes;
4398 return NT_STATUS_OK;
4401 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
4402 uint32_t buffer_size, uint32_t completion_filter,
4403 bool recursive, TALLOC_CTX *mem_ctx,
4404 struct notify_change **pchanges,
4405 uint32_t *pnum_changes)
4407 TALLOC_CTX *frame = talloc_stackframe();
4408 struct tevent_context *ev;
4409 struct tevent_req *req;
4410 NTSTATUS status = NT_STATUS_NO_MEMORY;
4412 if (smbXcli_conn_has_async_calls(cli->conn)) {
4414 * Can't use sync call while an async call is in flight
4416 status = NT_STATUS_INVALID_PARAMETER;
4419 ev = samba_tevent_context_init(frame);
4423 req = cli_smb2_notify_send(
4434 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4437 status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
4443 struct cli_smb2_set_reparse_point_fnum_state {
4444 struct cli_state *cli;
4446 struct smb2_hnd *ph;
4447 DATA_BLOB input_buffer;
4450 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
4452 struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
4453 TALLOC_CTX *mem_ctx,
4454 struct tevent_context *ev,
4455 struct cli_state *cli,
4459 struct tevent_req *req, *subreq;
4460 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
4463 req = tevent_req_create(mem_ctx, &state,
4464 struct cli_smb2_set_reparse_point_fnum_state);
4469 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4470 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4471 return tevent_req_post(req, ev);
4477 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4478 if (tevent_req_nterror(req, status)) {
4479 return tevent_req_post(req, ev);
4482 state->input_buffer = data_blob_talloc(state,
4485 if (state->input_buffer.data == NULL) {
4486 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4487 return tevent_req_post(req, ev);
4490 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4491 state->cli->timeout,
4492 state->cli->smb2.session,
4493 state->cli->smb2.tcon,
4494 state->ph->fid_persistent, /* in_fid_persistent */
4495 state->ph->fid_volatile, /* in_fid_volatile */
4496 FSCTL_SET_REPARSE_POINT,
4497 0, /* in_max_input_length */
4498 &state->input_buffer ,
4501 SMB2_IOCTL_FLAG_IS_FSCTL);
4503 if (tevent_req_nomem(subreq, req)) {
4504 return tevent_req_post(req, ev);
4506 tevent_req_set_callback(subreq,
4507 cli_smb2_set_reparse_point_fnum_done,
4513 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
4515 struct tevent_req *req = tevent_req_callback_data(
4516 subreq, struct tevent_req);
4517 struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
4518 req, struct cli_smb2_set_reparse_point_fnum_state);
4521 status = smb2cli_ioctl_recv(subreq, state,
4524 TALLOC_FREE(subreq);
4525 if (tevent_req_nterror(req, status)) {
4528 tevent_req_done(req);
4531 NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
4533 return tevent_req_simple_recv_ntstatus(req);
4536 struct cli_smb2_get_reparse_point_fnum_state {
4537 struct cli_state *cli;
4539 struct smb2_hnd *ph;
4540 DATA_BLOB output_buffer;
4543 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
4545 struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
4546 TALLOC_CTX *mem_ctx,
4547 struct tevent_context *ev,
4548 struct cli_state *cli,
4551 struct tevent_req *req, *subreq;
4552 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
4555 req = tevent_req_create(mem_ctx, &state,
4556 struct cli_smb2_get_reparse_point_fnum_state);
4561 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4562 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4563 return tevent_req_post(req, ev);
4569 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4570 if (tevent_req_nterror(req, status)) {
4571 return tevent_req_post(req, ev);
4574 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4575 state->cli->timeout,
4576 state->cli->smb2.session,
4577 state->cli->smb2.tcon,
4578 state->ph->fid_persistent, /* in_fid_persistent */
4579 state->ph->fid_volatile, /* in_fid_volatile */
4580 FSCTL_GET_REPARSE_POINT,
4581 0, /* in_max_input_length */
4585 SMB2_IOCTL_FLAG_IS_FSCTL);
4587 if (tevent_req_nomem(subreq, req)) {
4588 return tevent_req_post(req, ev);
4590 tevent_req_set_callback(subreq,
4591 cli_smb2_get_reparse_point_fnum_done,
4597 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
4599 struct tevent_req *req = tevent_req_callback_data(
4600 subreq, struct tevent_req);
4601 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
4602 req, struct cli_smb2_get_reparse_point_fnum_state);
4605 status = smb2cli_ioctl_recv(subreq, state,
4607 &state->output_buffer);
4608 TALLOC_FREE(subreq);
4609 if (tevent_req_nterror(req, status)) {
4610 state->cli->raw_status = status;
4613 tevent_req_done(req);
4616 NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
4617 TALLOC_CTX *mem_ctx,
4620 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
4621 req, struct cli_smb2_get_reparse_point_fnum_state);
4623 if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
4624 tevent_req_received(req);
4625 return state->cli->raw_status;
4627 *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
4628 if (output->data == NULL) {
4629 tevent_req_received(req);
4630 return NT_STATUS_NO_MEMORY;
4632 tevent_req_received(req);
4633 return NT_STATUS_OK;