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(uint32_t create_flags)
147 if (create_flags & REQUEST_BATCH_OPLOCK) {
148 return SMB2_OPLOCK_LEVEL_BATCH;
149 } else if (create_flags & REQUEST_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 uint32_t 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 uint32_t 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 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 0, /* create_flags */
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 0, /* create_flags */
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 0, /* create_flags */
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 0, /* create_flags */
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((const char *)dir_data + 8);
1234 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
1235 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
1236 finfo->ctime_ts = interpret_long_date((const char *)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((const char *)dir_data + 8);
1313 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
1314 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
1315 finfo->ctime_ts = interpret_long_date((const char *)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 (!NT_STATUS_IS_OK(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 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 directoy 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 0, /* create_flags */
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 0, /* create_flags */
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 0, /* create_flags */
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 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)) {
2030 * Naive option to match our SMB1 code. Assume the
2031 * symlink path that tripped us up was the last
2032 * component and try again. Eventually we will have to
2033 * deal with the returned path unprocessed component. JRA.
2035 subreq = cli_smb2_create_fnum_send(
2036 state, /* mem_ctx, */
2038 state->cli, /* cli */
2039 state->name, /* fname */
2040 0, /* create_flags */
2041 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation */
2042 state->desired_access, /* desired_access */
2043 0, /* file_attributes */
2046 FILE_SHARE_DELETE, /* share_access */
2047 FILE_OPEN, /* create_disposition */
2048 FILE_OPEN_REPARSE_POINT, /* create_options */
2049 NULL); /* in_cblobs */
2050 if (tevent_req_nomem(subreq, req)) {
2053 tevent_req_set_callback(
2054 subreq, get_fnum_from_path_opened_reparse, req);
2058 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
2059 subreq = cli_smb2_create_fnum_send(
2060 state, /* mem_ctx, */
2062 state->cli, /* cli */
2063 state->name, /* fname */
2064 0, /* create_flags */
2065 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation */
2066 state->desired_access, /* desired_access */
2067 0, /* file_attributes */
2070 FILE_SHARE_DELETE, /* share_access */
2071 FILE_OPEN, /* create_disposition */
2072 FILE_DIRECTORY_FILE, /* create_options */
2073 NULL); /* in_cblobs */
2074 if (tevent_req_nomem(subreq, req)) {
2077 tevent_req_set_callback(
2078 subreq, get_fnum_from_path_opened_dir, req);
2082 if (tevent_req_nterror(req, status)) {
2085 tevent_req_done(req);
2088 static void get_fnum_from_path_opened_reparse(struct tevent_req *subreq)
2090 struct tevent_req *req = tevent_req_callback_data(
2091 subreq, struct tevent_req);
2092 struct get_fnum_from_path_state *state = tevent_req_data(
2093 req, struct get_fnum_from_path_state);
2094 NTSTATUS status = cli_smb2_create_fnum_recv(
2095 subreq, &state->fnum, NULL, NULL, NULL, NULL);
2096 tevent_req_simple_finish_ntstatus(subreq, status);
2099 static void get_fnum_from_path_opened_dir(struct tevent_req *subreq)
2101 /* Abstraction violation, but these two are just the same... */
2102 get_fnum_from_path_opened_reparse(subreq);
2105 static NTSTATUS get_fnum_from_path_recv(
2106 struct tevent_req *req, uint16_t *pfnum)
2108 struct get_fnum_from_path_state *state = tevent_req_data(
2109 req, struct get_fnum_from_path_state);
2110 NTSTATUS status = NT_STATUS_OK;
2112 if (!tevent_req_is_nterror(req, &status)) {
2113 *pfnum = state->fnum;
2115 tevent_req_received(req);
2119 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
2121 uint32_t desired_access,
2124 TALLOC_CTX *frame = talloc_stackframe();
2125 struct tevent_context *ev = NULL;
2126 struct tevent_req *req = NULL;
2127 NTSTATUS status = NT_STATUS_NO_MEMORY;
2129 if (smbXcli_conn_has_async_calls(cli->conn)) {
2130 status = NT_STATUS_INVALID_PARAMETER;
2133 ev = samba_tevent_context_init(frame);
2137 req = get_fnum_from_path_send(frame, ev, cli, name, desired_access);
2141 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2144 status = get_fnum_from_path_recv(req, pfnum);
2150 /***************************************************************
2151 Wrapper that allows SMB2 to query a path info (ALTNAME level).
2153 ***************************************************************/
2155 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
2160 DATA_BLOB outbuf = data_blob_null;
2161 uint16_t fnum = 0xffff;
2162 uint32_t altnamelen = 0;
2163 TALLOC_CTX *frame = talloc_stackframe();
2165 if (smbXcli_conn_has_async_calls(cli->conn)) {
2167 * Can't use sync call while an async call is in flight
2169 status = NT_STATUS_INVALID_PARAMETER;
2173 status = get_fnum_from_path(cli,
2175 FILE_READ_ATTRIBUTES,
2178 if (!NT_STATUS_IS_OK(status)) {
2182 status = cli_smb2_query_info_fnum(
2185 1, /* in_info_type */
2186 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
2187 0xFFFF, /* in_max_output_length */
2188 NULL, /* in_input_buffer */
2189 0, /* in_additional_info */
2194 if (!NT_STATUS_IS_OK(status)) {
2198 /* Parse the reply. */
2199 if (outbuf.length < 4) {
2200 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2204 altnamelen = IVAL(outbuf.data, 0);
2205 if (altnamelen > outbuf.length - 4) {
2206 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2210 if (altnamelen > 0) {
2212 char *short_name = NULL;
2213 ret = pull_string_talloc(frame,
2215 FLAGS2_UNICODE_STRINGS,
2220 if (ret == (size_t)-1) {
2221 /* Bad conversion. */
2222 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2226 fstrcpy(alt_name, short_name);
2231 status = NT_STATUS_OK;
2235 if (fnum != 0xffff) {
2236 cli_smb2_close_fnum(cli, fnum);
2239 cli->raw_status = status;
2245 /***************************************************************
2246 Wrapper that allows SMB2 to get pathname attributes.
2248 ***************************************************************/
2250 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
2257 uint16_t fnum = 0xffff;
2258 struct timespec write_time_ts;
2259 TALLOC_CTX *frame = talloc_stackframe();
2261 if (smbXcli_conn_has_async_calls(cli->conn)) {
2263 * Can't use sync call while an async call is in flight
2265 status = NT_STATUS_INVALID_PARAMETER;
2269 status = get_fnum_from_path(cli,
2271 FILE_READ_ATTRIBUTES,
2274 if (!NT_STATUS_IS_OK(status)) {
2278 status = cli_qfileinfo_basic(
2283 NULL, /* create_time */
2284 NULL, /* access_time */
2286 NULL, /* change_time */
2288 if (!NT_STATUS_IS_OK(status)) {
2291 if (write_time != NULL) {
2292 *write_time = write_time_ts.tv_sec;
2297 if (fnum != 0xffff) {
2298 cli_smb2_close_fnum(cli, fnum);
2301 cli->raw_status = status;
2307 /***************************************************************
2308 Wrapper that allows SMB2 to query a pathname info (basic level).
2309 Implement on top of cli_qfileinfo_basic().
2311 ***************************************************************/
2313 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
2315 struct timespec *create_time,
2316 struct timespec *access_time,
2317 struct timespec *write_time,
2318 struct timespec *change_time,
2324 uint16_t fnum = 0xffff;
2325 TALLOC_CTX *frame = talloc_stackframe();
2327 if (smbXcli_conn_has_async_calls(cli->conn)) {
2329 * Can't use sync call while an async call is in flight
2331 status = NT_STATUS_INVALID_PARAMETER;
2335 status = get_fnum_from_path(cli,
2337 FILE_READ_ATTRIBUTES,
2340 if (!NT_STATUS_IS_OK(status)) {
2344 status = cli_qfileinfo_basic(
2357 if (fnum != 0xffff) {
2358 cli_smb2_close_fnum(cli, fnum);
2361 cli->raw_status = status;
2367 /***************************************************************
2368 Wrapper that allows SMB2 to query pathname streams.
2370 ***************************************************************/
2372 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
2374 TALLOC_CTX *mem_ctx,
2375 unsigned int *pnum_streams,
2376 struct stream_struct **pstreams)
2379 uint16_t fnum = 0xffff;
2380 DATA_BLOB outbuf = data_blob_null;
2381 TALLOC_CTX *frame = talloc_stackframe();
2383 if (smbXcli_conn_has_async_calls(cli->conn)) {
2385 * Can't use sync call while an async call is in flight
2387 status = NT_STATUS_INVALID_PARAMETER;
2391 status = get_fnum_from_path(cli,
2393 FILE_READ_ATTRIBUTES,
2396 if (!NT_STATUS_IS_OK(status)) {
2400 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2401 level 22 (SMB2_FILE_STREAM_INFORMATION). */
2403 status = cli_smb2_query_info_fnum(
2406 1, /* in_info_type */
2407 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
2408 0xFFFF, /* in_max_output_length */
2409 NULL, /* in_input_buffer */
2410 0, /* in_additional_info */
2415 if (!NT_STATUS_IS_OK(status)) {
2419 /* Parse the reply. */
2420 if (!parse_streams_blob(mem_ctx,
2425 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2431 if (fnum != 0xffff) {
2432 cli_smb2_close_fnum(cli, fnum);
2435 cli->raw_status = status;
2441 /***************************************************************
2442 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2445 ***************************************************************/
2447 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
2449 uint8_t in_info_type,
2450 uint8_t in_file_info_class,
2451 const DATA_BLOB *p_in_data)
2454 uint16_t fnum = 0xffff;
2455 TALLOC_CTX *frame = talloc_stackframe();
2457 if (smbXcli_conn_has_async_calls(cli->conn)) {
2459 * Can't use sync call while an async call is in flight
2461 status = NT_STATUS_INVALID_PARAMETER;
2465 status = get_fnum_from_path(cli,
2467 FILE_WRITE_ATTRIBUTES,
2470 if (!NT_STATUS_IS_OK(status)) {
2474 status = cli_smb2_set_info_fnum(
2479 p_in_data, /* in_input_buffer */
2480 0); /* in_additional_info */
2483 if (fnum != 0xffff) {
2484 cli_smb2_close_fnum(cli, fnum);
2487 cli->raw_status = status;
2494 /***************************************************************
2495 Wrapper that allows SMB2 to set pathname attributes.
2497 ***************************************************************/
2499 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
2504 uint8_t inbuf_store[40];
2505 DATA_BLOB inbuf = data_blob_null;
2507 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2508 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2510 inbuf.data = inbuf_store;
2511 inbuf.length = sizeof(inbuf_store);
2512 data_blob_clear(&inbuf);
2515 * SMB1 uses attr == 0 to clear all attributes
2516 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2517 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2518 * request attribute change.
2520 * SMB2 uses exactly the reverse. Unfortunately as the
2521 * cli_setatr() ABI is exposed inside libsmbclient,
2522 * we must make the SMB2 cli_smb2_setatr() call
2523 * export the same ABI as the SMB1 cli_setatr()
2524 * which calls it. This means reversing the sense
2525 * of the requested attr argument if it's zero
2526 * or FILE_ATTRIBUTE_NORMAL.
2528 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2532 attr = FILE_ATTRIBUTE_NORMAL;
2533 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
2537 SIVAL(inbuf.data, 32, attr);
2539 put_long_date((char *)inbuf.data + 16,mtime);
2541 /* Set all the other times to -1. */
2542 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2543 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
2544 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
2546 return cli_smb2_setpathinfo(cli,
2548 1, /* in_info_type */
2549 /* in_file_info_class */
2550 SMB_FILE_BASIC_INFORMATION - 1000,
2555 /***************************************************************
2556 Wrapper that allows SMB2 to set file handle times.
2558 ***************************************************************/
2560 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
2566 uint8_t inbuf_store[40];
2567 DATA_BLOB inbuf = data_blob_null;
2569 if (smbXcli_conn_has_async_calls(cli->conn)) {
2571 * Can't use sync call while an async call is in flight
2573 return NT_STATUS_INVALID_PARAMETER;
2576 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2577 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2579 inbuf.data = inbuf_store;
2580 inbuf.length = sizeof(inbuf_store);
2581 data_blob_clear(&inbuf);
2583 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2584 if (change_time != 0) {
2585 put_long_date((char *)inbuf.data + 24, change_time);
2587 if (access_time != 0) {
2588 put_long_date((char *)inbuf.data + 8, access_time);
2590 if (write_time != 0) {
2591 put_long_date((char *)inbuf.data + 16, write_time);
2594 cli->raw_status = cli_smb2_set_info_fnum(
2597 1, /* in_info_type */
2598 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
2599 &inbuf, /* in_input_buffer */
2600 0); /* in_additional_info */
2602 return cli->raw_status;
2605 /***************************************************************
2606 Wrapper that allows SMB2 to query disk attributes (size).
2608 ***************************************************************/
2610 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2611 uint64_t *bsize, uint64_t *total, uint64_t *avail)
2614 uint16_t fnum = 0xffff;
2615 DATA_BLOB outbuf = data_blob_null;
2616 uint32_t sectors_per_unit = 0;
2617 uint32_t bytes_per_sector = 0;
2618 uint64_t total_size = 0;
2619 uint64_t size_free = 0;
2620 TALLOC_CTX *frame = talloc_stackframe();
2622 if (smbXcli_conn_has_async_calls(cli->conn)) {
2624 * Can't use sync call while an async call is in flight
2626 status = NT_STATUS_INVALID_PARAMETER;
2630 /* First open the top level directory. */
2631 status = cli_smb2_create_fnum(cli,
2633 0, /* create_flags */
2634 SMB2_IMPERSONATION_IMPERSONATION,
2635 FILE_READ_ATTRIBUTES, /* desired_access */
2636 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2637 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2638 FILE_OPEN, /* create_disposition */
2639 FILE_DIRECTORY_FILE, /* create_options */
2646 if (!NT_STATUS_IS_OK(status)) {
2650 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2651 level 3 (SMB_FS_SIZE_INFORMATION). */
2653 status = cli_smb2_query_info_fnum(
2656 2, /* in_info_type */
2657 3, /* in_file_info_class */
2658 0xFFFF, /* in_max_output_length */
2659 NULL, /* in_input_buffer */
2660 0, /* in_additional_info */
2664 if (!NT_STATUS_IS_OK(status)) {
2668 /* Parse the reply. */
2669 if (outbuf.length != 24) {
2670 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2674 total_size = BVAL(outbuf.data, 0);
2675 size_free = BVAL(outbuf.data, 8);
2676 sectors_per_unit = IVAL(outbuf.data, 16);
2677 bytes_per_sector = IVAL(outbuf.data, 20);
2680 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2683 *total = total_size;
2689 status = NT_STATUS_OK;
2693 if (fnum != 0xffff) {
2694 cli_smb2_close_fnum(cli, fnum);
2697 cli->raw_status = status;
2703 /***************************************************************
2704 Wrapper that allows SMB2 to query file system sizes.
2706 ***************************************************************/
2708 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2709 uint64_t *total_allocation_units,
2710 uint64_t *caller_allocation_units,
2711 uint64_t *actual_allocation_units,
2712 uint64_t *sectors_per_allocation_unit,
2713 uint64_t *bytes_per_sector)
2716 uint16_t fnum = 0xffff;
2717 DATA_BLOB outbuf = data_blob_null;
2718 TALLOC_CTX *frame = talloc_stackframe();
2720 if (smbXcli_conn_has_async_calls(cli->conn)) {
2722 * Can't use sync call while an async call is in flight
2724 status = NT_STATUS_INVALID_PARAMETER;
2728 /* First open the top level directory. */
2730 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2731 SMB2_IMPERSONATION_IMPERSONATION,
2732 FILE_READ_ATTRIBUTES, /* desired_access */
2733 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2734 FILE_SHARE_READ | FILE_SHARE_WRITE |
2735 FILE_SHARE_DELETE, /* share_access */
2736 FILE_OPEN, /* create_disposition */
2737 FILE_DIRECTORY_FILE, /* create_options */
2744 if (!NT_STATUS_IS_OK(status)) {
2748 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2749 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2751 status = cli_smb2_query_info_fnum(
2754 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2755 SMB_FS_FULL_SIZE_INFORMATION - 1000, /* in_file_info_class */
2756 0xFFFF, /* in_max_output_length */
2757 NULL, /* in_input_buffer */
2758 0, /* in_additional_info */
2762 if (!NT_STATUS_IS_OK(status)) {
2766 if (outbuf.length < 32) {
2767 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2771 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2772 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2773 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2774 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2775 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2779 if (fnum != 0xffff) {
2780 cli_smb2_close_fnum(cli, fnum);
2783 cli->raw_status = status;
2789 /***************************************************************
2790 Wrapper that allows SMB2 to query file system attributes.
2792 ***************************************************************/
2794 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2797 uint16_t fnum = 0xffff;
2798 DATA_BLOB outbuf = data_blob_null;
2799 TALLOC_CTX *frame = talloc_stackframe();
2801 if (smbXcli_conn_has_async_calls(cli->conn)) {
2803 * Can't use sync call while an async call is in flight
2805 status = NT_STATUS_INVALID_PARAMETER;
2809 /* First open the top level directory. */
2811 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2812 SMB2_IMPERSONATION_IMPERSONATION,
2813 FILE_READ_ATTRIBUTES, /* desired_access */
2814 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2815 FILE_SHARE_READ | FILE_SHARE_WRITE |
2816 FILE_SHARE_DELETE, /* share_access */
2817 FILE_OPEN, /* create_disposition */
2818 FILE_DIRECTORY_FILE, /* create_options */
2825 if (!NT_STATUS_IS_OK(status)) {
2829 status = cli_smb2_query_info_fnum(
2832 2, /* in_info_type */
2833 5, /* in_file_info_class */
2834 0xFFFF, /* in_max_output_length */
2835 NULL, /* in_input_buffer */
2836 0, /* in_additional_info */
2840 if (!NT_STATUS_IS_OK(status)) {
2844 if (outbuf.length < 12) {
2845 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2849 *fs_attr = IVAL(outbuf.data, 0);
2853 if (fnum != 0xffff) {
2854 cli_smb2_close_fnum(cli, fnum);
2857 cli->raw_status = status;
2863 /***************************************************************
2864 Wrapper that allows SMB2 to query file system volume info.
2866 ***************************************************************/
2868 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2869 TALLOC_CTX *mem_ctx,
2870 char **_volume_name,
2871 uint32_t *pserial_number,
2875 uint16_t fnum = 0xffff;
2876 DATA_BLOB outbuf = data_blob_null;
2878 char *volume_name = NULL;
2879 TALLOC_CTX *frame = talloc_stackframe();
2881 if (smbXcli_conn_has_async_calls(cli->conn)) {
2883 * Can't use sync call while an async call is in flight
2885 status = NT_STATUS_INVALID_PARAMETER;
2889 /* First open the top level directory. */
2891 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2892 SMB2_IMPERSONATION_IMPERSONATION,
2893 FILE_READ_ATTRIBUTES, /* desired_access */
2894 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2895 FILE_SHARE_READ | FILE_SHARE_WRITE |
2896 FILE_SHARE_DELETE, /* share_access */
2897 FILE_OPEN, /* create_disposition */
2898 FILE_DIRECTORY_FILE, /* create_options */
2905 if (!NT_STATUS_IS_OK(status)) {
2909 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2910 level 1 (SMB_FS_VOLUME_INFORMATION). */
2912 status = cli_smb2_query_info_fnum(
2915 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2916 /* in_file_info_class */
2917 SMB_FS_VOLUME_INFORMATION - 1000,
2918 0xFFFF, /* in_max_output_length */
2919 NULL, /* in_input_buffer */
2920 0, /* in_additional_info */
2924 if (!NT_STATUS_IS_OK(status)) {
2928 if (outbuf.length < 24) {
2929 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2935 ts = interpret_long_date((char *)outbuf.data);
2938 if (pserial_number) {
2939 *pserial_number = IVAL(outbuf.data,8);
2941 nlen = IVAL(outbuf.data,12);
2942 if (nlen + 18 < 18) {
2944 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2948 * The next check is safe as we know outbuf.length >= 24
2951 if (nlen > (outbuf.length - 18)) {
2952 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2956 pull_string_talloc(mem_ctx,
2957 (const char *)outbuf.data,
2963 if (volume_name == NULL) {
2964 status = map_nt_error_from_unix(errno);
2968 *_volume_name = volume_name;
2972 if (fnum != 0xffff) {
2973 cli_smb2_close_fnum(cli, fnum);
2976 cli->raw_status = status;
2982 struct cli_smb2_mxac_state {
2983 struct tevent_context *ev;
2984 struct cli_state *cli;
2986 struct smb2_create_blobs in_cblobs;
2992 static void cli_smb2_mxac_opened(struct tevent_req *subreq);
2993 static void cli_smb2_mxac_closed(struct tevent_req *subreq);
2995 struct tevent_req *cli_smb2_query_mxac_send(TALLOC_CTX *mem_ctx,
2996 struct tevent_context *ev,
2997 struct cli_state *cli,
3000 struct tevent_req *req = NULL, *subreq = NULL;
3001 struct cli_smb2_mxac_state *state = NULL;
3004 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_mxac_state);
3008 *state = (struct cli_smb2_mxac_state) {
3014 status = smb2_create_blob_add(state,
3016 SMB2_CREATE_TAG_MXAC,
3017 data_blob(NULL, 0));
3018 if (tevent_req_nterror(req, status)) {
3019 return tevent_req_post(req, ev);
3022 subreq = cli_smb2_create_fnum_send(
3027 0, /* create_flags */
3028 SMB2_IMPERSONATION_IMPERSONATION,
3029 FILE_READ_ATTRIBUTES,
3030 0, /* file attributes */
3031 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
3033 0, /* create_options */
3035 if (tevent_req_nomem(subreq, req)) {
3036 return tevent_req_post(req, ev);
3038 tevent_req_set_callback(subreq, cli_smb2_mxac_opened, req);
3042 static void cli_smb2_mxac_opened(struct tevent_req *subreq)
3044 struct tevent_req *req = tevent_req_callback_data(
3045 subreq, struct tevent_req);
3046 struct cli_smb2_mxac_state *state = tevent_req_data(
3047 req, struct cli_smb2_mxac_state);
3048 struct smb2_create_blobs out_cblobs = {0};
3049 struct smb2_create_blob *mxac_blob = NULL;
3052 status = cli_smb2_create_fnum_recv(
3053 subreq, &state->fnum, NULL, state, &out_cblobs, NULL);
3054 TALLOC_FREE(subreq);
3056 if (tevent_req_nterror(req, status)) {
3060 mxac_blob = smb2_create_blob_find(&out_cblobs, SMB2_CREATE_TAG_MXAC);
3061 if (mxac_blob == NULL) {
3062 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3065 if (mxac_blob->data.length != 8) {
3066 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3070 state->status = NT_STATUS(IVAL(mxac_blob->data.data, 0));
3071 state->mxac = IVAL(mxac_blob->data.data, 4);
3074 subreq = cli_smb2_close_fnum_send(
3075 state, state->ev, state->cli, state->fnum);
3076 if (tevent_req_nomem(subreq, req)) {
3079 tevent_req_set_callback(subreq, cli_smb2_mxac_closed, req);
3084 static void cli_smb2_mxac_closed(struct tevent_req *subreq)
3086 struct tevent_req *req = tevent_req_callback_data(
3087 subreq, struct tevent_req);
3090 status = cli_smb2_close_fnum_recv(subreq);
3091 if (tevent_req_nterror(req, status)) {
3095 tevent_req_done(req);
3098 NTSTATUS cli_smb2_query_mxac_recv(struct tevent_req *req, uint32_t *mxac)
3100 struct cli_smb2_mxac_state *state = tevent_req_data(
3101 req, struct cli_smb2_mxac_state);
3104 if (tevent_req_is_nterror(req, &status)) {
3108 if (!NT_STATUS_IS_OK(state->status)) {
3109 return state->status;
3112 *mxac = state->mxac;
3113 return NT_STATUS_OK;
3116 NTSTATUS cli_smb2_query_mxac(struct cli_state *cli,
3120 TALLOC_CTX *frame = talloc_stackframe();
3121 struct tevent_context *ev = NULL;
3122 struct tevent_req *req = NULL;
3123 NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
3126 if (smbXcli_conn_has_async_calls(cli->conn)) {
3128 * Can't use sync call while an async call is in flight
3130 status = NT_STATUS_INVALID_PARAMETER;
3134 ev = samba_tevent_context_init(frame);
3138 req = cli_smb2_query_mxac_send(frame, ev, cli, fname);
3142 ok = tevent_req_poll_ntstatus(req, ev, &status);
3146 status = cli_smb2_query_mxac_recv(req, _mxac);
3149 cli->raw_status = status;
3154 struct cli_smb2_rename_fnum_state {
3158 static void cli_smb2_rename_fnum_done(struct tevent_req *subreq);
3160 static struct tevent_req *cli_smb2_rename_fnum_send(
3161 TALLOC_CTX *mem_ctx,
3162 struct tevent_context *ev,
3163 struct cli_state *cli,
3165 const char *fname_dst,
3168 struct tevent_req *req = NULL, *subreq = NULL;
3169 struct cli_smb2_rename_fnum_state *state = NULL;
3170 size_t namelen = strlen(fname_dst);
3171 smb_ucs2_t *converted_str = NULL;
3172 size_t converted_size_bytes = 0;
3176 req = tevent_req_create(
3177 mem_ctx, &state, struct cli_smb2_rename_fnum_state);
3183 * SMB2 is pickier about pathnames. Ensure it doesn't start in
3186 if (*fname_dst == '\\') {
3191 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
3194 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
3195 fname_dst = talloc_strndup(state, fname_dst, namelen-1);
3196 if (tevent_req_nomem(fname_dst, req)) {
3197 return tevent_req_post(req, ev);
3201 ok = push_ucs2_talloc(
3202 state, &converted_str, fname_dst, &converted_size_bytes);
3204 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3205 return tevent_req_post(req, ev);
3209 * W2K8 insists the dest name is not null terminated. Remove
3210 * the last 2 zero bytes and reduce the name length.
3212 if (converted_size_bytes < 2) {
3213 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3214 return tevent_req_post(req, ev);
3216 converted_size_bytes -= 2;
3218 inbuf_size = 20 + converted_size_bytes;
3219 if (inbuf_size < 20) {
3220 /* Integer wrap check. */
3221 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3222 return tevent_req_post(req, ev);
3226 * The Windows 10 SMB2 server has a minimum length
3227 * for a SMB2_FILE_RENAME_INFORMATION buffer of
3228 * 24 bytes. It returns NT_STATUS_INFO_LENGTH_MISMATCH
3229 * if the length is less. This isn't an alignment
3230 * issue as Windows client happily 2-byte align
3231 * for larget target name sizes. Also the Windows 10
3232 * SMB1 server doesn't have this restriction.
3234 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14403
3236 inbuf_size = MAX(inbuf_size, 24);
3238 state->inbuf = data_blob_talloc_zero(state, inbuf_size);
3239 if (tevent_req_nomem(state->inbuf.data, req)) {
3240 return tevent_req_post(req, ev);
3244 SCVAL(state->inbuf.data, 0, 1);
3247 SIVAL(state->inbuf.data, 16, converted_size_bytes);
3248 memcpy(state->inbuf.data + 20, converted_str, converted_size_bytes);
3250 TALLOC_FREE(converted_str);
3252 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3253 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3255 subreq = cli_smb2_set_info_fnum_send(
3256 state, /* mem_ctx */
3260 1, /* in_info_type */
3261 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
3262 &state->inbuf, /* in_input_buffer */
3263 0); /* in_additional_info */
3264 if (tevent_req_nomem(subreq, req)) {
3265 return tevent_req_post(req, ev);
3267 tevent_req_set_callback(subreq, cli_smb2_rename_fnum_done, req);
3271 static void cli_smb2_rename_fnum_done(struct tevent_req *subreq)
3273 NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
3274 tevent_req_simple_finish_ntstatus(subreq, status);
3277 static NTSTATUS cli_smb2_rename_fnum_recv(struct tevent_req *req)
3279 return tevent_req_simple_recv_ntstatus(req);
3282 /***************************************************************
3283 Wrapper that allows SMB2 to rename a file.
3284 ***************************************************************/
3286 struct cli_smb2_rename_state {
3287 struct tevent_context *ev;
3288 struct cli_state *cli;
3289 const char *fname_dst;
3293 NTSTATUS rename_status;
3296 static void cli_smb2_rename_opened(struct tevent_req *subreq);
3297 static void cli_smb2_rename_renamed(struct tevent_req *subreq);
3298 static void cli_smb2_rename_closed(struct tevent_req *subreq);
3300 struct tevent_req *cli_smb2_rename_send(
3301 TALLOC_CTX *mem_ctx,
3302 struct tevent_context *ev,
3303 struct cli_state *cli,
3304 const char *fname_src,
3305 const char *fname_dst,
3308 struct tevent_req *req = NULL, *subreq = NULL;
3309 struct cli_smb2_rename_state *state = NULL;
3312 req = tevent_req_create(
3313 mem_ctx, &state, struct cli_smb2_rename_state);
3319 * Strip a MSDFS path from fname_dst if we were given one.
3321 status = cli_dfs_target_check(state,
3325 if (tevent_req_nterror(req, status)) {
3326 return tevent_req_post(req, ev);
3331 state->fname_dst = fname_dst;
3332 state->replace = replace;
3334 subreq = get_fnum_from_path_send(
3335 state, ev, cli, fname_src, DELETE_ACCESS);
3336 if (tevent_req_nomem(subreq, req)) {
3337 return tevent_req_post(req, ev);
3339 tevent_req_set_callback(subreq, cli_smb2_rename_opened, req);
3343 static void cli_smb2_rename_opened(struct tevent_req *subreq)
3345 struct tevent_req *req = tevent_req_callback_data(
3346 subreq, struct tevent_req);
3347 struct cli_smb2_rename_state *state = tevent_req_data(
3348 req, struct cli_smb2_rename_state);
3351 status = get_fnum_from_path_recv(subreq, &state->fnum);
3352 TALLOC_FREE(subreq);
3353 if (tevent_req_nterror(req, status)) {
3357 subreq = cli_smb2_rename_fnum_send(
3364 if (tevent_req_nomem(subreq, req)) {
3367 tevent_req_set_callback(subreq, cli_smb2_rename_renamed, req);
3370 static void cli_smb2_rename_renamed(struct tevent_req *subreq)
3372 struct tevent_req *req = tevent_req_callback_data(
3373 subreq, struct tevent_req);
3374 struct cli_smb2_rename_state *state = tevent_req_data(
3375 req, struct cli_smb2_rename_state);
3377 state->rename_status = cli_smb2_rename_fnum_recv(subreq);
3378 TALLOC_FREE(subreq);
3380 subreq = cli_smb2_close_fnum_send(
3381 state, state->ev, state->cli, state->fnum);
3382 if (tevent_req_nomem(subreq, req)) {
3385 tevent_req_set_callback(subreq, cli_smb2_rename_closed, req);
3388 static void cli_smb2_rename_closed(struct tevent_req *subreq)
3390 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
3391 tevent_req_simple_finish_ntstatus(subreq, status);
3394 NTSTATUS cli_smb2_rename_recv(struct tevent_req *req)
3396 struct cli_smb2_rename_state *state = tevent_req_data(
3397 req, struct cli_smb2_rename_state);
3398 NTSTATUS status = NT_STATUS_OK;
3400 if (!tevent_req_is_nterror(req, &status)) {
3401 status = state->rename_status;
3403 tevent_req_received(req);
3407 /***************************************************************
3408 Wrapper that allows SMB2 to set an EA on a fnum.
3410 ***************************************************************/
3412 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
3414 const char *ea_name,
3419 DATA_BLOB inbuf = data_blob_null;
3421 char *ea_name_ascii = NULL;
3423 TALLOC_CTX *frame = talloc_stackframe();
3425 if (smbXcli_conn_has_async_calls(cli->conn)) {
3427 * Can't use sync call while an async call is in flight
3429 status = NT_STATUS_INVALID_PARAMETER;
3433 /* Marshall the SMB2 EA data. */
3434 if (ea_len > 0xFFFF) {
3435 status = NT_STATUS_INVALID_PARAMETER;
3439 if (!push_ascii_talloc(frame,
3443 status = NT_STATUS_INVALID_PARAMETER;
3447 if (namelen < 2 || namelen > 0xFF) {
3448 status = NT_STATUS_INVALID_PARAMETER;
3452 bloblen = 8 + ea_len + namelen;
3453 /* Round up to a 4 byte boundary. */
3454 bloblen = ((bloblen + 3)&~3);
3456 inbuf = data_blob_talloc_zero(frame, bloblen);
3457 if (inbuf.data == NULL) {
3458 status = NT_STATUS_NO_MEMORY;
3461 /* namelen doesn't include the NULL byte. */
3462 SCVAL(inbuf.data, 5, namelen - 1);
3463 SSVAL(inbuf.data, 6, ea_len);
3464 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
3465 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
3467 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3468 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3470 status = cli_smb2_set_info_fnum(
3473 1, /* in_info_type */
3474 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3475 &inbuf, /* in_input_buffer */
3476 0); /* in_additional_info */
3480 cli->raw_status = status;
3486 /***************************************************************
3487 Wrapper that allows SMB2 to set an EA on a pathname.
3489 ***************************************************************/
3491 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
3493 const char *ea_name,
3498 uint16_t fnum = 0xffff;
3500 if (smbXcli_conn_has_async_calls(cli->conn)) {
3502 * Can't use sync call while an async call is in flight
3504 status = NT_STATUS_INVALID_PARAMETER;
3508 status = get_fnum_from_path(cli,
3513 if (!NT_STATUS_IS_OK(status)) {
3517 status = cli_set_ea_fnum(cli,
3522 if (!NT_STATUS_IS_OK(status)) {
3528 if (fnum != 0xffff) {
3529 cli_smb2_close_fnum(cli, fnum);
3532 cli->raw_status = status;
3537 /***************************************************************
3538 Wrapper that allows SMB2 to get an EA list on a pathname.
3540 ***************************************************************/
3542 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
3546 struct ea_struct **pea_array)
3549 uint16_t fnum = 0xffff;
3550 DATA_BLOB outbuf = data_blob_null;
3551 struct ea_list *ea_list = NULL;
3552 struct ea_list *eal = NULL;
3553 size_t ea_count = 0;
3554 TALLOC_CTX *frame = talloc_stackframe();
3559 if (smbXcli_conn_has_async_calls(cli->conn)) {
3561 * Can't use sync call while an async call is in flight
3563 status = NT_STATUS_INVALID_PARAMETER;
3567 status = get_fnum_from_path(cli,
3572 if (!NT_STATUS_IS_OK(status)) {
3576 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3577 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3579 status = cli_smb2_query_info_fnum(
3582 1, /* in_info_type */
3583 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3584 0xFFFF, /* in_max_output_length */
3585 NULL, /* in_input_buffer */
3586 0, /* in_additional_info */
3591 if (!NT_STATUS_IS_OK(status)) {
3595 /* Parse the reply. */
3596 ea_list = read_nttrans_ea_list(ctx,
3597 (const char *)outbuf.data,
3599 if (ea_list == NULL) {
3600 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3604 /* Convert to an array. */
3605 for (eal = ea_list; eal; eal = eal->next) {
3610 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
3611 if (*pea_array == NULL) {
3612 status = NT_STATUS_NO_MEMORY;
3616 for (eal = ea_list; eal; eal = eal->next) {
3617 (*pea_array)[ea_count++] = eal->ea;
3619 *pnum_eas = ea_count;
3624 if (fnum != 0xffff) {
3625 cli_smb2_close_fnum(cli, fnum);
3628 cli->raw_status = status;
3634 /***************************************************************
3635 Wrapper that allows SMB2 to get user quota.
3637 ***************************************************************/
3639 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
3641 SMB_NTQUOTA_STRUCT *pqt)
3644 DATA_BLOB inbuf = data_blob_null;
3645 DATA_BLOB info_blob = data_blob_null;
3646 DATA_BLOB outbuf = data_blob_null;
3647 TALLOC_CTX *frame = talloc_stackframe();
3649 unsigned int offset;
3650 struct smb2_query_quota_info query = {0};
3651 struct file_get_quota_info info = {0};
3652 enum ndr_err_code err;
3653 struct ndr_push *ndr_push = NULL;
3655 if (smbXcli_conn_has_async_calls(cli->conn)) {
3657 * Can't use sync call while an async call is in flight
3659 status = NT_STATUS_INVALID_PARAMETER;
3663 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
3665 query.return_single = 1;
3667 info.next_entry_offset = 0;
3668 info.sid_length = sid_len;
3669 info.sid = pqt->sid;
3671 err = ndr_push_struct_blob(
3675 (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
3677 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3678 status = NT_STATUS_INTERNAL_ERROR;
3682 query.sid_list_length = info_blob.length;
3683 ndr_push = ndr_push_init_ctx(frame);
3685 status = NT_STATUS_NO_MEMORY;
3689 err = ndr_push_smb2_query_quota_info(ndr_push,
3690 NDR_SCALARS | NDR_BUFFERS,
3693 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3694 status = NT_STATUS_INTERNAL_ERROR;
3698 err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3701 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3702 status = NT_STATUS_INTERNAL_ERROR;
3705 inbuf.data = ndr_push->data;
3706 inbuf.length = ndr_push->offset;
3708 status = cli_smb2_query_info_fnum(
3711 4, /* in_info_type */
3712 0, /* in_file_info_class */
3713 0xFFFF, /* in_max_output_length */
3714 &inbuf, /* in_input_buffer */
3715 0, /* in_additional_info */
3720 if (!NT_STATUS_IS_OK(status)) {
3724 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3726 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3727 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3731 cli->raw_status = status;
3737 /***************************************************************
3738 Wrapper that allows SMB2 to list user quota.
3740 ***************************************************************/
3742 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3743 TALLOC_CTX *mem_ctx,
3745 SMB_NTQUOTA_LIST **pqt_list,
3749 DATA_BLOB inbuf = data_blob_null;
3750 DATA_BLOB outbuf = data_blob_null;
3751 TALLOC_CTX *frame = talloc_stackframe();
3752 struct smb2_query_quota_info info = {0};
3753 enum ndr_err_code err;
3755 if (smbXcli_conn_has_async_calls(cli->conn)) {
3757 * Can't use sync call while an async call is in flight
3759 status = NT_STATUS_INVALID_PARAMETER;
3763 info.restart_scan = first ? 1 : 0;
3765 err = ndr_push_struct_blob(
3769 (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3771 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3772 status = NT_STATUS_INTERNAL_ERROR;
3776 status = cli_smb2_query_info_fnum(
3779 4, /* in_info_type */
3780 0, /* in_file_info_class */
3781 0xFFFF, /* in_max_output_length */
3782 &inbuf, /* in_input_buffer */
3783 0, /* in_additional_info */
3789 * safeguard against panic from calling parse_user_quota_list with
3792 if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3793 status = NT_STATUS_NO_MORE_ENTRIES;
3796 if (!NT_STATUS_IS_OK(status)) {
3800 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3804 cli->raw_status = status;
3810 /***************************************************************
3811 Wrapper that allows SMB2 to get file system quota.
3813 ***************************************************************/
3815 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3817 SMB_NTQUOTA_STRUCT *pqt)
3820 DATA_BLOB outbuf = data_blob_null;
3821 TALLOC_CTX *frame = talloc_stackframe();
3823 if (smbXcli_conn_has_async_calls(cli->conn)) {
3825 * Can't use sync call while an async call is in flight
3827 status = NT_STATUS_INVALID_PARAMETER;
3831 status = cli_smb2_query_info_fnum(
3834 2, /* in_info_type */
3835 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3836 0xFFFF, /* in_max_output_length */
3837 NULL, /* in_input_buffer */
3838 0, /* in_additional_info */
3843 if (!NT_STATUS_IS_OK(status)) {
3847 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3850 cli->raw_status = status;
3856 /***************************************************************
3857 Wrapper that allows SMB2 to set user quota.
3859 ***************************************************************/
3861 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3863 SMB_NTQUOTA_LIST *qtl)
3866 DATA_BLOB inbuf = data_blob_null;
3867 TALLOC_CTX *frame = talloc_stackframe();
3869 if (smbXcli_conn_has_async_calls(cli->conn)) {
3871 * Can't use sync call while an async call is in flight
3873 status = NT_STATUS_INVALID_PARAMETER;
3877 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3878 if (!NT_STATUS_IS_OK(status)) {
3882 status = cli_smb2_set_info_fnum(
3885 4, /* in_info_type */
3886 0, /* in_file_info_class */
3887 &inbuf, /* in_input_buffer */
3888 0); /* in_additional_info */
3891 cli->raw_status = status;
3898 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3900 SMB_NTQUOTA_STRUCT *pqt)
3903 DATA_BLOB inbuf = data_blob_null;
3904 TALLOC_CTX *frame = talloc_stackframe();
3906 if (smbXcli_conn_has_async_calls(cli->conn)) {
3908 * Can't use sync call while an async call is in flight
3910 status = NT_STATUS_INVALID_PARAMETER;
3914 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3915 if (!NT_STATUS_IS_OK(status)) {
3919 status = cli_smb2_set_info_fnum(
3922 2, /* in_info_type */
3923 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3924 &inbuf, /* in_input_buffer */
3925 0); /* in_additional_info */
3927 cli->raw_status = status;
3933 struct cli_smb2_read_state {
3934 struct tevent_context *ev;
3935 struct cli_state *cli;
3936 struct smb2_hnd *ph;
3937 uint64_t start_offset;
3943 static void cli_smb2_read_done(struct tevent_req *subreq);
3945 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3946 struct tevent_context *ev,
3947 struct cli_state *cli,
3953 struct tevent_req *req, *subreq;
3954 struct cli_smb2_read_state *state;
3956 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3962 state->start_offset = (uint64_t)offset;
3963 state->size = (uint32_t)size;
3964 state->received = 0;
3967 status = map_fnum_to_smb2_handle(cli,
3970 if (tevent_req_nterror(req, status)) {
3971 return tevent_req_post(req, ev);
3974 subreq = smb2cli_read_send(state,
3977 state->cli->timeout,
3978 state->cli->smb2.session,
3979 state->cli->smb2.tcon,
3981 state->start_offset,
3982 state->ph->fid_persistent,
3983 state->ph->fid_volatile,
3984 0, /* minimum_count */
3985 0); /* remaining_bytes */
3987 if (tevent_req_nomem(subreq, req)) {
3988 return tevent_req_post(req, ev);
3990 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3994 static void cli_smb2_read_done(struct tevent_req *subreq)
3996 struct tevent_req *req = tevent_req_callback_data(
3997 subreq, struct tevent_req);
3998 struct cli_smb2_read_state *state = tevent_req_data(
3999 req, struct cli_smb2_read_state);
4002 status = smb2cli_read_recv(subreq, state,
4003 &state->buf, &state->received);
4004 if (tevent_req_nterror(req, status)) {
4008 if (state->received > state->size) {
4009 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4013 tevent_req_done(req);
4016 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
4021 struct cli_smb2_read_state *state = tevent_req_data(
4022 req, struct cli_smb2_read_state);
4024 if (tevent_req_is_nterror(req, &status)) {
4025 state->cli->raw_status = status;
4029 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
4030 * better make sure that you copy it away before you talloc_free(req).
4031 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
4033 *received = (ssize_t)state->received;
4034 *rcvbuf = state->buf;
4035 state->cli->raw_status = NT_STATUS_OK;
4036 return NT_STATUS_OK;
4039 struct cli_smb2_write_state {
4040 struct tevent_context *ev;
4041 struct cli_state *cli;
4042 struct smb2_hnd *ph;
4050 static void cli_smb2_write_written(struct tevent_req *req);
4052 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
4053 struct tevent_context *ev,
4054 struct cli_state *cli,
4062 struct tevent_req *req, *subreq = NULL;
4063 struct cli_smb2_write_state *state = NULL;
4065 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
4071 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4072 state->flags = (uint32_t)mode;
4074 state->offset = (uint64_t)offset;
4075 state->size = (uint32_t)size;
4078 status = map_fnum_to_smb2_handle(cli,
4081 if (tevent_req_nterror(req, status)) {
4082 return tevent_req_post(req, ev);
4085 subreq = smb2cli_write_send(state,
4088 state->cli->timeout,
4089 state->cli->smb2.session,
4090 state->cli->smb2.tcon,
4093 state->ph->fid_persistent,
4094 state->ph->fid_volatile,
4095 0, /* remaining_bytes */
4096 state->flags, /* flags */
4099 if (tevent_req_nomem(subreq, req)) {
4100 return tevent_req_post(req, ev);
4102 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
4106 static void cli_smb2_write_written(struct tevent_req *subreq)
4108 struct tevent_req *req = tevent_req_callback_data(
4109 subreq, struct tevent_req);
4110 struct cli_smb2_write_state *state = tevent_req_data(
4111 req, struct cli_smb2_write_state);
4115 status = smb2cli_write_recv(subreq, &written);
4116 TALLOC_FREE(subreq);
4117 if (tevent_req_nterror(req, status)) {
4121 state->written = written;
4123 tevent_req_done(req);
4126 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
4129 struct cli_smb2_write_state *state = tevent_req_data(
4130 req, struct cli_smb2_write_state);
4133 if (tevent_req_is_nterror(req, &status)) {
4134 state->cli->raw_status = status;
4135 tevent_req_received(req);
4139 if (pwritten != NULL) {
4140 *pwritten = (size_t)state->written;
4142 state->cli->raw_status = NT_STATUS_OK;
4143 tevent_req_received(req);
4144 return NT_STATUS_OK;
4147 /***************************************************************
4148 Wrapper that allows SMB2 async write using an fnum.
4149 This is mostly cut-and-paste from Volker's code inside
4150 source3/libsmb/clireadwrite.c, adapted for SMB2.
4152 Done this way so I can reuse all the logic inside cli_push()
4154 ***************************************************************/
4156 struct cli_smb2_writeall_state {
4157 struct tevent_context *ev;
4158 struct cli_state *cli;
4159 struct smb2_hnd *ph;
4167 static void cli_smb2_writeall_written(struct tevent_req *req);
4169 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
4170 struct tevent_context *ev,
4171 struct cli_state *cli,
4179 struct tevent_req *req, *subreq = NULL;
4180 struct cli_smb2_writeall_state *state = NULL;
4185 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
4191 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4192 state->flags = (uint32_t)mode;
4194 state->offset = (uint64_t)offset;
4195 state->size = (uint32_t)size;
4198 status = map_fnum_to_smb2_handle(cli,
4201 if (tevent_req_nterror(req, status)) {
4202 return tevent_req_post(req, ev);
4205 to_write = state->size;
4206 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4207 to_write = MIN(max_size, to_write);
4208 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4210 to_write = MIN(max_size, to_write);
4213 subreq = smb2cli_write_send(state,
4216 state->cli->timeout,
4217 state->cli->smb2.session,
4218 state->cli->smb2.tcon,
4221 state->ph->fid_persistent,
4222 state->ph->fid_volatile,
4223 0, /* remaining_bytes */
4224 state->flags, /* flags */
4225 state->buf + state->written);
4227 if (tevent_req_nomem(subreq, req)) {
4228 return tevent_req_post(req, ev);
4230 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4234 static void cli_smb2_writeall_written(struct tevent_req *subreq)
4236 struct tevent_req *req = tevent_req_callback_data(
4237 subreq, struct tevent_req);
4238 struct cli_smb2_writeall_state *state = tevent_req_data(
4239 req, struct cli_smb2_writeall_state);
4241 uint32_t written, to_write;
4245 status = smb2cli_write_recv(subreq, &written);
4246 TALLOC_FREE(subreq);
4247 if (tevent_req_nterror(req, status)) {
4251 state->written += written;
4253 if (state->written > state->size) {
4254 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4258 to_write = state->size - state->written;
4260 if (to_write == 0) {
4261 tevent_req_done(req);
4265 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4266 to_write = MIN(max_size, to_write);
4267 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4269 to_write = MIN(max_size, to_write);
4272 subreq = smb2cli_write_send(state,
4275 state->cli->timeout,
4276 state->cli->smb2.session,
4277 state->cli->smb2.tcon,
4279 state->offset + state->written,
4280 state->ph->fid_persistent,
4281 state->ph->fid_volatile,
4282 0, /* remaining_bytes */
4283 state->flags, /* flags */
4284 state->buf + state->written);
4286 if (tevent_req_nomem(subreq, req)) {
4289 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4292 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
4295 struct cli_smb2_writeall_state *state = tevent_req_data(
4296 req, struct cli_smb2_writeall_state);
4299 if (tevent_req_is_nterror(req, &status)) {
4300 state->cli->raw_status = status;
4303 if (pwritten != NULL) {
4304 *pwritten = (size_t)state->written;
4306 state->cli->raw_status = NT_STATUS_OK;
4307 return NT_STATUS_OK;
4310 struct cli_smb2_splice_state {
4311 struct tevent_context *ev;
4312 struct cli_state *cli;
4313 struct smb2_hnd *src_ph;
4314 struct smb2_hnd *dst_ph;
4315 int (*splice_cb)(off_t n, void *priv);
4322 struct req_resume_key_rsp resume_rsp;
4323 struct srv_copychunk_copy cc_copy;
4326 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4327 struct tevent_req *req);
4329 static void cli_splice_copychunk_done(struct tevent_req *subreq)
4331 struct tevent_req *req = tevent_req_callback_data(
4332 subreq, struct tevent_req);
4333 struct cli_smb2_splice_state *state =
4334 tevent_req_data(req,
4335 struct cli_smb2_splice_state);
4336 struct smbXcli_conn *conn = state->cli->conn;
4337 DATA_BLOB out_input_buffer = data_blob_null;
4338 DATA_BLOB out_output_buffer = data_blob_null;
4339 struct srv_copychunk_rsp cc_copy_rsp;
4340 enum ndr_err_code ndr_ret;
4343 status = smb2cli_ioctl_recv(subreq, state,
4345 &out_output_buffer);
4346 TALLOC_FREE(subreq);
4347 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
4348 state->resized) && tevent_req_nterror(req, status)) {
4352 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
4353 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
4354 if (ndr_ret != NDR_ERR_SUCCESS) {
4355 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4356 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4360 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
4361 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
4362 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
4363 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
4364 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
4365 tevent_req_nterror(req, status)) {
4369 state->resized = true;
4370 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
4371 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
4373 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4374 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4375 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
4376 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4379 state->src_offset += cc_copy_rsp.total_bytes_written;
4380 state->dst_offset += cc_copy_rsp.total_bytes_written;
4381 state->written += cc_copy_rsp.total_bytes_written;
4382 if (!state->splice_cb(state->written, state->priv)) {
4383 tevent_req_nterror(req, NT_STATUS_CANCELLED);
4388 cli_splice_copychunk_send(state, req);
4391 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4392 struct tevent_req *req)
4394 struct tevent_req *subreq;
4395 enum ndr_err_code ndr_ret;
4396 struct smbXcli_conn *conn = state->cli->conn;
4397 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
4398 off_t src_offset = state->src_offset;
4399 off_t dst_offset = state->dst_offset;
4400 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
4401 state->size - state->written);
4402 DATA_BLOB in_input_buffer = data_blob_null;
4403 DATA_BLOB in_output_buffer = data_blob_null;
4405 if (state->size - state->written == 0) {
4406 tevent_req_done(req);
4410 cc_copy->chunk_count = 0;
4412 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
4413 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
4414 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
4415 smb2cli_conn_cc_chunk_len(conn));
4416 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
4417 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4420 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
4421 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
4422 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
4423 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4426 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4427 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4428 cc_copy->chunk_count++;
4431 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
4432 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
4433 if (ndr_ret != NDR_ERR_SUCCESS) {
4434 DEBUG(0, ("failed to marshall copy chunk req\n"));
4435 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4439 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
4440 state->cli->timeout,
4441 state->cli->smb2.session,
4442 state->cli->smb2.tcon,
4443 state->dst_ph->fid_persistent, /* in_fid_persistent */
4444 state->dst_ph->fid_volatile, /* in_fid_volatile */
4445 FSCTL_SRV_COPYCHUNK_WRITE,
4446 0, /* in_max_input_length */
4448 12, /* in_max_output_length */
4450 SMB2_IOCTL_FLAG_IS_FSCTL);
4451 if (tevent_req_nomem(subreq, req)) {
4454 tevent_req_set_callback(subreq,
4455 cli_splice_copychunk_done,
4459 static void cli_splice_key_done(struct tevent_req *subreq)
4461 struct tevent_req *req = tevent_req_callback_data(
4462 subreq, struct tevent_req);
4463 struct cli_smb2_splice_state *state =
4464 tevent_req_data(req,
4465 struct cli_smb2_splice_state);
4466 enum ndr_err_code ndr_ret;
4469 DATA_BLOB out_input_buffer = data_blob_null;
4470 DATA_BLOB out_output_buffer = data_blob_null;
4472 status = smb2cli_ioctl_recv(subreq, state,
4474 &out_output_buffer);
4475 TALLOC_FREE(subreq);
4476 if (tevent_req_nterror(req, status)) {
4480 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
4481 state, &state->resume_rsp,
4482 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
4483 if (ndr_ret != NDR_ERR_SUCCESS) {
4484 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4485 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4489 memcpy(&state->cc_copy.source_key,
4490 &state->resume_rsp.resume_key,
4491 sizeof state->resume_rsp.resume_key);
4493 cli_splice_copychunk_send(state, req);
4496 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
4497 struct tevent_context *ev,
4498 struct cli_state *cli,
4499 uint16_t src_fnum, uint16_t dst_fnum,
4500 off_t size, off_t src_offset, off_t dst_offset,
4501 int (*splice_cb)(off_t n, void *priv),
4504 struct tevent_req *req;
4505 struct tevent_req *subreq;
4506 struct cli_smb2_splice_state *state;
4508 DATA_BLOB in_input_buffer = data_blob_null;
4509 DATA_BLOB in_output_buffer = data_blob_null;
4511 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
4517 state->splice_cb = splice_cb;
4521 state->src_offset = src_offset;
4522 state->dst_offset = dst_offset;
4523 state->cc_copy.chunks = talloc_array(state,
4524 struct srv_copychunk,
4525 smb2cli_conn_cc_max_chunks(cli->conn));
4526 if (state->cc_copy.chunks == NULL) {
4530 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
4531 if (tevent_req_nterror(req, status))
4532 return tevent_req_post(req, ev);
4534 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
4535 if (tevent_req_nterror(req, status))
4536 return tevent_req_post(req, ev);
4538 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
4542 state->src_ph->fid_persistent, /* in_fid_persistent */
4543 state->src_ph->fid_volatile, /* in_fid_volatile */
4544 FSCTL_SRV_REQUEST_RESUME_KEY,
4545 0, /* in_max_input_length */
4547 32, /* in_max_output_length */
4549 SMB2_IOCTL_FLAG_IS_FSCTL);
4550 if (tevent_req_nomem(subreq, req)) {
4553 tevent_req_set_callback(subreq,
4554 cli_splice_key_done,
4560 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
4562 struct cli_smb2_splice_state *state = tevent_req_data(
4563 req, struct cli_smb2_splice_state);
4566 if (tevent_req_is_nterror(req, &status)) {
4567 state->cli->raw_status = status;
4568 tevent_req_received(req);
4571 if (written != NULL) {
4572 *written = state->written;
4574 state->cli->raw_status = NT_STATUS_OK;
4575 tevent_req_received(req);
4576 return NT_STATUS_OK;
4579 /***************************************************************
4580 SMB2 enum shadow copy data.
4581 ***************************************************************/
4583 struct cli_smb2_shadow_copy_data_fnum_state {
4584 struct cli_state *cli;
4586 struct smb2_hnd *ph;
4587 DATA_BLOB out_input_buffer;
4588 DATA_BLOB out_output_buffer;
4591 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
4593 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
4594 TALLOC_CTX *mem_ctx,
4595 struct tevent_context *ev,
4596 struct cli_state *cli,
4600 struct tevent_req *req, *subreq;
4601 struct cli_smb2_shadow_copy_data_fnum_state *state;
4604 req = tevent_req_create(mem_ctx, &state,
4605 struct cli_smb2_shadow_copy_data_fnum_state);
4613 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4614 if (tevent_req_nterror(req, status)) {
4615 return tevent_req_post(req, ev);
4619 * TODO. Under SMB2 we should send a zero max_output_length
4620 * ioctl to get the required size, then send another ioctl
4621 * to get the data, but the current SMB1 implementation just
4622 * does one roundtrip with a 64K buffer size. Do the same
4626 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4627 state->cli->timeout,
4628 state->cli->smb2.session,
4629 state->cli->smb2.tcon,
4630 state->ph->fid_persistent, /* in_fid_persistent */
4631 state->ph->fid_volatile, /* in_fid_volatile */
4632 FSCTL_GET_SHADOW_COPY_DATA,
4633 0, /* in_max_input_length */
4634 NULL, /* in_input_buffer */
4636 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
4637 NULL, /* in_output_buffer */
4638 SMB2_IOCTL_FLAG_IS_FSCTL);
4640 if (tevent_req_nomem(subreq, req)) {
4641 return tevent_req_post(req, ev);
4643 tevent_req_set_callback(subreq,
4644 cli_smb2_shadow_copy_data_fnum_done,
4650 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4652 struct tevent_req *req = tevent_req_callback_data(
4653 subreq, struct tevent_req);
4654 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4655 req, struct cli_smb2_shadow_copy_data_fnum_state);
4658 status = smb2cli_ioctl_recv(subreq, state,
4659 &state->out_input_buffer,
4660 &state->out_output_buffer);
4661 tevent_req_simple_finish_ntstatus(subreq, status);
4664 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4665 TALLOC_CTX *mem_ctx,
4670 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4671 req, struct cli_smb2_shadow_copy_data_fnum_state);
4672 char **names = NULL;
4673 uint32_t num_names = 0;
4674 uint32_t num_names_returned = 0;
4675 uint32_t dlength = 0;
4677 uint8_t *endp = NULL;
4680 if (tevent_req_is_nterror(req, &status)) {
4684 if (state->out_output_buffer.length < 16) {
4685 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4688 num_names = IVAL(state->out_output_buffer.data, 0);
4689 num_names_returned = IVAL(state->out_output_buffer.data, 4);
4690 dlength = IVAL(state->out_output_buffer.data, 8);
4692 if (num_names > 0x7FFFFFFF) {
4693 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4696 if (get_names == false) {
4697 *pnum_names = (int)num_names;
4698 return NT_STATUS_OK;
4700 if (num_names != num_names_returned) {
4701 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4703 if (dlength + 12 < 12) {
4704 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4707 * NB. The below is an allowable return if there are
4708 * more snapshots than the buffer size we told the
4709 * server we can receive. We currently don't support
4712 if (dlength + 12 > state->out_output_buffer.length) {
4713 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4715 if (state->out_output_buffer.length +
4716 (2 * sizeof(SHADOW_COPY_LABEL)) <
4717 state->out_output_buffer.length) {
4718 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4721 names = talloc_array(mem_ctx, char *, num_names_returned);
4722 if (names == NULL) {
4723 return NT_STATUS_NO_MEMORY;
4726 endp = state->out_output_buffer.data +
4727 state->out_output_buffer.length;
4729 for (i=0; i<num_names_returned; i++) {
4732 size_t converted_size;
4734 src = state->out_output_buffer.data + 12 +
4735 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4737 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4738 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4740 ret = convert_string_talloc(
4741 names, CH_UTF16LE, CH_UNIX,
4742 src, 2 * sizeof(SHADOW_COPY_LABEL),
4743 &names[i], &converted_size);
4746 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4749 *pnum_names = num_names;
4751 return NT_STATUS_OK;
4754 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4755 struct cli_state *cli,
4761 TALLOC_CTX *frame = talloc_stackframe();
4762 struct tevent_context *ev;
4763 struct tevent_req *req;
4764 NTSTATUS status = NT_STATUS_NO_MEMORY;
4766 if (smbXcli_conn_has_async_calls(cli->conn)) {
4768 * Can't use sync call while an async call is in flight
4770 status = NT_STATUS_INVALID_PARAMETER;
4773 ev = samba_tevent_context_init(frame);
4777 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4785 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4788 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4794 cli->raw_status = status;
4800 /***************************************************************
4801 Wrapper that allows SMB2 to truncate a file.
4803 ***************************************************************/
4805 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4810 uint8_t buf[8] = {0};
4811 DATA_BLOB inbuf = { .data = buf, .length = sizeof(buf) };
4812 TALLOC_CTX *frame = talloc_stackframe();
4814 if (smbXcli_conn_has_async_calls(cli->conn)) {
4816 * Can't use sync call while an async call is in flight
4818 status = NT_STATUS_INVALID_PARAMETER;
4822 SBVAL(buf, 0, newsize);
4824 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4825 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4827 status = cli_smb2_set_info_fnum(
4830 1, /* in_info_type */
4831 SMB_FILE_END_OF_FILE_INFORMATION-1000, /* in_file_info_class */
4832 &inbuf, /* in_input_buffer */
4837 cli->raw_status = status;
4843 struct cli_smb2_notify_state {
4844 struct tevent_req *subreq;
4845 struct notify_change *changes;
4849 static void cli_smb2_notify_done(struct tevent_req *subreq);
4850 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4852 struct tevent_req *cli_smb2_notify_send(
4853 TALLOC_CTX *mem_ctx,
4854 struct tevent_context *ev,
4855 struct cli_state *cli,
4857 uint32_t buffer_size,
4858 uint32_t completion_filter,
4861 struct tevent_req *req = NULL;
4862 struct cli_smb2_notify_state *state = NULL;
4863 struct smb2_hnd *ph = NULL;
4866 req = tevent_req_create(mem_ctx, &state,
4867 struct cli_smb2_notify_state);
4872 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4873 if (tevent_req_nterror(req, status)) {
4874 return tevent_req_post(req, ev);
4877 state->subreq = smb2cli_notify_send(
4889 if (tevent_req_nomem(state->subreq, req)) {
4890 return tevent_req_post(req, ev);
4892 tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4893 tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4897 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4899 struct cli_smb2_notify_state *state = tevent_req_data(
4900 req, struct cli_smb2_notify_state);
4903 ok = tevent_req_cancel(state->subreq);
4907 static void cli_smb2_notify_done(struct tevent_req *subreq)
4909 struct tevent_req *req = tevent_req_callback_data(
4910 subreq, struct tevent_req);
4911 struct cli_smb2_notify_state *state = tevent_req_data(
4912 req, struct cli_smb2_notify_state);
4918 status = smb2cli_notify_recv(subreq, state, &base, &len);
4919 TALLOC_FREE(subreq);
4921 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4922 tevent_req_done(req);
4925 if (tevent_req_nterror(req, status)) {
4931 while (len - ofs >= 12) {
4932 struct notify_change *tmp;
4933 struct notify_change *c;
4934 uint32_t next_ofs = IVAL(base, ofs);
4935 uint32_t file_name_length = IVAL(base, ofs+8);
4939 tmp = talloc_realloc(
4942 struct notify_change,
4943 state->num_changes + 1);
4944 if (tevent_req_nomem(tmp, req)) {
4947 state->changes = tmp;
4948 c = &state->changes[state->num_changes];
4949 state->num_changes += 1;
4951 if (smb_buffer_oob(len, ofs, next_ofs) ||
4952 smb_buffer_oob(len, ofs+12, file_name_length)) {
4954 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4958 c->action = IVAL(base, ofs+4);
4960 ok = convert_string_talloc(
4970 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4974 if (next_ofs == 0) {
4980 tevent_req_done(req);
4983 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
4984 TALLOC_CTX *mem_ctx,
4985 struct notify_change **pchanges,
4986 uint32_t *pnum_changes)
4988 struct cli_smb2_notify_state *state = tevent_req_data(
4989 req, struct cli_smb2_notify_state);
4992 if (tevent_req_is_nterror(req, &status)) {
4995 *pchanges = talloc_move(mem_ctx, &state->changes);
4996 *pnum_changes = state->num_changes;
4997 return NT_STATUS_OK;
5000 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
5001 uint32_t buffer_size, uint32_t completion_filter,
5002 bool recursive, TALLOC_CTX *mem_ctx,
5003 struct notify_change **pchanges,
5004 uint32_t *pnum_changes)
5006 TALLOC_CTX *frame = talloc_stackframe();
5007 struct tevent_context *ev;
5008 struct tevent_req *req;
5009 NTSTATUS status = NT_STATUS_NO_MEMORY;
5011 if (smbXcli_conn_has_async_calls(cli->conn)) {
5013 * Can't use sync call while an async call is in flight
5015 status = NT_STATUS_INVALID_PARAMETER;
5018 ev = samba_tevent_context_init(frame);
5022 req = cli_smb2_notify_send(
5033 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5036 status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
5042 struct cli_smb2_fsctl_state {
5046 static void cli_smb2_fsctl_done(struct tevent_req *subreq);
5048 struct tevent_req *cli_smb2_fsctl_send(
5049 TALLOC_CTX *mem_ctx,
5050 struct tevent_context *ev,
5051 struct cli_state *cli,
5054 const DATA_BLOB *in,
5057 struct tevent_req *req = NULL, *subreq = NULL;
5058 struct cli_smb2_fsctl_state *state = NULL;
5059 struct smb2_hnd *ph = NULL;
5062 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_fsctl_state);
5067 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
5068 if (tevent_req_nterror(req, status)) {
5069 return tevent_req_post(req, ev);
5072 subreq = smb2cli_ioctl_send(
5082 0, /* in_max_input_length */
5086 SMB2_IOCTL_FLAG_IS_FSCTL);
5088 if (tevent_req_nomem(subreq, req)) {
5089 return tevent_req_post(req, ev);
5091 tevent_req_set_callback(subreq, cli_smb2_fsctl_done, req);
5095 static void cli_smb2_fsctl_done(struct tevent_req *subreq)
5097 struct tevent_req *req = tevent_req_callback_data(
5098 subreq, struct tevent_req);
5099 struct cli_smb2_fsctl_state *state = tevent_req_data(
5100 req, struct cli_smb2_fsctl_state);
5103 status = smb2cli_ioctl_recv(subreq, state, NULL, &state->out);
5104 tevent_req_simple_finish_ntstatus(subreq, status);
5107 NTSTATUS cli_smb2_fsctl_recv(
5108 struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *out)
5110 struct cli_smb2_fsctl_state *state = tevent_req_data(
5111 req, struct cli_smb2_fsctl_state);
5112 NTSTATUS status = NT_STATUS_OK;
5114 if (tevent_req_is_nterror(req, &status)) {
5115 tevent_req_received(req);
5119 if (state->out.length == 0) {
5120 *out = (DATA_BLOB) { .data = NULL, };
5123 * Can't use talloc_move() here, the outblobs from
5124 * smb2cli_ioctl_recv() are not standalone talloc
5125 * objects but just peek into the larger buffers
5126 * received, hanging off "state".
5128 *out = data_blob_talloc(
5129 mem_ctx, state->out.data, state->out.length);
5130 if (out->data == NULL) {
5131 status = NT_STATUS_NO_MEMORY;
5135 tevent_req_received(req);
5136 return NT_STATUS_OK;