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"
45 #include "lib/util/string_wrappers.h"
46 #include "lib/util/idtree.h"
49 uint64_t fid_persistent;
50 uint64_t fid_volatile;
54 * Handle mapping code.
57 /***************************************************************
58 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
59 Ensures handle is owned by cli struct.
60 ***************************************************************/
62 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
63 const struct smb2_hnd *ph, /* In */
64 uint16_t *pfnum) /* Out */
67 struct idr_context *idp = cli->smb2.open_handles;
68 struct smb2_hnd *owned_h = talloc_memdup(cli,
70 sizeof(struct smb2_hnd));
72 if (owned_h == NULL) {
73 return NT_STATUS_NO_MEMORY;
78 cli->smb2.open_handles = idr_init(cli);
79 if (cli->smb2.open_handles == NULL) {
81 return NT_STATUS_NO_MEMORY;
83 idp = cli->smb2.open_handles;
86 ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
89 return NT_STATUS_NO_MEMORY;
92 *pfnum = (uint16_t)ret;
96 /***************************************************************
97 Return the smb2_hnd pointer associated with the given fnum.
98 ***************************************************************/
100 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
101 uint16_t fnum, /* In */
102 struct smb2_hnd **pph) /* Out */
104 struct idr_context *idp = cli->smb2.open_handles;
107 return NT_STATUS_INVALID_PARAMETER;
109 *pph = (struct smb2_hnd *)idr_find(idp, fnum);
111 return NT_STATUS_INVALID_HANDLE;
116 /***************************************************************
117 Delete the fnum to smb2_hnd mapping. Zeros out handle on
119 ***************************************************************/
121 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
122 struct smb2_hnd **pph, /* In */
123 uint16_t fnum) /* In */
125 struct idr_context *idp = cli->smb2.open_handles;
129 return NT_STATUS_INVALID_PARAMETER;
132 ph = (struct smb2_hnd *)idr_find(idp, fnum);
134 return NT_STATUS_INVALID_PARAMETER;
136 idr_remove(idp, fnum);
141 /***************************************************************
143 ***************************************************************/
145 static uint8_t flags_to_smb2_oplock(struct cli_smb2_create_flags create_flags)
147 if (create_flags.batch_oplock) {
148 return SMB2_OPLOCK_LEVEL_BATCH;
149 } else if (create_flags.exclusive_oplock) {
150 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
153 /* create_flags doesn't do a level2 request. */
154 return SMB2_OPLOCK_LEVEL_NONE;
157 /***************************************************************
158 If we're on a DFS share, ensure we convert to a full DFS path
159 if this hasn't already been done.
160 ***************************************************************/
162 static char *smb2_dfs_share_path(TALLOC_CTX *ctx,
163 struct cli_state *cli,
166 bool is_dfs = smbXcli_conn_dfs_supported(cli->conn) &&
167 smbXcli_tcon_is_dfs_share(cli->smb2.tcon);
168 bool is_already_dfs_path = false;
173 is_already_dfs_path = cli_dfs_is_already_full_path(cli, path);
174 if (is_already_dfs_path) {
177 if (path[0] == '\0') {
178 return talloc_asprintf(ctx,
180 smbXcli_conn_remote_name(cli->conn),
183 while (*path == '\\') {
186 return talloc_asprintf(ctx,
188 smbXcli_conn_remote_name(cli->conn),
193 /***************************************************************
194 Small wrapper that allows SMB2 create to return a uint16_t fnum.
195 ***************************************************************/
197 struct cli_smb2_create_fnum_state {
198 struct cli_state *cli;
199 struct smb2_create_blobs in_cblobs;
200 struct smb2_create_blobs out_cblobs;
201 struct smb_create_returns cr;
202 struct symlink_reparse_struct *symlink;
204 struct tevent_req *subreq;
207 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
208 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
210 struct tevent_req *cli_smb2_create_fnum_send(
212 struct tevent_context *ev,
213 struct cli_state *cli,
214 const char *fname_in,
215 struct cli_smb2_create_flags create_flags,
216 uint32_t impersonation_level,
217 uint32_t desired_access,
218 uint32_t file_attributes,
219 uint32_t share_access,
220 uint32_t create_disposition,
221 uint32_t create_options,
222 const struct smb2_create_blobs *in_cblobs)
224 struct tevent_req *req, *subreq;
225 struct cli_smb2_create_fnum_state *state;
227 size_t fname_len = 0;
232 req = tevent_req_create(mem_ctx, &state,
233 struct cli_smb2_create_fnum_state);
239 fname = talloc_strdup(state, fname_in);
240 if (tevent_req_nomem(fname, req)) {
241 return tevent_req_post(req, ev);
244 if (cli->backup_intent) {
245 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
248 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
249 have_twrp = clistr_smb2_extract_snapshot_token(fname, &ntt);
251 status = smb2_create_blob_add(
254 SMB2_CREATE_TAG_TWRP,
256 .data = (uint8_t *)&ntt,
257 .length = sizeof(ntt),
259 if (tevent_req_nterror(req, status)) {
260 return tevent_req_post(req, ev);
264 if (in_cblobs != NULL) {
266 for (i=0; i<in_cblobs->num_blobs; i++) {
267 struct smb2_create_blob *b = &in_cblobs->blobs[i];
268 status = smb2_create_blob_add(
269 state, &state->in_cblobs, b->tag, b->data);
270 if (!NT_STATUS_IS_OK(status)) {
271 tevent_req_nterror(req, status);
272 return tevent_req_post(req, ev);
277 fname = smb2_dfs_share_path(state, cli, fname);
278 if (tevent_req_nomem(fname, req)) {
279 return tevent_req_post(req, ev);
281 fname_len = strlen(fname);
283 /* SMB2 is pickier about pathnames. Ensure it doesn't
285 if (*fname == '\\') {
290 /* Or end in a '\' */
291 if (fname_len > 0 && fname[fname_len-1] == '\\') {
292 fname[fname_len-1] = '\0';
295 subreq = smb2cli_create_send(state, ev,
301 flags_to_smb2_oplock(create_flags),
309 if (tevent_req_nomem(subreq, req)) {
310 return tevent_req_post(req, ev);
312 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
314 state->subreq = subreq;
315 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
320 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
322 struct tevent_req *req = tevent_req_callback_data(
323 subreq, struct tevent_req);
324 struct cli_smb2_create_fnum_state *state = tevent_req_data(
325 req, struct cli_smb2_create_fnum_state);
329 status = smb2cli_create_recv(
332 &h.fid_volatile, &state->cr,
337 if (tevent_req_nterror(req, status)) {
341 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
342 if (tevent_req_nterror(req, status)) {
345 tevent_req_done(req);
348 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
350 struct cli_smb2_create_fnum_state *state = tevent_req_data(
351 req, struct cli_smb2_create_fnum_state);
352 return tevent_req_cancel(state->subreq);
355 NTSTATUS cli_smb2_create_fnum_recv(
356 struct tevent_req *req,
358 struct smb_create_returns *cr,
360 struct smb2_create_blobs *out_cblobs,
361 struct symlink_reparse_struct **symlink)
363 struct cli_smb2_create_fnum_state *state = tevent_req_data(
364 req, struct cli_smb2_create_fnum_state);
367 if (tevent_req_is_nterror(req, &status)) {
368 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) &&
370 *symlink = talloc_move(mem_ctx, &state->symlink);
372 state->cli->raw_status = status;
376 *pfnum = state->fnum;
381 if (out_cblobs != NULL) {
382 *out_cblobs = (struct smb2_create_blobs) {
383 .num_blobs = state->out_cblobs.num_blobs,
384 .blobs = talloc_move(
385 mem_ctx, &state->out_cblobs.blobs),
388 state->cli->raw_status = NT_STATUS_OK;
392 NTSTATUS cli_smb2_create_fnum(
393 struct cli_state *cli,
395 struct cli_smb2_create_flags create_flags,
396 uint32_t impersonation_level,
397 uint32_t desired_access,
398 uint32_t file_attributes,
399 uint32_t share_access,
400 uint32_t create_disposition,
401 uint32_t create_options,
402 const struct smb2_create_blobs *in_cblobs,
404 struct smb_create_returns *cr,
406 struct smb2_create_blobs *out_cblobs)
408 TALLOC_CTX *frame = talloc_stackframe();
409 struct tevent_context *ev;
410 struct tevent_req *req;
411 NTSTATUS status = NT_STATUS_NO_MEMORY;
413 if (smbXcli_conn_has_async_calls(cli->conn)) {
415 * Can't use sync call while an async call is in flight
417 status = NT_STATUS_INVALID_PARAMETER;
420 ev = samba_tevent_context_init(frame);
424 req = cli_smb2_create_fnum_send(
440 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
443 status = cli_smb2_create_fnum_recv(
444 req, pfid, cr, mem_ctx, out_cblobs, NULL);
450 /***************************************************************
451 Small wrapper that allows SMB2 close to use a uint16_t fnum.
452 ***************************************************************/
454 struct cli_smb2_close_fnum_state {
455 struct cli_state *cli;
460 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
462 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
463 struct tevent_context *ev,
464 struct cli_state *cli,
467 struct tevent_req *req, *subreq;
468 struct cli_smb2_close_fnum_state *state;
471 req = tevent_req_create(mem_ctx, &state,
472 struct cli_smb2_close_fnum_state);
479 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
480 if (tevent_req_nterror(req, status)) {
481 return tevent_req_post(req, ev);
484 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
485 cli->smb2.session, cli->smb2.tcon,
486 0, state->ph->fid_persistent,
487 state->ph->fid_volatile);
488 if (tevent_req_nomem(subreq, req)) {
489 return tevent_req_post(req, ev);
491 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
495 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
497 struct tevent_req *req = tevent_req_callback_data(
498 subreq, struct tevent_req);
499 struct cli_smb2_close_fnum_state *state = tevent_req_data(
500 req, struct cli_smb2_close_fnum_state);
503 status = smb2cli_close_recv(subreq);
504 if (tevent_req_nterror(req, status)) {
508 /* Delete the fnum -> handle mapping. */
509 status = delete_smb2_handle_mapping(state->cli, &state->ph,
511 if (tevent_req_nterror(req, status)) {
514 tevent_req_done(req);
517 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
519 struct cli_smb2_close_fnum_state *state = tevent_req_data(
520 req, struct cli_smb2_close_fnum_state);
521 NTSTATUS status = NT_STATUS_OK;
523 if (tevent_req_is_nterror(req, &status)) {
524 state->cli->raw_status = status;
526 tevent_req_received(req);
530 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
532 TALLOC_CTX *frame = talloc_stackframe();
533 struct tevent_context *ev;
534 struct tevent_req *req;
535 NTSTATUS status = NT_STATUS_NO_MEMORY;
537 if (smbXcli_conn_has_async_calls(cli->conn)) {
539 * Can't use sync call while an async call is in flight
541 status = NT_STATUS_INVALID_PARAMETER;
544 ev = samba_tevent_context_init(frame);
548 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
552 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
555 status = cli_smb2_close_fnum_recv(req);
561 struct cli_smb2_set_info_fnum_state {
565 static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq);
567 struct tevent_req *cli_smb2_set_info_fnum_send(
569 struct tevent_context *ev,
570 struct cli_state *cli,
572 uint8_t in_info_type,
573 uint8_t in_info_class,
574 const DATA_BLOB *in_input_buffer,
575 uint32_t in_additional_info)
577 struct tevent_req *req = NULL, *subreq = NULL;
578 struct cli_smb2_set_info_fnum_state *state = NULL;
579 struct smb2_hnd *ph = NULL;
582 req = tevent_req_create(
583 mem_ctx, &state, struct cli_smb2_set_info_fnum_state);
588 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
589 if (tevent_req_nterror(req, status)) {
590 return tevent_req_post(req, ev);
593 subreq = smb2cli_set_info_send(
606 if (tevent_req_nomem(subreq, req)) {
607 return tevent_req_post(req, ev);
609 tevent_req_set_callback(subreq, cli_smb2_set_info_fnum_done, req);
613 static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq)
615 NTSTATUS status = smb2cli_set_info_recv(subreq);
616 tevent_req_simple_finish_ntstatus(subreq, status);
619 NTSTATUS cli_smb2_set_info_fnum_recv(struct tevent_req *req)
621 return tevent_req_simple_recv_ntstatus(req);
624 NTSTATUS cli_smb2_set_info_fnum(
625 struct cli_state *cli,
627 uint8_t in_info_type,
628 uint8_t in_info_class,
629 const DATA_BLOB *in_input_buffer,
630 uint32_t in_additional_info)
632 TALLOC_CTX *frame = talloc_stackframe();
633 struct tevent_context *ev = NULL;
634 struct tevent_req *req = NULL;
635 NTSTATUS status = NT_STATUS_NO_MEMORY;
638 if (smbXcli_conn_has_async_calls(cli->conn)) {
640 * Can't use sync call while an async call is in flight
642 status = NT_STATUS_INVALID_PARAMETER;
645 ev = samba_tevent_context_init(frame);
649 req = cli_smb2_set_info_fnum_send(
661 ok = tevent_req_poll_ntstatus(req, ev, &status);
665 status = cli_smb2_set_info_fnum_recv(req);
671 struct cli_smb2_delete_on_close_state {
672 struct cli_state *cli;
677 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
679 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
680 struct tevent_context *ev,
681 struct cli_state *cli,
685 struct tevent_req *req = NULL;
686 struct cli_smb2_delete_on_close_state *state = NULL;
687 struct tevent_req *subreq = NULL;
688 uint8_t in_info_type;
689 uint8_t in_file_info_class;
691 req = tevent_req_create(mem_ctx, &state,
692 struct cli_smb2_delete_on_close_state);
699 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
700 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
703 in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
704 /* Setup data array. */
705 SCVAL(&state->data[0], 0, flag ? 1 : 0);
706 state->inbuf.data = &state->data[0];
707 state->inbuf.length = 1;
709 subreq = cli_smb2_set_info_fnum_send(
718 if (tevent_req_nomem(subreq, req)) {
719 return tevent_req_post(req, ev);
721 tevent_req_set_callback(subreq,
722 cli_smb2_delete_on_close_done,
727 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
729 NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
730 tevent_req_simple_finish_ntstatus(subreq, status);
733 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
735 struct cli_smb2_delete_on_close_state *state =
737 struct cli_smb2_delete_on_close_state);
740 if (tevent_req_is_nterror(req, &status)) {
741 state->cli->raw_status = status;
742 tevent_req_received(req);
746 state->cli->raw_status = NT_STATUS_OK;
747 tevent_req_received(req);
751 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
753 TALLOC_CTX *frame = talloc_stackframe();
754 struct tevent_context *ev;
755 struct tevent_req *req;
756 NTSTATUS status = NT_STATUS_NO_MEMORY;
758 if (smbXcli_conn_has_async_calls(cli->conn)) {
760 * Can't use sync call while an async call is in flight
762 status = NT_STATUS_INVALID_PARAMETER;
765 ev = samba_tevent_context_init(frame);
769 req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
773 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
776 status = cli_smb2_delete_on_close_recv(req);
782 struct cli_smb2_mkdir_state {
783 struct tevent_context *ev;
784 struct cli_state *cli;
787 static void cli_smb2_mkdir_opened(struct tevent_req *subreq);
788 static void cli_smb2_mkdir_closed(struct tevent_req *subreq);
790 struct tevent_req *cli_smb2_mkdir_send(
792 struct tevent_context *ev,
793 struct cli_state *cli,
796 struct tevent_req *req = NULL, *subreq = NULL;
797 struct cli_smb2_mkdir_state *state = NULL;
799 req = tevent_req_create(
800 mem_ctx, &state, struct cli_smb2_mkdir_state);
807 /* Ensure this is a directory. */
808 subreq = cli_smb2_create_fnum_send(
813 (struct cli_smb2_create_flags){0}, /* create_flags */
814 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level */
815 FILE_READ_ATTRIBUTES, /* desired_access */
816 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
818 FILE_SHARE_WRITE, /* share_access */
819 FILE_CREATE, /* create_disposition */
820 FILE_DIRECTORY_FILE, /* create_options */
821 NULL); /* in_cblobs */
822 if (tevent_req_nomem(subreq, req)) {
823 return tevent_req_post(req, ev);
825 tevent_req_set_callback(subreq, cli_smb2_mkdir_opened, req);
829 static void cli_smb2_mkdir_opened(struct tevent_req *subreq)
831 struct tevent_req *req = tevent_req_callback_data(
832 subreq, struct tevent_req);
833 struct cli_smb2_mkdir_state *state = tevent_req_data(
834 req, struct cli_smb2_mkdir_state);
836 uint16_t fnum = 0xffff;
838 status = cli_smb2_create_fnum_recv(
839 subreq, &fnum, NULL, NULL, NULL, NULL);
841 if (tevent_req_nterror(req, status)) {
845 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
846 if (tevent_req_nomem(subreq, req)) {
849 tevent_req_set_callback(subreq, cli_smb2_mkdir_closed, req);
852 static void cli_smb2_mkdir_closed(struct tevent_req *subreq)
854 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
855 tevent_req_simple_finish_ntstatus(subreq, status);
858 NTSTATUS cli_smb2_mkdir_recv(struct tevent_req *req)
860 return tevent_req_simple_recv_ntstatus(req);
863 struct cli_smb2_rmdir_state {
864 struct tevent_context *ev;
865 struct cli_state *cli;
867 const struct smb2_create_blobs *in_cblobs;
872 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq);
873 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq);
874 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq);
875 static void cli_smb2_rmdir_closed(struct tevent_req *subreq);
877 struct tevent_req *cli_smb2_rmdir_send(
879 struct tevent_context *ev,
880 struct cli_state *cli,
882 const struct smb2_create_blobs *in_cblobs)
884 struct tevent_req *req = NULL, *subreq = NULL;
885 struct cli_smb2_rmdir_state *state = NULL;
887 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_rmdir_state);
893 state->dname = dname;
894 state->in_cblobs = in_cblobs;
896 subreq = cli_smb2_create_fnum_send(
901 (struct cli_smb2_create_flags){0},
902 SMB2_IMPERSONATION_IMPERSONATION,
903 DELETE_ACCESS, /* desired_access */
904 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
905 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
906 FILE_OPEN, /* create_disposition */
907 FILE_DIRECTORY_FILE, /* create_options */
908 state->in_cblobs); /* in_cblobs */
909 if (tevent_req_nomem(subreq, req)) {
910 return tevent_req_post(req, ev);
912 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened1, req);
916 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq)
918 struct tevent_req *req = tevent_req_callback_data(
919 subreq, struct tevent_req);
920 struct cli_smb2_rmdir_state *state = tevent_req_data(
921 req, struct cli_smb2_rmdir_state);
924 status = cli_smb2_create_fnum_recv(
925 subreq, &state->fnum, NULL, NULL, NULL, NULL);
928 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
930 * Naive option to match our SMB1 code. Assume the
931 * symlink path that tripped us up was the last
932 * component and try again. Eventually we will have to
933 * deal with the returned path unprocessed component. JRA.
935 subreq = cli_smb2_create_fnum_send(
940 (struct cli_smb2_create_flags){0},
941 SMB2_IMPERSONATION_IMPERSONATION,
942 DELETE_ACCESS, /* desired_access */
943 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
944 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
945 FILE_OPEN, /* create_disposition */
947 FILE_DELETE_ON_CLOSE|
948 FILE_OPEN_REPARSE_POINT, /* create_options */
949 state->in_cblobs); /* in_cblobs */
950 if (tevent_req_nomem(subreq, req)) {
953 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened2, req);
957 if (tevent_req_nterror(req, status)) {
961 subreq = cli_smb2_delete_on_close_send(
962 state, state->ev, state->cli, state->fnum, true);
963 if (tevent_req_nomem(subreq, req)) {
966 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
969 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq)
971 struct tevent_req *req = tevent_req_callback_data(
972 subreq, struct tevent_req);
973 struct cli_smb2_rmdir_state *state = tevent_req_data(
974 req, struct cli_smb2_rmdir_state);
977 status = cli_smb2_create_fnum_recv(
978 subreq, &state->fnum, NULL, NULL, NULL, NULL);
980 if (tevent_req_nterror(req, status)) {
984 subreq = cli_smb2_delete_on_close_send(
985 state, state->ev, state->cli, state->fnum, true);
986 if (tevent_req_nomem(subreq, req)) {
989 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
992 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq)
994 struct tevent_req *req = tevent_req_callback_data(
995 subreq, struct tevent_req);
996 struct cli_smb2_rmdir_state *state = tevent_req_data(
997 req, struct cli_smb2_rmdir_state);
999 state->status = cli_smb2_delete_on_close_recv(subreq);
1000 TALLOC_FREE(subreq);
1003 * Close the fd even if the set_disp failed
1006 subreq = cli_smb2_close_fnum_send(
1007 state, state->ev, state->cli, state->fnum);
1008 if (tevent_req_nomem(subreq, req)) {
1011 tevent_req_set_callback(subreq, cli_smb2_rmdir_closed, req);
1014 static void cli_smb2_rmdir_closed(struct tevent_req *subreq)
1016 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1017 tevent_req_simple_finish_ntstatus(subreq, status);
1020 NTSTATUS cli_smb2_rmdir_recv(struct tevent_req *req)
1022 struct cli_smb2_rmdir_state *state = tevent_req_data(
1023 req, struct cli_smb2_rmdir_state);
1026 if (tevent_req_is_nterror(req, &status)) {
1029 return state->status;
1032 /***************************************************************
1033 Small wrapper that allows SMB2 to unlink a pathname.
1034 ***************************************************************/
1036 struct cli_smb2_unlink_state {
1037 struct tevent_context *ev;
1038 struct cli_state *cli;
1040 const struct smb2_create_blobs *in_cblobs;
1043 static void cli_smb2_unlink_opened1(struct tevent_req *subreq);
1044 static void cli_smb2_unlink_opened2(struct tevent_req *subreq);
1045 static void cli_smb2_unlink_closed(struct tevent_req *subreq);
1047 struct tevent_req *cli_smb2_unlink_send(
1048 TALLOC_CTX *mem_ctx,
1049 struct tevent_context *ev,
1050 struct cli_state *cli,
1052 const struct smb2_create_blobs *in_cblobs)
1054 struct tevent_req *req = NULL, *subreq = NULL;
1055 struct cli_smb2_unlink_state *state = NULL;
1057 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_unlink_state);
1063 state->fname = fname;
1064 state->in_cblobs = in_cblobs;
1066 subreq = cli_smb2_create_fnum_send(
1067 state, /* mem_ctx */
1068 state->ev, /* tevent_context */
1069 state->cli, /* cli_struct */
1070 state->fname, /* filename */
1071 (struct cli_smb2_create_flags){0},
1072 SMB2_IMPERSONATION_IMPERSONATION,
1073 DELETE_ACCESS, /* desired_access */
1074 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1077 FILE_SHARE_DELETE, /* share_access */
1078 FILE_OPEN, /* create_disposition */
1079 FILE_DELETE_ON_CLOSE, /* create_options */
1080 state->in_cblobs); /* in_cblobs */
1081 if (tevent_req_nomem(subreq, req)) {
1082 return tevent_req_post(req, ev);
1084 tevent_req_set_callback(subreq, cli_smb2_unlink_opened1, req);
1088 static void cli_smb2_unlink_opened1(struct tevent_req *subreq)
1090 struct tevent_req *req = tevent_req_callback_data(
1091 subreq, struct tevent_req);
1092 struct cli_smb2_unlink_state *state = tevent_req_data(
1093 req, struct cli_smb2_unlink_state);
1094 uint16_t fnum = 0xffff;
1097 status = cli_smb2_create_fnum_recv(
1098 subreq, &fnum, NULL, NULL, NULL, NULL);
1099 TALLOC_FREE(subreq);
1101 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) ||
1102 NT_STATUS_EQUAL(status, NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED)) {
1104 * Naive option to match our SMB1 code. Assume the
1105 * symlink path that tripped us up was the last
1106 * component and try again. Eventually we will have to
1107 * deal with the returned path unprocessed component. JRA.
1109 subreq = cli_smb2_create_fnum_send(
1110 state, /* mem_ctx */
1111 state->ev, /* tevent_context */
1112 state->cli, /* cli_struct */
1113 state->fname, /* filename */
1114 (struct cli_smb2_create_flags){0},
1115 SMB2_IMPERSONATION_IMPERSONATION,
1116 DELETE_ACCESS, /* desired_access */
1117 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1120 FILE_SHARE_DELETE, /* share_access */
1121 FILE_OPEN, /* create_disposition */
1122 FILE_DELETE_ON_CLOSE|
1123 FILE_OPEN_REPARSE_POINT, /* create_options */
1124 state->in_cblobs); /* in_cblobs */
1125 if (tevent_req_nomem(subreq, req)) {
1128 tevent_req_set_callback(subreq, cli_smb2_unlink_opened2, req);
1132 if (tevent_req_nterror(req, status)) {
1136 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1137 if (tevent_req_nomem(subreq, req)) {
1140 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1143 static void cli_smb2_unlink_opened2(struct tevent_req *subreq)
1145 struct tevent_req *req = tevent_req_callback_data(
1146 subreq, struct tevent_req);
1147 struct cli_smb2_unlink_state *state = tevent_req_data(
1148 req, struct cli_smb2_unlink_state);
1149 uint16_t fnum = 0xffff;
1152 status = cli_smb2_create_fnum_recv(
1153 subreq, &fnum, NULL, NULL, NULL, NULL);
1154 TALLOC_FREE(subreq);
1155 if (tevent_req_nterror(req, status)) {
1159 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1160 if (tevent_req_nomem(subreq, req)) {
1163 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1166 static void cli_smb2_unlink_closed(struct tevent_req *subreq)
1168 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1169 tevent_req_simple_finish_ntstatus(subreq, status);
1172 NTSTATUS cli_smb2_unlink_recv(struct tevent_req *req)
1174 return tevent_req_simple_recv_ntstatus(req);
1177 static ssize_t sid_parse_wire(TALLOC_CTX *mem_ctx, const uint8_t *data,
1178 struct dom_sid *sid, size_t num_rdata)
1181 enum ndr_err_code ndr_err;
1182 DATA_BLOB in = data_blob_const(data, num_rdata);
1184 ndr_err = ndr_pull_struct_blob(&in,
1187 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
1188 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1192 sid_size = ndr_size_dom_sid(sid, 0);
1193 if (sid_size > num_rdata) {
1200 /***************************************************************
1201 Utility function to parse a SMB2_FIND_POSIX_INFORMATION reply.
1202 ***************************************************************/
1204 static NTSTATUS parse_finfo_posix_info(const uint8_t *dir_data,
1205 uint32_t dir_data_length,
1206 struct file_info *finfo,
1207 uint32_t *next_offset)
1210 size_t slen = 0, slen2 = 0;
1212 uint32_t _next_offset = 0;
1214 if (dir_data_length < 4) {
1215 return NT_STATUS_INFO_LENGTH_MISMATCH;
1218 _next_offset = IVAL(dir_data, 0);
1220 if (_next_offset > dir_data_length) {
1221 return NT_STATUS_INFO_LENGTH_MISMATCH;
1224 if (_next_offset != 0) {
1225 /* Ensure we only read what in this record. */
1226 dir_data_length = _next_offset;
1229 if (dir_data_length < 92) {
1230 return NT_STATUS_INFO_LENGTH_MISMATCH;
1233 finfo->btime_ts = interpret_long_date(BVAL(dir_data, 8));
1234 finfo->atime_ts = interpret_long_date(BVAL(dir_data, 16));
1235 finfo->mtime_ts = interpret_long_date(BVAL(dir_data, 24));
1236 finfo->ctime_ts = interpret_long_date(BVAL(dir_data, 32));
1237 finfo->allocated_size = PULL_LE_U64(dir_data, 40);
1238 finfo->size = PULL_LE_U64(dir_data, 48);
1239 finfo->mode = PULL_LE_U32(dir_data, 56);
1240 finfo->ino = PULL_LE_U64(dir_data, 60);
1241 finfo->st_ex_dev = PULL_LE_U32(dir_data, 68);
1242 finfo->st_ex_nlink = PULL_LE_U32(dir_data, 76);
1243 finfo->reparse_tag = PULL_LE_U32(dir_data, 80);
1244 finfo->st_ex_mode = wire_perms_to_unix(PULL_LE_U32(dir_data, 84));
1246 slen = sid_parse_wire(finfo, dir_data+88, &finfo->owner_sid,
1247 dir_data_length-88);
1249 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1251 slen2 = sid_parse_wire(finfo, dir_data+88+slen, &finfo->group_sid,
1252 dir_data_length-88-slen);
1254 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1258 namelen = PULL_LE_U32(dir_data, 88+slen);
1259 ret = pull_string_talloc(finfo,
1261 FLAGS2_UNICODE_STRINGS,
1266 if (ret == (size_t)-1) {
1267 /* Bad conversion. */
1268 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1271 if (finfo->name == NULL) {
1272 /* Bad conversion. */
1273 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1276 *next_offset = _next_offset;
1277 return NT_STATUS_OK;
1280 /***************************************************************
1281 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1282 ***************************************************************/
1284 static NTSTATUS parse_finfo_id_both_directory_info(const uint8_t *dir_data,
1285 uint32_t dir_data_length,
1286 struct file_info *finfo,
1287 uint32_t *next_offset)
1293 if (dir_data_length < 4) {
1294 return NT_STATUS_INFO_LENGTH_MISMATCH;
1297 *next_offset = IVAL(dir_data, 0);
1299 if (*next_offset > dir_data_length) {
1300 return NT_STATUS_INFO_LENGTH_MISMATCH;
1303 if (*next_offset != 0) {
1304 /* Ensure we only read what in this record. */
1305 dir_data_length = *next_offset;
1308 if (dir_data_length < 105) {
1309 return NT_STATUS_INFO_LENGTH_MISMATCH;
1312 finfo->btime_ts = interpret_long_date(BVAL(dir_data, 8));
1313 finfo->atime_ts = interpret_long_date(BVAL(dir_data, 16));
1314 finfo->mtime_ts = interpret_long_date(BVAL(dir_data, 24));
1315 finfo->ctime_ts = interpret_long_date(BVAL(dir_data, 32));
1316 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
1317 finfo->allocated_size = IVAL2_TO_SMB_BIG_UINT(dir_data + 48, 0);
1318 finfo->attr = IVAL(dir_data + 56, 0);
1319 finfo->ino = IVAL2_TO_SMB_BIG_UINT(dir_data + 96, 0);
1320 namelen = IVAL(dir_data + 60,0);
1321 if (namelen > (dir_data_length - 104)) {
1322 return NT_STATUS_INFO_LENGTH_MISMATCH;
1324 slen = CVAL(dir_data + 68, 0);
1326 return NT_STATUS_INFO_LENGTH_MISMATCH;
1328 ret = pull_string_talloc(finfo,
1330 FLAGS2_UNICODE_STRINGS,
1335 if (ret == (size_t)-1) {
1336 /* Bad conversion. */
1337 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1340 ret = pull_string_talloc(finfo,
1342 FLAGS2_UNICODE_STRINGS,
1347 if (ret == (size_t)-1) {
1348 /* Bad conversion. */
1349 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1352 if (finfo->name == NULL) {
1353 /* Bad conversion. */
1354 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1357 return NT_STATUS_OK;
1360 /*******************************************************************
1361 Given a filename - get its directory name
1362 ********************************************************************/
1364 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
1372 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
1375 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
1386 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
1389 (*parent)[len] = '\0';
1397 struct cli_smb2_list_dir_data {
1402 struct cli_smb2_list_state {
1403 struct tevent_context *ev;
1404 struct cli_state *cli;
1410 struct cli_smb2_list_dir_data *response;
1412 unsigned int info_level;
1415 static void cli_smb2_list_opened(struct tevent_req *subreq);
1416 static void cli_smb2_list_done(struct tevent_req *subreq);
1417 static void cli_smb2_list_closed(struct tevent_req *subreq);
1419 struct tevent_req *cli_smb2_list_send(
1420 TALLOC_CTX *mem_ctx,
1421 struct tevent_context *ev,
1422 struct cli_state *cli,
1423 const char *pathname,
1424 unsigned int info_level,
1427 struct tevent_req *req = NULL, *subreq = NULL;
1428 struct cli_smb2_list_state *state = NULL;
1429 char *parent = NULL;
1431 struct smb2_create_blobs *in_cblobs = NULL;
1433 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_list_state);
1439 state->status = NT_STATUS_OK;
1440 state->info_level = info_level;
1442 ok = windows_parent_dirname(state, pathname, &parent, &state->mask);
1444 tevent_req_oom(req);
1445 return tevent_req_post(req, ev);
1448 if (smbXcli_conn_have_posix(cli->conn) && posix) {
1451 /* The mode MUST be 0 when opening an existing file/dir, and
1452 * will be ignored by the server.
1454 uint8_t linear_mode[4] = { 0 };
1455 DATA_BLOB blob = { .data=linear_mode,
1456 .length=sizeof(linear_mode) };
1458 in_cblobs = talloc_zero(mem_ctx, struct smb2_create_blobs);
1459 if (in_cblobs == NULL) {
1463 status = smb2_create_blob_add(in_cblobs, in_cblobs,
1464 SMB2_CREATE_TAG_POSIX, blob);
1465 if (tevent_req_nterror(req, status)) {
1466 tevent_req_nterror(req, status);
1467 return tevent_req_post(req, ev);
1471 subreq = cli_smb2_create_fnum_send(
1472 state, /* mem_ctx */
1476 (struct cli_smb2_create_flags){0}, /* create_flags */
1477 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level */
1478 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE, /* desired_access */
1479 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
1480 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
1481 FILE_OPEN, /* create_disposition */
1482 FILE_DIRECTORY_FILE, /* create_options */
1483 in_cblobs); /* in_cblobs */
1484 TALLOC_FREE(in_cblobs);
1485 if (tevent_req_nomem(subreq, req)) {
1486 return tevent_req_post(req, ev);
1488 tevent_req_set_callback(subreq, cli_smb2_list_opened, req);
1492 static void cli_smb2_list_opened(struct tevent_req *subreq)
1494 struct tevent_req *req = tevent_req_callback_data(
1495 subreq, struct tevent_req);
1496 struct cli_smb2_list_state *state = tevent_req_data(
1497 req, struct cli_smb2_list_state);
1500 status = cli_smb2_create_fnum_recv(
1501 subreq, &state->fnum, NULL, NULL, NULL, NULL);
1502 TALLOC_FREE(subreq);
1503 if (tevent_req_nterror(req, status)) {
1508 * Make our caller get back to us via cli_smb2_list_recv(),
1509 * triggering the smb2_query_directory_send()
1511 tevent_req_defer_callback(req, state->ev);
1512 tevent_req_notify_callback(req);
1515 static void cli_smb2_list_done(struct tevent_req *subreq)
1517 struct tevent_req *req = tevent_req_callback_data(
1518 subreq, struct tevent_req);
1519 struct cli_smb2_list_state *state = tevent_req_data(
1520 req, struct cli_smb2_list_state);
1521 struct cli_smb2_list_dir_data *response = NULL;
1523 response = talloc(state, struct cli_smb2_list_dir_data);
1524 if (tevent_req_nomem(response, req)) {
1528 state->status = smb2cli_query_directory_recv(
1529 subreq, response, &response->data, &response->length);
1530 TALLOC_FREE(subreq);
1532 if (NT_STATUS_IS_OK(state->status)) {
1533 state->response = response;
1536 tevent_req_defer_callback(req, state->ev);
1537 tevent_req_notify_callback(req);
1541 TALLOC_FREE(response);
1543 subreq = cli_smb2_close_fnum_send(
1544 state, state->ev, state->cli, state->fnum);
1545 if (tevent_req_nomem(subreq, req)) {
1548 tevent_req_set_callback(subreq, cli_smb2_list_closed, req);
1551 static void cli_smb2_list_closed(struct tevent_req *subreq)
1553 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1554 tevent_req_simple_finish_ntstatus(subreq, status);
1558 * Return the next finfo directory.
1560 * This parses the blob returned from QUERY_DIRECTORY step by step. If
1561 * the blob ends, this triggers a fresh QUERY_DIRECTORY and returns
1562 * NT_STATUS_RETRY, which will then trigger the caller again when the
1563 * QUERY_DIRECTORY has returned with another buffer. This way we
1564 * guarantee that no asynchronous request is open after this call
1565 * returns an entry, so that other synchronous requests can be issued
1566 * on the same connection while the directory listing proceeds.
1568 NTSTATUS cli_smb2_list_recv(
1569 struct tevent_req *req,
1570 TALLOC_CTX *mem_ctx,
1571 struct file_info **pfinfo)
1573 struct cli_smb2_list_state *state = tevent_req_data(
1574 req, struct cli_smb2_list_state);
1575 struct cli_smb2_list_dir_data *response = NULL;
1576 struct file_info *finfo = NULL;
1578 uint32_t next_offset = 0;
1581 in_progress = tevent_req_is_in_progress(req);
1584 if (!tevent_req_is_nterror(req, &status)) {
1585 status = NT_STATUS_NO_MORE_FILES;
1590 response = state->response;
1591 if (response == NULL) {
1592 struct tevent_req *subreq = NULL;
1593 struct cli_state *cli = state->cli;
1594 struct smb2_hnd *ph = NULL;
1595 uint32_t max_trans, max_avail_len;
1598 if (!NT_STATUS_IS_OK(state->status)) {
1599 status = state->status;
1603 status = map_fnum_to_smb2_handle(cli, state->fnum, &ph);
1604 if (!NT_STATUS_IS_OK(status)) {
1608 max_trans = smb2cli_conn_max_trans_size(cli->conn);
1609 ok = smb2cli_conn_req_possible(cli->conn, &max_avail_len);
1611 max_trans = MIN(max_trans, max_avail_len);
1614 subreq = smb2cli_query_directory_send(
1615 state, /* mem_ctx */
1617 cli->conn, /* conn */
1618 cli->timeout, /* timeout_msec */
1619 cli->smb2.session, /* session */
1620 cli->smb2.tcon, /* tcon */
1621 state->info_level, /* level */
1624 ph->fid_persistent, /* fid_persistent */
1625 ph->fid_volatile, /* fid_volatile */
1626 state->mask, /* mask */
1627 max_trans); /* outbuf_len */
1628 if (subreq == NULL) {
1629 status = NT_STATUS_NO_MEMORY;
1632 tevent_req_set_callback(subreq, cli_smb2_list_done, req);
1633 return NT_STATUS_RETRY;
1636 SMB_ASSERT(response->length > state->offset);
1638 finfo = talloc_zero(mem_ctx, struct file_info);
1639 if (finfo == NULL) {
1640 status = NT_STATUS_NO_MEMORY;
1644 if (state->info_level == SMB2_FIND_POSIX_INFORMATION) {
1645 status = parse_finfo_posix_info(
1646 response->data + state->offset,
1647 response->length - state->offset,
1651 status = parse_finfo_id_both_directory_info(
1652 response->data + state->offset,
1653 response->length - state->offset,
1657 if (!NT_STATUS_IS_OK(status)) {
1661 status = is_bad_finfo_name(state->cli, finfo);
1662 if (!NT_STATUS_IS_OK(status)) {
1667 * parse_finfo_id_both_directory_info() checks for overflow,
1668 * no need to check again here.
1670 state->offset += next_offset;
1672 if (next_offset == 0) {
1673 TALLOC_FREE(state->response);
1676 tevent_req_defer_callback(req, state->ev);
1677 tevent_req_notify_callback(req);
1680 return NT_STATUS_OK;
1684 tevent_req_received(req);
1688 /***************************************************************
1689 Wrapper that allows SMB2 to query a path info (basic level).
1691 ***************************************************************/
1693 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1695 SMB_STRUCT_STAT *sbuf,
1696 uint32_t *attributes)
1699 struct smb_create_returns cr;
1700 uint16_t fnum = 0xffff;
1701 size_t namelen = strlen(name);
1703 if (smbXcli_conn_has_async_calls(cli->conn)) {
1705 * Can't use sync call while an async call is in flight
1707 return NT_STATUS_INVALID_PARAMETER;
1710 /* SMB2 is pickier about pathnames. Ensure it doesn't
1712 if (namelen > 0 && name[namelen-1] == '\\') {
1713 char *modname = talloc_strndup(talloc_tos(), name, namelen-1);
1714 if (modname == NULL) {
1715 return NT_STATUS_NO_MEMORY;
1720 /* This is commonly used as a 'cd'. Try qpathinfo on
1721 a directory handle first. */
1723 status = cli_smb2_create_fnum(cli,
1725 (struct cli_smb2_create_flags){0},
1726 SMB2_IMPERSONATION_IMPERSONATION,
1727 FILE_READ_ATTRIBUTES, /* desired_access */
1728 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1729 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1730 FILE_OPEN, /* create_disposition */
1731 FILE_DIRECTORY_FILE, /* create_options */
1738 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1739 /* Maybe a file ? */
1740 status = cli_smb2_create_fnum(cli,
1742 (struct cli_smb2_create_flags){0},
1743 SMB2_IMPERSONATION_IMPERSONATION,
1744 FILE_READ_ATTRIBUTES, /* desired_access */
1745 0, /* file attributes */
1746 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1747 FILE_OPEN, /* create_disposition */
1748 0, /* create_options */
1756 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1757 /* Maybe a reparse point ? */
1758 status = cli_smb2_create_fnum(cli,
1760 (struct cli_smb2_create_flags){0},
1761 SMB2_IMPERSONATION_IMPERSONATION,
1762 FILE_READ_ATTRIBUTES, /* desired_access */
1763 0, /* file attributes */
1764 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1765 FILE_OPEN, /* create_disposition */
1766 FILE_OPEN_REPARSE_POINT, /* create_options */
1774 if (!NT_STATUS_IS_OK(status)) {
1778 status = cli_smb2_close_fnum(cli, fnum);
1782 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1783 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1784 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1785 sbuf->st_ex_size = cr.end_of_file;
1786 *attributes = cr.file_attributes;
1791 struct cli_smb2_query_info_fnum_state {
1795 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq);
1797 struct tevent_req *cli_smb2_query_info_fnum_send(
1798 TALLOC_CTX *mem_ctx,
1799 struct tevent_context *ev,
1800 struct cli_state *cli,
1802 uint8_t in_info_type,
1803 uint8_t in_info_class,
1804 uint32_t in_max_output_length,
1805 const DATA_BLOB *in_input_buffer,
1806 uint32_t in_additional_info,
1809 struct tevent_req *req = NULL, *subreq = NULL;
1810 struct cli_smb2_query_info_fnum_state *state = NULL;
1811 struct smb2_hnd *ph = NULL;
1814 req = tevent_req_create(
1815 mem_ctx, &state, struct cli_smb2_query_info_fnum_state);
1820 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1821 if (tevent_req_nterror(req, status)) {
1822 return tevent_req_post(req, ev);
1825 subreq = smb2cli_query_info_send(
1834 in_max_output_length,
1840 if (tevent_req_nomem(subreq, req)) {
1841 return tevent_req_post(req, ev);
1843 tevent_req_set_callback(subreq, cli_smb2_query_info_fnum_done, req);
1847 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq)
1849 struct tevent_req *req = tevent_req_callback_data(
1850 subreq, struct tevent_req);
1851 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1852 req, struct cli_smb2_query_info_fnum_state);
1856 status = smb2cli_query_info_recv(subreq, state, &outbuf);
1857 TALLOC_FREE(subreq);
1858 if (tevent_req_nterror(req, status)) {
1863 * We have to dup the memory here because outbuf.data is not
1864 * returned as a talloc object by smb2cli_query_info_recv.
1865 * It's a pointer into the received buffer.
1867 state->outbuf = data_blob_dup_talloc(state, outbuf);
1869 if ((outbuf.length != 0) &&
1870 tevent_req_nomem(state->outbuf.data, req)) {
1873 tevent_req_done(req);
1876 NTSTATUS cli_smb2_query_info_fnum_recv(
1877 struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *outbuf)
1879 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1880 req, struct cli_smb2_query_info_fnum_state);
1883 if (tevent_req_is_nterror(req, &status)) {
1886 *outbuf = (DATA_BLOB) {
1887 .data = talloc_move(mem_ctx, &state->outbuf.data),
1888 .length = state->outbuf.length,
1890 return NT_STATUS_OK;
1893 NTSTATUS cli_smb2_query_info_fnum(
1894 struct cli_state *cli,
1896 uint8_t in_info_type,
1897 uint8_t in_info_class,
1898 uint32_t in_max_output_length,
1899 const DATA_BLOB *in_input_buffer,
1900 uint32_t in_additional_info,
1902 TALLOC_CTX *mem_ctx,
1905 TALLOC_CTX *frame = talloc_stackframe();
1906 struct tevent_context *ev = NULL;
1907 struct tevent_req *req = NULL;
1908 NTSTATUS status = NT_STATUS_NO_MEMORY;
1911 if (smbXcli_conn_has_async_calls(cli->conn)) {
1913 * Can't use sync call while an async call is in flight
1915 status = NT_STATUS_INVALID_PARAMETER;
1918 ev = samba_tevent_context_init(frame);
1922 req = cli_smb2_query_info_fnum_send(
1929 in_max_output_length,
1936 ok = tevent_req_poll_ntstatus(req, ev, &status);
1940 status = cli_smb2_query_info_fnum_recv(req, mem_ctx, outbuf);
1946 /***************************************************************
1947 Helper function for pathname operations.
1948 ***************************************************************/
1950 struct get_fnum_from_path_state {
1951 struct tevent_context *ev;
1952 struct cli_state *cli;
1954 uint32_t desired_access;
1958 static void get_fnum_from_path_opened_file(struct tevent_req *subreq);
1959 static void get_fnum_from_path_opened_reparse(struct tevent_req *subreq);
1960 static void get_fnum_from_path_opened_dir(struct tevent_req *subreq);
1962 static struct tevent_req *get_fnum_from_path_send(
1963 TALLOC_CTX *mem_ctx,
1964 struct tevent_context *ev,
1965 struct cli_state *cli,
1967 uint32_t desired_access)
1969 struct tevent_req *req = NULL, *subreq = NULL;
1970 struct get_fnum_from_path_state *state = NULL;
1971 size_t namelen = strlen(name);
1973 req = tevent_req_create(
1974 mem_ctx, &state, struct get_fnum_from_path_state);
1981 state->desired_access = desired_access;
1984 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
1987 if (namelen > 0 && name[namelen-1] == '\\') {
1988 state->name = talloc_strndup(state, name, namelen-1);
1989 if (tevent_req_nomem(state->name, req)) {
1990 return tevent_req_post(req, ev);
1994 subreq = cli_smb2_create_fnum_send(
1995 state, /* mem_ctx, */
1998 state->name, /* fname */
1999 (struct cli_smb2_create_flags){0}, /* create_flags */
2000 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level */
2001 desired_access, /* desired_access */
2002 0, /* file_attributes */
2005 FILE_SHARE_DELETE, /* share_access */
2006 FILE_OPEN, /* create_disposition */
2007 0, /* create_options */
2008 NULL); /* in_cblobs */
2009 if (tevent_req_nomem(subreq, req)) {
2010 return tevent_req_post(req, ev);
2012 tevent_req_set_callback(subreq, get_fnum_from_path_opened_file, req);
2016 static void get_fnum_from_path_opened_file(struct tevent_req *subreq)
2018 struct tevent_req *req = tevent_req_callback_data(
2019 subreq, struct tevent_req);
2020 struct get_fnum_from_path_state *state = tevent_req_data(
2021 req, struct get_fnum_from_path_state);
2024 status = cli_smb2_create_fnum_recv(
2025 subreq, &state->fnum, NULL, NULL, NULL, NULL);
2026 TALLOC_FREE(subreq);
2028 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) ||
2029 NT_STATUS_EQUAL(status, NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED)) {
2031 * Naive option to match our SMB1 code. Assume the
2032 * symlink path that tripped us up was the last
2033 * component and try again. Eventually we will have to
2034 * deal with the returned path unprocessed component. JRA.
2036 subreq = cli_smb2_create_fnum_send(
2037 state, /* mem_ctx, */
2039 state->cli, /* cli */
2040 state->name, /* fname */
2041 (struct cli_smb2_create_flags){0}, /* create_flags */
2042 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation */
2043 state->desired_access, /* desired_access */
2044 0, /* file_attributes */
2047 FILE_SHARE_DELETE, /* share_access */
2048 FILE_OPEN, /* create_disposition */
2049 FILE_OPEN_REPARSE_POINT, /* create_options */
2050 NULL); /* in_cblobs */
2051 if (tevent_req_nomem(subreq, req)) {
2054 tevent_req_set_callback(
2055 subreq, get_fnum_from_path_opened_reparse, req);
2059 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
2060 subreq = cli_smb2_create_fnum_send(
2061 state, /* mem_ctx, */
2063 state->cli, /* cli */
2064 state->name, /* fname */
2065 (struct cli_smb2_create_flags){0}, /* create_flags */
2066 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation */
2067 state->desired_access, /* desired_access */
2068 0, /* file_attributes */
2071 FILE_SHARE_DELETE, /* share_access */
2072 FILE_OPEN, /* create_disposition */
2073 FILE_DIRECTORY_FILE, /* create_options */
2074 NULL); /* in_cblobs */
2075 if (tevent_req_nomem(subreq, req)) {
2078 tevent_req_set_callback(
2079 subreq, get_fnum_from_path_opened_dir, req);
2083 if (tevent_req_nterror(req, status)) {
2086 tevent_req_done(req);
2089 static void get_fnum_from_path_opened_reparse(struct tevent_req *subreq)
2091 struct tevent_req *req = tevent_req_callback_data(
2092 subreq, struct tevent_req);
2093 struct get_fnum_from_path_state *state = tevent_req_data(
2094 req, struct get_fnum_from_path_state);
2095 NTSTATUS status = cli_smb2_create_fnum_recv(
2096 subreq, &state->fnum, NULL, NULL, NULL, NULL);
2097 tevent_req_simple_finish_ntstatus(subreq, status);
2100 static void get_fnum_from_path_opened_dir(struct tevent_req *subreq)
2102 /* Abstraction violation, but these two are just the same... */
2103 get_fnum_from_path_opened_reparse(subreq);
2106 static NTSTATUS get_fnum_from_path_recv(
2107 struct tevent_req *req, uint16_t *pfnum)
2109 struct get_fnum_from_path_state *state = tevent_req_data(
2110 req, struct get_fnum_from_path_state);
2111 NTSTATUS status = NT_STATUS_OK;
2113 if (!tevent_req_is_nterror(req, &status)) {
2114 *pfnum = state->fnum;
2116 tevent_req_received(req);
2120 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
2122 uint32_t desired_access,
2125 TALLOC_CTX *frame = talloc_stackframe();
2126 struct tevent_context *ev = NULL;
2127 struct tevent_req *req = NULL;
2128 NTSTATUS status = NT_STATUS_NO_MEMORY;
2130 if (smbXcli_conn_has_async_calls(cli->conn)) {
2131 status = NT_STATUS_INVALID_PARAMETER;
2134 ev = samba_tevent_context_init(frame);
2138 req = get_fnum_from_path_send(frame, ev, cli, name, desired_access);
2142 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2145 status = get_fnum_from_path_recv(req, pfnum);
2151 /***************************************************************
2152 Wrapper that allows SMB2 to query a path info (ALTNAME level).
2154 ***************************************************************/
2156 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
2161 DATA_BLOB outbuf = data_blob_null;
2162 uint16_t fnum = 0xffff;
2163 uint32_t altnamelen = 0;
2164 TALLOC_CTX *frame = talloc_stackframe();
2166 if (smbXcli_conn_has_async_calls(cli->conn)) {
2168 * Can't use sync call while an async call is in flight
2170 status = NT_STATUS_INVALID_PARAMETER;
2174 status = get_fnum_from_path(cli,
2176 FILE_READ_ATTRIBUTES,
2179 if (!NT_STATUS_IS_OK(status)) {
2183 status = cli_smb2_query_info_fnum(
2186 1, /* in_info_type */
2187 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
2188 0xFFFF, /* in_max_output_length */
2189 NULL, /* in_input_buffer */
2190 0, /* in_additional_info */
2195 if (!NT_STATUS_IS_OK(status)) {
2199 /* Parse the reply. */
2200 if (outbuf.length < 4) {
2201 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2205 altnamelen = IVAL(outbuf.data, 0);
2206 if (altnamelen > outbuf.length - 4) {
2207 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2211 if (altnamelen > 0) {
2213 char *short_name = NULL;
2214 ret = pull_string_talloc(frame,
2216 FLAGS2_UNICODE_STRINGS,
2221 if (ret == (size_t)-1) {
2222 /* Bad conversion. */
2223 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2227 fstrcpy(alt_name, short_name);
2232 status = NT_STATUS_OK;
2236 if (fnum != 0xffff) {
2237 cli_smb2_close_fnum(cli, fnum);
2240 cli->raw_status = status;
2246 struct cli_smb2_qpathinfo_state {
2247 struct tevent_context *ev;
2248 struct cli_state *cli;
2259 static void cli_smb2_qpathinfo_opened(struct tevent_req *subreq);
2260 static void cli_smb2_qpathinfo_done(struct tevent_req *subreq);
2261 static void cli_smb2_qpathinfo_closed(struct tevent_req *subreq);
2263 struct tevent_req *cli_smb2_qpathinfo_send(TALLOC_CTX *mem_ctx,
2264 struct tevent_context *ev,
2265 struct cli_state *cli,
2271 struct tevent_req *req = NULL, *subreq = NULL;
2272 struct cli_smb2_qpathinfo_state *state = NULL;
2274 req = tevent_req_create(mem_ctx,
2276 struct cli_smb2_qpathinfo_state);
2282 state->level = level;
2283 state->min_rdata = min_rdata;
2284 state->max_rdata = max_rdata;
2286 subreq = get_fnum_from_path_send(state,
2290 FILE_READ_ATTRIBUTES);
2291 if (tevent_req_nomem(subreq, req)) {
2292 return tevent_req_post(req, ev);
2294 tevent_req_set_callback(subreq, cli_smb2_qpathinfo_opened, req);
2298 static void cli_smb2_qpathinfo_opened(struct tevent_req *subreq)
2300 struct tevent_req *req =
2301 tevent_req_callback_data(subreq, struct tevent_req);
2302 struct cli_smb2_qpathinfo_state *state =
2303 tevent_req_data(req, struct cli_smb2_qpathinfo_state);
2306 status = get_fnum_from_path_recv(subreq, &state->fnum);
2307 TALLOC_FREE(subreq);
2308 if (tevent_req_nterror(req, status)) {
2312 subreq = cli_smb2_query_info_fnum_send(state,
2316 1, /* in_info_type */
2319 NULL, /* in_input_buffer */
2320 0, /* in_additional_info */
2322 if (tevent_req_nomem(subreq, req)) {
2325 tevent_req_set_callback(subreq, cli_smb2_qpathinfo_done, req);
2328 static void cli_smb2_qpathinfo_done(struct tevent_req *subreq)
2330 struct tevent_req *req =
2331 tevent_req_callback_data(subreq, struct tevent_req);
2332 struct cli_smb2_qpathinfo_state *state =
2333 tevent_req_data(req, struct cli_smb2_qpathinfo_state);
2336 cli_smb2_query_info_fnum_recv(subreq, state, &state->out);
2337 TALLOC_FREE(subreq);
2339 if (NT_STATUS_IS_OK(state->status) &&
2340 (state->out.length < state->min_rdata)) {
2341 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2344 subreq = cli_smb2_close_fnum_send(state,
2348 if (tevent_req_nomem(subreq, req)) {
2351 tevent_req_set_callback(subreq, cli_smb2_qpathinfo_closed, req);
2354 static void cli_smb2_qpathinfo_closed(struct tevent_req *subreq)
2356 struct tevent_req *req =
2357 tevent_req_callback_data(subreq, struct tevent_req);
2358 struct cli_smb2_qpathinfo_state *state =
2359 tevent_req_data(req, struct cli_smb2_qpathinfo_state);
2362 status = cli_smb2_close_fnum_recv(subreq);
2363 TALLOC_FREE(subreq);
2364 if (tevent_req_nterror(req, status)) {
2367 if (tevent_req_nterror(req, state->status)) {
2370 tevent_req_done(req);
2373 NTSTATUS cli_smb2_qpathinfo_recv(struct tevent_req *req,
2374 TALLOC_CTX *mem_ctx,
2376 uint32_t *num_rdata)
2378 struct cli_smb2_qpathinfo_state *state =
2379 tevent_req_data(req, struct cli_smb2_qpathinfo_state);
2382 if (tevent_req_is_nterror(req, &status)) {
2386 *rdata = talloc_move(mem_ctx, &state->out.data);
2387 *num_rdata = state->out.length;
2388 tevent_req_received(req);
2389 return NT_STATUS_OK;
2392 /***************************************************************
2393 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2396 ***************************************************************/
2398 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
2400 uint8_t in_info_type,
2401 uint8_t in_file_info_class,
2402 const DATA_BLOB *p_in_data)
2405 uint16_t fnum = 0xffff;
2406 TALLOC_CTX *frame = talloc_stackframe();
2408 if (smbXcli_conn_has_async_calls(cli->conn)) {
2410 * Can't use sync call while an async call is in flight
2412 status = NT_STATUS_INVALID_PARAMETER;
2416 status = get_fnum_from_path(cli,
2418 FILE_WRITE_ATTRIBUTES,
2421 if (!NT_STATUS_IS_OK(status)) {
2425 status = cli_smb2_set_info_fnum(
2430 p_in_data, /* in_input_buffer */
2431 0); /* in_additional_info */
2434 if (fnum != 0xffff) {
2435 cli_smb2_close_fnum(cli, fnum);
2438 cli->raw_status = status;
2445 /***************************************************************
2446 Wrapper that allows SMB2 to set pathname attributes.
2448 ***************************************************************/
2450 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
2455 uint8_t inbuf_store[40];
2456 DATA_BLOB inbuf = data_blob_null;
2458 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2459 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2461 inbuf.data = inbuf_store;
2462 inbuf.length = sizeof(inbuf_store);
2463 data_blob_clear(&inbuf);
2466 * SMB1 uses attr == 0 to clear all attributes
2467 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2468 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2469 * request attribute change.
2471 * SMB2 uses exactly the reverse. Unfortunately as the
2472 * cli_setatr() ABI is exposed inside libsmbclient,
2473 * we must make the SMB2 cli_smb2_setatr() call
2474 * export the same ABI as the SMB1 cli_setatr()
2475 * which calls it. This means reversing the sense
2476 * of the requested attr argument if it's zero
2477 * or FILE_ATTRIBUTE_NORMAL.
2479 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2483 attr = FILE_ATTRIBUTE_NORMAL;
2484 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
2488 SIVAL(inbuf.data, 32, attr);
2490 put_long_date((char *)inbuf.data + 16,mtime);
2492 /* Set all the other times to -1. */
2493 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2494 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
2495 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
2497 return cli_smb2_setpathinfo(cli,
2499 1, /* in_info_type */
2500 /* in_file_info_class */
2501 SMB_FILE_BASIC_INFORMATION - 1000,
2506 /***************************************************************
2507 Wrapper that allows SMB2 to set file handle times.
2509 ***************************************************************/
2511 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
2517 uint8_t inbuf_store[40];
2518 DATA_BLOB inbuf = data_blob_null;
2521 if (smbXcli_conn_has_async_calls(cli->conn)) {
2523 * Can't use sync call while an async call is in flight
2525 return NT_STATUS_INVALID_PARAMETER;
2528 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2529 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2531 inbuf.data = inbuf_store;
2532 inbuf.length = sizeof(inbuf_store);
2533 data_blob_clear(&inbuf);
2535 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2536 if (change_time != 0) {
2537 put_long_date((char *)inbuf.data + 24, change_time);
2539 if (access_time != 0) {
2540 put_long_date((char *)inbuf.data + 8, access_time);
2542 if (write_time != 0) {
2543 put_long_date((char *)inbuf.data + 16, write_time);
2546 status = cli_smb2_set_info_fnum(cli,
2548 1, /* in_info_type */
2549 SMB_FILE_BASIC_INFORMATION -
2550 1000, /* in_file_info_class */
2551 &inbuf, /* in_input_buffer */
2552 0); /* in_additional_info */
2553 cli->raw_status = status;
2557 /***************************************************************
2558 Wrapper that allows SMB2 to query disk attributes (size).
2560 ***************************************************************/
2562 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2563 uint64_t *bsize, uint64_t *total, uint64_t *avail)
2566 uint16_t fnum = 0xffff;
2567 DATA_BLOB outbuf = data_blob_null;
2568 uint32_t sectors_per_unit = 0;
2569 uint32_t bytes_per_sector = 0;
2570 uint64_t total_size = 0;
2571 uint64_t size_free = 0;
2572 TALLOC_CTX *frame = talloc_stackframe();
2574 if (smbXcli_conn_has_async_calls(cli->conn)) {
2576 * Can't use sync call while an async call is in flight
2578 status = NT_STATUS_INVALID_PARAMETER;
2582 /* First open the top level directory. */
2583 status = cli_smb2_create_fnum(cli,
2585 (struct cli_smb2_create_flags){0},
2586 SMB2_IMPERSONATION_IMPERSONATION,
2587 FILE_READ_ATTRIBUTES, /* desired_access */
2588 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2589 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2590 FILE_OPEN, /* create_disposition */
2591 FILE_DIRECTORY_FILE, /* create_options */
2598 if (!NT_STATUS_IS_OK(status)) {
2602 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2603 level 3 (SMB_FS_SIZE_INFORMATION). */
2605 status = cli_smb2_query_info_fnum(
2608 2, /* in_info_type */
2609 3, /* in_file_info_class */
2610 0xFFFF, /* in_max_output_length */
2611 NULL, /* in_input_buffer */
2612 0, /* in_additional_info */
2616 if (!NT_STATUS_IS_OK(status)) {
2620 /* Parse the reply. */
2621 if (outbuf.length != 24) {
2622 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2626 total_size = BVAL(outbuf.data, 0);
2627 size_free = BVAL(outbuf.data, 8);
2628 sectors_per_unit = IVAL(outbuf.data, 16);
2629 bytes_per_sector = IVAL(outbuf.data, 20);
2632 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2635 *total = total_size;
2641 status = NT_STATUS_OK;
2645 if (fnum != 0xffff) {
2646 cli_smb2_close_fnum(cli, fnum);
2649 cli->raw_status = status;
2655 /***************************************************************
2656 Wrapper that allows SMB2 to query file system sizes.
2658 ***************************************************************/
2660 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2661 uint64_t *total_allocation_units,
2662 uint64_t *caller_allocation_units,
2663 uint64_t *actual_allocation_units,
2664 uint64_t *sectors_per_allocation_unit,
2665 uint64_t *bytes_per_sector)
2668 uint16_t fnum = 0xffff;
2669 DATA_BLOB outbuf = data_blob_null;
2670 TALLOC_CTX *frame = talloc_stackframe();
2672 if (smbXcli_conn_has_async_calls(cli->conn)) {
2674 * Can't use sync call while an async call is in flight
2676 status = NT_STATUS_INVALID_PARAMETER;
2680 /* First open the top level directory. */
2682 cli_smb2_create_fnum(cli, "",
2683 (struct cli_smb2_create_flags){0},
2684 SMB2_IMPERSONATION_IMPERSONATION,
2685 FILE_READ_ATTRIBUTES, /* desired_access */
2686 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2687 FILE_SHARE_READ | FILE_SHARE_WRITE |
2688 FILE_SHARE_DELETE, /* share_access */
2689 FILE_OPEN, /* create_disposition */
2690 FILE_DIRECTORY_FILE, /* create_options */
2697 if (!NT_STATUS_IS_OK(status)) {
2701 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2702 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2704 status = cli_smb2_query_info_fnum(
2707 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2708 SMB_FS_FULL_SIZE_INFORMATION - 1000, /* in_file_info_class */
2709 0xFFFF, /* in_max_output_length */
2710 NULL, /* in_input_buffer */
2711 0, /* in_additional_info */
2715 if (!NT_STATUS_IS_OK(status)) {
2719 if (outbuf.length < 32) {
2720 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2724 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2725 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2726 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2727 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2728 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2732 if (fnum != 0xffff) {
2733 cli_smb2_close_fnum(cli, fnum);
2736 cli->raw_status = status;
2742 /***************************************************************
2743 Wrapper that allows SMB2 to query file system attributes.
2745 ***************************************************************/
2747 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2750 uint16_t fnum = 0xffff;
2751 DATA_BLOB outbuf = data_blob_null;
2752 TALLOC_CTX *frame = talloc_stackframe();
2754 if (smbXcli_conn_has_async_calls(cli->conn)) {
2756 * Can't use sync call while an async call is in flight
2758 status = NT_STATUS_INVALID_PARAMETER;
2762 /* First open the top level directory. */
2764 cli_smb2_create_fnum(cli, "",
2765 (struct cli_smb2_create_flags){0},
2766 SMB2_IMPERSONATION_IMPERSONATION,
2767 FILE_READ_ATTRIBUTES, /* desired_access */
2768 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2769 FILE_SHARE_READ | FILE_SHARE_WRITE |
2770 FILE_SHARE_DELETE, /* share_access */
2771 FILE_OPEN, /* create_disposition */
2772 FILE_DIRECTORY_FILE, /* create_options */
2779 if (!NT_STATUS_IS_OK(status)) {
2783 status = cli_smb2_query_info_fnum(
2786 2, /* in_info_type */
2787 5, /* in_file_info_class */
2788 0xFFFF, /* in_max_output_length */
2789 NULL, /* in_input_buffer */
2790 0, /* in_additional_info */
2794 if (!NT_STATUS_IS_OK(status)) {
2798 if (outbuf.length < 12) {
2799 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2803 *fs_attr = IVAL(outbuf.data, 0);
2807 if (fnum != 0xffff) {
2808 cli_smb2_close_fnum(cli, fnum);
2811 cli->raw_status = status;
2817 /***************************************************************
2818 Wrapper that allows SMB2 to query file system volume info.
2820 ***************************************************************/
2822 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2823 TALLOC_CTX *mem_ctx,
2824 char **_volume_name,
2825 uint32_t *pserial_number,
2829 uint16_t fnum = 0xffff;
2830 DATA_BLOB outbuf = data_blob_null;
2832 char *volume_name = NULL;
2833 TALLOC_CTX *frame = talloc_stackframe();
2835 if (smbXcli_conn_has_async_calls(cli->conn)) {
2837 * Can't use sync call while an async call is in flight
2839 status = NT_STATUS_INVALID_PARAMETER;
2843 /* First open the top level directory. */
2845 cli_smb2_create_fnum(cli, "",
2846 (struct cli_smb2_create_flags){0},
2847 SMB2_IMPERSONATION_IMPERSONATION,
2848 FILE_READ_ATTRIBUTES, /* desired_access */
2849 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2850 FILE_SHARE_READ | FILE_SHARE_WRITE |
2851 FILE_SHARE_DELETE, /* share_access */
2852 FILE_OPEN, /* create_disposition */
2853 FILE_DIRECTORY_FILE, /* create_options */
2860 if (!NT_STATUS_IS_OK(status)) {
2864 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2865 level 1 (SMB_FS_VOLUME_INFORMATION). */
2867 status = cli_smb2_query_info_fnum(
2870 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2871 /* in_file_info_class */
2872 SMB_FS_VOLUME_INFORMATION - 1000,
2873 0xFFFF, /* in_max_output_length */
2874 NULL, /* in_input_buffer */
2875 0, /* in_additional_info */
2879 if (!NT_STATUS_IS_OK(status)) {
2883 if (outbuf.length < 24) {
2884 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2890 ts = interpret_long_date(BVAL(outbuf.data, 0));
2893 if (pserial_number) {
2894 *pserial_number = IVAL(outbuf.data,8);
2896 nlen = IVAL(outbuf.data,12);
2897 if (nlen + 18 < 18) {
2899 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2903 * The next check is safe as we know outbuf.length >= 24
2906 if (nlen > (outbuf.length - 18)) {
2907 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2911 pull_string_talloc(mem_ctx,
2912 (const char *)outbuf.data,
2918 if (volume_name == NULL) {
2919 status = map_nt_error_from_unix(errno);
2923 *_volume_name = volume_name;
2927 if (fnum != 0xffff) {
2928 cli_smb2_close_fnum(cli, fnum);
2931 cli->raw_status = status;
2937 struct cli_smb2_mxac_state {
2938 struct tevent_context *ev;
2939 struct cli_state *cli;
2941 struct smb2_create_blobs in_cblobs;
2947 static void cli_smb2_mxac_opened(struct tevent_req *subreq);
2948 static void cli_smb2_mxac_closed(struct tevent_req *subreq);
2950 struct tevent_req *cli_smb2_query_mxac_send(TALLOC_CTX *mem_ctx,
2951 struct tevent_context *ev,
2952 struct cli_state *cli,
2955 struct tevent_req *req = NULL, *subreq = NULL;
2956 struct cli_smb2_mxac_state *state = NULL;
2959 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_mxac_state);
2963 *state = (struct cli_smb2_mxac_state) {
2969 status = smb2_create_blob_add(state,
2971 SMB2_CREATE_TAG_MXAC,
2972 data_blob(NULL, 0));
2973 if (tevent_req_nterror(req, status)) {
2974 return tevent_req_post(req, ev);
2977 subreq = cli_smb2_create_fnum_send(
2982 (struct cli_smb2_create_flags){0},
2983 SMB2_IMPERSONATION_IMPERSONATION,
2984 FILE_READ_ATTRIBUTES,
2985 0, /* file attributes */
2986 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
2988 0, /* create_options */
2990 if (tevent_req_nomem(subreq, req)) {
2991 return tevent_req_post(req, ev);
2993 tevent_req_set_callback(subreq, cli_smb2_mxac_opened, req);
2997 static void cli_smb2_mxac_opened(struct tevent_req *subreq)
2999 struct tevent_req *req = tevent_req_callback_data(
3000 subreq, struct tevent_req);
3001 struct cli_smb2_mxac_state *state = tevent_req_data(
3002 req, struct cli_smb2_mxac_state);
3003 struct smb2_create_blobs out_cblobs = {0};
3004 struct smb2_create_blob *mxac_blob = NULL;
3007 status = cli_smb2_create_fnum_recv(
3008 subreq, &state->fnum, NULL, state, &out_cblobs, NULL);
3009 TALLOC_FREE(subreq);
3011 if (tevent_req_nterror(req, status)) {
3015 mxac_blob = smb2_create_blob_find(&out_cblobs, SMB2_CREATE_TAG_MXAC);
3016 if (mxac_blob == NULL) {
3017 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3020 if (mxac_blob->data.length != 8) {
3021 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3025 state->status = NT_STATUS(IVAL(mxac_blob->data.data, 0));
3026 state->mxac = IVAL(mxac_blob->data.data, 4);
3029 subreq = cli_smb2_close_fnum_send(
3030 state, state->ev, state->cli, state->fnum);
3031 if (tevent_req_nomem(subreq, req)) {
3034 tevent_req_set_callback(subreq, cli_smb2_mxac_closed, req);
3039 static void cli_smb2_mxac_closed(struct tevent_req *subreq)
3041 struct tevent_req *req = tevent_req_callback_data(
3042 subreq, struct tevent_req);
3045 status = cli_smb2_close_fnum_recv(subreq);
3046 if (tevent_req_nterror(req, status)) {
3050 tevent_req_done(req);
3053 NTSTATUS cli_smb2_query_mxac_recv(struct tevent_req *req, uint32_t *mxac)
3055 struct cli_smb2_mxac_state *state = tevent_req_data(
3056 req, struct cli_smb2_mxac_state);
3059 if (tevent_req_is_nterror(req, &status)) {
3063 if (!NT_STATUS_IS_OK(state->status)) {
3064 return state->status;
3067 *mxac = state->mxac;
3068 return NT_STATUS_OK;
3071 NTSTATUS cli_smb2_query_mxac(struct cli_state *cli,
3075 TALLOC_CTX *frame = talloc_stackframe();
3076 struct tevent_context *ev = NULL;
3077 struct tevent_req *req = NULL;
3078 NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
3081 if (smbXcli_conn_has_async_calls(cli->conn)) {
3083 * Can't use sync call while an async call is in flight
3085 status = NT_STATUS_INVALID_PARAMETER;
3089 ev = samba_tevent_context_init(frame);
3093 req = cli_smb2_query_mxac_send(frame, ev, cli, fname);
3097 ok = tevent_req_poll_ntstatus(req, ev, &status);
3101 status = cli_smb2_query_mxac_recv(req, _mxac);
3104 cli->raw_status = status;
3109 struct cli_smb2_rename_fnum_state {
3113 static void cli_smb2_rename_fnum_done(struct tevent_req *subreq);
3115 static struct tevent_req *cli_smb2_rename_fnum_send(
3116 TALLOC_CTX *mem_ctx,
3117 struct tevent_context *ev,
3118 struct cli_state *cli,
3120 const char *fname_dst,
3123 struct tevent_req *req = NULL, *subreq = NULL;
3124 struct cli_smb2_rename_fnum_state *state = NULL;
3125 size_t namelen = strlen(fname_dst);
3126 smb_ucs2_t *converted_str = NULL;
3127 size_t converted_size_bytes = 0;
3131 req = tevent_req_create(
3132 mem_ctx, &state, struct cli_smb2_rename_fnum_state);
3138 * SMB2 is pickier about pathnames. Ensure it doesn't start in
3141 if (*fname_dst == '\\') {
3146 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
3149 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
3150 fname_dst = talloc_strndup(state, fname_dst, namelen-1);
3151 if (tevent_req_nomem(fname_dst, req)) {
3152 return tevent_req_post(req, ev);
3156 ok = push_ucs2_talloc(
3157 state, &converted_str, fname_dst, &converted_size_bytes);
3159 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3160 return tevent_req_post(req, ev);
3164 * W2K8 insists the dest name is not null terminated. Remove
3165 * the last 2 zero bytes and reduce the name length.
3167 if (converted_size_bytes < 2) {
3168 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3169 return tevent_req_post(req, ev);
3171 converted_size_bytes -= 2;
3173 inbuf_size = 20 + converted_size_bytes;
3174 if (inbuf_size < 20) {
3175 /* Integer wrap check. */
3176 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3177 return tevent_req_post(req, ev);
3181 * The Windows 10 SMB2 server has a minimum length
3182 * for a SMB2_FILE_RENAME_INFORMATION buffer of
3183 * 24 bytes. It returns NT_STATUS_INFO_LENGTH_MISMATCH
3184 * if the length is less. This isn't an alignment
3185 * issue as Windows client accepts happily 2-byte align
3186 * for larger target name sizes. Also the Windows 10
3187 * SMB1 server doesn't have this restriction.
3189 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14403
3191 inbuf_size = MAX(inbuf_size, 24);
3193 state->inbuf = data_blob_talloc_zero(state, inbuf_size);
3194 if (tevent_req_nomem(state->inbuf.data, req)) {
3195 return tevent_req_post(req, ev);
3199 SCVAL(state->inbuf.data, 0, 1);
3202 SIVAL(state->inbuf.data, 16, converted_size_bytes);
3203 memcpy(state->inbuf.data + 20, converted_str, converted_size_bytes);
3205 TALLOC_FREE(converted_str);
3207 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3208 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3210 subreq = cli_smb2_set_info_fnum_send(
3211 state, /* mem_ctx */
3215 1, /* in_info_type */
3216 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
3217 &state->inbuf, /* in_input_buffer */
3218 0); /* in_additional_info */
3219 if (tevent_req_nomem(subreq, req)) {
3220 return tevent_req_post(req, ev);
3222 tevent_req_set_callback(subreq, cli_smb2_rename_fnum_done, req);
3226 static void cli_smb2_rename_fnum_done(struct tevent_req *subreq)
3228 NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
3229 tevent_req_simple_finish_ntstatus(subreq, status);
3232 static NTSTATUS cli_smb2_rename_fnum_recv(struct tevent_req *req)
3234 return tevent_req_simple_recv_ntstatus(req);
3237 /***************************************************************
3238 Wrapper that allows SMB2 to rename a file.
3239 ***************************************************************/
3241 struct cli_smb2_rename_state {
3242 struct tevent_context *ev;
3243 struct cli_state *cli;
3244 const char *fname_dst;
3248 NTSTATUS rename_status;
3251 static void cli_smb2_rename_opened(struct tevent_req *subreq);
3252 static void cli_smb2_rename_renamed(struct tevent_req *subreq);
3253 static void cli_smb2_rename_closed(struct tevent_req *subreq);
3255 struct tevent_req *cli_smb2_rename_send(
3256 TALLOC_CTX *mem_ctx,
3257 struct tevent_context *ev,
3258 struct cli_state *cli,
3259 const char *fname_src,
3260 const char *fname_dst,
3263 struct tevent_req *req = NULL, *subreq = NULL;
3264 struct cli_smb2_rename_state *state = NULL;
3267 req = tevent_req_create(
3268 mem_ctx, &state, struct cli_smb2_rename_state);
3274 * Strip a MSDFS path from fname_dst if we were given one.
3276 status = cli_dfs_target_check(state,
3280 if (tevent_req_nterror(req, status)) {
3281 return tevent_req_post(req, ev);
3286 state->fname_dst = fname_dst;
3287 state->replace = replace;
3289 subreq = get_fnum_from_path_send(
3290 state, ev, cli, fname_src, DELETE_ACCESS);
3291 if (tevent_req_nomem(subreq, req)) {
3292 return tevent_req_post(req, ev);
3294 tevent_req_set_callback(subreq, cli_smb2_rename_opened, req);
3298 static void cli_smb2_rename_opened(struct tevent_req *subreq)
3300 struct tevent_req *req = tevent_req_callback_data(
3301 subreq, struct tevent_req);
3302 struct cli_smb2_rename_state *state = tevent_req_data(
3303 req, struct cli_smb2_rename_state);
3306 status = get_fnum_from_path_recv(subreq, &state->fnum);
3307 TALLOC_FREE(subreq);
3308 if (tevent_req_nterror(req, status)) {
3312 subreq = cli_smb2_rename_fnum_send(
3319 if (tevent_req_nomem(subreq, req)) {
3322 tevent_req_set_callback(subreq, cli_smb2_rename_renamed, req);
3325 static void cli_smb2_rename_renamed(struct tevent_req *subreq)
3327 struct tevent_req *req = tevent_req_callback_data(
3328 subreq, struct tevent_req);
3329 struct cli_smb2_rename_state *state = tevent_req_data(
3330 req, struct cli_smb2_rename_state);
3332 state->rename_status = cli_smb2_rename_fnum_recv(subreq);
3333 TALLOC_FREE(subreq);
3335 subreq = cli_smb2_close_fnum_send(
3336 state, state->ev, state->cli, state->fnum);
3337 if (tevent_req_nomem(subreq, req)) {
3340 tevent_req_set_callback(subreq, cli_smb2_rename_closed, req);
3343 static void cli_smb2_rename_closed(struct tevent_req *subreq)
3345 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
3346 tevent_req_simple_finish_ntstatus(subreq, status);
3349 NTSTATUS cli_smb2_rename_recv(struct tevent_req *req)
3351 struct cli_smb2_rename_state *state = tevent_req_data(
3352 req, struct cli_smb2_rename_state);
3353 NTSTATUS status = NT_STATUS_OK;
3355 if (!tevent_req_is_nterror(req, &status)) {
3356 status = state->rename_status;
3358 tevent_req_received(req);
3362 /***************************************************************
3363 Wrapper that allows SMB2 to set an EA on a fnum.
3365 ***************************************************************/
3367 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
3369 const char *ea_name,
3374 DATA_BLOB inbuf = data_blob_null;
3376 char *ea_name_ascii = NULL;
3378 TALLOC_CTX *frame = talloc_stackframe();
3380 if (smbXcli_conn_has_async_calls(cli->conn)) {
3382 * Can't use sync call while an async call is in flight
3384 status = NT_STATUS_INVALID_PARAMETER;
3388 /* Marshall the SMB2 EA data. */
3389 if (ea_len > 0xFFFF) {
3390 status = NT_STATUS_INVALID_PARAMETER;
3394 if (!push_ascii_talloc(frame,
3398 status = NT_STATUS_INVALID_PARAMETER;
3402 if (namelen < 2 || namelen > 0xFF) {
3403 status = NT_STATUS_INVALID_PARAMETER;
3407 bloblen = 8 + ea_len + namelen;
3408 /* Round up to a 4 byte boundary. */
3409 bloblen = ((bloblen + 3)&~3);
3411 inbuf = data_blob_talloc_zero(frame, bloblen);
3412 if (inbuf.data == NULL) {
3413 status = NT_STATUS_NO_MEMORY;
3416 /* namelen doesn't include the NULL byte. */
3417 SCVAL(inbuf.data, 5, namelen - 1);
3418 SSVAL(inbuf.data, 6, ea_len);
3419 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
3420 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
3422 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3423 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3425 status = cli_smb2_set_info_fnum(
3428 1, /* in_info_type */
3429 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3430 &inbuf, /* in_input_buffer */
3431 0); /* in_additional_info */
3435 cli->raw_status = status;
3441 /***************************************************************
3442 Wrapper that allows SMB2 to set an EA on a pathname.
3444 ***************************************************************/
3446 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
3448 const char *ea_name,
3453 uint16_t fnum = 0xffff;
3455 if (smbXcli_conn_has_async_calls(cli->conn)) {
3457 * Can't use sync call while an async call is in flight
3459 status = NT_STATUS_INVALID_PARAMETER;
3463 status = get_fnum_from_path(cli,
3468 if (!NT_STATUS_IS_OK(status)) {
3472 status = cli_set_ea_fnum(cli,
3477 if (!NT_STATUS_IS_OK(status)) {
3483 if (fnum != 0xffff) {
3484 cli_smb2_close_fnum(cli, fnum);
3487 cli->raw_status = status;
3492 /***************************************************************
3493 Wrapper that allows SMB2 to get an EA list on a pathname.
3495 ***************************************************************/
3497 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
3501 struct ea_struct **pea_array)
3504 uint16_t fnum = 0xffff;
3505 DATA_BLOB outbuf = data_blob_null;
3506 struct ea_list *ea_list = NULL;
3507 struct ea_list *eal = NULL;
3508 size_t ea_count = 0;
3509 TALLOC_CTX *frame = talloc_stackframe();
3514 if (smbXcli_conn_has_async_calls(cli->conn)) {
3516 * Can't use sync call while an async call is in flight
3518 status = NT_STATUS_INVALID_PARAMETER;
3522 status = get_fnum_from_path(cli,
3527 if (!NT_STATUS_IS_OK(status)) {
3531 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3532 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3534 status = cli_smb2_query_info_fnum(
3537 1, /* in_info_type */
3538 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3539 0xFFFF, /* in_max_output_length */
3540 NULL, /* in_input_buffer */
3541 0, /* in_additional_info */
3546 if (!NT_STATUS_IS_OK(status)) {
3550 /* Parse the reply. */
3551 ea_list = read_nttrans_ea_list(ctx,
3552 (const char *)outbuf.data,
3554 if (ea_list == NULL) {
3555 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3559 /* Convert to an array. */
3560 for (eal = ea_list; eal; eal = eal->next) {
3565 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
3566 if (*pea_array == NULL) {
3567 status = NT_STATUS_NO_MEMORY;
3571 for (eal = ea_list; eal; eal = eal->next) {
3572 (*pea_array)[ea_count++] = eal->ea;
3574 *pnum_eas = ea_count;
3579 if (fnum != 0xffff) {
3580 cli_smb2_close_fnum(cli, fnum);
3583 cli->raw_status = status;
3589 /***************************************************************
3590 Wrapper that allows SMB2 to get user quota.
3592 ***************************************************************/
3594 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
3596 SMB_NTQUOTA_STRUCT *pqt)
3599 DATA_BLOB inbuf = data_blob_null;
3600 DATA_BLOB info_blob = data_blob_null;
3601 DATA_BLOB outbuf = data_blob_null;
3602 TALLOC_CTX *frame = talloc_stackframe();
3604 unsigned int offset;
3605 struct smb2_query_quota_info query = {0};
3606 struct file_get_quota_info info = {0};
3607 enum ndr_err_code err;
3608 struct ndr_push *ndr_push = NULL;
3610 if (smbXcli_conn_has_async_calls(cli->conn)) {
3612 * Can't use sync call while an async call is in flight
3614 status = NT_STATUS_INVALID_PARAMETER;
3618 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
3620 query.return_single = 1;
3622 info.next_entry_offset = 0;
3623 info.sid_length = sid_len;
3624 info.sid = pqt->sid;
3626 err = ndr_push_struct_blob(
3630 (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
3632 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3633 status = NT_STATUS_INTERNAL_ERROR;
3637 query.sid_list_length = info_blob.length;
3638 ndr_push = ndr_push_init_ctx(frame);
3640 status = NT_STATUS_NO_MEMORY;
3644 err = ndr_push_smb2_query_quota_info(ndr_push,
3645 NDR_SCALARS | NDR_BUFFERS,
3648 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3649 status = NT_STATUS_INTERNAL_ERROR;
3653 err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3656 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3657 status = NT_STATUS_INTERNAL_ERROR;
3660 inbuf.data = ndr_push->data;
3661 inbuf.length = ndr_push->offset;
3663 status = cli_smb2_query_info_fnum(
3666 4, /* in_info_type */
3667 0, /* in_file_info_class */
3668 0xFFFF, /* in_max_output_length */
3669 &inbuf, /* in_input_buffer */
3670 0, /* in_additional_info */
3675 if (!NT_STATUS_IS_OK(status)) {
3679 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3681 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3682 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3686 cli->raw_status = status;
3692 /***************************************************************
3693 Wrapper that allows SMB2 to list user quota.
3695 ***************************************************************/
3697 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3698 TALLOC_CTX *mem_ctx,
3700 SMB_NTQUOTA_LIST **pqt_list,
3704 DATA_BLOB inbuf = data_blob_null;
3705 DATA_BLOB outbuf = data_blob_null;
3706 TALLOC_CTX *frame = talloc_stackframe();
3707 struct smb2_query_quota_info info = {0};
3708 enum ndr_err_code err;
3710 if (smbXcli_conn_has_async_calls(cli->conn)) {
3712 * Can't use sync call while an async call is in flight
3714 status = NT_STATUS_INVALID_PARAMETER;
3718 info.restart_scan = first ? 1 : 0;
3720 err = ndr_push_struct_blob(
3724 (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3726 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3727 status = NT_STATUS_INTERNAL_ERROR;
3731 status = cli_smb2_query_info_fnum(
3734 4, /* in_info_type */
3735 0, /* in_file_info_class */
3736 0xFFFF, /* in_max_output_length */
3737 &inbuf, /* in_input_buffer */
3738 0, /* in_additional_info */
3744 * safeguard against panic from calling parse_user_quota_list with
3747 if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3748 status = NT_STATUS_NO_MORE_ENTRIES;
3751 if (!NT_STATUS_IS_OK(status)) {
3755 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3759 cli->raw_status = status;
3765 /***************************************************************
3766 Wrapper that allows SMB2 to get file system quota.
3768 ***************************************************************/
3770 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3772 SMB_NTQUOTA_STRUCT *pqt)
3775 DATA_BLOB outbuf = data_blob_null;
3776 TALLOC_CTX *frame = talloc_stackframe();
3778 if (smbXcli_conn_has_async_calls(cli->conn)) {
3780 * Can't use sync call while an async call is in flight
3782 status = NT_STATUS_INVALID_PARAMETER;
3786 status = cli_smb2_query_info_fnum(
3789 2, /* in_info_type */
3790 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3791 0xFFFF, /* in_max_output_length */
3792 NULL, /* in_input_buffer */
3793 0, /* in_additional_info */
3798 if (!NT_STATUS_IS_OK(status)) {
3802 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3805 cli->raw_status = status;
3811 /***************************************************************
3812 Wrapper that allows SMB2 to set user quota.
3814 ***************************************************************/
3816 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3818 SMB_NTQUOTA_LIST *qtl)
3821 DATA_BLOB inbuf = data_blob_null;
3822 TALLOC_CTX *frame = talloc_stackframe();
3824 if (smbXcli_conn_has_async_calls(cli->conn)) {
3826 * Can't use sync call while an async call is in flight
3828 status = NT_STATUS_INVALID_PARAMETER;
3832 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3833 if (!NT_STATUS_IS_OK(status)) {
3837 status = cli_smb2_set_info_fnum(
3840 4, /* in_info_type */
3841 0, /* in_file_info_class */
3842 &inbuf, /* in_input_buffer */
3843 0); /* in_additional_info */
3846 cli->raw_status = status;
3853 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3855 SMB_NTQUOTA_STRUCT *pqt)
3858 DATA_BLOB inbuf = data_blob_null;
3859 TALLOC_CTX *frame = talloc_stackframe();
3861 if (smbXcli_conn_has_async_calls(cli->conn)) {
3863 * Can't use sync call while an async call is in flight
3865 status = NT_STATUS_INVALID_PARAMETER;
3869 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3870 if (!NT_STATUS_IS_OK(status)) {
3874 status = cli_smb2_set_info_fnum(
3877 2, /* in_info_type */
3878 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3879 &inbuf, /* in_input_buffer */
3880 0); /* in_additional_info */
3882 cli->raw_status = status;
3888 struct cli_smb2_read_state {
3889 struct tevent_context *ev;
3890 struct cli_state *cli;
3891 struct smb2_hnd *ph;
3892 uint64_t start_offset;
3898 static void cli_smb2_read_done(struct tevent_req *subreq);
3900 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3901 struct tevent_context *ev,
3902 struct cli_state *cli,
3908 struct tevent_req *req, *subreq;
3909 struct cli_smb2_read_state *state;
3911 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3917 state->start_offset = (uint64_t)offset;
3918 state->size = (uint32_t)size;
3919 state->received = 0;
3922 status = map_fnum_to_smb2_handle(cli,
3925 if (tevent_req_nterror(req, status)) {
3926 return tevent_req_post(req, ev);
3929 subreq = smb2cli_read_send(state,
3932 state->cli->timeout,
3933 state->cli->smb2.session,
3934 state->cli->smb2.tcon,
3936 state->start_offset,
3937 state->ph->fid_persistent,
3938 state->ph->fid_volatile,
3939 0, /* minimum_count */
3940 0); /* remaining_bytes */
3942 if (tevent_req_nomem(subreq, req)) {
3943 return tevent_req_post(req, ev);
3945 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3949 static void cli_smb2_read_done(struct tevent_req *subreq)
3951 struct tevent_req *req = tevent_req_callback_data(
3952 subreq, struct tevent_req);
3953 struct cli_smb2_read_state *state = tevent_req_data(
3954 req, struct cli_smb2_read_state);
3957 status = smb2cli_read_recv(subreq, state,
3958 &state->buf, &state->received);
3959 if (tevent_req_nterror(req, status)) {
3963 if (state->received > state->size) {
3964 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3968 tevent_req_done(req);
3971 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
3976 struct cli_smb2_read_state *state = tevent_req_data(
3977 req, struct cli_smb2_read_state);
3979 if (tevent_req_is_nterror(req, &status)) {
3980 state->cli->raw_status = status;
3984 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3985 * better make sure that you copy it away before you talloc_free(req).
3986 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3988 *received = (ssize_t)state->received;
3989 *rcvbuf = state->buf;
3990 state->cli->raw_status = NT_STATUS_OK;
3991 return NT_STATUS_OK;
3994 struct cli_smb2_write_state {
3995 struct tevent_context *ev;
3996 struct cli_state *cli;
3997 struct smb2_hnd *ph;
4005 static void cli_smb2_write_written(struct tevent_req *req);
4007 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
4008 struct tevent_context *ev,
4009 struct cli_state *cli,
4017 struct tevent_req *req, *subreq = NULL;
4018 struct cli_smb2_write_state *state = NULL;
4020 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
4026 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4027 state->flags = (uint32_t)mode;
4029 state->offset = (uint64_t)offset;
4030 state->size = (uint32_t)size;
4033 status = map_fnum_to_smb2_handle(cli,
4036 if (tevent_req_nterror(req, status)) {
4037 return tevent_req_post(req, ev);
4040 subreq = smb2cli_write_send(state,
4043 state->cli->timeout,
4044 state->cli->smb2.session,
4045 state->cli->smb2.tcon,
4048 state->ph->fid_persistent,
4049 state->ph->fid_volatile,
4050 0, /* remaining_bytes */
4051 state->flags, /* flags */
4054 if (tevent_req_nomem(subreq, req)) {
4055 return tevent_req_post(req, ev);
4057 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
4061 static void cli_smb2_write_written(struct tevent_req *subreq)
4063 struct tevent_req *req = tevent_req_callback_data(
4064 subreq, struct tevent_req);
4065 struct cli_smb2_write_state *state = tevent_req_data(
4066 req, struct cli_smb2_write_state);
4070 status = smb2cli_write_recv(subreq, &written);
4071 TALLOC_FREE(subreq);
4072 if (tevent_req_nterror(req, status)) {
4076 state->written = written;
4078 tevent_req_done(req);
4081 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
4084 struct cli_smb2_write_state *state = tevent_req_data(
4085 req, struct cli_smb2_write_state);
4088 if (tevent_req_is_nterror(req, &status)) {
4089 state->cli->raw_status = status;
4090 tevent_req_received(req);
4094 if (pwritten != NULL) {
4095 *pwritten = (size_t)state->written;
4097 state->cli->raw_status = NT_STATUS_OK;
4098 tevent_req_received(req);
4099 return NT_STATUS_OK;
4102 /***************************************************************
4103 Wrapper that allows SMB2 async write using an fnum.
4104 This is mostly cut-and-paste from Volker's code inside
4105 source3/libsmb/clireadwrite.c, adapted for SMB2.
4107 Done this way so I can reuse all the logic inside cli_push()
4109 ***************************************************************/
4111 struct cli_smb2_writeall_state {
4112 struct tevent_context *ev;
4113 struct cli_state *cli;
4114 struct smb2_hnd *ph;
4122 static void cli_smb2_writeall_written(struct tevent_req *req);
4124 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
4125 struct tevent_context *ev,
4126 struct cli_state *cli,
4134 struct tevent_req *req, *subreq = NULL;
4135 struct cli_smb2_writeall_state *state = NULL;
4140 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
4146 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4147 state->flags = (uint32_t)mode;
4149 state->offset = (uint64_t)offset;
4150 state->size = (uint32_t)size;
4153 status = map_fnum_to_smb2_handle(cli,
4156 if (tevent_req_nterror(req, status)) {
4157 return tevent_req_post(req, ev);
4160 to_write = state->size;
4161 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4162 to_write = MIN(max_size, to_write);
4163 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4165 to_write = MIN(max_size, to_write);
4168 subreq = smb2cli_write_send(state,
4171 state->cli->timeout,
4172 state->cli->smb2.session,
4173 state->cli->smb2.tcon,
4176 state->ph->fid_persistent,
4177 state->ph->fid_volatile,
4178 0, /* remaining_bytes */
4179 state->flags, /* flags */
4180 state->buf + state->written);
4182 if (tevent_req_nomem(subreq, req)) {
4183 return tevent_req_post(req, ev);
4185 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4189 static void cli_smb2_writeall_written(struct tevent_req *subreq)
4191 struct tevent_req *req = tevent_req_callback_data(
4192 subreq, struct tevent_req);
4193 struct cli_smb2_writeall_state *state = tevent_req_data(
4194 req, struct cli_smb2_writeall_state);
4196 uint32_t written, to_write;
4200 status = smb2cli_write_recv(subreq, &written);
4201 TALLOC_FREE(subreq);
4202 if (tevent_req_nterror(req, status)) {
4206 state->written += written;
4208 if (state->written > state->size) {
4209 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4213 to_write = state->size - state->written;
4215 if (to_write == 0) {
4216 tevent_req_done(req);
4220 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4221 to_write = MIN(max_size, to_write);
4222 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4224 to_write = MIN(max_size, to_write);
4227 subreq = smb2cli_write_send(state,
4230 state->cli->timeout,
4231 state->cli->smb2.session,
4232 state->cli->smb2.tcon,
4234 state->offset + state->written,
4235 state->ph->fid_persistent,
4236 state->ph->fid_volatile,
4237 0, /* remaining_bytes */
4238 state->flags, /* flags */
4239 state->buf + state->written);
4241 if (tevent_req_nomem(subreq, req)) {
4244 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4247 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
4250 struct cli_smb2_writeall_state *state = tevent_req_data(
4251 req, struct cli_smb2_writeall_state);
4254 if (tevent_req_is_nterror(req, &status)) {
4255 state->cli->raw_status = status;
4258 if (pwritten != NULL) {
4259 *pwritten = (size_t)state->written;
4261 state->cli->raw_status = NT_STATUS_OK;
4262 return NT_STATUS_OK;
4265 struct cli_smb2_splice_state {
4266 struct tevent_context *ev;
4267 struct cli_state *cli;
4268 struct smb2_hnd *src_ph;
4269 struct smb2_hnd *dst_ph;
4270 int (*splice_cb)(off_t n, void *priv);
4277 struct req_resume_key_rsp resume_rsp;
4278 struct srv_copychunk_copy cc_copy;
4281 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4282 struct tevent_req *req);
4284 static void cli_splice_copychunk_done(struct tevent_req *subreq)
4286 struct tevent_req *req = tevent_req_callback_data(
4287 subreq, struct tevent_req);
4288 struct cli_smb2_splice_state *state =
4289 tevent_req_data(req,
4290 struct cli_smb2_splice_state);
4291 struct smbXcli_conn *conn = state->cli->conn;
4292 DATA_BLOB out_input_buffer = data_blob_null;
4293 DATA_BLOB out_output_buffer = data_blob_null;
4294 struct srv_copychunk_rsp cc_copy_rsp;
4295 enum ndr_err_code ndr_ret;
4298 status = smb2cli_ioctl_recv(subreq, state,
4300 &out_output_buffer);
4301 TALLOC_FREE(subreq);
4302 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
4303 state->resized) && tevent_req_nterror(req, status)) {
4307 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
4308 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
4309 if (ndr_ret != NDR_ERR_SUCCESS) {
4310 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4311 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4315 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
4316 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
4317 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
4318 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
4319 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
4320 tevent_req_nterror(req, status)) {
4324 state->resized = true;
4325 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
4326 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
4328 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4329 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4330 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
4331 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4334 state->src_offset += cc_copy_rsp.total_bytes_written;
4335 state->dst_offset += cc_copy_rsp.total_bytes_written;
4336 state->written += cc_copy_rsp.total_bytes_written;
4337 if (!state->splice_cb(state->written, state->priv)) {
4338 tevent_req_nterror(req, NT_STATUS_CANCELLED);
4343 cli_splice_copychunk_send(state, req);
4346 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4347 struct tevent_req *req)
4349 struct tevent_req *subreq;
4350 enum ndr_err_code ndr_ret;
4351 struct smbXcli_conn *conn = state->cli->conn;
4352 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
4353 off_t src_offset = state->src_offset;
4354 off_t dst_offset = state->dst_offset;
4355 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
4356 state->size - state->written);
4357 DATA_BLOB in_input_buffer = data_blob_null;
4358 DATA_BLOB in_output_buffer = data_blob_null;
4360 if (state->size - state->written == 0) {
4361 tevent_req_done(req);
4365 cc_copy->chunk_count = 0;
4367 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
4368 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
4369 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
4370 smb2cli_conn_cc_chunk_len(conn));
4371 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
4372 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4375 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
4376 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
4377 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
4378 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4381 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4382 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4383 cc_copy->chunk_count++;
4386 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
4387 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
4388 if (ndr_ret != NDR_ERR_SUCCESS) {
4389 DEBUG(0, ("failed to marshall copy chunk req\n"));
4390 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4394 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
4395 state->cli->timeout,
4396 state->cli->smb2.session,
4397 state->cli->smb2.tcon,
4398 state->dst_ph->fid_persistent, /* in_fid_persistent */
4399 state->dst_ph->fid_volatile, /* in_fid_volatile */
4400 FSCTL_SRV_COPYCHUNK_WRITE,
4401 0, /* in_max_input_length */
4403 12, /* in_max_output_length */
4405 SMB2_IOCTL_FLAG_IS_FSCTL);
4406 if (tevent_req_nomem(subreq, req)) {
4409 tevent_req_set_callback(subreq,
4410 cli_splice_copychunk_done,
4414 static void cli_splice_key_done(struct tevent_req *subreq)
4416 struct tevent_req *req = tevent_req_callback_data(
4417 subreq, struct tevent_req);
4418 struct cli_smb2_splice_state *state =
4419 tevent_req_data(req,
4420 struct cli_smb2_splice_state);
4421 enum ndr_err_code ndr_ret;
4424 DATA_BLOB out_input_buffer = data_blob_null;
4425 DATA_BLOB out_output_buffer = data_blob_null;
4427 status = smb2cli_ioctl_recv(subreq, state,
4429 &out_output_buffer);
4430 TALLOC_FREE(subreq);
4431 if (tevent_req_nterror(req, status)) {
4435 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
4436 state, &state->resume_rsp,
4437 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
4438 if (ndr_ret != NDR_ERR_SUCCESS) {
4439 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4440 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4444 memcpy(&state->cc_copy.source_key,
4445 &state->resume_rsp.resume_key,
4446 sizeof state->resume_rsp.resume_key);
4448 cli_splice_copychunk_send(state, req);
4451 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
4452 struct tevent_context *ev,
4453 struct cli_state *cli,
4454 uint16_t src_fnum, uint16_t dst_fnum,
4455 off_t size, off_t src_offset, off_t dst_offset,
4456 int (*splice_cb)(off_t n, void *priv),
4459 struct tevent_req *req;
4460 struct tevent_req *subreq;
4461 struct cli_smb2_splice_state *state;
4463 DATA_BLOB in_input_buffer = data_blob_null;
4464 DATA_BLOB in_output_buffer = data_blob_null;
4466 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
4472 state->splice_cb = splice_cb;
4476 state->src_offset = src_offset;
4477 state->dst_offset = dst_offset;
4478 state->cc_copy.chunks = talloc_array(state,
4479 struct srv_copychunk,
4480 smb2cli_conn_cc_max_chunks(cli->conn));
4481 if (state->cc_copy.chunks == NULL) {
4485 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
4486 if (tevent_req_nterror(req, status))
4487 return tevent_req_post(req, ev);
4489 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
4490 if (tevent_req_nterror(req, status))
4491 return tevent_req_post(req, ev);
4493 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
4497 state->src_ph->fid_persistent, /* in_fid_persistent */
4498 state->src_ph->fid_volatile, /* in_fid_volatile */
4499 FSCTL_SRV_REQUEST_RESUME_KEY,
4500 0, /* in_max_input_length */
4502 32, /* in_max_output_length */
4504 SMB2_IOCTL_FLAG_IS_FSCTL);
4505 if (tevent_req_nomem(subreq, req)) {
4508 tevent_req_set_callback(subreq,
4509 cli_splice_key_done,
4515 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
4517 struct cli_smb2_splice_state *state = tevent_req_data(
4518 req, struct cli_smb2_splice_state);
4521 if (tevent_req_is_nterror(req, &status)) {
4522 state->cli->raw_status = status;
4523 tevent_req_received(req);
4526 if (written != NULL) {
4527 *written = state->written;
4529 state->cli->raw_status = NT_STATUS_OK;
4530 tevent_req_received(req);
4531 return NT_STATUS_OK;
4534 /***************************************************************
4535 SMB2 enum shadow copy data.
4536 ***************************************************************/
4538 struct cli_smb2_shadow_copy_data_fnum_state {
4539 struct cli_state *cli;
4541 struct smb2_hnd *ph;
4542 DATA_BLOB out_input_buffer;
4543 DATA_BLOB out_output_buffer;
4546 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
4548 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
4549 TALLOC_CTX *mem_ctx,
4550 struct tevent_context *ev,
4551 struct cli_state *cli,
4555 struct tevent_req *req, *subreq;
4556 struct cli_smb2_shadow_copy_data_fnum_state *state;
4559 req = tevent_req_create(mem_ctx, &state,
4560 struct cli_smb2_shadow_copy_data_fnum_state);
4568 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4569 if (tevent_req_nterror(req, status)) {
4570 return tevent_req_post(req, ev);
4574 * TODO. Under SMB2 we should send a zero max_output_length
4575 * ioctl to get the required size, then send another ioctl
4576 * to get the data, but the current SMB1 implementation just
4577 * does one roundtrip with a 64K buffer size. Do the same
4581 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4582 state->cli->timeout,
4583 state->cli->smb2.session,
4584 state->cli->smb2.tcon,
4585 state->ph->fid_persistent, /* in_fid_persistent */
4586 state->ph->fid_volatile, /* in_fid_volatile */
4587 FSCTL_GET_SHADOW_COPY_DATA,
4588 0, /* in_max_input_length */
4589 NULL, /* in_input_buffer */
4591 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
4592 NULL, /* in_output_buffer */
4593 SMB2_IOCTL_FLAG_IS_FSCTL);
4595 if (tevent_req_nomem(subreq, req)) {
4596 return tevent_req_post(req, ev);
4598 tevent_req_set_callback(subreq,
4599 cli_smb2_shadow_copy_data_fnum_done,
4605 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4607 struct tevent_req *req = tevent_req_callback_data(
4608 subreq, struct tevent_req);
4609 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4610 req, struct cli_smb2_shadow_copy_data_fnum_state);
4613 status = smb2cli_ioctl_recv(subreq, state,
4614 &state->out_input_buffer,
4615 &state->out_output_buffer);
4616 tevent_req_simple_finish_ntstatus(subreq, status);
4619 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4620 TALLOC_CTX *mem_ctx,
4625 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4626 req, struct cli_smb2_shadow_copy_data_fnum_state);
4627 char **names = NULL;
4628 uint32_t num_names = 0;
4629 uint32_t num_names_returned = 0;
4630 uint32_t dlength = 0;
4632 uint8_t *endp = NULL;
4635 if (tevent_req_is_nterror(req, &status)) {
4639 if (state->out_output_buffer.length < 16) {
4640 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4643 num_names = IVAL(state->out_output_buffer.data, 0);
4644 num_names_returned = IVAL(state->out_output_buffer.data, 4);
4645 dlength = IVAL(state->out_output_buffer.data, 8);
4647 if (num_names > 0x7FFFFFFF) {
4648 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4651 if (get_names == false) {
4652 *pnum_names = (int)num_names;
4653 return NT_STATUS_OK;
4655 if (num_names != num_names_returned) {
4656 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4658 if (dlength + 12 < 12) {
4659 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4662 * NB. The below is an allowable return if there are
4663 * more snapshots than the buffer size we told the
4664 * server we can receive. We currently don't support
4667 if (dlength + 12 > state->out_output_buffer.length) {
4668 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4670 if (state->out_output_buffer.length +
4671 (2 * sizeof(SHADOW_COPY_LABEL)) <
4672 state->out_output_buffer.length) {
4673 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4676 names = talloc_array(mem_ctx, char *, num_names_returned);
4677 if (names == NULL) {
4678 return NT_STATUS_NO_MEMORY;
4681 endp = state->out_output_buffer.data +
4682 state->out_output_buffer.length;
4684 for (i=0; i<num_names_returned; i++) {
4687 size_t converted_size;
4689 src = state->out_output_buffer.data + 12 +
4690 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4692 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4693 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4695 ret = convert_string_talloc(
4696 names, CH_UTF16LE, CH_UNIX,
4697 src, 2 * sizeof(SHADOW_COPY_LABEL),
4698 &names[i], &converted_size);
4701 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4704 *pnum_names = num_names;
4706 return NT_STATUS_OK;
4709 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4710 struct cli_state *cli,
4716 TALLOC_CTX *frame = talloc_stackframe();
4717 struct tevent_context *ev;
4718 struct tevent_req *req;
4719 NTSTATUS status = NT_STATUS_NO_MEMORY;
4721 if (smbXcli_conn_has_async_calls(cli->conn)) {
4723 * Can't use sync call while an async call is in flight
4725 status = NT_STATUS_INVALID_PARAMETER;
4728 ev = samba_tevent_context_init(frame);
4732 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4740 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4743 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4749 cli->raw_status = status;
4755 /***************************************************************
4756 Wrapper that allows SMB2 to truncate a file.
4758 ***************************************************************/
4760 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4765 uint8_t buf[8] = {0};
4766 DATA_BLOB inbuf = { .data = buf, .length = sizeof(buf) };
4767 TALLOC_CTX *frame = talloc_stackframe();
4769 if (smbXcli_conn_has_async_calls(cli->conn)) {
4771 * Can't use sync call while an async call is in flight
4773 status = NT_STATUS_INVALID_PARAMETER;
4777 SBVAL(buf, 0, newsize);
4779 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4780 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4782 status = cli_smb2_set_info_fnum(
4785 1, /* in_info_type */
4786 SMB_FILE_END_OF_FILE_INFORMATION-1000, /* in_file_info_class */
4787 &inbuf, /* in_input_buffer */
4792 cli->raw_status = status;
4798 struct cli_smb2_notify_state {
4799 struct tevent_req *subreq;
4800 struct notify_change *changes;
4804 static void cli_smb2_notify_done(struct tevent_req *subreq);
4805 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4807 struct tevent_req *cli_smb2_notify_send(
4808 TALLOC_CTX *mem_ctx,
4809 struct tevent_context *ev,
4810 struct cli_state *cli,
4812 uint32_t buffer_size,
4813 uint32_t completion_filter,
4816 struct tevent_req *req = NULL;
4817 struct cli_smb2_notify_state *state = NULL;
4818 struct smb2_hnd *ph = NULL;
4821 req = tevent_req_create(mem_ctx, &state,
4822 struct cli_smb2_notify_state);
4827 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4828 if (tevent_req_nterror(req, status)) {
4829 return tevent_req_post(req, ev);
4832 state->subreq = smb2cli_notify_send(
4844 if (tevent_req_nomem(state->subreq, req)) {
4845 return tevent_req_post(req, ev);
4847 tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4848 tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4852 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4854 struct cli_smb2_notify_state *state = tevent_req_data(
4855 req, struct cli_smb2_notify_state);
4858 ok = tevent_req_cancel(state->subreq);
4862 static void cli_smb2_notify_done(struct tevent_req *subreq)
4864 struct tevent_req *req = tevent_req_callback_data(
4865 subreq, struct tevent_req);
4866 struct cli_smb2_notify_state *state = tevent_req_data(
4867 req, struct cli_smb2_notify_state);
4873 status = smb2cli_notify_recv(subreq, state, &base, &len);
4874 TALLOC_FREE(subreq);
4876 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4877 tevent_req_done(req);
4880 if (tevent_req_nterror(req, status)) {
4886 while (len - ofs >= 12) {
4887 struct notify_change *tmp;
4888 struct notify_change *c;
4889 uint32_t next_ofs = IVAL(base, ofs);
4890 uint32_t file_name_length = IVAL(base, ofs+8);
4894 tmp = talloc_realloc(
4897 struct notify_change,
4898 state->num_changes + 1);
4899 if (tevent_req_nomem(tmp, req)) {
4902 state->changes = tmp;
4903 c = &state->changes[state->num_changes];
4904 state->num_changes += 1;
4906 if (smb_buffer_oob(len, ofs, next_ofs) ||
4907 smb_buffer_oob(len, ofs+12, file_name_length)) {
4909 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4913 c->action = IVAL(base, ofs+4);
4915 ok = convert_string_talloc(
4925 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4929 if (next_ofs == 0) {
4935 tevent_req_done(req);
4938 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
4939 TALLOC_CTX *mem_ctx,
4940 struct notify_change **pchanges,
4941 uint32_t *pnum_changes)
4943 struct cli_smb2_notify_state *state = tevent_req_data(
4944 req, struct cli_smb2_notify_state);
4947 if (tevent_req_is_nterror(req, &status)) {
4950 *pchanges = talloc_move(mem_ctx, &state->changes);
4951 *pnum_changes = state->num_changes;
4952 return NT_STATUS_OK;
4955 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
4956 uint32_t buffer_size, uint32_t completion_filter,
4957 bool recursive, TALLOC_CTX *mem_ctx,
4958 struct notify_change **pchanges,
4959 uint32_t *pnum_changes)
4961 TALLOC_CTX *frame = talloc_stackframe();
4962 struct tevent_context *ev;
4963 struct tevent_req *req;
4964 NTSTATUS status = NT_STATUS_NO_MEMORY;
4966 if (smbXcli_conn_has_async_calls(cli->conn)) {
4968 * Can't use sync call while an async call is in flight
4970 status = NT_STATUS_INVALID_PARAMETER;
4973 ev = samba_tevent_context_init(frame);
4977 req = cli_smb2_notify_send(
4988 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4991 status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
4997 struct cli_smb2_fsctl_state {
5001 static void cli_smb2_fsctl_done(struct tevent_req *subreq);
5003 struct tevent_req *cli_smb2_fsctl_send(
5004 TALLOC_CTX *mem_ctx,
5005 struct tevent_context *ev,
5006 struct cli_state *cli,
5009 const DATA_BLOB *in,
5012 struct tevent_req *req = NULL, *subreq = NULL;
5013 struct cli_smb2_fsctl_state *state = NULL;
5014 struct smb2_hnd *ph = NULL;
5017 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_fsctl_state);
5022 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
5023 if (tevent_req_nterror(req, status)) {
5024 return tevent_req_post(req, ev);
5027 subreq = smb2cli_ioctl_send(
5037 0, /* in_max_input_length */
5041 SMB2_IOCTL_FLAG_IS_FSCTL);
5043 if (tevent_req_nomem(subreq, req)) {
5044 return tevent_req_post(req, ev);
5046 tevent_req_set_callback(subreq, cli_smb2_fsctl_done, req);
5050 static void cli_smb2_fsctl_done(struct tevent_req *subreq)
5052 struct tevent_req *req = tevent_req_callback_data(
5053 subreq, struct tevent_req);
5054 struct cli_smb2_fsctl_state *state = tevent_req_data(
5055 req, struct cli_smb2_fsctl_state);
5058 status = smb2cli_ioctl_recv(subreq, state, NULL, &state->out);
5059 tevent_req_simple_finish_ntstatus(subreq, status);
5062 NTSTATUS cli_smb2_fsctl_recv(
5063 struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *out)
5065 struct cli_smb2_fsctl_state *state = tevent_req_data(
5066 req, struct cli_smb2_fsctl_state);
5067 NTSTATUS status = NT_STATUS_OK;
5069 if (tevent_req_is_nterror(req, &status)) {
5070 tevent_req_received(req);
5074 if (state->out.length == 0) {
5075 *out = (DATA_BLOB) { .data = NULL, };
5078 * Can't use talloc_move() here, the outblobs from
5079 * smb2cli_ioctl_recv() are not standalone talloc
5080 * objects but just peek into the larger buffers
5081 * received, hanging off "state".
5083 *out = data_blob_talloc(
5084 mem_ctx, state->out.data, state->out.length);
5085 if (out->data == NULL) {
5086 status = NT_STATUS_NO_MEMORY;
5090 tevent_req_received(req);
5091 return NT_STATUS_OK;