2 Unix SMB/CIFS implementation.
4 Copyright (C) Jeremy Allison 2013
5 Copyright (C) Volker Lendecke 2013
6 Copyright (C) Stefan Metzmacher 2013
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This code is a thin wrapper around the existing
24 cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c,
25 but allows the handles to be mapped to uint16_t fnums,
26 which are easier for smbclient to use.
31 #include "async_smb.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "cli_smb2_fnum.h"
36 #include "../libcli/smb/smb2_create_blob.h"
37 #include "libsmb/proto.h"
38 #include "lib/util/tevent_ntstatus.h"
39 #include "../libcli/security/security.h"
40 #include "../librpc/gen_ndr/ndr_security.h"
41 #include "lib/util_ea.h"
42 #include "librpc/gen_ndr/ndr_ioctl.h"
44 #include "librpc/gen_ndr/ndr_quota.h"
47 uint64_t fid_persistent;
48 uint64_t fid_volatile;
52 * Handle mapping code.
55 /***************************************************************
56 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
57 Ensures handle is owned by cli struct.
58 ***************************************************************/
60 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
61 const struct smb2_hnd *ph, /* In */
62 uint16_t *pfnum) /* Out */
65 struct idr_context *idp = cli->smb2.open_handles;
66 struct smb2_hnd *owned_h = talloc_memdup(cli,
68 sizeof(struct smb2_hnd));
70 if (owned_h == NULL) {
71 return NT_STATUS_NO_MEMORY;
76 cli->smb2.open_handles = idr_init(cli);
77 if (cli->smb2.open_handles == NULL) {
79 return NT_STATUS_NO_MEMORY;
81 idp = cli->smb2.open_handles;
84 ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
87 return NT_STATUS_NO_MEMORY;
90 *pfnum = (uint16_t)ret;
94 /***************************************************************
95 Return the smb2_hnd pointer associated with the given fnum.
96 ***************************************************************/
98 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
99 uint16_t fnum, /* In */
100 struct smb2_hnd **pph) /* Out */
102 struct idr_context *idp = cli->smb2.open_handles;
105 return NT_STATUS_INVALID_PARAMETER;
107 *pph = (struct smb2_hnd *)idr_find(idp, fnum);
109 return NT_STATUS_INVALID_HANDLE;
114 /***************************************************************
115 Delete the fnum to smb2_hnd mapping. Zeros out handle on
117 ***************************************************************/
119 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
120 struct smb2_hnd **pph, /* In */
121 uint16_t fnum) /* In */
123 struct idr_context *idp = cli->smb2.open_handles;
127 return NT_STATUS_INVALID_PARAMETER;
130 ph = (struct smb2_hnd *)idr_find(idp, fnum);
132 return NT_STATUS_INVALID_PARAMETER;
134 idr_remove(idp, fnum);
139 /***************************************************************
141 ***************************************************************/
143 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
145 if (create_flags & REQUEST_BATCH_OPLOCK) {
146 return SMB2_OPLOCK_LEVEL_BATCH;
147 } else if (create_flags & REQUEST_OPLOCK) {
148 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
151 /* create_flags doesn't do a level2 request. */
152 return SMB2_OPLOCK_LEVEL_NONE;
155 /***************************************************************
156 Small wrapper that allows SMB2 create to return a uint16_t fnum.
157 ***************************************************************/
159 struct cli_smb2_create_fnum_state {
160 struct cli_state *cli;
161 struct smb_create_returns cr;
163 struct tevent_req *subreq;
166 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
167 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
169 struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
170 struct tevent_context *ev,
171 struct cli_state *cli,
173 uint32_t create_flags,
174 uint32_t impersonation_level,
175 uint32_t desired_access,
176 uint32_t file_attributes,
177 uint32_t share_access,
178 uint32_t create_disposition,
179 uint32_t create_options)
181 struct tevent_req *req, *subreq;
182 struct cli_smb2_create_fnum_state *state;
183 size_t fname_len = 0;
184 const char *startp = NULL;
185 const char *endp = NULL;
186 time_t tstamp = (time_t)0;
187 struct smb2_create_blobs *cblobs = NULL;
189 req = tevent_req_create(mem_ctx, &state,
190 struct cli_smb2_create_fnum_state);
196 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
197 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
198 return tevent_req_post(req, ev);
201 if (cli->backup_intent) {
202 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
205 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
206 fname_len = strlen(fname);
207 if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
208 size_t len_before_gmt = startp - fname;
209 size_t len_after_gmt = fname + fname_len - endp;
214 char *new_fname = talloc_array(state, char,
215 len_before_gmt + len_after_gmt + 1);
217 if (tevent_req_nomem(new_fname, req)) {
218 return tevent_req_post(req, ev);
221 memcpy(new_fname, fname, len_before_gmt);
222 memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
224 fname_len = len_before_gmt + len_after_gmt;
226 unix_to_nt_time(&ntt, tstamp);
227 twrp_blob = data_blob_const((const void *)&ntt, 8);
229 cblobs = talloc_zero(state, struct smb2_create_blobs);
230 if (tevent_req_nomem(cblobs, req)) {
231 return tevent_req_post(req, ev);
234 status = smb2_create_blob_add(state, cblobs,
235 SMB2_CREATE_TAG_TWRP, twrp_blob);
236 if (!NT_STATUS_IS_OK(status)) {
237 tevent_req_nterror(req, status);
238 return tevent_req_post(req, ev);
242 /* SMB2 is pickier about pathnames. Ensure it doesn't
244 if (*fname == '\\') {
249 /* Or end in a '\' */
250 if (fname_len > 0 && fname[fname_len-1] == '\\') {
251 char *new_fname = talloc_strdup(state, fname);
252 if (tevent_req_nomem(new_fname, req)) {
253 return tevent_req_post(req, ev);
255 new_fname[fname_len-1] = '\0';
259 subreq = smb2cli_create_send(state, ev,
265 flags_to_smb2_oplock(create_flags),
273 if (tevent_req_nomem(subreq, req)) {
274 return tevent_req_post(req, ev);
276 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
278 state->subreq = subreq;
279 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
284 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
286 struct tevent_req *req = tevent_req_callback_data(
287 subreq, struct tevent_req);
288 struct cli_smb2_create_fnum_state *state = tevent_req_data(
289 req, struct cli_smb2_create_fnum_state);
293 status = smb2cli_create_recv(subreq, &h.fid_persistent,
294 &h.fid_volatile, &state->cr, NULL, NULL);
296 if (tevent_req_nterror(req, status)) {
300 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
301 if (tevent_req_nterror(req, status)) {
304 tevent_req_done(req);
307 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
309 struct cli_smb2_create_fnum_state *state = tevent_req_data(
310 req, struct cli_smb2_create_fnum_state);
311 return tevent_req_cancel(state->subreq);
314 NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum,
315 struct smb_create_returns *cr)
317 struct cli_smb2_create_fnum_state *state = tevent_req_data(
318 req, struct cli_smb2_create_fnum_state);
321 if (tevent_req_is_nterror(req, &status)) {
322 state->cli->raw_status = status;
326 *pfnum = state->fnum;
331 state->cli->raw_status = NT_STATUS_OK;
335 NTSTATUS cli_smb2_create_fnum(struct cli_state *cli,
337 uint32_t create_flags,
338 uint32_t 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(frame, ev, cli, fname, create_flags,
365 desired_access, file_attributes,
366 share_access, create_disposition,
371 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
374 status = cli_smb2_create_fnum_recv(req, pfid, cr);
380 /***************************************************************
381 Small wrapper that allows SMB2 close to use a uint16_t fnum.
382 ***************************************************************/
384 struct cli_smb2_close_fnum_state {
385 struct cli_state *cli;
390 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
392 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
393 struct tevent_context *ev,
394 struct cli_state *cli,
397 struct tevent_req *req, *subreq;
398 struct cli_smb2_close_fnum_state *state;
401 req = tevent_req_create(mem_ctx, &state,
402 struct cli_smb2_close_fnum_state);
409 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
410 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
411 return tevent_req_post(req, ev);
414 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
415 if (tevent_req_nterror(req, status)) {
416 return tevent_req_post(req, ev);
419 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
420 cli->smb2.session, cli->smb2.tcon,
421 0, state->ph->fid_persistent,
422 state->ph->fid_volatile);
423 if (tevent_req_nomem(subreq, req)) {
424 return tevent_req_post(req, ev);
426 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
430 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
432 struct tevent_req *req = tevent_req_callback_data(
433 subreq, struct tevent_req);
434 struct cli_smb2_close_fnum_state *state = tevent_req_data(
435 req, struct cli_smb2_close_fnum_state);
438 status = smb2cli_close_recv(subreq);
439 if (tevent_req_nterror(req, status)) {
443 /* Delete the fnum -> handle mapping. */
444 status = delete_smb2_handle_mapping(state->cli, &state->ph,
446 if (tevent_req_nterror(req, status)) {
449 tevent_req_done(req);
452 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
454 struct cli_smb2_close_fnum_state *state = tevent_req_data(
455 req, struct cli_smb2_close_fnum_state);
456 NTSTATUS status = NT_STATUS_OK;
458 if (tevent_req_is_nterror(req, &status)) {
459 state->cli->raw_status = status;
461 tevent_req_received(req);
465 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
467 TALLOC_CTX *frame = talloc_stackframe();
468 struct tevent_context *ev;
469 struct tevent_req *req;
470 NTSTATUS status = NT_STATUS_NO_MEMORY;
472 if (smbXcli_conn_has_async_calls(cli->conn)) {
474 * Can't use sync call while an async call is in flight
476 status = NT_STATUS_INVALID_PARAMETER;
479 ev = samba_tevent_context_init(frame);
483 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
487 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
490 status = cli_smb2_close_fnum_recv(req);
496 struct cli_smb2_delete_on_close_state {
497 struct cli_state *cli;
504 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
506 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
507 struct tevent_context *ev,
508 struct cli_state *cli,
512 struct tevent_req *req = NULL;
513 struct cli_smb2_delete_on_close_state *state = NULL;
514 struct tevent_req *subreq = NULL;
515 uint8_t in_info_type;
516 uint8_t in_file_info_class;
519 req = tevent_req_create(mem_ctx, &state,
520 struct cli_smb2_delete_on_close_state);
527 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
528 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
529 return tevent_req_post(req, ev);
532 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
533 if (tevent_req_nterror(req, status)) {
534 return tevent_req_post(req, ev);
538 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
539 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
542 in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
543 /* Setup data array. */
544 SCVAL(&state->data[0], 0, flag ? 1 : 0);
545 state->inbuf.data = &state->data[0];
546 state->inbuf.length = 1;
548 subreq = smb2cli_set_info_send(state, ev,
555 &state->inbuf, /* in_input_buffer */
556 0, /* in_additional_info */
557 state->ph->fid_persistent,
558 state->ph->fid_volatile);
559 if (tevent_req_nomem(subreq, req)) {
560 return tevent_req_post(req, ev);
562 tevent_req_set_callback(subreq,
563 cli_smb2_delete_on_close_done,
568 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
570 NTSTATUS status = smb2cli_set_info_recv(subreq);
571 tevent_req_simple_finish_ntstatus(subreq, status);
574 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
576 struct cli_smb2_delete_on_close_state *state =
578 struct cli_smb2_delete_on_close_state);
581 if (tevent_req_is_nterror(req, &status)) {
582 state->cli->raw_status = status;
583 tevent_req_received(req);
587 state->cli->raw_status = NT_STATUS_OK;
588 tevent_req_received(req);
592 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
594 TALLOC_CTX *frame = talloc_stackframe();
595 struct tevent_context *ev;
596 struct tevent_req *req;
597 NTSTATUS status = NT_STATUS_NO_MEMORY;
599 if (smbXcli_conn_has_async_calls(cli->conn)) {
601 * Can't use sync call while an async call is in flight
603 status = NT_STATUS_INVALID_PARAMETER;
606 ev = samba_tevent_context_init(frame);
610 req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
614 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
617 status = cli_smb2_delete_on_close_recv(req);
623 /***************************************************************
624 Small wrapper that allows SMB2 to create a directory
626 ***************************************************************/
628 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
633 if (smbXcli_conn_has_async_calls(cli->conn)) {
635 * Can't use sync call while an async call is in flight
637 return NT_STATUS_INVALID_PARAMETER;
640 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
641 return NT_STATUS_INVALID_PARAMETER;
644 status = cli_smb2_create_fnum(cli,
646 0, /* create_flags */
647 SMB2_IMPERSONATION_IMPERSONATION,
648 FILE_READ_ATTRIBUTES, /* desired_access */
649 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
650 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
651 FILE_CREATE, /* create_disposition */
652 FILE_DIRECTORY_FILE, /* create_options */
656 if (!NT_STATUS_IS_OK(status)) {
659 return cli_smb2_close_fnum(cli, fnum);
662 /***************************************************************
663 Small wrapper that allows SMB2 to delete a directory
665 ***************************************************************/
667 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
672 if (smbXcli_conn_has_async_calls(cli->conn)) {
674 * Can't use sync call while an async call is in flight
676 return NT_STATUS_INVALID_PARAMETER;
679 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
680 return NT_STATUS_INVALID_PARAMETER;
683 status = cli_smb2_create_fnum(cli,
685 0, /* create_flags */
686 SMB2_IMPERSONATION_IMPERSONATION,
687 DELETE_ACCESS, /* desired_access */
688 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
689 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
690 FILE_OPEN, /* create_disposition */
691 FILE_DIRECTORY_FILE, /* create_options */
695 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
697 * Naive option to match our SMB1 code. Assume the
698 * symlink path that tripped us up was the last
699 * component and try again. Eventually we will have to
700 * deal with the returned path unprocessed component. JRA.
702 status = cli_smb2_create_fnum(cli,
704 0, /* create_flags */
705 SMB2_IMPERSONATION_IMPERSONATION,
706 DELETE_ACCESS, /* desired_access */
707 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
708 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
709 FILE_OPEN, /* create_disposition */
711 FILE_DELETE_ON_CLOSE|
712 FILE_OPEN_REPARSE_POINT, /* create_options */
717 if (!NT_STATUS_IS_OK(status)) {
721 status = cli_smb2_delete_on_close(cli, fnum, true);
722 if (!NT_STATUS_IS_OK(status)) {
723 cli_smb2_close_fnum(cli, fnum);
727 return cli_smb2_close_fnum(cli, fnum);
730 /***************************************************************
731 Small wrapper that allows SMB2 to unlink a pathname.
733 ***************************************************************/
735 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
740 if (smbXcli_conn_has_async_calls(cli->conn)) {
742 * Can't use sync call while an async call is in flight
744 return NT_STATUS_INVALID_PARAMETER;
747 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
748 return NT_STATUS_INVALID_PARAMETER;
751 status = cli_smb2_create_fnum(cli,
753 0, /* create_flags */
754 SMB2_IMPERSONATION_IMPERSONATION,
755 DELETE_ACCESS, /* desired_access */
756 FILE_ATTRIBUTE_NORMAL, /* file attributes */
757 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
758 FILE_OPEN, /* create_disposition */
759 FILE_DELETE_ON_CLOSE, /* create_options */
763 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
765 * Naive option to match our SMB1 code. Assume the
766 * symlink path that tripped us up was the last
767 * component and try again. Eventually we will have to
768 * deal with the returned path unprocessed component. JRA.
770 status = cli_smb2_create_fnum(cli,
772 0, /* create_flags */
773 SMB2_IMPERSONATION_IMPERSONATION,
774 DELETE_ACCESS, /* desired_access */
775 FILE_ATTRIBUTE_NORMAL, /* file attributes */
776 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
777 FILE_OPEN, /* create_disposition */
778 FILE_DELETE_ON_CLOSE|
779 FILE_OPEN_REPARSE_POINT, /* create_options */
784 if (!NT_STATUS_IS_OK(status)) {
787 return cli_smb2_close_fnum(cli, fnum);
790 /***************************************************************
791 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
792 ***************************************************************/
794 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
795 uint32_t dir_data_length,
796 struct file_info *finfo,
797 uint32_t *next_offset)
803 if (dir_data_length < 4) {
804 return NT_STATUS_INFO_LENGTH_MISMATCH;
807 *next_offset = IVAL(dir_data, 0);
809 if (*next_offset > dir_data_length) {
810 return NT_STATUS_INFO_LENGTH_MISMATCH;
813 if (*next_offset != 0) {
814 /* Ensure we only read what in this record. */
815 dir_data_length = *next_offset;
818 if (dir_data_length < 105) {
819 return NT_STATUS_INFO_LENGTH_MISMATCH;
822 finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
823 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
824 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
825 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
826 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
827 finfo->mode = CVAL(dir_data + 56, 0);
828 namelen = IVAL(dir_data + 60,0);
829 if (namelen > (dir_data_length - 104)) {
830 return NT_STATUS_INFO_LENGTH_MISMATCH;
832 slen = CVAL(dir_data + 68, 0);
834 return NT_STATUS_INFO_LENGTH_MISMATCH;
836 ret = pull_string_talloc(finfo,
838 FLAGS2_UNICODE_STRINGS,
843 if (ret == (size_t)-1) {
844 /* Bad conversion. */
845 return NT_STATUS_INVALID_NETWORK_RESPONSE;
848 ret = pull_string_talloc(finfo,
850 FLAGS2_UNICODE_STRINGS,
855 if (ret == (size_t)-1) {
856 /* Bad conversion. */
857 return NT_STATUS_INVALID_NETWORK_RESPONSE;
862 /*******************************************************************
863 Given a filename - get its directory name
864 ********************************************************************/
866 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
874 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
877 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
888 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
891 (*parent)[len] = '\0';
899 /***************************************************************
900 Wrapper that allows SMB2 to list a directory.
902 ***************************************************************/
904 NTSTATUS cli_smb2_list(struct cli_state *cli,
905 const char *pathname,
907 NTSTATUS (*fn)(const char *,
914 uint16_t fnum = 0xffff;
915 char *parent_dir = NULL;
916 const char *mask = NULL;
917 struct smb2_hnd *ph = NULL;
918 bool processed_file = false;
919 TALLOC_CTX *frame = talloc_stackframe();
920 TALLOC_CTX *subframe = NULL;
922 uint32_t max_trans = smb2cli_conn_max_trans_size(cli->conn);
924 if (smbXcli_conn_has_async_calls(cli->conn)) {
926 * Can't use sync call while an async call is in flight
928 status = NT_STATUS_INVALID_PARAMETER;
932 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
933 status = NT_STATUS_INVALID_PARAMETER;
937 /* Get the directory name. */
938 if (!windows_parent_dirname(frame,
942 status = NT_STATUS_NO_MEMORY;
946 mask_has_wild = ms_has_wild(mask);
948 status = cli_smb2_create_fnum(cli,
950 0, /* create_flags */
951 SMB2_IMPERSONATION_IMPERSONATION,
952 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
953 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
954 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
955 FILE_OPEN, /* create_disposition */
956 FILE_DIRECTORY_FILE, /* create_options */
960 if (!NT_STATUS_IS_OK(status)) {
964 status = map_fnum_to_smb2_handle(cli,
967 if (!NT_STATUS_IS_OK(status)) {
972 uint8_t *dir_data = NULL;
973 uint32_t dir_data_length = 0;
974 uint32_t next_offset = 0;
975 subframe = talloc_stackframe();
977 status = smb2cli_query_directory(cli->conn,
981 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
992 if (!NT_STATUS_IS_OK(status)) {
993 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1000 struct file_info *finfo = talloc_zero(subframe,
1003 if (finfo == NULL) {
1004 status = NT_STATUS_NO_MEMORY;
1008 status = parse_finfo_id_both_directory_info(dir_data,
1013 if (!NT_STATUS_IS_OK(status)) {
1017 if (dir_check_ftype((uint32_t)finfo->mode,
1018 (uint32_t)attribute)) {
1020 * Only process if attributes match.
1021 * On SMB1 server does this, so on
1022 * SMB2 we need to emulate in the
1025 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1027 processed_file = true;
1029 status = fn(cli->dfs_mountpoint,
1034 if (!NT_STATUS_IS_OK(status)) {
1041 /* Move to next entry. */
1043 dir_data += next_offset;
1044 dir_data_length -= next_offset;
1046 } while (next_offset != 0);
1048 TALLOC_FREE(subframe);
1050 if (!mask_has_wild) {
1052 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1053 * when handed a non-wildcard path. Do it
1054 * for the server (with a non-wildcard path
1055 * there should only ever be one file returned.
1057 status = STATUS_NO_MORE_FILES;
1061 } while (NT_STATUS_IS_OK(status));
1063 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1064 status = NT_STATUS_OK;
1067 if (NT_STATUS_IS_OK(status) && !processed_file) {
1069 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1070 * if no files match. Emulate this in the client.
1072 status = NT_STATUS_NO_SUCH_FILE;
1077 if (fnum != 0xffff) {
1078 cli_smb2_close_fnum(cli, fnum);
1081 cli->raw_status = status;
1083 TALLOC_FREE(subframe);
1088 /***************************************************************
1089 Wrapper that allows SMB2 to query a path info (basic level).
1091 ***************************************************************/
1093 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1095 SMB_STRUCT_STAT *sbuf,
1096 uint32_t *attributes)
1099 struct smb_create_returns cr;
1100 uint16_t fnum = 0xffff;
1101 size_t namelen = strlen(name);
1103 if (smbXcli_conn_has_async_calls(cli->conn)) {
1105 * Can't use sync call while an async call is in flight
1107 return NT_STATUS_INVALID_PARAMETER;
1110 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1111 return NT_STATUS_INVALID_PARAMETER;
1114 /* SMB2 is pickier about pathnames. Ensure it doesn't
1116 if (namelen > 0 && name[namelen-1] == '\\') {
1117 char *modname = talloc_strdup(talloc_tos(), name);
1118 modname[namelen-1] = '\0';
1122 /* This is commonly used as a 'cd'. Try qpathinfo on
1123 a directory handle first. */
1125 status = cli_smb2_create_fnum(cli,
1127 0, /* create_flags */
1128 SMB2_IMPERSONATION_IMPERSONATION,
1129 FILE_READ_ATTRIBUTES, /* desired_access */
1130 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1131 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1132 FILE_OPEN, /* create_disposition */
1133 FILE_DIRECTORY_FILE, /* create_options */
1137 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1138 /* Maybe a file ? */
1139 status = cli_smb2_create_fnum(cli,
1141 0, /* create_flags */
1142 SMB2_IMPERSONATION_IMPERSONATION,
1143 FILE_READ_ATTRIBUTES, /* desired_access */
1144 0, /* file attributes */
1145 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1146 FILE_OPEN, /* create_disposition */
1147 0, /* create_options */
1152 if (!NT_STATUS_IS_OK(status)) {
1156 status = cli_smb2_close_fnum(cli, fnum);
1160 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1161 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1162 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1163 sbuf->st_ex_size = cr.end_of_file;
1164 *attributes = cr.file_attributes;
1169 /***************************************************************
1170 Wrapper that allows SMB2 to check if a path is a directory.
1172 ***************************************************************/
1174 NTSTATUS cli_smb2_chkpath(struct cli_state *cli,
1178 uint16_t fnum = 0xffff;
1180 if (smbXcli_conn_has_async_calls(cli->conn)) {
1182 * Can't use sync call while an async call is in flight
1184 return NT_STATUS_INVALID_PARAMETER;
1187 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1188 return NT_STATUS_INVALID_PARAMETER;
1191 /* Ensure this is a directory. */
1192 status = cli_smb2_create_fnum(cli,
1194 0, /* create_flags */
1195 SMB2_IMPERSONATION_IMPERSONATION,
1196 FILE_READ_ATTRIBUTES, /* desired_access */
1197 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1198 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1199 FILE_OPEN, /* create_disposition */
1200 FILE_DIRECTORY_FILE, /* create_options */
1204 if (!NT_STATUS_IS_OK(status)) {
1208 return cli_smb2_close_fnum(cli, fnum);
1211 /***************************************************************
1212 Helper function for pathname operations.
1213 ***************************************************************/
1215 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1217 uint32_t desired_access,
1221 size_t namelen = strlen(name);
1222 TALLOC_CTX *frame = talloc_stackframe();
1223 uint32_t create_options = 0;
1225 /* SMB2 is pickier about pathnames. Ensure it doesn't
1227 if (namelen > 0 && name[namelen-1] == '\\') {
1228 char *modname = talloc_strdup(frame, name);
1229 if (modname == NULL) {
1230 status = NT_STATUS_NO_MEMORY;
1233 modname[namelen-1] = '\0';
1237 /* Try to open a file handle first. */
1238 status = cli_smb2_create_fnum(cli,
1240 0, /* create_flags */
1241 SMB2_IMPERSONATION_IMPERSONATION,
1243 0, /* file attributes */
1244 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1245 FILE_OPEN, /* create_disposition */
1250 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1252 * Naive option to match our SMB1 code. Assume the
1253 * symlink path that tripped us up was the last
1254 * component and try again. Eventually we will have to
1255 * deal with the returned path unprocessed component. JRA.
1257 create_options |= FILE_OPEN_REPARSE_POINT;
1258 status = cli_smb2_create_fnum(cli,
1260 0, /* create_flags */
1261 SMB2_IMPERSONATION_IMPERSONATION,
1263 0, /* file attributes */
1264 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1265 FILE_OPEN, /* create_disposition */
1271 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1272 create_options |= FILE_DIRECTORY_FILE;
1273 status = cli_smb2_create_fnum(cli,
1275 0, /* create_flags */
1276 SMB2_IMPERSONATION_IMPERSONATION,
1278 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1279 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1280 FILE_OPEN, /* create_disposition */
1281 FILE_DIRECTORY_FILE, /* create_options */
1292 /***************************************************************
1293 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1295 ***************************************************************/
1297 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1302 DATA_BLOB outbuf = data_blob_null;
1303 uint16_t fnum = 0xffff;
1304 struct smb2_hnd *ph = NULL;
1305 uint32_t altnamelen = 0;
1306 TALLOC_CTX *frame = talloc_stackframe();
1308 if (smbXcli_conn_has_async_calls(cli->conn)) {
1310 * Can't use sync call while an async call is in flight
1312 status = NT_STATUS_INVALID_PARAMETER;
1316 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1317 status = NT_STATUS_INVALID_PARAMETER;
1321 status = get_fnum_from_path(cli,
1323 FILE_READ_ATTRIBUTES,
1326 if (!NT_STATUS_IS_OK(status)) {
1330 status = map_fnum_to_smb2_handle(cli,
1333 if (!NT_STATUS_IS_OK(status)) {
1337 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1338 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1340 status = smb2cli_query_info(cli->conn,
1344 1, /* in_info_type */
1345 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1346 0xFFFF, /* in_max_output_length */
1347 NULL, /* in_input_buffer */
1348 0, /* in_additional_info */
1355 if (!NT_STATUS_IS_OK(status)) {
1359 /* Parse the reply. */
1360 if (outbuf.length < 4) {
1361 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1365 altnamelen = IVAL(outbuf.data, 0);
1366 if (altnamelen > outbuf.length - 4) {
1367 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1371 if (altnamelen > 0) {
1373 char *short_name = NULL;
1374 ret = pull_string_talloc(frame,
1376 FLAGS2_UNICODE_STRINGS,
1381 if (ret == (size_t)-1) {
1382 /* Bad conversion. */
1383 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1387 fstrcpy(alt_name, short_name);
1392 status = NT_STATUS_OK;
1396 if (fnum != 0xffff) {
1397 cli_smb2_close_fnum(cli, fnum);
1400 cli->raw_status = status;
1407 /***************************************************************
1408 Wrapper that allows SMB2 to query a fnum info (basic level).
1410 ***************************************************************/
1412 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1416 struct timespec *create_time,
1417 struct timespec *access_time,
1418 struct timespec *write_time,
1419 struct timespec *change_time,
1423 DATA_BLOB outbuf = data_blob_null;
1424 struct smb2_hnd *ph = NULL;
1425 TALLOC_CTX *frame = talloc_stackframe();
1427 if (smbXcli_conn_has_async_calls(cli->conn)) {
1429 * Can't use sync call while an async call is in flight
1431 status = NT_STATUS_INVALID_PARAMETER;
1435 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1436 status = NT_STATUS_INVALID_PARAMETER;
1440 status = map_fnum_to_smb2_handle(cli,
1443 if (!NT_STATUS_IS_OK(status)) {
1447 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1448 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1450 status = smb2cli_query_info(cli->conn,
1454 1, /* in_info_type */
1455 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1456 0xFFFF, /* in_max_output_length */
1457 NULL, /* in_input_buffer */
1458 0, /* in_additional_info */
1464 if (!NT_STATUS_IS_OK(status)) {
1468 /* Parse the reply. */
1469 if (outbuf.length < 0x60) {
1470 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1475 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1478 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1481 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1484 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1487 uint32_t attr = IVAL(outbuf.data, 0x20);
1488 *mode = (uint16_t)attr;
1491 uint64_t file_size = BVAL(outbuf.data, 0x30);
1492 *size = (off_t)file_size;
1495 uint64_t file_index = BVAL(outbuf.data, 0x40);
1496 *ino = (SMB_INO_T)file_index;
1501 cli->raw_status = status;
1507 /***************************************************************
1508 Wrapper that allows SMB2 to query an fnum.
1509 Implement on top of cli_smb2_qfileinfo_basic().
1511 ***************************************************************/
1513 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1517 time_t *change_time,
1518 time_t *access_time,
1521 struct timespec access_time_ts;
1522 struct timespec write_time_ts;
1523 struct timespec change_time_ts;
1524 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1534 cli->raw_status = status;
1536 if (!NT_STATUS_IS_OK(status)) {
1541 *change_time = change_time_ts.tv_sec;
1544 *access_time = access_time_ts.tv_sec;
1547 *write_time = write_time_ts.tv_sec;
1549 return NT_STATUS_OK;
1552 /***************************************************************
1553 Wrapper that allows SMB2 to get pathname attributes.
1555 ***************************************************************/
1557 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1564 uint16_t fnum = 0xffff;
1565 struct smb2_hnd *ph = NULL;
1566 TALLOC_CTX *frame = talloc_stackframe();
1568 if (smbXcli_conn_has_async_calls(cli->conn)) {
1570 * Can't use sync call while an async call is in flight
1572 status = NT_STATUS_INVALID_PARAMETER;
1576 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1577 status = NT_STATUS_INVALID_PARAMETER;
1581 status = get_fnum_from_path(cli,
1583 FILE_READ_ATTRIBUTES,
1586 if (!NT_STATUS_IS_OK(status)) {
1590 status = map_fnum_to_smb2_handle(cli,
1593 if (!NT_STATUS_IS_OK(status)) {
1596 status = cli_smb2_getattrE(cli,
1603 if (!NT_STATUS_IS_OK(status)) {
1609 if (fnum != 0xffff) {
1610 cli_smb2_close_fnum(cli, fnum);
1613 cli->raw_status = status;
1619 /***************************************************************
1620 Wrapper that allows SMB2 to query a pathname info (basic level).
1621 Implement on top of cli_smb2_qfileinfo_basic().
1623 ***************************************************************/
1625 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1627 struct timespec *create_time,
1628 struct timespec *access_time,
1629 struct timespec *write_time,
1630 struct timespec *change_time,
1636 struct smb2_hnd *ph = NULL;
1637 uint16_t fnum = 0xffff;
1638 TALLOC_CTX *frame = talloc_stackframe();
1640 if (smbXcli_conn_has_async_calls(cli->conn)) {
1642 * Can't use sync call while an async call is in flight
1644 status = NT_STATUS_INVALID_PARAMETER;
1648 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1649 status = NT_STATUS_INVALID_PARAMETER;
1653 status = get_fnum_from_path(cli,
1655 FILE_READ_ATTRIBUTES,
1658 if (!NT_STATUS_IS_OK(status)) {
1662 status = map_fnum_to_smb2_handle(cli,
1665 if (!NT_STATUS_IS_OK(status)) {
1669 status = cli_smb2_qfileinfo_basic(cli,
1681 if (fnum != 0xffff) {
1682 cli_smb2_close_fnum(cli, fnum);
1685 cli->raw_status = status;
1691 /***************************************************************
1692 Wrapper that allows SMB2 to query pathname streams.
1694 ***************************************************************/
1696 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1698 TALLOC_CTX *mem_ctx,
1699 unsigned int *pnum_streams,
1700 struct stream_struct **pstreams)
1703 struct smb2_hnd *ph = NULL;
1704 uint16_t fnum = 0xffff;
1705 DATA_BLOB outbuf = data_blob_null;
1706 TALLOC_CTX *frame = talloc_stackframe();
1708 if (smbXcli_conn_has_async_calls(cli->conn)) {
1710 * Can't use sync call while an async call is in flight
1712 status = NT_STATUS_INVALID_PARAMETER;
1716 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1717 status = NT_STATUS_INVALID_PARAMETER;
1721 status = get_fnum_from_path(cli,
1723 FILE_READ_ATTRIBUTES,
1726 if (!NT_STATUS_IS_OK(status)) {
1730 status = map_fnum_to_smb2_handle(cli,
1733 if (!NT_STATUS_IS_OK(status)) {
1737 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1738 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1740 status = smb2cli_query_info(cli->conn,
1744 1, /* in_info_type */
1745 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1746 0xFFFF, /* in_max_output_length */
1747 NULL, /* in_input_buffer */
1748 0, /* in_additional_info */
1755 if (!NT_STATUS_IS_OK(status)) {
1759 /* Parse the reply. */
1760 if (!parse_streams_blob(mem_ctx,
1765 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1771 if (fnum != 0xffff) {
1772 cli_smb2_close_fnum(cli, fnum);
1775 cli->raw_status = status;
1781 /***************************************************************
1782 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
1785 ***************************************************************/
1787 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
1789 uint8_t in_info_type,
1790 uint8_t in_file_info_class,
1791 const DATA_BLOB *p_in_data)
1794 uint16_t fnum = 0xffff;
1795 struct smb2_hnd *ph = NULL;
1796 TALLOC_CTX *frame = talloc_stackframe();
1798 if (smbXcli_conn_has_async_calls(cli->conn)) {
1800 * Can't use sync call while an async call is in flight
1802 status = NT_STATUS_INVALID_PARAMETER;
1806 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1807 status = NT_STATUS_INVALID_PARAMETER;
1811 status = get_fnum_from_path(cli,
1813 FILE_WRITE_ATTRIBUTES,
1816 if (!NT_STATUS_IS_OK(status)) {
1820 status = map_fnum_to_smb2_handle(cli,
1823 if (!NT_STATUS_IS_OK(status)) {
1827 status = smb2cli_set_info(cli->conn,
1833 p_in_data, /* in_input_buffer */
1834 0, /* in_additional_info */
1839 if (fnum != 0xffff) {
1840 cli_smb2_close_fnum(cli, fnum);
1843 cli->raw_status = status;
1850 /***************************************************************
1851 Wrapper that allows SMB2 to set pathname attributes.
1853 ***************************************************************/
1855 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1860 uint8_t inbuf_store[40];
1861 DATA_BLOB inbuf = data_blob_null;
1863 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1864 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1866 inbuf.data = inbuf_store;
1867 inbuf.length = sizeof(inbuf_store);
1868 data_blob_clear(&inbuf);
1871 * SMB1 uses attr == 0 to clear all attributes
1872 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
1873 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
1874 * request attribute change.
1876 * SMB2 uses exactly the reverse. Unfortunately as the
1877 * cli_setatr() ABI is exposed inside libsmbclient,
1878 * we must make the SMB2 cli_smb2_setatr() call
1879 * export the same ABI as the SMB1 cli_setatr()
1880 * which calls it. This means reversing the sense
1881 * of the requested attr argument if it's zero
1882 * or FILE_ATTRIBUTE_NORMAL.
1884 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
1888 attr = FILE_ATTRIBUTE_NORMAL;
1889 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
1893 SSVAL(inbuf.data, 32, attr);
1895 put_long_date((char *)inbuf.data + 16,mtime);
1897 /* Set all the other times to -1. */
1898 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1899 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1900 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1902 return cli_smb2_setpathinfo(cli,
1904 1, /* in_info_type */
1905 /* in_file_info_class */
1906 SMB_FILE_BASIC_INFORMATION - 1000,
1911 /***************************************************************
1912 Wrapper that allows SMB2 to set file handle times.
1914 ***************************************************************/
1916 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1923 struct smb2_hnd *ph = NULL;
1924 uint8_t inbuf_store[40];
1925 DATA_BLOB inbuf = data_blob_null;
1927 if (smbXcli_conn_has_async_calls(cli->conn)) {
1929 * Can't use sync call while an async call is in flight
1931 return NT_STATUS_INVALID_PARAMETER;
1934 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1935 return NT_STATUS_INVALID_PARAMETER;
1938 status = map_fnum_to_smb2_handle(cli,
1941 if (!NT_STATUS_IS_OK(status)) {
1945 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1946 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1948 inbuf.data = inbuf_store;
1949 inbuf.length = sizeof(inbuf_store);
1950 data_blob_clear(&inbuf);
1952 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1953 if (change_time != 0) {
1954 put_long_date((char *)inbuf.data + 24, change_time);
1956 if (access_time != 0) {
1957 put_long_date((char *)inbuf.data + 8, access_time);
1959 if (write_time != 0) {
1960 put_long_date((char *)inbuf.data + 16, write_time);
1963 cli->raw_status = smb2cli_set_info(cli->conn,
1967 1, /* in_info_type */
1968 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1969 &inbuf, /* in_input_buffer */
1970 0, /* in_additional_info */
1974 return cli->raw_status;
1977 /***************************************************************
1978 Wrapper that allows SMB2 to query disk attributes (size).
1980 ***************************************************************/
1982 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
1983 uint64_t *bsize, uint64_t *total, uint64_t *avail)
1986 uint16_t fnum = 0xffff;
1987 DATA_BLOB outbuf = data_blob_null;
1988 struct smb2_hnd *ph = NULL;
1989 uint32_t sectors_per_unit = 0;
1990 uint32_t bytes_per_sector = 0;
1991 uint64_t total_size = 0;
1992 uint64_t size_free = 0;
1993 TALLOC_CTX *frame = talloc_stackframe();
1995 if (smbXcli_conn_has_async_calls(cli->conn)) {
1997 * Can't use sync call while an async call is in flight
1999 status = NT_STATUS_INVALID_PARAMETER;
2003 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2004 status = NT_STATUS_INVALID_PARAMETER;
2008 /* First open the top level directory. */
2009 status = cli_smb2_create_fnum(cli,
2011 0, /* create_flags */
2012 SMB2_IMPERSONATION_IMPERSONATION,
2013 FILE_READ_ATTRIBUTES, /* desired_access */
2014 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2015 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2016 FILE_OPEN, /* create_disposition */
2017 FILE_DIRECTORY_FILE, /* create_options */
2021 if (!NT_STATUS_IS_OK(status)) {
2025 status = map_fnum_to_smb2_handle(cli,
2028 if (!NT_STATUS_IS_OK(status)) {
2032 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2033 level 3 (SMB_FS_SIZE_INFORMATION). */
2035 status = smb2cli_query_info(cli->conn,
2039 2, /* in_info_type */
2040 3, /* in_file_info_class */
2041 0xFFFF, /* in_max_output_length */
2042 NULL, /* in_input_buffer */
2043 0, /* in_additional_info */
2049 if (!NT_STATUS_IS_OK(status)) {
2053 /* Parse the reply. */
2054 if (outbuf.length != 24) {
2055 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2059 total_size = BVAL(outbuf.data, 0);
2060 size_free = BVAL(outbuf.data, 8);
2061 sectors_per_unit = IVAL(outbuf.data, 16);
2062 bytes_per_sector = IVAL(outbuf.data, 20);
2065 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2068 *total = total_size;
2074 status = NT_STATUS_OK;
2078 if (fnum != 0xffff) {
2079 cli_smb2_close_fnum(cli, fnum);
2082 cli->raw_status = status;
2088 /***************************************************************
2089 Wrapper that allows SMB2 to query file system sizes.
2091 ***************************************************************/
2093 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2094 uint64_t *total_allocation_units,
2095 uint64_t *caller_allocation_units,
2096 uint64_t *actual_allocation_units,
2097 uint64_t *sectors_per_allocation_unit,
2098 uint64_t *bytes_per_sector)
2101 uint16_t fnum = 0xffff;
2102 DATA_BLOB outbuf = data_blob_null;
2103 struct smb2_hnd *ph = NULL;
2104 TALLOC_CTX *frame = talloc_stackframe();
2106 if (smbXcli_conn_has_async_calls(cli->conn)) {
2108 * Can't use sync call while an async call is in flight
2110 status = NT_STATUS_INVALID_PARAMETER;
2114 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2115 status = NT_STATUS_INVALID_PARAMETER;
2119 /* First open the top level directory. */
2121 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2122 SMB2_IMPERSONATION_IMPERSONATION,
2123 FILE_READ_ATTRIBUTES, /* desired_access */
2124 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2125 FILE_SHARE_READ | FILE_SHARE_WRITE |
2126 FILE_SHARE_DELETE, /* share_access */
2127 FILE_OPEN, /* create_disposition */
2128 FILE_DIRECTORY_FILE, /* create_options */
2132 if (!NT_STATUS_IS_OK(status)) {
2136 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2137 if (!NT_STATUS_IS_OK(status)) {
2141 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2142 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2144 status = smb2cli_query_info(cli->conn,
2148 SMB2_GETINFO_FS, /* in_info_type */
2149 /* in_file_info_class */
2150 SMB_FS_FULL_SIZE_INFORMATION - 1000,
2151 0xFFFF, /* in_max_output_length */
2152 NULL, /* in_input_buffer */
2153 0, /* in_additional_info */
2159 if (!NT_STATUS_IS_OK(status)) {
2163 if (outbuf.length < 32) {
2164 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2168 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2169 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2170 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2171 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2172 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2176 if (fnum != 0xffff) {
2177 cli_smb2_close_fnum(cli, fnum);
2180 cli->raw_status = status;
2186 /***************************************************************
2187 Wrapper that allows SMB2 to query file system attributes.
2189 ***************************************************************/
2191 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2194 uint16_t fnum = 0xffff;
2195 DATA_BLOB outbuf = data_blob_null;
2196 struct smb2_hnd *ph = NULL;
2197 TALLOC_CTX *frame = talloc_stackframe();
2199 if (smbXcli_conn_has_async_calls(cli->conn)) {
2201 * Can't use sync call while an async call is in flight
2203 status = NT_STATUS_INVALID_PARAMETER;
2207 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2208 status = NT_STATUS_INVALID_PARAMETER;
2212 /* First open the top level directory. */
2214 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2215 SMB2_IMPERSONATION_IMPERSONATION,
2216 FILE_READ_ATTRIBUTES, /* desired_access */
2217 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2218 FILE_SHARE_READ | FILE_SHARE_WRITE |
2219 FILE_SHARE_DELETE, /* share_access */
2220 FILE_OPEN, /* create_disposition */
2221 FILE_DIRECTORY_FILE, /* create_options */
2225 if (!NT_STATUS_IS_OK(status)) {
2229 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2230 if (!NT_STATUS_IS_OK(status)) {
2234 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2235 cli->smb2.tcon, 2, /* in_info_type */
2236 5, /* in_file_info_class */
2237 0xFFFF, /* in_max_output_length */
2238 NULL, /* in_input_buffer */
2239 0, /* in_additional_info */
2241 ph->fid_persistent, ph->fid_volatile, frame,
2243 if (!NT_STATUS_IS_OK(status)) {
2247 if (outbuf.length < 12) {
2248 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2252 *fs_attr = IVAL(outbuf.data, 0);
2256 if (fnum != 0xffff) {
2257 cli_smb2_close_fnum(cli, fnum);
2260 cli->raw_status = status;
2266 /***************************************************************
2267 Wrapper that allows SMB2 to query file system volume info.
2269 ***************************************************************/
2271 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2272 TALLOC_CTX *mem_ctx,
2273 char **_volume_name,
2274 uint32_t *pserial_number,
2278 uint16_t fnum = 0xffff;
2279 DATA_BLOB outbuf = data_blob_null;
2280 struct smb2_hnd *ph = NULL;
2282 char *volume_name = NULL;
2283 TALLOC_CTX *frame = talloc_stackframe();
2285 if (smbXcli_conn_has_async_calls(cli->conn)) {
2287 * Can't use sync call while an async call is in flight
2289 status = NT_STATUS_INVALID_PARAMETER;
2293 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2294 status = NT_STATUS_INVALID_PARAMETER;
2298 /* First open the top level directory. */
2300 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2301 SMB2_IMPERSONATION_IMPERSONATION,
2302 FILE_READ_ATTRIBUTES, /* desired_access */
2303 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2304 FILE_SHARE_READ | FILE_SHARE_WRITE |
2305 FILE_SHARE_DELETE, /* share_access */
2306 FILE_OPEN, /* create_disposition */
2307 FILE_DIRECTORY_FILE, /* create_options */
2311 if (!NT_STATUS_IS_OK(status)) {
2315 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2316 if (!NT_STATUS_IS_OK(status)) {
2320 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2321 level 1 (SMB_FS_VOLUME_INFORMATION). */
2323 status = smb2cli_query_info(cli->conn,
2327 SMB2_GETINFO_FS, /* in_info_type */
2328 /* in_file_info_class */
2329 SMB_FS_VOLUME_INFORMATION - 1000,
2330 0xFFFF, /* in_max_output_length */
2331 NULL, /* in_input_buffer */
2332 0, /* in_additional_info */
2338 if (!NT_STATUS_IS_OK(status)) {
2342 if (outbuf.length < 24) {
2343 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2349 ts = interpret_long_date((char *)outbuf.data);
2352 if (pserial_number) {
2353 *pserial_number = IVAL(outbuf.data,8);
2355 nlen = IVAL(outbuf.data,12);
2356 if (nlen + 18 < 18) {
2358 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2362 * The next check is safe as we know outbuf.length >= 24
2365 if (nlen > (outbuf.length - 18)) {
2366 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2370 clistr_pull_talloc(mem_ctx,
2371 (const char *)outbuf.data,
2377 if (volume_name == NULL) {
2378 status = map_nt_error_from_unix(errno);
2382 *_volume_name = volume_name;
2386 if (fnum != 0xffff) {
2387 cli_smb2_close_fnum(cli, fnum);
2390 cli->raw_status = status;
2397 /***************************************************************
2398 Wrapper that allows SMB2 to query a security descriptor.
2400 ***************************************************************/
2402 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2405 TALLOC_CTX *mem_ctx,
2406 struct security_descriptor **ppsd)
2409 DATA_BLOB outbuf = data_blob_null;
2410 struct smb2_hnd *ph = NULL;
2411 struct security_descriptor *lsd = NULL;
2412 TALLOC_CTX *frame = talloc_stackframe();
2414 if (smbXcli_conn_has_async_calls(cli->conn)) {
2416 * Can't use sync call while an async call is in flight
2418 status = NT_STATUS_INVALID_PARAMETER;
2422 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2423 status = NT_STATUS_INVALID_PARAMETER;
2427 status = map_fnum_to_smb2_handle(cli,
2430 if (!NT_STATUS_IS_OK(status)) {
2434 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2436 status = smb2cli_query_info(cli->conn,
2440 3, /* in_info_type */
2441 0, /* in_file_info_class */
2442 0xFFFF, /* in_max_output_length */
2443 NULL, /* in_input_buffer */
2444 sec_info, /* in_additional_info */
2451 if (!NT_STATUS_IS_OK(status)) {
2455 /* Parse the reply. */
2456 status = unmarshall_sec_desc(mem_ctx,
2461 if (!NT_STATUS_IS_OK(status)) {
2473 cli->raw_status = status;
2479 /***************************************************************
2480 Wrapper that allows SMB2 to set a security descriptor.
2482 ***************************************************************/
2484 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
2487 const struct security_descriptor *sd)
2490 DATA_BLOB inbuf = data_blob_null;
2491 struct smb2_hnd *ph = NULL;
2492 TALLOC_CTX *frame = talloc_stackframe();
2494 if (smbXcli_conn_has_async_calls(cli->conn)) {
2496 * Can't use sync call while an async call is in flight
2498 status = NT_STATUS_INVALID_PARAMETER;
2502 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2503 status = NT_STATUS_INVALID_PARAMETER;
2507 status = map_fnum_to_smb2_handle(cli,
2510 if (!NT_STATUS_IS_OK(status)) {
2514 status = marshall_sec_desc(frame,
2519 if (!NT_STATUS_IS_OK(status)) {
2523 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2525 status = smb2cli_set_info(cli->conn,
2529 3, /* in_info_type */
2530 0, /* in_file_info_class */
2531 &inbuf, /* in_input_buffer */
2532 sec_info, /* in_additional_info */
2538 cli->raw_status = status;
2544 /***************************************************************
2545 Wrapper that allows SMB2 to rename a file.
2547 ***************************************************************/
2549 NTSTATUS cli_smb2_rename(struct cli_state *cli,
2550 const char *fname_src,
2551 const char *fname_dst,
2555 DATA_BLOB inbuf = data_blob_null;
2556 uint16_t fnum = 0xffff;
2557 struct smb2_hnd *ph = NULL;
2558 smb_ucs2_t *converted_str = NULL;
2559 size_t converted_size_bytes = 0;
2561 TALLOC_CTX *frame = talloc_stackframe();
2563 if (smbXcli_conn_has_async_calls(cli->conn)) {
2565 * Can't use sync call while an async call is in flight
2567 status = NT_STATUS_INVALID_PARAMETER;
2571 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2572 status = NT_STATUS_INVALID_PARAMETER;
2576 status = get_fnum_from_path(cli,
2581 if (!NT_STATUS_IS_OK(status)) {
2585 status = map_fnum_to_smb2_handle(cli,
2588 if (!NT_STATUS_IS_OK(status)) {
2592 /* SMB2 is pickier about pathnames. Ensure it doesn't
2594 if (*fname_dst == '\\') {
2598 /* SMB2 is pickier about pathnames. Ensure it doesn't
2600 namelen = strlen(fname_dst);
2601 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2602 char *modname = talloc_strdup(frame, fname_dst);
2603 modname[namelen-1] = '\0';
2604 fname_dst = modname;
2607 if (!push_ucs2_talloc(frame,
2610 &converted_size_bytes)) {
2611 status = NT_STATUS_INVALID_PARAMETER;
2615 /* W2K8 insists the dest name is not null
2616 terminated. Remove the last 2 zero bytes
2617 and reduce the name length. */
2619 if (converted_size_bytes < 2) {
2620 status = NT_STATUS_INVALID_PARAMETER;
2623 converted_size_bytes -= 2;
2625 inbuf = data_blob_talloc_zero(frame,
2626 20 + converted_size_bytes);
2627 if (inbuf.data == NULL) {
2628 status = NT_STATUS_NO_MEMORY;
2633 SCVAL(inbuf.data, 0, 1);
2636 SIVAL(inbuf.data, 16, converted_size_bytes);
2637 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2639 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2640 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2642 status = smb2cli_set_info(cli->conn,
2646 1, /* in_info_type */
2647 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2648 &inbuf, /* in_input_buffer */
2649 0, /* in_additional_info */
2655 if (fnum != 0xffff) {
2656 cli_smb2_close_fnum(cli, fnum);
2659 cli->raw_status = status;
2665 /***************************************************************
2666 Wrapper that allows SMB2 to set an EA on a fnum.
2668 ***************************************************************/
2670 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2672 const char *ea_name,
2677 DATA_BLOB inbuf = data_blob_null;
2679 char *ea_name_ascii = NULL;
2681 struct smb2_hnd *ph = NULL;
2682 TALLOC_CTX *frame = talloc_stackframe();
2684 if (smbXcli_conn_has_async_calls(cli->conn)) {
2686 * Can't use sync call while an async call is in flight
2688 status = NT_STATUS_INVALID_PARAMETER;
2692 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2693 status = NT_STATUS_INVALID_PARAMETER;
2697 status = map_fnum_to_smb2_handle(cli,
2700 if (!NT_STATUS_IS_OK(status)) {
2704 /* Marshall the SMB2 EA data. */
2705 if (ea_len > 0xFFFF) {
2706 status = NT_STATUS_INVALID_PARAMETER;
2710 if (!push_ascii_talloc(frame,
2714 status = NT_STATUS_INVALID_PARAMETER;
2718 if (namelen < 2 || namelen > 0xFF) {
2719 status = NT_STATUS_INVALID_PARAMETER;
2723 bloblen = 8 + ea_len + namelen;
2724 /* Round up to a 4 byte boundary. */
2725 bloblen = ((bloblen + 3)&~3);
2727 inbuf = data_blob_talloc_zero(frame, bloblen);
2728 if (inbuf.data == NULL) {
2729 status = NT_STATUS_NO_MEMORY;
2732 /* namelen doesn't include the NULL byte. */
2733 SCVAL(inbuf.data, 5, namelen - 1);
2734 SSVAL(inbuf.data, 6, ea_len);
2735 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2736 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2738 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2739 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2741 status = smb2cli_set_info(cli->conn,
2745 1, /* in_info_type */
2746 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2747 &inbuf, /* in_input_buffer */
2748 0, /* in_additional_info */
2754 cli->raw_status = status;
2760 /***************************************************************
2761 Wrapper that allows SMB2 to set an EA on a pathname.
2763 ***************************************************************/
2765 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2767 const char *ea_name,
2772 uint16_t fnum = 0xffff;
2774 if (smbXcli_conn_has_async_calls(cli->conn)) {
2776 * Can't use sync call while an async call is in flight
2778 status = NT_STATUS_INVALID_PARAMETER;
2782 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2783 status = NT_STATUS_INVALID_PARAMETER;
2787 status = get_fnum_from_path(cli,
2792 if (!NT_STATUS_IS_OK(status)) {
2796 status = cli_set_ea_fnum(cli,
2801 if (!NT_STATUS_IS_OK(status)) {
2807 if (fnum != 0xffff) {
2808 cli_smb2_close_fnum(cli, fnum);
2811 cli->raw_status = status;
2816 /***************************************************************
2817 Wrapper that allows SMB2 to get an EA list on a pathname.
2819 ***************************************************************/
2821 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2825 struct ea_struct **pea_array)
2828 uint16_t fnum = 0xffff;
2829 DATA_BLOB outbuf = data_blob_null;
2830 struct smb2_hnd *ph = NULL;
2831 struct ea_list *ea_list = NULL;
2832 struct ea_list *eal = NULL;
2833 size_t ea_count = 0;
2834 TALLOC_CTX *frame = talloc_stackframe();
2839 if (smbXcli_conn_has_async_calls(cli->conn)) {
2841 * Can't use sync call while an async call is in flight
2843 status = NT_STATUS_INVALID_PARAMETER;
2847 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2848 status = NT_STATUS_INVALID_PARAMETER;
2852 status = get_fnum_from_path(cli,
2857 if (!NT_STATUS_IS_OK(status)) {
2861 status = map_fnum_to_smb2_handle(cli,
2864 if (!NT_STATUS_IS_OK(status)) {
2868 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2869 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2871 status = smb2cli_query_info(cli->conn,
2875 1, /* in_info_type */
2876 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2877 0xFFFF, /* in_max_output_length */
2878 NULL, /* in_input_buffer */
2879 0, /* in_additional_info */
2886 if (!NT_STATUS_IS_OK(status)) {
2890 /* Parse the reply. */
2891 ea_list = read_nttrans_ea_list(ctx,
2892 (const char *)outbuf.data,
2894 if (ea_list == NULL) {
2895 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2899 /* Convert to an array. */
2900 for (eal = ea_list; eal; eal = eal->next) {
2905 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2906 if (*pea_array == NULL) {
2907 status = NT_STATUS_NO_MEMORY;
2911 for (eal = ea_list; eal; eal = eal->next) {
2912 (*pea_array)[ea_count++] = eal->ea;
2914 *pnum_eas = ea_count;
2919 if (fnum != 0xffff) {
2920 cli_smb2_close_fnum(cli, fnum);
2923 cli->raw_status = status;
2929 /***************************************************************
2930 Wrapper that allows SMB2 to get user quota.
2932 ***************************************************************/
2934 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
2936 SMB_NTQUOTA_STRUCT *pqt)
2939 DATA_BLOB inbuf = data_blob_null;
2940 DATA_BLOB info_blob = data_blob_null;
2941 DATA_BLOB outbuf = data_blob_null;
2942 struct smb2_hnd *ph = NULL;
2943 TALLOC_CTX *frame = talloc_stackframe();
2945 unsigned int offset;
2946 struct smb2_query_quota_info query = {0};
2947 struct file_get_quota_info info = {0};
2948 enum ndr_err_code err;
2949 struct ndr_push *ndr_push = NULL;
2951 if (smbXcli_conn_has_async_calls(cli->conn)) {
2953 * Can't use sync call while an async call is in flight
2955 status = NT_STATUS_INVALID_PARAMETER;
2959 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2960 status = NT_STATUS_INVALID_PARAMETER;
2964 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2965 if (!NT_STATUS_IS_OK(status)) {
2969 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
2971 query.return_single = 1;
2973 info.next_entry_offset = 0;
2974 info.sid_length = sid_len;
2975 info.sid = pqt->sid;
2977 err = ndr_push_struct_blob(
2981 (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
2983 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
2984 status = NT_STATUS_INTERNAL_ERROR;
2988 query.sid_list_length = info_blob.length;
2989 ndr_push = ndr_push_init_ctx(frame);
2991 status = NT_STATUS_NO_MEMORY;
2995 err = ndr_push_smb2_query_quota_info(ndr_push,
2996 NDR_SCALARS | NDR_BUFFERS,
2999 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3000 status = NT_STATUS_INTERNAL_ERROR;
3004 err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3007 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3008 status = NT_STATUS_INTERNAL_ERROR;
3011 inbuf.data = ndr_push->data;
3012 inbuf.length = ndr_push->offset;
3014 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
3015 cli->smb2.tcon, 4, /* in_info_type */
3016 0, /* in_file_info_class */
3017 0xFFFF, /* in_max_output_length */
3018 &inbuf, /* in_input_buffer */
3019 0, /* in_additional_info */
3021 ph->fid_persistent, ph->fid_volatile, frame,
3024 if (!NT_STATUS_IS_OK(status)) {
3028 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3030 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3031 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3035 cli->raw_status = status;
3041 /***************************************************************
3042 Wrapper that allows SMB2 to list user quota.
3044 ***************************************************************/
3046 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3047 TALLOC_CTX *mem_ctx,
3049 SMB_NTQUOTA_LIST **pqt_list,
3053 DATA_BLOB inbuf = data_blob_null;
3054 DATA_BLOB outbuf = data_blob_null;
3055 struct smb2_hnd *ph = NULL;
3056 TALLOC_CTX *frame = talloc_stackframe();
3057 struct smb2_query_quota_info info = {0};
3058 enum ndr_err_code err;
3060 if (smbXcli_conn_has_async_calls(cli->conn)) {
3062 * Can't use sync call while an async call is in flight
3064 status = NT_STATUS_INVALID_PARAMETER;
3068 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3069 status = NT_STATUS_INVALID_PARAMETER;
3073 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3074 if (!NT_STATUS_IS_OK(status)) {
3079 info.restart_scan = first ? 1 : 0;
3081 err = ndr_push_struct_blob(
3085 (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3087 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3088 status = NT_STATUS_INTERNAL_ERROR;
3092 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
3093 cli->smb2.tcon, 4, /* in_info_type */
3094 0, /* in_file_info_class */
3095 0xFFFF, /* in_max_output_length */
3096 &inbuf, /* in_input_buffer */
3097 0, /* in_additional_info */
3099 ph->fid_persistent, ph->fid_volatile, frame,
3103 * safeguard against panic from calling parse_user_quota_list with
3106 if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3107 status = NT_STATUS_NO_MORE_ENTRIES;
3110 if (!NT_STATUS_IS_OK(status)) {
3114 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3118 cli->raw_status = status;
3124 /***************************************************************
3125 Wrapper that allows SMB2 to get file system quota.
3127 ***************************************************************/
3129 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3131 SMB_NTQUOTA_STRUCT *pqt)
3134 DATA_BLOB outbuf = data_blob_null;
3135 struct smb2_hnd *ph = NULL;
3136 TALLOC_CTX *frame = talloc_stackframe();
3138 if (smbXcli_conn_has_async_calls(cli->conn)) {
3140 * Can't use sync call while an async call is in flight
3142 status = NT_STATUS_INVALID_PARAMETER;
3146 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3147 status = NT_STATUS_INVALID_PARAMETER;
3151 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3152 if (!NT_STATUS_IS_OK(status)) {
3156 status = smb2cli_query_info(
3157 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3158 2, /* in_info_type */
3159 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3160 0xFFFF, /* in_max_output_length */
3161 NULL, /* in_input_buffer */
3162 0, /* in_additional_info */
3164 ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
3166 if (!NT_STATUS_IS_OK(status)) {
3170 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3173 cli->raw_status = status;
3179 /***************************************************************
3180 Wrapper that allows SMB2 to set user quota.
3182 ***************************************************************/
3184 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3186 SMB_NTQUOTA_LIST *qtl)
3189 DATA_BLOB inbuf = data_blob_null;
3190 struct smb2_hnd *ph = NULL;
3191 TALLOC_CTX *frame = talloc_stackframe();
3193 if (smbXcli_conn_has_async_calls(cli->conn)) {
3195 * Can't use sync call while an async call is in flight
3197 status = NT_STATUS_INVALID_PARAMETER;
3201 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3202 status = NT_STATUS_INVALID_PARAMETER;
3206 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3207 if (!NT_STATUS_IS_OK(status)) {
3211 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3212 if (!NT_STATUS_IS_OK(status)) {
3216 status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
3217 cli->smb2.tcon, 4, /* in_info_type */
3218 0, /* in_file_info_class */
3219 &inbuf, /* in_input_buffer */
3220 0, /* in_additional_info */
3221 ph->fid_persistent, ph->fid_volatile);
3224 cli->raw_status = status;
3231 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3233 SMB_NTQUOTA_STRUCT *pqt)
3236 DATA_BLOB inbuf = data_blob_null;
3237 struct smb2_hnd *ph = NULL;
3238 TALLOC_CTX *frame = talloc_stackframe();
3240 if (smbXcli_conn_has_async_calls(cli->conn)) {
3242 * Can't use sync call while an async call is in flight
3244 status = NT_STATUS_INVALID_PARAMETER;
3248 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3249 status = NT_STATUS_INVALID_PARAMETER;
3253 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3254 if (!NT_STATUS_IS_OK(status)) {
3258 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3259 if (!NT_STATUS_IS_OK(status)) {
3263 status = smb2cli_set_info(
3264 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3265 2, /* in_info_type */
3266 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3267 &inbuf, /* in_input_buffer */
3268 0, /* in_additional_info */
3269 ph->fid_persistent, ph->fid_volatile);
3271 cli->raw_status = status;
3277 struct cli_smb2_read_state {
3278 struct tevent_context *ev;
3279 struct cli_state *cli;
3280 struct smb2_hnd *ph;
3281 uint64_t start_offset;
3287 static void cli_smb2_read_done(struct tevent_req *subreq);
3289 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3290 struct tevent_context *ev,
3291 struct cli_state *cli,
3297 struct tevent_req *req, *subreq;
3298 struct cli_smb2_read_state *state;
3300 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3306 state->start_offset = (uint64_t)offset;
3307 state->size = (uint32_t)size;
3308 state->received = 0;
3311 status = map_fnum_to_smb2_handle(cli,
3314 if (tevent_req_nterror(req, status)) {
3315 return tevent_req_post(req, ev);
3318 subreq = smb2cli_read_send(state,
3321 state->cli->timeout,
3322 state->cli->smb2.session,
3323 state->cli->smb2.tcon,
3325 state->start_offset,
3326 state->ph->fid_persistent,
3327 state->ph->fid_volatile,
3328 0, /* minimum_count */
3329 0); /* remaining_bytes */
3331 if (tevent_req_nomem(subreq, req)) {
3332 return tevent_req_post(req, ev);
3334 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3338 static void cli_smb2_read_done(struct tevent_req *subreq)
3340 struct tevent_req *req = tevent_req_callback_data(
3341 subreq, struct tevent_req);
3342 struct cli_smb2_read_state *state = tevent_req_data(
3343 req, struct cli_smb2_read_state);
3346 status = smb2cli_read_recv(subreq, state,
3347 &state->buf, &state->received);
3348 if (tevent_req_nterror(req, status)) {
3352 if (state->received > state->size) {
3353 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3357 tevent_req_done(req);
3360 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
3365 struct cli_smb2_read_state *state = tevent_req_data(
3366 req, struct cli_smb2_read_state);
3368 if (tevent_req_is_nterror(req, &status)) {
3369 state->cli->raw_status = status;
3373 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3374 * better make sure that you copy it away before you talloc_free(req).
3375 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3377 *received = (ssize_t)state->received;
3378 *rcvbuf = state->buf;
3379 state->cli->raw_status = NT_STATUS_OK;
3380 return NT_STATUS_OK;
3383 struct cli_smb2_write_state {
3384 struct tevent_context *ev;
3385 struct cli_state *cli;
3386 struct smb2_hnd *ph;
3394 static void cli_smb2_write_written(struct tevent_req *req);
3396 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
3397 struct tevent_context *ev,
3398 struct cli_state *cli,
3406 struct tevent_req *req, *subreq = NULL;
3407 struct cli_smb2_write_state *state = NULL;
3409 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
3415 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3416 state->flags = (uint32_t)mode;
3418 state->offset = (uint64_t)offset;
3419 state->size = (uint32_t)size;
3422 status = map_fnum_to_smb2_handle(cli,
3425 if (tevent_req_nterror(req, status)) {
3426 return tevent_req_post(req, ev);
3429 subreq = smb2cli_write_send(state,
3432 state->cli->timeout,
3433 state->cli->smb2.session,
3434 state->cli->smb2.tcon,
3437 state->ph->fid_persistent,
3438 state->ph->fid_volatile,
3439 0, /* remaining_bytes */
3440 state->flags, /* flags */
3443 if (tevent_req_nomem(subreq, req)) {
3444 return tevent_req_post(req, ev);
3446 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
3450 static void cli_smb2_write_written(struct tevent_req *subreq)
3452 struct tevent_req *req = tevent_req_callback_data(
3453 subreq, struct tevent_req);
3454 struct cli_smb2_write_state *state = tevent_req_data(
3455 req, struct cli_smb2_write_state);
3459 status = smb2cli_write_recv(subreq, &written);
3460 TALLOC_FREE(subreq);
3461 if (tevent_req_nterror(req, status)) {
3465 state->written = written;
3467 tevent_req_done(req);
3470 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
3473 struct cli_smb2_write_state *state = tevent_req_data(
3474 req, struct cli_smb2_write_state);
3477 if (tevent_req_is_nterror(req, &status)) {
3478 state->cli->raw_status = status;
3479 tevent_req_received(req);
3483 if (pwritten != NULL) {
3484 *pwritten = (size_t)state->written;
3486 state->cli->raw_status = NT_STATUS_OK;
3487 tevent_req_received(req);
3488 return NT_STATUS_OK;
3491 /***************************************************************
3492 Wrapper that allows SMB2 async write using an fnum.
3493 This is mostly cut-and-paste from Volker's code inside
3494 source3/libsmb/clireadwrite.c, adapted for SMB2.
3496 Done this way so I can reuse all the logic inside cli_push()
3498 ***************************************************************/
3500 struct cli_smb2_writeall_state {
3501 struct tevent_context *ev;
3502 struct cli_state *cli;
3503 struct smb2_hnd *ph;
3511 static void cli_smb2_writeall_written(struct tevent_req *req);
3513 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
3514 struct tevent_context *ev,
3515 struct cli_state *cli,
3523 struct tevent_req *req, *subreq = NULL;
3524 struct cli_smb2_writeall_state *state = NULL;
3529 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
3535 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3536 state->flags = (uint32_t)mode;
3538 state->offset = (uint64_t)offset;
3539 state->size = (uint32_t)size;
3542 status = map_fnum_to_smb2_handle(cli,
3545 if (tevent_req_nterror(req, status)) {
3546 return tevent_req_post(req, ev);
3549 to_write = state->size;
3550 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3551 to_write = MIN(max_size, to_write);
3552 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3554 to_write = MIN(max_size, to_write);
3557 subreq = smb2cli_write_send(state,
3560 state->cli->timeout,
3561 state->cli->smb2.session,
3562 state->cli->smb2.tcon,
3565 state->ph->fid_persistent,
3566 state->ph->fid_volatile,
3567 0, /* remaining_bytes */
3568 state->flags, /* flags */
3569 state->buf + state->written);
3571 if (tevent_req_nomem(subreq, req)) {
3572 return tevent_req_post(req, ev);
3574 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3578 static void cli_smb2_writeall_written(struct tevent_req *subreq)
3580 struct tevent_req *req = tevent_req_callback_data(
3581 subreq, struct tevent_req);
3582 struct cli_smb2_writeall_state *state = tevent_req_data(
3583 req, struct cli_smb2_writeall_state);
3585 uint32_t written, to_write;
3589 status = smb2cli_write_recv(subreq, &written);
3590 TALLOC_FREE(subreq);
3591 if (tevent_req_nterror(req, status)) {
3595 state->written += written;
3597 if (state->written > state->size) {
3598 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3602 to_write = state->size - state->written;
3604 if (to_write == 0) {
3605 tevent_req_done(req);
3609 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3610 to_write = MIN(max_size, to_write);
3611 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3613 to_write = MIN(max_size, to_write);
3616 subreq = smb2cli_write_send(state,
3619 state->cli->timeout,
3620 state->cli->smb2.session,
3621 state->cli->smb2.tcon,
3623 state->offset + state->written,
3624 state->ph->fid_persistent,
3625 state->ph->fid_volatile,
3626 0, /* remaining_bytes */
3627 state->flags, /* flags */
3628 state->buf + state->written);
3630 if (tevent_req_nomem(subreq, req)) {
3633 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3636 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
3639 struct cli_smb2_writeall_state *state = tevent_req_data(
3640 req, struct cli_smb2_writeall_state);
3643 if (tevent_req_is_nterror(req, &status)) {
3644 state->cli->raw_status = status;
3647 if (pwritten != NULL) {
3648 *pwritten = (size_t)state->written;
3650 state->cli->raw_status = NT_STATUS_OK;
3651 return NT_STATUS_OK;
3654 struct cli_smb2_splice_state {
3655 struct tevent_context *ev;
3656 struct cli_state *cli;
3657 struct smb2_hnd *src_ph;
3658 struct smb2_hnd *dst_ph;
3659 int (*splice_cb)(off_t n, void *priv);
3666 struct req_resume_key_rsp resume_rsp;
3667 struct srv_copychunk_copy cc_copy;
3670 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3671 struct tevent_req *req);
3673 static void cli_splice_copychunk_done(struct tevent_req *subreq)
3675 struct tevent_req *req = tevent_req_callback_data(
3676 subreq, struct tevent_req);
3677 struct cli_smb2_splice_state *state =
3678 tevent_req_data(req,
3679 struct cli_smb2_splice_state);
3680 struct smbXcli_conn *conn = state->cli->conn;
3681 DATA_BLOB out_input_buffer = data_blob_null;
3682 DATA_BLOB out_output_buffer = data_blob_null;
3683 struct srv_copychunk_rsp cc_copy_rsp;
3684 enum ndr_err_code ndr_ret;
3687 status = smb2cli_ioctl_recv(subreq, state,
3689 &out_output_buffer);
3690 TALLOC_FREE(subreq);
3691 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
3692 state->resized) && tevent_req_nterror(req, status)) {
3696 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
3697 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
3698 if (ndr_ret != NDR_ERR_SUCCESS) {
3699 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3700 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3704 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
3705 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
3706 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
3707 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
3708 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
3709 tevent_req_nterror(req, status)) {
3713 state->resized = true;
3714 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
3715 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
3717 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3718 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3719 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
3720 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3723 state->src_offset += cc_copy_rsp.total_bytes_written;
3724 state->dst_offset += cc_copy_rsp.total_bytes_written;
3725 state->written += cc_copy_rsp.total_bytes_written;
3726 if (!state->splice_cb(state->written, state->priv)) {
3727 tevent_req_nterror(req, NT_STATUS_CANCELLED);
3732 cli_splice_copychunk_send(state, req);
3735 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3736 struct tevent_req *req)
3738 struct tevent_req *subreq;
3739 enum ndr_err_code ndr_ret;
3740 struct smbXcli_conn *conn = state->cli->conn;
3741 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
3742 off_t src_offset = state->src_offset;
3743 off_t dst_offset = state->dst_offset;
3744 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
3745 state->size - state->written);
3746 DATA_BLOB in_input_buffer = data_blob_null;
3747 DATA_BLOB in_output_buffer = data_blob_null;
3749 if (state->size - state->written == 0) {
3750 tevent_req_done(req);
3754 cc_copy->chunk_count = 0;
3756 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
3757 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
3758 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
3759 smb2cli_conn_cc_chunk_len(conn));
3760 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
3761 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3764 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
3765 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
3766 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
3767 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3770 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3771 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3772 cc_copy->chunk_count++;
3775 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
3776 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
3777 if (ndr_ret != NDR_ERR_SUCCESS) {
3778 DEBUG(0, ("failed to marshall copy chunk req\n"));
3779 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3783 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
3784 state->cli->timeout,
3785 state->cli->smb2.session,
3786 state->cli->smb2.tcon,
3787 state->dst_ph->fid_persistent, /* in_fid_persistent */
3788 state->dst_ph->fid_volatile, /* in_fid_volatile */
3789 FSCTL_SRV_COPYCHUNK_WRITE,
3790 0, /* in_max_input_length */
3792 12, /* in_max_output_length */
3794 SMB2_IOCTL_FLAG_IS_FSCTL);
3795 if (tevent_req_nomem(subreq, req)) {
3798 tevent_req_set_callback(subreq,
3799 cli_splice_copychunk_done,
3803 static void cli_splice_key_done(struct tevent_req *subreq)
3805 struct tevent_req *req = tevent_req_callback_data(
3806 subreq, struct tevent_req);
3807 struct cli_smb2_splice_state *state =
3808 tevent_req_data(req,
3809 struct cli_smb2_splice_state);
3810 enum ndr_err_code ndr_ret;
3813 DATA_BLOB out_input_buffer = data_blob_null;
3814 DATA_BLOB out_output_buffer = data_blob_null;
3816 status = smb2cli_ioctl_recv(subreq, state,
3818 &out_output_buffer);
3819 TALLOC_FREE(subreq);
3820 if (tevent_req_nterror(req, status)) {
3824 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
3825 state, &state->resume_rsp,
3826 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
3827 if (ndr_ret != NDR_ERR_SUCCESS) {
3828 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3829 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3833 memcpy(&state->cc_copy.source_key,
3834 &state->resume_rsp.resume_key,
3835 sizeof state->resume_rsp.resume_key);
3837 cli_splice_copychunk_send(state, req);
3840 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
3841 struct tevent_context *ev,
3842 struct cli_state *cli,
3843 uint16_t src_fnum, uint16_t dst_fnum,
3844 off_t size, off_t src_offset, off_t dst_offset,
3845 int (*splice_cb)(off_t n, void *priv),
3848 struct tevent_req *req;
3849 struct tevent_req *subreq;
3850 struct cli_smb2_splice_state *state;
3852 DATA_BLOB in_input_buffer = data_blob_null;
3853 DATA_BLOB in_output_buffer = data_blob_null;
3855 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
3861 state->splice_cb = splice_cb;
3865 state->src_offset = src_offset;
3866 state->dst_offset = dst_offset;
3867 state->cc_copy.chunks = talloc_array(state,
3868 struct srv_copychunk,
3869 smb2cli_conn_cc_max_chunks(cli->conn));
3870 if (state->cc_copy.chunks == NULL) {
3874 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
3875 if (tevent_req_nterror(req, status))
3876 return tevent_req_post(req, ev);
3878 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
3879 if (tevent_req_nterror(req, status))
3880 return tevent_req_post(req, ev);
3882 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
3886 state->src_ph->fid_persistent, /* in_fid_persistent */
3887 state->src_ph->fid_volatile, /* in_fid_volatile */
3888 FSCTL_SRV_REQUEST_RESUME_KEY,
3889 0, /* in_max_input_length */
3891 32, /* in_max_output_length */
3893 SMB2_IOCTL_FLAG_IS_FSCTL);
3894 if (tevent_req_nomem(subreq, req)) {
3897 tevent_req_set_callback(subreq,
3898 cli_splice_key_done,
3904 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
3906 struct cli_smb2_splice_state *state = tevent_req_data(
3907 req, struct cli_smb2_splice_state);
3910 if (tevent_req_is_nterror(req, &status)) {
3911 state->cli->raw_status = status;
3912 tevent_req_received(req);
3915 if (written != NULL) {
3916 *written = state->written;
3918 state->cli->raw_status = NT_STATUS_OK;
3919 tevent_req_received(req);
3920 return NT_STATUS_OK;
3923 /***************************************************************
3924 SMB2 enum shadow copy data.
3925 ***************************************************************/
3927 struct cli_smb2_shadow_copy_data_fnum_state {
3928 struct cli_state *cli;
3930 struct smb2_hnd *ph;
3931 DATA_BLOB out_input_buffer;
3932 DATA_BLOB out_output_buffer;
3935 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
3937 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
3938 TALLOC_CTX *mem_ctx,
3939 struct tevent_context *ev,
3940 struct cli_state *cli,
3944 struct tevent_req *req, *subreq;
3945 struct cli_smb2_shadow_copy_data_fnum_state *state;
3948 req = tevent_req_create(mem_ctx, &state,
3949 struct cli_smb2_shadow_copy_data_fnum_state);
3954 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3955 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3956 return tevent_req_post(req, ev);
3962 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
3963 if (tevent_req_nterror(req, status)) {
3964 return tevent_req_post(req, ev);
3968 * TODO. Under SMB2 we should send a zero max_output_length
3969 * ioctl to get the required size, then send another ioctl
3970 * to get the data, but the current SMB1 implementation just
3971 * does one roundtrip with a 64K buffer size. Do the same
3975 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
3976 state->cli->timeout,
3977 state->cli->smb2.session,
3978 state->cli->smb2.tcon,
3979 state->ph->fid_persistent, /* in_fid_persistent */
3980 state->ph->fid_volatile, /* in_fid_volatile */
3981 FSCTL_GET_SHADOW_COPY_DATA,
3982 0, /* in_max_input_length */
3983 NULL, /* in_input_buffer */
3985 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
3986 NULL, /* in_output_buffer */
3987 SMB2_IOCTL_FLAG_IS_FSCTL);
3989 if (tevent_req_nomem(subreq, req)) {
3990 return tevent_req_post(req, ev);
3992 tevent_req_set_callback(subreq,
3993 cli_smb2_shadow_copy_data_fnum_done,
3999 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4001 struct tevent_req *req = tevent_req_callback_data(
4002 subreq, struct tevent_req);
4003 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4004 req, struct cli_smb2_shadow_copy_data_fnum_state);
4007 status = smb2cli_ioctl_recv(subreq, state,
4008 &state->out_input_buffer,
4009 &state->out_output_buffer);
4010 TALLOC_FREE(subreq);
4011 if (tevent_req_nterror(req, status)) {
4014 tevent_req_done(req);
4017 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4018 TALLOC_CTX *mem_ctx,
4023 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4024 req, struct cli_smb2_shadow_copy_data_fnum_state);
4025 char **names = NULL;
4026 uint32_t num_names = 0;
4027 uint32_t num_names_returned = 0;
4028 uint32_t dlength = 0;
4030 uint8_t *endp = NULL;
4033 if (tevent_req_is_nterror(req, &status)) {
4037 if (state->out_output_buffer.length < 16) {
4038 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4041 num_names = IVAL(state->out_output_buffer.data, 0);
4042 num_names_returned = IVAL(state->out_output_buffer.data, 4);
4043 dlength = IVAL(state->out_output_buffer.data, 8);
4045 if (num_names > 0x7FFFFFFF) {
4046 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4049 if (get_names == false) {
4050 *pnum_names = (int)num_names;
4051 return NT_STATUS_OK;
4053 if (num_names != num_names_returned) {
4054 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4056 if (dlength + 12 < 12) {
4057 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4060 * NB. The below is an allowable return if there are
4061 * more snapshots than the buffer size we told the
4062 * server we can receive. We currently don't support
4065 if (dlength + 12 > state->out_output_buffer.length) {
4066 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4068 if (state->out_output_buffer.length +
4069 (2 * sizeof(SHADOW_COPY_LABEL)) <
4070 state->out_output_buffer.length) {
4071 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4074 names = talloc_array(mem_ctx, char *, num_names_returned);
4075 if (names == NULL) {
4076 return NT_STATUS_NO_MEMORY;
4079 endp = state->out_output_buffer.data +
4080 state->out_output_buffer.length;
4082 for (i=0; i<num_names_returned; i++) {
4085 size_t converted_size;
4087 src = state->out_output_buffer.data + 12 +
4088 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4090 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4091 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4093 ret = convert_string_talloc(
4094 names, CH_UTF16LE, CH_UNIX,
4095 src, 2 * sizeof(SHADOW_COPY_LABEL),
4096 &names[i], &converted_size);
4099 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4102 *pnum_names = num_names;
4104 return NT_STATUS_OK;
4107 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4108 struct cli_state *cli,
4114 TALLOC_CTX *frame = talloc_stackframe();
4115 struct tevent_context *ev;
4116 struct tevent_req *req;
4117 NTSTATUS status = NT_STATUS_NO_MEMORY;
4119 if (smbXcli_conn_has_async_calls(cli->conn)) {
4121 * Can't use sync call while an async call is in flight
4123 status = NT_STATUS_INVALID_PARAMETER;
4126 ev = samba_tevent_context_init(frame);
4130 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4138 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4141 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4147 cli->raw_status = status;
4153 /***************************************************************
4154 Wrapper that allows SMB2 to truncate a file.
4156 ***************************************************************/
4158 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4163 DATA_BLOB inbuf = data_blob_null;
4164 struct smb2_hnd *ph = NULL;
4165 TALLOC_CTX *frame = talloc_stackframe();
4167 if (smbXcli_conn_has_async_calls(cli->conn)) {
4169 * Can't use sync call while an async call is in flight
4171 status = NT_STATUS_INVALID_PARAMETER;
4175 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4176 status = NT_STATUS_INVALID_PARAMETER;
4180 status = map_fnum_to_smb2_handle(cli,
4183 if (!NT_STATUS_IS_OK(status)) {
4187 inbuf = data_blob_talloc_zero(frame, 8);
4188 if (inbuf.data == NULL) {
4189 status = NT_STATUS_NO_MEMORY;
4193 SBVAL(inbuf.data, 0, newsize);
4195 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4196 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4198 status = smb2cli_set_info(cli->conn,
4202 1, /* in_info_type */
4203 /* in_file_info_class */
4204 SMB_FILE_END_OF_FILE_INFORMATION - 1000,
4205 &inbuf, /* in_input_buffer */
4206 0, /* in_additional_info */
4212 cli->raw_status = status;
4218 struct cli_smb2_notify_state {
4219 struct tevent_req *subreq;
4220 struct notify_change *changes;
4224 static void cli_smb2_notify_done(struct tevent_req *subreq);
4225 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4227 struct tevent_req *cli_smb2_notify_send(
4228 TALLOC_CTX *mem_ctx,
4229 struct tevent_context *ev,
4230 struct cli_state *cli,
4232 uint32_t buffer_size,
4233 uint32_t completion_filter,
4236 struct tevent_req *req = NULL;
4237 struct cli_smb2_notify_state *state = NULL;
4238 struct smb2_hnd *ph = NULL;
4241 req = tevent_req_create(mem_ctx, &state,
4242 struct cli_smb2_notify_state);
4247 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4248 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4249 return tevent_req_post(req, ev);
4252 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4253 if (tevent_req_nterror(req, status)) {
4254 return tevent_req_post(req, ev);
4257 state->subreq = smb2cli_notify_send(
4269 if (tevent_req_nomem(state->subreq, req)) {
4270 return tevent_req_post(req, ev);
4272 tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4273 tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4277 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4279 struct cli_smb2_notify_state *state = tevent_req_data(
4280 req, struct cli_smb2_notify_state);
4283 ok = tevent_req_cancel(state->subreq);
4287 static void cli_smb2_notify_done(struct tevent_req *subreq)
4289 struct tevent_req *req = tevent_req_callback_data(
4290 subreq, struct tevent_req);
4291 struct cli_smb2_notify_state *state = tevent_req_data(
4292 req, struct cli_smb2_notify_state);
4298 status = smb2cli_notify_recv(subreq, state, &base, &len);
4299 TALLOC_FREE(subreq);
4301 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4302 tevent_req_done(req);
4305 if (tevent_req_nterror(req, status)) {
4311 while (len - ofs >= 12) {
4312 struct notify_change *tmp;
4313 struct notify_change *c;
4314 uint32_t next_ofs = IVAL(base, ofs);
4315 uint32_t file_name_length = IVAL(base, ofs+8);
4319 tmp = talloc_realloc(
4322 struct notify_change,
4323 state->num_changes + 1);
4324 if (tevent_req_nomem(tmp, req)) {
4327 state->changes = tmp;
4328 c = &state->changes[state->num_changes];
4329 state->num_changes += 1;
4331 if (smb_buffer_oob(len, ofs, next_ofs) ||
4332 smb_buffer_oob(len, ofs+12, file_name_length)) {
4334 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4338 c->action = IVAL(base, ofs+4);
4340 ok = convert_string_talloc(
4350 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4354 if (next_ofs == 0) {
4360 tevent_req_done(req);
4363 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
4364 TALLOC_CTX *mem_ctx,
4365 struct notify_change **pchanges,
4366 uint32_t *pnum_changes)
4368 struct cli_smb2_notify_state *state = tevent_req_data(
4369 req, struct cli_smb2_notify_state);
4372 if (tevent_req_is_nterror(req, &status)) {
4375 *pchanges = talloc_move(mem_ctx, &state->changes);
4376 *pnum_changes = state->num_changes;
4377 return NT_STATUS_OK;
4380 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
4381 uint32_t buffer_size, uint32_t completion_filter,
4382 bool recursive, TALLOC_CTX *mem_ctx,
4383 struct notify_change **pchanges,
4384 uint32_t *pnum_changes)
4386 TALLOC_CTX *frame = talloc_stackframe();
4387 struct tevent_context *ev;
4388 struct tevent_req *req;
4389 NTSTATUS status = NT_STATUS_NO_MEMORY;
4391 if (smbXcli_conn_has_async_calls(cli->conn)) {
4393 * Can't use sync call while an async call is in flight
4395 status = NT_STATUS_INVALID_PARAMETER;
4398 ev = samba_tevent_context_init(frame);
4402 req = cli_smb2_notify_send(
4413 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4416 status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
4422 struct cli_smb2_set_reparse_point_fnum_state {
4423 struct cli_state *cli;
4425 struct smb2_hnd *ph;
4426 DATA_BLOB input_buffer;
4429 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
4431 struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
4432 TALLOC_CTX *mem_ctx,
4433 struct tevent_context *ev,
4434 struct cli_state *cli,
4438 struct tevent_req *req, *subreq;
4439 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
4442 req = tevent_req_create(mem_ctx, &state,
4443 struct cli_smb2_set_reparse_point_fnum_state);
4448 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4449 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4450 return tevent_req_post(req, ev);
4456 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4457 if (tevent_req_nterror(req, status)) {
4458 return tevent_req_post(req, ev);
4461 state->input_buffer = data_blob_talloc(state,
4464 if (state->input_buffer.data == NULL) {
4465 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4466 return tevent_req_post(req, ev);
4469 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4470 state->cli->timeout,
4471 state->cli->smb2.session,
4472 state->cli->smb2.tcon,
4473 state->ph->fid_persistent, /* in_fid_persistent */
4474 state->ph->fid_volatile, /* in_fid_volatile */
4475 FSCTL_SET_REPARSE_POINT,
4476 0, /* in_max_input_length */
4477 &state->input_buffer ,
4480 SMB2_IOCTL_FLAG_IS_FSCTL);
4482 if (tevent_req_nomem(subreq, req)) {
4483 return tevent_req_post(req, ev);
4485 tevent_req_set_callback(subreq,
4486 cli_smb2_set_reparse_point_fnum_done,
4492 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
4494 struct tevent_req *req = tevent_req_callback_data(
4495 subreq, struct tevent_req);
4496 struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
4497 req, struct cli_smb2_set_reparse_point_fnum_state);
4500 status = smb2cli_ioctl_recv(subreq, state,
4503 TALLOC_FREE(subreq);
4504 if (tevent_req_nterror(req, status)) {
4507 tevent_req_done(req);
4510 NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
4512 return tevent_req_simple_recv_ntstatus(req);
4515 struct cli_smb2_get_reparse_point_fnum_state {
4516 struct cli_state *cli;
4518 struct smb2_hnd *ph;
4519 DATA_BLOB output_buffer;
4522 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
4524 struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
4525 TALLOC_CTX *mem_ctx,
4526 struct tevent_context *ev,
4527 struct cli_state *cli,
4530 struct tevent_req *req, *subreq;
4531 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
4534 req = tevent_req_create(mem_ctx, &state,
4535 struct cli_smb2_get_reparse_point_fnum_state);
4540 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4541 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4542 return tevent_req_post(req, ev);
4548 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4549 if (tevent_req_nterror(req, status)) {
4550 return tevent_req_post(req, ev);
4553 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4554 state->cli->timeout,
4555 state->cli->smb2.session,
4556 state->cli->smb2.tcon,
4557 state->ph->fid_persistent, /* in_fid_persistent */
4558 state->ph->fid_volatile, /* in_fid_volatile */
4559 FSCTL_GET_REPARSE_POINT,
4560 0, /* in_max_input_length */
4564 SMB2_IOCTL_FLAG_IS_FSCTL);
4566 if (tevent_req_nomem(subreq, req)) {
4567 return tevent_req_post(req, ev);
4569 tevent_req_set_callback(subreq,
4570 cli_smb2_get_reparse_point_fnum_done,
4576 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
4578 struct tevent_req *req = tevent_req_callback_data(
4579 subreq, struct tevent_req);
4580 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
4581 req, struct cli_smb2_get_reparse_point_fnum_state);
4584 status = smb2cli_ioctl_recv(subreq, state,
4586 &state->output_buffer);
4587 TALLOC_FREE(subreq);
4588 if (tevent_req_nterror(req, status)) {
4589 state->cli->raw_status = status;
4592 tevent_req_done(req);
4595 NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
4596 TALLOC_CTX *mem_ctx,
4599 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
4600 req, struct cli_smb2_get_reparse_point_fnum_state);
4602 if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
4603 tevent_req_received(req);
4604 return state->cli->raw_status;
4606 *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
4607 if (output->data == NULL) {
4608 tevent_req_received(req);
4609 return NT_STATUS_NO_MEMORY;
4611 tevent_req_received(req);
4612 return NT_STATUS_OK;