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"
48 uint64_t fid_persistent;
49 uint64_t fid_volatile;
53 * Handle mapping code.
56 /***************************************************************
57 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
58 Ensures handle is owned by cli struct.
59 ***************************************************************/
61 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
62 const struct smb2_hnd *ph, /* In */
63 uint16_t *pfnum) /* Out */
66 struct idr_context *idp = cli->smb2.open_handles;
67 struct smb2_hnd *owned_h = talloc_memdup(cli,
69 sizeof(struct smb2_hnd));
71 if (owned_h == NULL) {
72 return NT_STATUS_NO_MEMORY;
77 cli->smb2.open_handles = idr_init(cli);
78 if (cli->smb2.open_handles == NULL) {
80 return NT_STATUS_NO_MEMORY;
82 idp = cli->smb2.open_handles;
85 ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
88 return NT_STATUS_NO_MEMORY;
91 *pfnum = (uint16_t)ret;
95 /***************************************************************
96 Return the smb2_hnd pointer associated with the given fnum.
97 ***************************************************************/
99 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
100 uint16_t fnum, /* In */
101 struct smb2_hnd **pph) /* Out */
103 struct idr_context *idp = cli->smb2.open_handles;
106 return NT_STATUS_INVALID_PARAMETER;
108 *pph = (struct smb2_hnd *)idr_find(idp, fnum);
110 return NT_STATUS_INVALID_HANDLE;
115 /***************************************************************
116 Delete the fnum to smb2_hnd mapping. Zeros out handle on
118 ***************************************************************/
120 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
121 struct smb2_hnd **pph, /* In */
122 uint16_t fnum) /* In */
124 struct idr_context *idp = cli->smb2.open_handles;
128 return NT_STATUS_INVALID_PARAMETER;
131 ph = (struct smb2_hnd *)idr_find(idp, fnum);
133 return NT_STATUS_INVALID_PARAMETER;
135 idr_remove(idp, fnum);
140 /***************************************************************
142 ***************************************************************/
144 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
146 if (create_flags & REQUEST_BATCH_OPLOCK) {
147 return SMB2_OPLOCK_LEVEL_BATCH;
148 } else if (create_flags & REQUEST_OPLOCK) {
149 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
152 /* create_flags doesn't do a level2 request. */
153 return SMB2_OPLOCK_LEVEL_NONE;
156 /***************************************************************
157 If we're on a DFS share, ensure we convert to a full DFS path
158 if this hasn't already been done.
159 ***************************************************************/
161 static char *smb2_dfs_share_path(TALLOC_CTX *ctx,
162 struct cli_state *cli,
165 bool is_dfs = smbXcli_conn_dfs_supported(cli->conn) &&
166 smbXcli_tcon_is_dfs_share(cli->smb2.tcon);
167 bool is_already_dfs_path = false;
172 is_already_dfs_path = cli_dfs_is_already_full_path(cli, path);
173 if (is_already_dfs_path) {
176 if (path[0] == '\0') {
177 return talloc_asprintf(ctx,
179 smbXcli_conn_remote_name(cli->conn),
182 while (*path == '\\') {
185 return talloc_asprintf(ctx,
187 smbXcli_conn_remote_name(cli->conn),
192 /***************************************************************
193 Small wrapper that allows SMB2 create to return a uint16_t fnum.
194 ***************************************************************/
196 struct cli_smb2_create_fnum_state {
197 struct cli_state *cli;
198 struct smb2_create_blobs in_cblobs;
199 struct smb2_create_blobs out_cblobs;
200 struct smb_create_returns cr;
201 struct symlink_reparse_struct *symlink;
203 struct tevent_req *subreq;
206 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
207 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
209 struct tevent_req *cli_smb2_create_fnum_send(
211 struct tevent_context *ev,
212 struct cli_state *cli,
213 const char *fname_in,
214 uint32_t create_flags,
215 uint32_t impersonation_level,
216 uint32_t desired_access,
217 uint32_t file_attributes,
218 uint32_t share_access,
219 uint32_t create_disposition,
220 uint32_t create_options,
221 const struct smb2_create_blobs *in_cblobs)
223 struct tevent_req *req, *subreq;
224 struct cli_smb2_create_fnum_state *state;
226 size_t fname_len = 0;
227 const char *startp = NULL;
228 const char *endp = NULL;
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 fname_len = strlen(fname);
250 if (clistr_is_previous_version_path(fname, &startp, &endp, &ntt)) {
251 size_t len_before_gmt = startp - fname;
252 size_t len_after_gmt = fname + fname_len - endp;
254 char *new_fname = talloc_array(state, char,
255 len_before_gmt + len_after_gmt + 1);
257 if (tevent_req_nomem(new_fname, req)) {
258 return tevent_req_post(req, ev);
261 memcpy(new_fname, fname, len_before_gmt);
262 memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
264 fname_len = len_before_gmt + len_after_gmt;
266 status = smb2_create_blob_add(
269 SMB2_CREATE_TAG_TWRP,
271 .data = (uint8_t *)&ntt,
272 .length = sizeof(ntt),
274 if (tevent_req_nterror(req, status)) {
275 return tevent_req_post(req, ev);
279 if (in_cblobs != NULL) {
281 for (i=0; i<in_cblobs->num_blobs; i++) {
282 struct smb2_create_blob *b = &in_cblobs->blobs[i];
283 status = smb2_create_blob_add(
284 state, &state->in_cblobs, b->tag, b->data);
285 if (!NT_STATUS_IS_OK(status)) {
286 tevent_req_nterror(req, status);
287 return tevent_req_post(req, ev);
292 fname = smb2_dfs_share_path(state, cli, fname);
293 if (tevent_req_nomem(fname, req)) {
294 return tevent_req_post(req, ev);
296 fname_len = strlen(fname);
298 /* SMB2 is pickier about pathnames. Ensure it doesn't
300 if (*fname == '\\') {
305 /* Or end in a '\' */
306 if (fname_len > 0 && fname[fname_len-1] == '\\') {
307 char *new_fname = talloc_strdup(state, fname);
308 if (tevent_req_nomem(new_fname, req)) {
309 return tevent_req_post(req, ev);
311 new_fname[fname_len-1] = '\0';
315 subreq = smb2cli_create_send(state, ev,
321 flags_to_smb2_oplock(create_flags),
329 if (tevent_req_nomem(subreq, req)) {
330 return tevent_req_post(req, ev);
332 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
334 state->subreq = subreq;
335 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
340 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
342 struct tevent_req *req = tevent_req_callback_data(
343 subreq, struct tevent_req);
344 struct cli_smb2_create_fnum_state *state = tevent_req_data(
345 req, struct cli_smb2_create_fnum_state);
349 status = smb2cli_create_recv(
352 &h.fid_volatile, &state->cr,
357 if (tevent_req_nterror(req, status)) {
361 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
362 if (tevent_req_nterror(req, status)) {
365 tevent_req_done(req);
368 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
370 struct cli_smb2_create_fnum_state *state = tevent_req_data(
371 req, struct cli_smb2_create_fnum_state);
372 return tevent_req_cancel(state->subreq);
375 NTSTATUS cli_smb2_create_fnum_recv(
376 struct tevent_req *req,
378 struct smb_create_returns *cr,
380 struct smb2_create_blobs *out_cblobs,
381 struct symlink_reparse_struct **symlink)
383 struct cli_smb2_create_fnum_state *state = tevent_req_data(
384 req, struct cli_smb2_create_fnum_state);
387 if (tevent_req_is_nterror(req, &status)) {
388 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) &&
390 *symlink = talloc_move(mem_ctx, &state->symlink);
392 state->cli->raw_status = status;
396 *pfnum = state->fnum;
401 if (out_cblobs != NULL) {
402 *out_cblobs = (struct smb2_create_blobs) {
403 .num_blobs = state->out_cblobs.num_blobs,
404 .blobs = talloc_move(
405 mem_ctx, &state->out_cblobs.blobs),
408 state->cli->raw_status = NT_STATUS_OK;
412 NTSTATUS cli_smb2_create_fnum(
413 struct cli_state *cli,
415 uint32_t create_flags,
416 uint32_t impersonation_level,
417 uint32_t desired_access,
418 uint32_t file_attributes,
419 uint32_t share_access,
420 uint32_t create_disposition,
421 uint32_t create_options,
422 const struct smb2_create_blobs *in_cblobs,
424 struct smb_create_returns *cr,
426 struct smb2_create_blobs *out_cblobs)
428 TALLOC_CTX *frame = talloc_stackframe();
429 struct tevent_context *ev;
430 struct tevent_req *req;
431 NTSTATUS status = NT_STATUS_NO_MEMORY;
433 if (smbXcli_conn_has_async_calls(cli->conn)) {
435 * Can't use sync call while an async call is in flight
437 status = NT_STATUS_INVALID_PARAMETER;
440 ev = samba_tevent_context_init(frame);
444 req = cli_smb2_create_fnum_send(
460 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
463 status = cli_smb2_create_fnum_recv(
464 req, pfid, cr, mem_ctx, out_cblobs, NULL);
470 /***************************************************************
471 Small wrapper that allows SMB2 close to use a uint16_t fnum.
472 ***************************************************************/
474 struct cli_smb2_close_fnum_state {
475 struct cli_state *cli;
480 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
482 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
483 struct tevent_context *ev,
484 struct cli_state *cli,
487 struct tevent_req *req, *subreq;
488 struct cli_smb2_close_fnum_state *state;
491 req = tevent_req_create(mem_ctx, &state,
492 struct cli_smb2_close_fnum_state);
499 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
500 if (tevent_req_nterror(req, status)) {
501 return tevent_req_post(req, ev);
504 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
505 cli->smb2.session, cli->smb2.tcon,
506 0, state->ph->fid_persistent,
507 state->ph->fid_volatile);
508 if (tevent_req_nomem(subreq, req)) {
509 return tevent_req_post(req, ev);
511 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
515 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
517 struct tevent_req *req = tevent_req_callback_data(
518 subreq, struct tevent_req);
519 struct cli_smb2_close_fnum_state *state = tevent_req_data(
520 req, struct cli_smb2_close_fnum_state);
523 status = smb2cli_close_recv(subreq);
524 if (tevent_req_nterror(req, status)) {
528 /* Delete the fnum -> handle mapping. */
529 status = delete_smb2_handle_mapping(state->cli, &state->ph,
531 if (tevent_req_nterror(req, status)) {
534 tevent_req_done(req);
537 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
539 struct cli_smb2_close_fnum_state *state = tevent_req_data(
540 req, struct cli_smb2_close_fnum_state);
541 NTSTATUS status = NT_STATUS_OK;
543 if (tevent_req_is_nterror(req, &status)) {
544 state->cli->raw_status = status;
546 tevent_req_received(req);
550 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
552 TALLOC_CTX *frame = talloc_stackframe();
553 struct tevent_context *ev;
554 struct tevent_req *req;
555 NTSTATUS status = NT_STATUS_NO_MEMORY;
557 if (smbXcli_conn_has_async_calls(cli->conn)) {
559 * Can't use sync call while an async call is in flight
561 status = NT_STATUS_INVALID_PARAMETER;
564 ev = samba_tevent_context_init(frame);
568 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
572 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
575 status = cli_smb2_close_fnum_recv(req);
581 struct cli_smb2_set_info_fnum_state {
585 static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq);
587 struct tevent_req *cli_smb2_set_info_fnum_send(
589 struct tevent_context *ev,
590 struct cli_state *cli,
592 uint8_t in_info_type,
593 uint8_t in_info_class,
594 const DATA_BLOB *in_input_buffer,
595 uint32_t in_additional_info)
597 struct tevent_req *req = NULL, *subreq = NULL;
598 struct cli_smb2_set_info_fnum_state *state = NULL;
599 struct smb2_hnd *ph = NULL;
602 req = tevent_req_create(
603 mem_ctx, &state, struct cli_smb2_set_info_fnum_state);
608 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
609 if (tevent_req_nterror(req, status)) {
610 return tevent_req_post(req, ev);
613 subreq = smb2cli_set_info_send(
626 if (tevent_req_nomem(subreq, req)) {
627 return tevent_req_post(req, ev);
629 tevent_req_set_callback(subreq, cli_smb2_set_info_fnum_done, req);
633 static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq)
635 NTSTATUS status = smb2cli_set_info_recv(subreq);
636 tevent_req_simple_finish_ntstatus(subreq, status);
639 NTSTATUS cli_smb2_set_info_fnum_recv(struct tevent_req *req)
641 return tevent_req_simple_recv_ntstatus(req);
644 NTSTATUS cli_smb2_set_info_fnum(
645 struct cli_state *cli,
647 uint8_t in_info_type,
648 uint8_t in_info_class,
649 const DATA_BLOB *in_input_buffer,
650 uint32_t in_additional_info)
652 TALLOC_CTX *frame = talloc_stackframe();
653 struct tevent_context *ev = NULL;
654 struct tevent_req *req = NULL;
655 NTSTATUS status = NT_STATUS_NO_MEMORY;
658 if (smbXcli_conn_has_async_calls(cli->conn)) {
660 * Can't use sync call while an async call is in flight
662 status = NT_STATUS_INVALID_PARAMETER;
665 ev = samba_tevent_context_init(frame);
669 req = cli_smb2_set_info_fnum_send(
681 ok = tevent_req_poll_ntstatus(req, ev, &status);
685 status = cli_smb2_set_info_fnum_recv(req);
691 struct cli_smb2_delete_on_close_state {
692 struct cli_state *cli;
697 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
699 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
700 struct tevent_context *ev,
701 struct cli_state *cli,
705 struct tevent_req *req = NULL;
706 struct cli_smb2_delete_on_close_state *state = NULL;
707 struct tevent_req *subreq = NULL;
708 uint8_t in_info_type;
709 uint8_t in_file_info_class;
711 req = tevent_req_create(mem_ctx, &state,
712 struct cli_smb2_delete_on_close_state);
719 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
720 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
723 in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
724 /* Setup data array. */
725 SCVAL(&state->data[0], 0, flag ? 1 : 0);
726 state->inbuf.data = &state->data[0];
727 state->inbuf.length = 1;
729 subreq = cli_smb2_set_info_fnum_send(
738 if (tevent_req_nomem(subreq, req)) {
739 return tevent_req_post(req, ev);
741 tevent_req_set_callback(subreq,
742 cli_smb2_delete_on_close_done,
747 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
749 NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
750 tevent_req_simple_finish_ntstatus(subreq, status);
753 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
755 struct cli_smb2_delete_on_close_state *state =
757 struct cli_smb2_delete_on_close_state);
760 if (tevent_req_is_nterror(req, &status)) {
761 state->cli->raw_status = status;
762 tevent_req_received(req);
766 state->cli->raw_status = NT_STATUS_OK;
767 tevent_req_received(req);
771 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
773 TALLOC_CTX *frame = talloc_stackframe();
774 struct tevent_context *ev;
775 struct tevent_req *req;
776 NTSTATUS status = NT_STATUS_NO_MEMORY;
778 if (smbXcli_conn_has_async_calls(cli->conn)) {
780 * Can't use sync call while an async call is in flight
782 status = NT_STATUS_INVALID_PARAMETER;
785 ev = samba_tevent_context_init(frame);
789 req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
793 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
796 status = cli_smb2_delete_on_close_recv(req);
802 struct cli_smb2_mkdir_state {
803 struct tevent_context *ev;
804 struct cli_state *cli;
807 static void cli_smb2_mkdir_opened(struct tevent_req *subreq);
808 static void cli_smb2_mkdir_closed(struct tevent_req *subreq);
810 struct tevent_req *cli_smb2_mkdir_send(
812 struct tevent_context *ev,
813 struct cli_state *cli,
816 struct tevent_req *req = NULL, *subreq = NULL;
817 struct cli_smb2_mkdir_state *state = NULL;
819 req = tevent_req_create(
820 mem_ctx, &state, struct cli_smb2_mkdir_state);
827 /* Ensure this is a directory. */
828 subreq = cli_smb2_create_fnum_send(
833 0, /* create_flags */
834 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level */
835 FILE_READ_ATTRIBUTES, /* desired_access */
836 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
838 FILE_SHARE_WRITE, /* share_access */
839 FILE_CREATE, /* create_disposition */
840 FILE_DIRECTORY_FILE, /* create_options */
841 NULL); /* in_cblobs */
842 if (tevent_req_nomem(subreq, req)) {
843 return tevent_req_post(req, ev);
845 tevent_req_set_callback(subreq, cli_smb2_mkdir_opened, req);
849 static void cli_smb2_mkdir_opened(struct tevent_req *subreq)
851 struct tevent_req *req = tevent_req_callback_data(
852 subreq, struct tevent_req);
853 struct cli_smb2_mkdir_state *state = tevent_req_data(
854 req, struct cli_smb2_mkdir_state);
856 uint16_t fnum = 0xffff;
858 status = cli_smb2_create_fnum_recv(
859 subreq, &fnum, NULL, NULL, NULL, NULL);
861 if (tevent_req_nterror(req, status)) {
865 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
866 if (tevent_req_nomem(subreq, req)) {
869 tevent_req_set_callback(subreq, cli_smb2_mkdir_closed, req);
872 static void cli_smb2_mkdir_closed(struct tevent_req *subreq)
874 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
875 tevent_req_simple_finish_ntstatus(subreq, status);
878 NTSTATUS cli_smb2_mkdir_recv(struct tevent_req *req)
880 return tevent_req_simple_recv_ntstatus(req);
883 struct cli_smb2_rmdir_state {
884 struct tevent_context *ev;
885 struct cli_state *cli;
887 const struct smb2_create_blobs *in_cblobs;
892 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq);
893 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq);
894 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq);
895 static void cli_smb2_rmdir_closed(struct tevent_req *subreq);
897 struct tevent_req *cli_smb2_rmdir_send(
899 struct tevent_context *ev,
900 struct cli_state *cli,
902 const struct smb2_create_blobs *in_cblobs)
904 struct tevent_req *req = NULL, *subreq = NULL;
905 struct cli_smb2_rmdir_state *state = NULL;
907 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_rmdir_state);
913 state->dname = dname;
914 state->in_cblobs = in_cblobs;
916 subreq = cli_smb2_create_fnum_send(
921 0, /* create_flags */
922 SMB2_IMPERSONATION_IMPERSONATION,
923 DELETE_ACCESS, /* desired_access */
924 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
925 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
926 FILE_OPEN, /* create_disposition */
927 FILE_DIRECTORY_FILE, /* create_options */
928 state->in_cblobs); /* in_cblobs */
929 if (tevent_req_nomem(subreq, req)) {
930 return tevent_req_post(req, ev);
932 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened1, req);
936 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq)
938 struct tevent_req *req = tevent_req_callback_data(
939 subreq, struct tevent_req);
940 struct cli_smb2_rmdir_state *state = tevent_req_data(
941 req, struct cli_smb2_rmdir_state);
944 status = cli_smb2_create_fnum_recv(
945 subreq, &state->fnum, NULL, NULL, NULL, NULL);
948 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
950 * Naive option to match our SMB1 code. Assume the
951 * symlink path that tripped us up was the last
952 * component and try again. Eventually we will have to
953 * deal with the returned path unprocessed component. JRA.
955 subreq = cli_smb2_create_fnum_send(
960 0, /* create_flags */
961 SMB2_IMPERSONATION_IMPERSONATION,
962 DELETE_ACCESS, /* desired_access */
963 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
964 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
965 FILE_OPEN, /* create_disposition */
967 FILE_DELETE_ON_CLOSE|
968 FILE_OPEN_REPARSE_POINT, /* create_options */
969 state->in_cblobs); /* in_cblobs */
970 if (tevent_req_nomem(subreq, req)) {
973 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened2, req);
977 if (tevent_req_nterror(req, status)) {
981 subreq = cli_smb2_delete_on_close_send(
982 state, state->ev, state->cli, state->fnum, true);
983 if (tevent_req_nomem(subreq, req)) {
986 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
989 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq)
991 struct tevent_req *req = tevent_req_callback_data(
992 subreq, struct tevent_req);
993 struct cli_smb2_rmdir_state *state = tevent_req_data(
994 req, struct cli_smb2_rmdir_state);
997 status = cli_smb2_create_fnum_recv(
998 subreq, &state->fnum, NULL, NULL, NULL, NULL);
1000 if (tevent_req_nterror(req, status)) {
1004 subreq = cli_smb2_delete_on_close_send(
1005 state, state->ev, state->cli, state->fnum, true);
1006 if (tevent_req_nomem(subreq, req)) {
1009 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
1012 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq)
1014 struct tevent_req *req = tevent_req_callback_data(
1015 subreq, struct tevent_req);
1016 struct cli_smb2_rmdir_state *state = tevent_req_data(
1017 req, struct cli_smb2_rmdir_state);
1019 state->status = cli_smb2_delete_on_close_recv(subreq);
1020 TALLOC_FREE(subreq);
1023 * Close the fd even if the set_disp failed
1026 subreq = cli_smb2_close_fnum_send(
1027 state, state->ev, state->cli, state->fnum);
1028 if (tevent_req_nomem(subreq, req)) {
1031 tevent_req_set_callback(subreq, cli_smb2_rmdir_closed, req);
1034 static void cli_smb2_rmdir_closed(struct tevent_req *subreq)
1036 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1037 tevent_req_simple_finish_ntstatus(subreq, status);
1040 NTSTATUS cli_smb2_rmdir_recv(struct tevent_req *req)
1042 struct cli_smb2_rmdir_state *state = tevent_req_data(
1043 req, struct cli_smb2_rmdir_state);
1046 if (tevent_req_is_nterror(req, &status)) {
1049 return state->status;
1052 /***************************************************************
1053 Small wrapper that allows SMB2 to unlink a pathname.
1054 ***************************************************************/
1056 struct cli_smb2_unlink_state {
1057 struct tevent_context *ev;
1058 struct cli_state *cli;
1060 const struct smb2_create_blobs *in_cblobs;
1063 static void cli_smb2_unlink_opened1(struct tevent_req *subreq);
1064 static void cli_smb2_unlink_opened2(struct tevent_req *subreq);
1065 static void cli_smb2_unlink_closed(struct tevent_req *subreq);
1067 struct tevent_req *cli_smb2_unlink_send(
1068 TALLOC_CTX *mem_ctx,
1069 struct tevent_context *ev,
1070 struct cli_state *cli,
1072 const struct smb2_create_blobs *in_cblobs)
1074 struct tevent_req *req = NULL, *subreq = NULL;
1075 struct cli_smb2_unlink_state *state = NULL;
1077 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_unlink_state);
1083 state->fname = fname;
1084 state->in_cblobs = in_cblobs;
1086 subreq = cli_smb2_create_fnum_send(
1087 state, /* mem_ctx */
1088 state->ev, /* tevent_context */
1089 state->cli, /* cli_struct */
1090 state->fname, /* filename */
1091 0, /* create_flags */
1092 SMB2_IMPERSONATION_IMPERSONATION,
1093 DELETE_ACCESS, /* desired_access */
1094 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1097 FILE_SHARE_DELETE, /* share_access */
1098 FILE_OPEN, /* create_disposition */
1099 FILE_DELETE_ON_CLOSE, /* create_options */
1100 state->in_cblobs); /* in_cblobs */
1101 if (tevent_req_nomem(subreq, req)) {
1102 return tevent_req_post(req, ev);
1104 tevent_req_set_callback(subreq, cli_smb2_unlink_opened1, req);
1108 static void cli_smb2_unlink_opened1(struct tevent_req *subreq)
1110 struct tevent_req *req = tevent_req_callback_data(
1111 subreq, struct tevent_req);
1112 struct cli_smb2_unlink_state *state = tevent_req_data(
1113 req, struct cli_smb2_unlink_state);
1114 uint16_t fnum = 0xffff;
1117 status = cli_smb2_create_fnum_recv(
1118 subreq, &fnum, NULL, NULL, NULL, NULL);
1119 TALLOC_FREE(subreq);
1121 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) ||
1122 NT_STATUS_EQUAL(status, NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED)) {
1124 * Naive option to match our SMB1 code. Assume the
1125 * symlink path that tripped us up was the last
1126 * component and try again. Eventually we will have to
1127 * deal with the returned path unprocessed component. JRA.
1129 subreq = cli_smb2_create_fnum_send(
1130 state, /* mem_ctx */
1131 state->ev, /* tevent_context */
1132 state->cli, /* cli_struct */
1133 state->fname, /* filename */
1134 0, /* create_flags */
1135 SMB2_IMPERSONATION_IMPERSONATION,
1136 DELETE_ACCESS, /* desired_access */
1137 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1140 FILE_SHARE_DELETE, /* share_access */
1141 FILE_OPEN, /* create_disposition */
1142 FILE_DELETE_ON_CLOSE|
1143 FILE_OPEN_REPARSE_POINT, /* create_options */
1144 state->in_cblobs); /* in_cblobs */
1145 if (tevent_req_nomem(subreq, req)) {
1148 tevent_req_set_callback(subreq, cli_smb2_unlink_opened2, req);
1152 if (tevent_req_nterror(req, status)) {
1156 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1157 if (tevent_req_nomem(subreq, req)) {
1160 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1163 static void cli_smb2_unlink_opened2(struct tevent_req *subreq)
1165 struct tevent_req *req = tevent_req_callback_data(
1166 subreq, struct tevent_req);
1167 struct cli_smb2_unlink_state *state = tevent_req_data(
1168 req, struct cli_smb2_unlink_state);
1169 uint16_t fnum = 0xffff;
1172 status = cli_smb2_create_fnum_recv(
1173 subreq, &fnum, NULL, NULL, NULL, NULL);
1174 TALLOC_FREE(subreq);
1175 if (tevent_req_nterror(req, status)) {
1179 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1180 if (tevent_req_nomem(subreq, req)) {
1183 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1186 static void cli_smb2_unlink_closed(struct tevent_req *subreq)
1188 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1189 tevent_req_simple_finish_ntstatus(subreq, status);
1192 NTSTATUS cli_smb2_unlink_recv(struct tevent_req *req)
1194 return tevent_req_simple_recv_ntstatus(req);
1197 static ssize_t sid_parse_wire(TALLOC_CTX *mem_ctx, const uint8_t *data,
1198 struct dom_sid *sid, size_t num_rdata)
1201 enum ndr_err_code ndr_err;
1202 DATA_BLOB in = data_blob_const(data, num_rdata);
1204 ndr_err = ndr_pull_struct_blob(&in,
1207 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
1208 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1212 sid_size = ndr_size_dom_sid(sid, 0);
1213 if (sid_size > num_rdata) {
1220 /***************************************************************
1221 Utility function to parse a SMB2_FIND_POSIX_INFORMATION reply.
1222 ***************************************************************/
1224 static NTSTATUS parse_finfo_posix_info(const uint8_t *dir_data,
1225 uint32_t dir_data_length,
1226 struct file_info *finfo,
1227 uint32_t *next_offset)
1230 size_t slen = 0, slen2 = 0;
1232 uint32_t _next_offset = 0;
1234 if (dir_data_length < 4) {
1235 return NT_STATUS_INFO_LENGTH_MISMATCH;
1238 _next_offset = IVAL(dir_data, 0);
1240 if (_next_offset > dir_data_length) {
1241 return NT_STATUS_INFO_LENGTH_MISMATCH;
1244 if (_next_offset != 0) {
1245 /* Ensure we only read what in this record. */
1246 dir_data_length = _next_offset;
1249 if (dir_data_length < 92) {
1250 return NT_STATUS_INFO_LENGTH_MISMATCH;
1253 finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
1254 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
1255 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
1256 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
1257 finfo->allocated_size = PULL_LE_U64(dir_data, 40);
1258 finfo->size = PULL_LE_U64(dir_data, 48);
1259 finfo->mode = PULL_LE_U32(dir_data, 56);
1260 finfo->ino = PULL_LE_U64(dir_data, 60);
1261 finfo->st_ex_dev = PULL_LE_U32(dir_data, 68);
1262 finfo->st_ex_nlink = PULL_LE_U32(dir_data, 76);
1263 finfo->reparse_tag = PULL_LE_U32(dir_data, 80);
1264 finfo->st_ex_mode = wire_perms_to_unix(PULL_LE_U32(dir_data, 84));
1266 slen = sid_parse_wire(finfo, dir_data+88, &finfo->owner_sid,
1267 dir_data_length-88);
1269 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1271 slen2 = sid_parse_wire(finfo, dir_data+88+slen, &finfo->group_sid,
1272 dir_data_length-88-slen);
1274 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1278 namelen = PULL_LE_U32(dir_data, 88+slen);
1279 ret = pull_string_talloc(finfo,
1281 FLAGS2_UNICODE_STRINGS,
1286 if (ret == (size_t)-1) {
1287 /* Bad conversion. */
1288 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1291 if (finfo->name == NULL) {
1292 /* Bad conversion. */
1293 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1296 *next_offset = _next_offset;
1297 return NT_STATUS_OK;
1300 /***************************************************************
1301 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1302 ***************************************************************/
1304 static NTSTATUS parse_finfo_id_both_directory_info(const uint8_t *dir_data,
1305 uint32_t dir_data_length,
1306 struct file_info *finfo,
1307 uint32_t *next_offset)
1313 if (dir_data_length < 4) {
1314 return NT_STATUS_INFO_LENGTH_MISMATCH;
1317 *next_offset = IVAL(dir_data, 0);
1319 if (*next_offset > dir_data_length) {
1320 return NT_STATUS_INFO_LENGTH_MISMATCH;
1323 if (*next_offset != 0) {
1324 /* Ensure we only read what in this record. */
1325 dir_data_length = *next_offset;
1328 if (dir_data_length < 105) {
1329 return NT_STATUS_INFO_LENGTH_MISMATCH;
1332 finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
1333 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
1334 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
1335 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
1336 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
1337 finfo->allocated_size = IVAL2_TO_SMB_BIG_UINT(dir_data + 48, 0);
1338 finfo->attr = IVAL(dir_data + 56, 0);
1339 finfo->ino = IVAL2_TO_SMB_BIG_UINT(dir_data + 96, 0);
1340 namelen = IVAL(dir_data + 60,0);
1341 if (namelen > (dir_data_length - 104)) {
1342 return NT_STATUS_INFO_LENGTH_MISMATCH;
1344 slen = CVAL(dir_data + 68, 0);
1346 return NT_STATUS_INFO_LENGTH_MISMATCH;
1348 ret = pull_string_talloc(finfo,
1350 FLAGS2_UNICODE_STRINGS,
1355 if (ret == (size_t)-1) {
1356 /* Bad conversion. */
1357 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1360 ret = pull_string_talloc(finfo,
1362 FLAGS2_UNICODE_STRINGS,
1367 if (ret == (size_t)-1) {
1368 /* Bad conversion. */
1369 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1372 if (finfo->name == NULL) {
1373 /* Bad conversion. */
1374 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1377 return NT_STATUS_OK;
1380 /*******************************************************************
1381 Given a filename - get its directory name
1382 ********************************************************************/
1384 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
1392 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
1395 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
1406 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
1409 (*parent)[len] = '\0';
1417 struct cli_smb2_list_dir_data {
1422 struct cli_smb2_list_state {
1423 struct tevent_context *ev;
1424 struct cli_state *cli;
1430 struct cli_smb2_list_dir_data *response;
1432 unsigned int info_level;
1435 static void cli_smb2_list_opened(struct tevent_req *subreq);
1436 static void cli_smb2_list_done(struct tevent_req *subreq);
1437 static void cli_smb2_list_closed(struct tevent_req *subreq);
1439 struct tevent_req *cli_smb2_list_send(
1440 TALLOC_CTX *mem_ctx,
1441 struct tevent_context *ev,
1442 struct cli_state *cli,
1443 const char *pathname,
1444 unsigned int info_level,
1447 struct tevent_req *req = NULL, *subreq = NULL;
1448 struct cli_smb2_list_state *state = NULL;
1449 char *parent = NULL;
1451 struct smb2_create_blobs *in_cblobs = NULL;
1453 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_list_state);
1459 state->status = NT_STATUS_OK;
1460 state->info_level = info_level;
1462 ok = windows_parent_dirname(state, pathname, &parent, &state->mask);
1464 tevent_req_oom(req);
1465 return tevent_req_post(req, ev);
1468 if (smbXcli_conn_have_posix(cli->conn) && posix) {
1471 /* The mode MUST be 0 when opening an existing file/dir, and
1472 * will be ignored by the server.
1474 uint8_t linear_mode[4] = { 0 };
1475 DATA_BLOB blob = { .data=linear_mode,
1476 .length=sizeof(linear_mode) };
1478 in_cblobs = talloc_zero(mem_ctx, struct smb2_create_blobs);
1479 if (in_cblobs == NULL) {
1483 status = smb2_create_blob_add(in_cblobs, in_cblobs,
1484 SMB2_CREATE_TAG_POSIX, blob);
1485 if (!NT_STATUS_IS_OK(status)) {
1486 tevent_req_nterror(req, status);
1487 return tevent_req_post(req, ev);
1491 subreq = cli_smb2_create_fnum_send(
1492 state, /* mem_ctx */
1496 0, /* create_flags */
1497 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level */
1498 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE, /* desired_access */
1499 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
1500 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
1501 FILE_OPEN, /* create_disposition */
1502 FILE_DIRECTORY_FILE, /* create_options */
1503 in_cblobs); /* in_cblobs */
1504 TALLOC_FREE(in_cblobs);
1505 if (tevent_req_nomem(subreq, req)) {
1506 return tevent_req_post(req, ev);
1508 tevent_req_set_callback(subreq, cli_smb2_list_opened, req);
1512 static void cli_smb2_list_opened(struct tevent_req *subreq)
1514 struct tevent_req *req = tevent_req_callback_data(
1515 subreq, struct tevent_req);
1516 struct cli_smb2_list_state *state = tevent_req_data(
1517 req, struct cli_smb2_list_state);
1520 status = cli_smb2_create_fnum_recv(
1521 subreq, &state->fnum, NULL, NULL, NULL, NULL);
1522 TALLOC_FREE(subreq);
1523 if (tevent_req_nterror(req, status)) {
1528 * Make our caller get back to us via cli_smb2_list_recv(),
1529 * triggering the smb2_query_directory_send()
1531 tevent_req_defer_callback(req, state->ev);
1532 tevent_req_notify_callback(req);
1535 static void cli_smb2_list_done(struct tevent_req *subreq)
1537 struct tevent_req *req = tevent_req_callback_data(
1538 subreq, struct tevent_req);
1539 struct cli_smb2_list_state *state = tevent_req_data(
1540 req, struct cli_smb2_list_state);
1541 struct cli_smb2_list_dir_data *response = NULL;
1543 response = talloc(state, struct cli_smb2_list_dir_data);
1544 if (tevent_req_nomem(response, req)) {
1548 state->status = smb2cli_query_directory_recv(
1549 subreq, response, &response->data, &response->length);
1550 TALLOC_FREE(subreq);
1552 if (NT_STATUS_IS_OK(state->status)) {
1553 state->response = response;
1556 tevent_req_defer_callback(req, state->ev);
1557 tevent_req_notify_callback(req);
1561 TALLOC_FREE(response);
1563 subreq = cli_smb2_close_fnum_send(
1564 state, state->ev, state->cli, state->fnum);
1565 if (tevent_req_nomem(subreq, req)) {
1568 tevent_req_set_callback(subreq, cli_smb2_list_closed, req);
1571 static void cli_smb2_list_closed(struct tevent_req *subreq)
1573 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1574 tevent_req_simple_finish_ntstatus(subreq, status);
1578 * Return the next finfo directory.
1580 * This parses the blob returned from QUERY_DIRECTORY step by step. If
1581 * the blob ends, this triggers a fresh QUERY_DIRECTORY and returns
1582 * NT_STATUS_RETRY, which will then trigger the caller again when the
1583 * QUERY_DIRECTORY has returned with another buffer. This way we
1584 * guarantee that no asynchronous request is open after this call
1585 * returns an entry, so that other synchronous requests can be issued
1586 * on the same connection while the directoy listing proceeds.
1588 NTSTATUS cli_smb2_list_recv(
1589 struct tevent_req *req,
1590 TALLOC_CTX *mem_ctx,
1591 struct file_info **pfinfo)
1593 struct cli_smb2_list_state *state = tevent_req_data(
1594 req, struct cli_smb2_list_state);
1595 struct cli_smb2_list_dir_data *response = NULL;
1596 struct file_info *finfo = NULL;
1598 uint32_t next_offset = 0;
1601 in_progress = tevent_req_is_in_progress(req);
1604 if (!tevent_req_is_nterror(req, &status)) {
1605 status = NT_STATUS_NO_MORE_FILES;
1610 response = state->response;
1611 if (response == NULL) {
1612 struct tevent_req *subreq = NULL;
1613 struct cli_state *cli = state->cli;
1614 struct smb2_hnd *ph = NULL;
1615 uint32_t max_trans, max_avail_len;
1618 if (!NT_STATUS_IS_OK(state->status)) {
1619 status = state->status;
1623 status = map_fnum_to_smb2_handle(cli, state->fnum, &ph);
1624 if (!NT_STATUS_IS_OK(status)) {
1628 max_trans = smb2cli_conn_max_trans_size(cli->conn);
1629 ok = smb2cli_conn_req_possible(cli->conn, &max_avail_len);
1631 max_trans = MIN(max_trans, max_avail_len);
1634 subreq = smb2cli_query_directory_send(
1635 state, /* mem_ctx */
1637 cli->conn, /* conn */
1638 cli->timeout, /* timeout_msec */
1639 cli->smb2.session, /* session */
1640 cli->smb2.tcon, /* tcon */
1641 state->info_level, /* level */
1644 ph->fid_persistent, /* fid_persistent */
1645 ph->fid_volatile, /* fid_volatile */
1646 state->mask, /* mask */
1647 max_trans); /* outbuf_len */
1648 if (subreq == NULL) {
1649 status = NT_STATUS_NO_MEMORY;
1652 tevent_req_set_callback(subreq, cli_smb2_list_done, req);
1653 return NT_STATUS_RETRY;
1656 SMB_ASSERT(response->length > state->offset);
1658 finfo = talloc_zero(mem_ctx, struct file_info);
1659 if (finfo == NULL) {
1660 status = NT_STATUS_NO_MEMORY;
1664 if (state->info_level == SMB2_FIND_POSIX_INFORMATION) {
1665 status = parse_finfo_posix_info(
1666 response->data + state->offset,
1667 response->length - state->offset,
1671 status = parse_finfo_id_both_directory_info(
1672 response->data + state->offset,
1673 response->length - state->offset,
1677 if (!NT_STATUS_IS_OK(status)) {
1681 status = is_bad_finfo_name(state->cli, finfo);
1682 if (!NT_STATUS_IS_OK(status)) {
1687 * parse_finfo_id_both_directory_info() checks for overflow,
1688 * no need to check again here.
1690 state->offset += next_offset;
1692 if (next_offset == 0) {
1693 TALLOC_FREE(state->response);
1696 tevent_req_defer_callback(req, state->ev);
1697 tevent_req_notify_callback(req);
1700 return NT_STATUS_OK;
1704 tevent_req_received(req);
1708 /***************************************************************
1709 Wrapper that allows SMB2 to query a path info (basic level).
1711 ***************************************************************/
1713 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1715 SMB_STRUCT_STAT *sbuf,
1716 uint32_t *attributes)
1719 struct smb_create_returns cr;
1720 uint16_t fnum = 0xffff;
1721 size_t namelen = strlen(name);
1723 if (smbXcli_conn_has_async_calls(cli->conn)) {
1725 * Can't use sync call while an async call is in flight
1727 return NT_STATUS_INVALID_PARAMETER;
1730 /* SMB2 is pickier about pathnames. Ensure it doesn't
1732 if (namelen > 0 && name[namelen-1] == '\\') {
1733 char *modname = talloc_strndup(talloc_tos(), name, namelen-1);
1734 if (modname == NULL) {
1735 return NT_STATUS_NO_MEMORY;
1740 /* This is commonly used as a 'cd'. Try qpathinfo on
1741 a directory handle first. */
1743 status = cli_smb2_create_fnum(cli,
1745 0, /* create_flags */
1746 SMB2_IMPERSONATION_IMPERSONATION,
1747 FILE_READ_ATTRIBUTES, /* desired_access */
1748 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1749 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1750 FILE_OPEN, /* create_disposition */
1751 FILE_DIRECTORY_FILE, /* create_options */
1758 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1759 /* Maybe a file ? */
1760 status = cli_smb2_create_fnum(cli,
1762 0, /* create_flags */
1763 SMB2_IMPERSONATION_IMPERSONATION,
1764 FILE_READ_ATTRIBUTES, /* desired_access */
1765 0, /* file attributes */
1766 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1767 FILE_OPEN, /* create_disposition */
1768 0, /* create_options */
1776 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1777 /* Maybe a reparse point ? */
1778 status = cli_smb2_create_fnum(cli,
1780 0, /* create_flags */
1781 SMB2_IMPERSONATION_IMPERSONATION,
1782 FILE_READ_ATTRIBUTES, /* desired_access */
1783 0, /* file attributes */
1784 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1785 FILE_OPEN, /* create_disposition */
1786 FILE_OPEN_REPARSE_POINT, /* create_options */
1794 if (!NT_STATUS_IS_OK(status)) {
1798 status = cli_smb2_close_fnum(cli, fnum);
1802 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1803 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1804 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1805 sbuf->st_ex_size = cr.end_of_file;
1806 *attributes = cr.file_attributes;
1811 struct cli_smb2_query_info_fnum_state {
1815 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq);
1817 struct tevent_req *cli_smb2_query_info_fnum_send(
1818 TALLOC_CTX *mem_ctx,
1819 struct tevent_context *ev,
1820 struct cli_state *cli,
1822 uint8_t in_info_type,
1823 uint8_t in_info_class,
1824 uint32_t in_max_output_length,
1825 const DATA_BLOB *in_input_buffer,
1826 uint32_t in_additional_info,
1829 struct tevent_req *req = NULL, *subreq = NULL;
1830 struct cli_smb2_query_info_fnum_state *state = NULL;
1831 struct smb2_hnd *ph = NULL;
1834 req = tevent_req_create(
1835 mem_ctx, &state, struct cli_smb2_query_info_fnum_state);
1840 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1841 if (tevent_req_nterror(req, status)) {
1842 return tevent_req_post(req, ev);
1845 subreq = smb2cli_query_info_send(
1854 in_max_output_length,
1860 if (tevent_req_nomem(subreq, req)) {
1861 return tevent_req_post(req, ev);
1863 tevent_req_set_callback(subreq, cli_smb2_query_info_fnum_done, req);
1867 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq)
1869 struct tevent_req *req = tevent_req_callback_data(
1870 subreq, struct tevent_req);
1871 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1872 req, struct cli_smb2_query_info_fnum_state);
1876 status = smb2cli_query_info_recv(subreq, state, &outbuf);
1877 TALLOC_FREE(subreq);
1878 if (tevent_req_nterror(req, status)) {
1883 * We have to dup the memory here because outbuf.data is not
1884 * returned as a talloc object by smb2cli_query_info_recv.
1885 * It's a pointer into the received buffer.
1887 state->outbuf = data_blob_dup_talloc(state, outbuf);
1889 if ((outbuf.length != 0) &&
1890 tevent_req_nomem(state->outbuf.data, req)) {
1893 tevent_req_done(req);
1896 NTSTATUS cli_smb2_query_info_fnum_recv(
1897 struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *outbuf)
1899 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1900 req, struct cli_smb2_query_info_fnum_state);
1903 if (tevent_req_is_nterror(req, &status)) {
1906 *outbuf = (DATA_BLOB) {
1907 .data = talloc_move(mem_ctx, &state->outbuf.data),
1908 .length = state->outbuf.length,
1910 return NT_STATUS_OK;
1913 NTSTATUS cli_smb2_query_info_fnum(
1914 struct cli_state *cli,
1916 uint8_t in_info_type,
1917 uint8_t in_info_class,
1918 uint32_t in_max_output_length,
1919 const DATA_BLOB *in_input_buffer,
1920 uint32_t in_additional_info,
1922 TALLOC_CTX *mem_ctx,
1925 TALLOC_CTX *frame = talloc_stackframe();
1926 struct tevent_context *ev = NULL;
1927 struct tevent_req *req = NULL;
1928 NTSTATUS status = NT_STATUS_NO_MEMORY;
1931 if (smbXcli_conn_has_async_calls(cli->conn)) {
1933 * Can't use sync call while an async call is in flight
1935 status = NT_STATUS_INVALID_PARAMETER;
1938 ev = samba_tevent_context_init(frame);
1942 req = cli_smb2_query_info_fnum_send(
1949 in_max_output_length,
1956 ok = tevent_req_poll_ntstatus(req, ev, &status);
1960 status = cli_smb2_query_info_fnum_recv(req, mem_ctx, outbuf);
1966 /***************************************************************
1967 Helper function for pathname operations.
1968 ***************************************************************/
1970 struct get_fnum_from_path_state {
1971 struct tevent_context *ev;
1972 struct cli_state *cli;
1974 uint32_t desired_access;
1978 static void get_fnum_from_path_opened_file(struct tevent_req *subreq);
1979 static void get_fnum_from_path_opened_reparse(struct tevent_req *subreq);
1980 static void get_fnum_from_path_opened_dir(struct tevent_req *subreq);
1982 static struct tevent_req *get_fnum_from_path_send(
1983 TALLOC_CTX *mem_ctx,
1984 struct tevent_context *ev,
1985 struct cli_state *cli,
1987 uint32_t desired_access)
1989 struct tevent_req *req = NULL, *subreq = NULL;
1990 struct get_fnum_from_path_state *state = NULL;
1991 size_t namelen = strlen(name);
1993 req = tevent_req_create(
1994 mem_ctx, &state, struct get_fnum_from_path_state);
2001 state->desired_access = desired_access;
2004 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
2007 if (namelen > 0 && name[namelen-1] == '\\') {
2008 state->name = talloc_strndup(state, name, namelen-1);
2009 if (tevent_req_nomem(state->name, req)) {
2010 return tevent_req_post(req, ev);
2014 subreq = cli_smb2_create_fnum_send(
2015 state, /* mem_ctx, */
2018 state->name, /* fname */
2019 0, /* create_flags */
2020 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level */
2021 desired_access, /* desired_access */
2022 0, /* file_attributes */
2025 FILE_SHARE_DELETE, /* share_access */
2026 FILE_OPEN, /* create_disposition */
2027 0, /* create_options */
2028 NULL); /* in_cblobs */
2029 if (tevent_req_nomem(subreq, req)) {
2030 return tevent_req_post(req, ev);
2032 tevent_req_set_callback(subreq, get_fnum_from_path_opened_file, req);
2036 static void get_fnum_from_path_opened_file(struct tevent_req *subreq)
2038 struct tevent_req *req = tevent_req_callback_data(
2039 subreq, struct tevent_req);
2040 struct get_fnum_from_path_state *state = tevent_req_data(
2041 req, struct get_fnum_from_path_state);
2044 status = cli_smb2_create_fnum_recv(
2045 subreq, &state->fnum, NULL, NULL, NULL, NULL);
2046 TALLOC_FREE(subreq);
2048 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
2050 * Naive option to match our SMB1 code. Assume the
2051 * symlink path that tripped us up was the last
2052 * component and try again. Eventually we will have to
2053 * deal with the returned path unprocessed component. JRA.
2055 subreq = cli_smb2_create_fnum_send(
2056 state, /* mem_ctx, */
2058 state->cli, /* cli */
2059 state->name, /* fname */
2060 0, /* create_flags */
2061 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation */
2062 state->desired_access, /* desired_access */
2063 0, /* file_attributes */
2066 FILE_SHARE_DELETE, /* share_access */
2067 FILE_OPEN, /* create_disposition */
2068 FILE_OPEN_REPARSE_POINT, /* create_options */
2069 NULL); /* in_cblobs */
2070 if (tevent_req_nomem(subreq, req)) {
2073 tevent_req_set_callback(
2074 subreq, get_fnum_from_path_opened_reparse, req);
2078 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
2079 subreq = cli_smb2_create_fnum_send(
2080 state, /* mem_ctx, */
2082 state->cli, /* cli */
2083 state->name, /* fname */
2084 0, /* create_flags */
2085 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation */
2086 state->desired_access, /* desired_access */
2087 0, /* file_attributes */
2090 FILE_SHARE_DELETE, /* share_access */
2091 FILE_OPEN, /* create_disposition */
2092 FILE_DIRECTORY_FILE, /* create_options */
2093 NULL); /* in_cblobs */
2094 if (tevent_req_nomem(subreq, req)) {
2097 tevent_req_set_callback(
2098 subreq, get_fnum_from_path_opened_dir, req);
2102 if (tevent_req_nterror(req, status)) {
2105 tevent_req_done(req);
2108 static void get_fnum_from_path_opened_reparse(struct tevent_req *subreq)
2110 struct tevent_req *req = tevent_req_callback_data(
2111 subreq, struct tevent_req);
2112 struct get_fnum_from_path_state *state = tevent_req_data(
2113 req, struct get_fnum_from_path_state);
2114 NTSTATUS status = cli_smb2_create_fnum_recv(
2115 subreq, &state->fnum, NULL, NULL, NULL, NULL);
2116 tevent_req_simple_finish_ntstatus(subreq, status);
2119 static void get_fnum_from_path_opened_dir(struct tevent_req *subreq)
2121 /* Abstraction violation, but these two are just the same... */
2122 get_fnum_from_path_opened_reparse(subreq);
2125 static NTSTATUS get_fnum_from_path_recv(
2126 struct tevent_req *req, uint16_t *pfnum)
2128 struct get_fnum_from_path_state *state = tevent_req_data(
2129 req, struct get_fnum_from_path_state);
2130 NTSTATUS status = NT_STATUS_OK;
2132 if (!tevent_req_is_nterror(req, &status)) {
2133 *pfnum = state->fnum;
2135 tevent_req_received(req);
2139 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
2141 uint32_t desired_access,
2144 TALLOC_CTX *frame = talloc_stackframe();
2145 struct tevent_context *ev = NULL;
2146 struct tevent_req *req = NULL;
2147 NTSTATUS status = NT_STATUS_NO_MEMORY;
2149 if (smbXcli_conn_has_async_calls(cli->conn)) {
2150 status = NT_STATUS_INVALID_PARAMETER;
2153 ev = samba_tevent_context_init(frame);
2157 req = get_fnum_from_path_send(frame, ev, cli, name, desired_access);
2161 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2164 status = get_fnum_from_path_recv(req, pfnum);
2170 /***************************************************************
2171 Wrapper that allows SMB2 to query a path info (ALTNAME level).
2173 ***************************************************************/
2175 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
2180 DATA_BLOB outbuf = data_blob_null;
2181 uint16_t fnum = 0xffff;
2182 uint32_t altnamelen = 0;
2183 TALLOC_CTX *frame = talloc_stackframe();
2185 if (smbXcli_conn_has_async_calls(cli->conn)) {
2187 * Can't use sync call while an async call is in flight
2189 status = NT_STATUS_INVALID_PARAMETER;
2193 status = get_fnum_from_path(cli,
2195 FILE_READ_ATTRIBUTES,
2198 if (!NT_STATUS_IS_OK(status)) {
2202 status = cli_smb2_query_info_fnum(
2205 1, /* in_info_type */
2206 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
2207 0xFFFF, /* in_max_output_length */
2208 NULL, /* in_input_buffer */
2209 0, /* in_additional_info */
2214 if (!NT_STATUS_IS_OK(status)) {
2218 /* Parse the reply. */
2219 if (outbuf.length < 4) {
2220 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2224 altnamelen = IVAL(outbuf.data, 0);
2225 if (altnamelen > outbuf.length - 4) {
2226 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2230 if (altnamelen > 0) {
2232 char *short_name = NULL;
2233 ret = pull_string_talloc(frame,
2235 FLAGS2_UNICODE_STRINGS,
2240 if (ret == (size_t)-1) {
2241 /* Bad conversion. */
2242 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2246 fstrcpy(alt_name, short_name);
2251 status = NT_STATUS_OK;
2255 if (fnum != 0xffff) {
2256 cli_smb2_close_fnum(cli, fnum);
2259 cli->raw_status = status;
2265 /***************************************************************
2266 Wrapper that allows SMB2 to get pathname attributes.
2268 ***************************************************************/
2270 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
2277 uint16_t fnum = 0xffff;
2278 struct timespec write_time_ts;
2279 TALLOC_CTX *frame = talloc_stackframe();
2281 if (smbXcli_conn_has_async_calls(cli->conn)) {
2283 * Can't use sync call while an async call is in flight
2285 status = NT_STATUS_INVALID_PARAMETER;
2289 status = get_fnum_from_path(cli,
2291 FILE_READ_ATTRIBUTES,
2294 if (!NT_STATUS_IS_OK(status)) {
2298 status = cli_qfileinfo_basic(
2303 NULL, /* create_time */
2304 NULL, /* access_time */
2306 NULL, /* change_time */
2308 if (!NT_STATUS_IS_OK(status)) {
2311 if (write_time != NULL) {
2312 *write_time = write_time_ts.tv_sec;
2317 if (fnum != 0xffff) {
2318 cli_smb2_close_fnum(cli, fnum);
2321 cli->raw_status = status;
2327 /***************************************************************
2328 Wrapper that allows SMB2 to query a pathname info (basic level).
2329 Implement on top of cli_qfileinfo_basic().
2331 ***************************************************************/
2333 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
2335 struct timespec *create_time,
2336 struct timespec *access_time,
2337 struct timespec *write_time,
2338 struct timespec *change_time,
2344 uint16_t fnum = 0xffff;
2345 TALLOC_CTX *frame = talloc_stackframe();
2347 if (smbXcli_conn_has_async_calls(cli->conn)) {
2349 * Can't use sync call while an async call is in flight
2351 status = NT_STATUS_INVALID_PARAMETER;
2355 status = get_fnum_from_path(cli,
2357 FILE_READ_ATTRIBUTES,
2360 if (!NT_STATUS_IS_OK(status)) {
2364 status = cli_qfileinfo_basic(
2377 if (fnum != 0xffff) {
2378 cli_smb2_close_fnum(cli, fnum);
2381 cli->raw_status = status;
2387 /***************************************************************
2388 Wrapper that allows SMB2 to query pathname streams.
2390 ***************************************************************/
2392 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
2394 TALLOC_CTX *mem_ctx,
2395 unsigned int *pnum_streams,
2396 struct stream_struct **pstreams)
2399 uint16_t fnum = 0xffff;
2400 DATA_BLOB outbuf = data_blob_null;
2401 TALLOC_CTX *frame = talloc_stackframe();
2403 if (smbXcli_conn_has_async_calls(cli->conn)) {
2405 * Can't use sync call while an async call is in flight
2407 status = NT_STATUS_INVALID_PARAMETER;
2411 status = get_fnum_from_path(cli,
2413 FILE_READ_ATTRIBUTES,
2416 if (!NT_STATUS_IS_OK(status)) {
2420 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2421 level 22 (SMB2_FILE_STREAM_INFORMATION). */
2423 status = cli_smb2_query_info_fnum(
2426 1, /* in_info_type */
2427 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
2428 0xFFFF, /* in_max_output_length */
2429 NULL, /* in_input_buffer */
2430 0, /* in_additional_info */
2435 if (!NT_STATUS_IS_OK(status)) {
2439 /* Parse the reply. */
2440 if (!parse_streams_blob(mem_ctx,
2445 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2451 if (fnum != 0xffff) {
2452 cli_smb2_close_fnum(cli, fnum);
2455 cli->raw_status = status;
2461 /***************************************************************
2462 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2465 ***************************************************************/
2467 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
2469 uint8_t in_info_type,
2470 uint8_t in_file_info_class,
2471 const DATA_BLOB *p_in_data)
2474 uint16_t fnum = 0xffff;
2475 TALLOC_CTX *frame = talloc_stackframe();
2477 if (smbXcli_conn_has_async_calls(cli->conn)) {
2479 * Can't use sync call while an async call is in flight
2481 status = NT_STATUS_INVALID_PARAMETER;
2485 status = get_fnum_from_path(cli,
2487 FILE_WRITE_ATTRIBUTES,
2490 if (!NT_STATUS_IS_OK(status)) {
2494 status = cli_smb2_set_info_fnum(
2499 p_in_data, /* in_input_buffer */
2500 0); /* in_additional_info */
2503 if (fnum != 0xffff) {
2504 cli_smb2_close_fnum(cli, fnum);
2507 cli->raw_status = status;
2514 /***************************************************************
2515 Wrapper that allows SMB2 to set pathname attributes.
2517 ***************************************************************/
2519 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
2524 uint8_t inbuf_store[40];
2525 DATA_BLOB inbuf = data_blob_null;
2527 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2528 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2530 inbuf.data = inbuf_store;
2531 inbuf.length = sizeof(inbuf_store);
2532 data_blob_clear(&inbuf);
2535 * SMB1 uses attr == 0 to clear all attributes
2536 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2537 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2538 * request attribute change.
2540 * SMB2 uses exactly the reverse. Unfortunately as the
2541 * cli_setatr() ABI is exposed inside libsmbclient,
2542 * we must make the SMB2 cli_smb2_setatr() call
2543 * export the same ABI as the SMB1 cli_setatr()
2544 * which calls it. This means reversing the sense
2545 * of the requested attr argument if it's zero
2546 * or FILE_ATTRIBUTE_NORMAL.
2548 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2552 attr = FILE_ATTRIBUTE_NORMAL;
2553 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
2557 SIVAL(inbuf.data, 32, attr);
2559 put_long_date((char *)inbuf.data + 16,mtime);
2561 /* Set all the other times to -1. */
2562 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2563 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
2564 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
2566 return cli_smb2_setpathinfo(cli,
2568 1, /* in_info_type */
2569 /* in_file_info_class */
2570 SMB_FILE_BASIC_INFORMATION - 1000,
2575 /***************************************************************
2576 Wrapper that allows SMB2 to set file handle times.
2578 ***************************************************************/
2580 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
2586 uint8_t inbuf_store[40];
2587 DATA_BLOB inbuf = data_blob_null;
2589 if (smbXcli_conn_has_async_calls(cli->conn)) {
2591 * Can't use sync call while an async call is in flight
2593 return NT_STATUS_INVALID_PARAMETER;
2596 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2597 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2599 inbuf.data = inbuf_store;
2600 inbuf.length = sizeof(inbuf_store);
2601 data_blob_clear(&inbuf);
2603 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2604 if (change_time != 0) {
2605 put_long_date((char *)inbuf.data + 24, change_time);
2607 if (access_time != 0) {
2608 put_long_date((char *)inbuf.data + 8, access_time);
2610 if (write_time != 0) {
2611 put_long_date((char *)inbuf.data + 16, write_time);
2614 cli->raw_status = cli_smb2_set_info_fnum(
2617 1, /* in_info_type */
2618 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
2619 &inbuf, /* in_input_buffer */
2620 0); /* in_additional_info */
2622 return cli->raw_status;
2625 /***************************************************************
2626 Wrapper that allows SMB2 to query disk attributes (size).
2628 ***************************************************************/
2630 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2631 uint64_t *bsize, uint64_t *total, uint64_t *avail)
2634 uint16_t fnum = 0xffff;
2635 DATA_BLOB outbuf = data_blob_null;
2636 uint32_t sectors_per_unit = 0;
2637 uint32_t bytes_per_sector = 0;
2638 uint64_t total_size = 0;
2639 uint64_t size_free = 0;
2640 TALLOC_CTX *frame = talloc_stackframe();
2642 if (smbXcli_conn_has_async_calls(cli->conn)) {
2644 * Can't use sync call while an async call is in flight
2646 status = NT_STATUS_INVALID_PARAMETER;
2650 /* First open the top level directory. */
2651 status = cli_smb2_create_fnum(cli,
2653 0, /* create_flags */
2654 SMB2_IMPERSONATION_IMPERSONATION,
2655 FILE_READ_ATTRIBUTES, /* desired_access */
2656 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2657 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2658 FILE_OPEN, /* create_disposition */
2659 FILE_DIRECTORY_FILE, /* create_options */
2666 if (!NT_STATUS_IS_OK(status)) {
2670 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2671 level 3 (SMB_FS_SIZE_INFORMATION). */
2673 status = cli_smb2_query_info_fnum(
2676 2, /* in_info_type */
2677 3, /* in_file_info_class */
2678 0xFFFF, /* in_max_output_length */
2679 NULL, /* in_input_buffer */
2680 0, /* in_additional_info */
2684 if (!NT_STATUS_IS_OK(status)) {
2688 /* Parse the reply. */
2689 if (outbuf.length != 24) {
2690 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2694 total_size = BVAL(outbuf.data, 0);
2695 size_free = BVAL(outbuf.data, 8);
2696 sectors_per_unit = IVAL(outbuf.data, 16);
2697 bytes_per_sector = IVAL(outbuf.data, 20);
2700 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2703 *total = total_size;
2709 status = NT_STATUS_OK;
2713 if (fnum != 0xffff) {
2714 cli_smb2_close_fnum(cli, fnum);
2717 cli->raw_status = status;
2723 /***************************************************************
2724 Wrapper that allows SMB2 to query file system sizes.
2726 ***************************************************************/
2728 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2729 uint64_t *total_allocation_units,
2730 uint64_t *caller_allocation_units,
2731 uint64_t *actual_allocation_units,
2732 uint64_t *sectors_per_allocation_unit,
2733 uint64_t *bytes_per_sector)
2736 uint16_t fnum = 0xffff;
2737 DATA_BLOB outbuf = data_blob_null;
2738 TALLOC_CTX *frame = talloc_stackframe();
2740 if (smbXcli_conn_has_async_calls(cli->conn)) {
2742 * Can't use sync call while an async call is in flight
2744 status = NT_STATUS_INVALID_PARAMETER;
2748 /* First open the top level directory. */
2750 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2751 SMB2_IMPERSONATION_IMPERSONATION,
2752 FILE_READ_ATTRIBUTES, /* desired_access */
2753 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2754 FILE_SHARE_READ | FILE_SHARE_WRITE |
2755 FILE_SHARE_DELETE, /* share_access */
2756 FILE_OPEN, /* create_disposition */
2757 FILE_DIRECTORY_FILE, /* create_options */
2764 if (!NT_STATUS_IS_OK(status)) {
2768 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2769 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2771 status = cli_smb2_query_info_fnum(
2774 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2775 SMB_FS_FULL_SIZE_INFORMATION - 1000, /* in_file_info_class */
2776 0xFFFF, /* in_max_output_length */
2777 NULL, /* in_input_buffer */
2778 0, /* in_additional_info */
2782 if (!NT_STATUS_IS_OK(status)) {
2786 if (outbuf.length < 32) {
2787 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2791 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2792 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2793 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2794 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2795 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2799 if (fnum != 0xffff) {
2800 cli_smb2_close_fnum(cli, fnum);
2803 cli->raw_status = status;
2809 /***************************************************************
2810 Wrapper that allows SMB2 to query file system attributes.
2812 ***************************************************************/
2814 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2817 uint16_t fnum = 0xffff;
2818 DATA_BLOB outbuf = data_blob_null;
2819 TALLOC_CTX *frame = talloc_stackframe();
2821 if (smbXcli_conn_has_async_calls(cli->conn)) {
2823 * Can't use sync call while an async call is in flight
2825 status = NT_STATUS_INVALID_PARAMETER;
2829 /* First open the top level directory. */
2831 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2832 SMB2_IMPERSONATION_IMPERSONATION,
2833 FILE_READ_ATTRIBUTES, /* desired_access */
2834 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2835 FILE_SHARE_READ | FILE_SHARE_WRITE |
2836 FILE_SHARE_DELETE, /* share_access */
2837 FILE_OPEN, /* create_disposition */
2838 FILE_DIRECTORY_FILE, /* create_options */
2845 if (!NT_STATUS_IS_OK(status)) {
2849 status = cli_smb2_query_info_fnum(
2852 2, /* in_info_type */
2853 5, /* in_file_info_class */
2854 0xFFFF, /* in_max_output_length */
2855 NULL, /* in_input_buffer */
2856 0, /* in_additional_info */
2860 if (!NT_STATUS_IS_OK(status)) {
2864 if (outbuf.length < 12) {
2865 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2869 *fs_attr = IVAL(outbuf.data, 0);
2873 if (fnum != 0xffff) {
2874 cli_smb2_close_fnum(cli, fnum);
2877 cli->raw_status = status;
2883 /***************************************************************
2884 Wrapper that allows SMB2 to query file system volume info.
2886 ***************************************************************/
2888 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2889 TALLOC_CTX *mem_ctx,
2890 char **_volume_name,
2891 uint32_t *pserial_number,
2895 uint16_t fnum = 0xffff;
2896 DATA_BLOB outbuf = data_blob_null;
2898 char *volume_name = NULL;
2899 TALLOC_CTX *frame = talloc_stackframe();
2901 if (smbXcli_conn_has_async_calls(cli->conn)) {
2903 * Can't use sync call while an async call is in flight
2905 status = NT_STATUS_INVALID_PARAMETER;
2909 /* First open the top level directory. */
2911 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2912 SMB2_IMPERSONATION_IMPERSONATION,
2913 FILE_READ_ATTRIBUTES, /* desired_access */
2914 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2915 FILE_SHARE_READ | FILE_SHARE_WRITE |
2916 FILE_SHARE_DELETE, /* share_access */
2917 FILE_OPEN, /* create_disposition */
2918 FILE_DIRECTORY_FILE, /* create_options */
2925 if (!NT_STATUS_IS_OK(status)) {
2929 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2930 level 1 (SMB_FS_VOLUME_INFORMATION). */
2932 status = cli_smb2_query_info_fnum(
2935 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2936 /* in_file_info_class */
2937 SMB_FS_VOLUME_INFORMATION - 1000,
2938 0xFFFF, /* in_max_output_length */
2939 NULL, /* in_input_buffer */
2940 0, /* in_additional_info */
2944 if (!NT_STATUS_IS_OK(status)) {
2948 if (outbuf.length < 24) {
2949 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2955 ts = interpret_long_date((char *)outbuf.data);
2958 if (pserial_number) {
2959 *pserial_number = IVAL(outbuf.data,8);
2961 nlen = IVAL(outbuf.data,12);
2962 if (nlen + 18 < 18) {
2964 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2968 * The next check is safe as we know outbuf.length >= 24
2971 if (nlen > (outbuf.length - 18)) {
2972 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2976 pull_string_talloc(mem_ctx,
2977 (const char *)outbuf.data,
2983 if (volume_name == NULL) {
2984 status = map_nt_error_from_unix(errno);
2988 *_volume_name = volume_name;
2992 if (fnum != 0xffff) {
2993 cli_smb2_close_fnum(cli, fnum);
2996 cli->raw_status = status;
3002 struct cli_smb2_mxac_state {
3003 struct tevent_context *ev;
3004 struct cli_state *cli;
3006 struct smb2_create_blobs in_cblobs;
3012 static void cli_smb2_mxac_opened(struct tevent_req *subreq);
3013 static void cli_smb2_mxac_closed(struct tevent_req *subreq);
3015 struct tevent_req *cli_smb2_query_mxac_send(TALLOC_CTX *mem_ctx,
3016 struct tevent_context *ev,
3017 struct cli_state *cli,
3020 struct tevent_req *req = NULL, *subreq = NULL;
3021 struct cli_smb2_mxac_state *state = NULL;
3024 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_mxac_state);
3028 *state = (struct cli_smb2_mxac_state) {
3034 status = smb2_create_blob_add(state,
3036 SMB2_CREATE_TAG_MXAC,
3037 data_blob(NULL, 0));
3038 if (tevent_req_nterror(req, status)) {
3039 return tevent_req_post(req, ev);
3042 subreq = cli_smb2_create_fnum_send(
3047 0, /* create_flags */
3048 SMB2_IMPERSONATION_IMPERSONATION,
3049 FILE_READ_ATTRIBUTES,
3050 0, /* file attributes */
3051 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
3053 0, /* create_options */
3055 if (tevent_req_nomem(subreq, req)) {
3056 return tevent_req_post(req, ev);
3058 tevent_req_set_callback(subreq, cli_smb2_mxac_opened, req);
3062 static void cli_smb2_mxac_opened(struct tevent_req *subreq)
3064 struct tevent_req *req = tevent_req_callback_data(
3065 subreq, struct tevent_req);
3066 struct cli_smb2_mxac_state *state = tevent_req_data(
3067 req, struct cli_smb2_mxac_state);
3068 struct smb2_create_blobs out_cblobs = {0};
3069 struct smb2_create_blob *mxac_blob = NULL;
3072 status = cli_smb2_create_fnum_recv(
3073 subreq, &state->fnum, NULL, state, &out_cblobs, NULL);
3074 TALLOC_FREE(subreq);
3076 if (tevent_req_nterror(req, status)) {
3080 mxac_blob = smb2_create_blob_find(&out_cblobs, SMB2_CREATE_TAG_MXAC);
3081 if (mxac_blob == NULL) {
3082 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3085 if (mxac_blob->data.length != 8) {
3086 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3090 state->status = NT_STATUS(IVAL(mxac_blob->data.data, 0));
3091 state->mxac = IVAL(mxac_blob->data.data, 4);
3094 subreq = cli_smb2_close_fnum_send(
3095 state, state->ev, state->cli, state->fnum);
3096 if (tevent_req_nomem(subreq, req)) {
3099 tevent_req_set_callback(subreq, cli_smb2_mxac_closed, req);
3104 static void cli_smb2_mxac_closed(struct tevent_req *subreq)
3106 struct tevent_req *req = tevent_req_callback_data(
3107 subreq, struct tevent_req);
3110 status = cli_smb2_close_fnum_recv(subreq);
3111 if (tevent_req_nterror(req, status)) {
3115 tevent_req_done(req);
3118 NTSTATUS cli_smb2_query_mxac_recv(struct tevent_req *req, uint32_t *mxac)
3120 struct cli_smb2_mxac_state *state = tevent_req_data(
3121 req, struct cli_smb2_mxac_state);
3124 if (tevent_req_is_nterror(req, &status)) {
3128 if (!NT_STATUS_IS_OK(state->status)) {
3129 return state->status;
3132 *mxac = state->mxac;
3133 return NT_STATUS_OK;
3136 NTSTATUS cli_smb2_query_mxac(struct cli_state *cli,
3140 TALLOC_CTX *frame = talloc_stackframe();
3141 struct tevent_context *ev = NULL;
3142 struct tevent_req *req = NULL;
3143 NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
3146 if (smbXcli_conn_has_async_calls(cli->conn)) {
3148 * Can't use sync call while an async call is in flight
3150 status = NT_STATUS_INVALID_PARAMETER;
3154 ev = samba_tevent_context_init(frame);
3158 req = cli_smb2_query_mxac_send(frame, ev, cli, fname);
3162 ok = tevent_req_poll_ntstatus(req, ev, &status);
3166 status = cli_smb2_query_mxac_recv(req, _mxac);
3169 cli->raw_status = status;
3174 struct cli_smb2_rename_fnum_state {
3178 static void cli_smb2_rename_fnum_done(struct tevent_req *subreq);
3180 static struct tevent_req *cli_smb2_rename_fnum_send(
3181 TALLOC_CTX *mem_ctx,
3182 struct tevent_context *ev,
3183 struct cli_state *cli,
3185 const char *fname_dst,
3188 struct tevent_req *req = NULL, *subreq = NULL;
3189 struct cli_smb2_rename_fnum_state *state = NULL;
3190 size_t namelen = strlen(fname_dst);
3191 smb_ucs2_t *converted_str = NULL;
3192 size_t converted_size_bytes = 0;
3196 req = tevent_req_create(
3197 mem_ctx, &state, struct cli_smb2_rename_fnum_state);
3203 * SMB2 is pickier about pathnames. Ensure it doesn't start in
3206 if (*fname_dst == '\\') {
3211 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
3214 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
3215 fname_dst = talloc_strndup(state, fname_dst, namelen-1);
3216 if (tevent_req_nomem(fname_dst, req)) {
3217 return tevent_req_post(req, ev);
3221 ok = push_ucs2_talloc(
3222 state, &converted_str, fname_dst, &converted_size_bytes);
3224 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3225 return tevent_req_post(req, ev);
3229 * W2K8 insists the dest name is not null terminated. Remove
3230 * the last 2 zero bytes and reduce the name length.
3232 if (converted_size_bytes < 2) {
3233 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3234 return tevent_req_post(req, ev);
3236 converted_size_bytes -= 2;
3238 inbuf_size = 20 + converted_size_bytes;
3239 if (inbuf_size < 20) {
3240 /* Integer wrap check. */
3241 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3242 return tevent_req_post(req, ev);
3246 * The Windows 10 SMB2 server has a minimum length
3247 * for a SMB2_FILE_RENAME_INFORMATION buffer of
3248 * 24 bytes. It returns NT_STATUS_INFO_LENGTH_MISMATCH
3249 * if the length is less. This isn't an alignment
3250 * issue as Windows client happily 2-byte align
3251 * for larget target name sizes. Also the Windows 10
3252 * SMB1 server doesn't have this restriction.
3254 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14403
3256 inbuf_size = MAX(inbuf_size, 24);
3258 state->inbuf = data_blob_talloc_zero(state, inbuf_size);
3259 if (tevent_req_nomem(state->inbuf.data, req)) {
3260 return tevent_req_post(req, ev);
3264 SCVAL(state->inbuf.data, 0, 1);
3267 SIVAL(state->inbuf.data, 16, converted_size_bytes);
3268 memcpy(state->inbuf.data + 20, converted_str, converted_size_bytes);
3270 TALLOC_FREE(converted_str);
3272 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3273 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3275 subreq = cli_smb2_set_info_fnum_send(
3276 state, /* mem_ctx */
3280 1, /* in_info_type */
3281 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
3282 &state->inbuf, /* in_input_buffer */
3283 0); /* in_additional_info */
3284 if (tevent_req_nomem(subreq, req)) {
3285 return tevent_req_post(req, ev);
3287 tevent_req_set_callback(subreq, cli_smb2_rename_fnum_done, req);
3291 static void cli_smb2_rename_fnum_done(struct tevent_req *subreq)
3293 NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
3294 tevent_req_simple_finish_ntstatus(subreq, status);
3297 static NTSTATUS cli_smb2_rename_fnum_recv(struct tevent_req *req)
3299 return tevent_req_simple_recv_ntstatus(req);
3302 /***************************************************************
3303 Wrapper that allows SMB2 to rename a file.
3304 ***************************************************************/
3306 struct cli_smb2_rename_state {
3307 struct tevent_context *ev;
3308 struct cli_state *cli;
3309 const char *fname_dst;
3313 NTSTATUS rename_status;
3316 static void cli_smb2_rename_opened(struct tevent_req *subreq);
3317 static void cli_smb2_rename_renamed(struct tevent_req *subreq);
3318 static void cli_smb2_rename_closed(struct tevent_req *subreq);
3320 struct tevent_req *cli_smb2_rename_send(
3321 TALLOC_CTX *mem_ctx,
3322 struct tevent_context *ev,
3323 struct cli_state *cli,
3324 const char *fname_src,
3325 const char *fname_dst,
3328 struct tevent_req *req = NULL, *subreq = NULL;
3329 struct cli_smb2_rename_state *state = NULL;
3332 req = tevent_req_create(
3333 mem_ctx, &state, struct cli_smb2_rename_state);
3339 * Strip a MSDFS path from fname_dst if we were given one.
3341 status = cli_dfs_target_check(state,
3345 if (tevent_req_nterror(req, status)) {
3346 return tevent_req_post(req, ev);
3351 state->fname_dst = fname_dst;
3352 state->replace = replace;
3354 subreq = get_fnum_from_path_send(
3355 state, ev, cli, fname_src, DELETE_ACCESS);
3356 if (tevent_req_nomem(subreq, req)) {
3357 return tevent_req_post(req, ev);
3359 tevent_req_set_callback(subreq, cli_smb2_rename_opened, req);
3363 static void cli_smb2_rename_opened(struct tevent_req *subreq)
3365 struct tevent_req *req = tevent_req_callback_data(
3366 subreq, struct tevent_req);
3367 struct cli_smb2_rename_state *state = tevent_req_data(
3368 req, struct cli_smb2_rename_state);
3371 status = get_fnum_from_path_recv(subreq, &state->fnum);
3372 TALLOC_FREE(subreq);
3373 if (tevent_req_nterror(req, status)) {
3377 subreq = cli_smb2_rename_fnum_send(
3384 if (tevent_req_nomem(subreq, req)) {
3387 tevent_req_set_callback(subreq, cli_smb2_rename_renamed, req);
3390 static void cli_smb2_rename_renamed(struct tevent_req *subreq)
3392 struct tevent_req *req = tevent_req_callback_data(
3393 subreq, struct tevent_req);
3394 struct cli_smb2_rename_state *state = tevent_req_data(
3395 req, struct cli_smb2_rename_state);
3397 state->rename_status = cli_smb2_rename_fnum_recv(subreq);
3398 TALLOC_FREE(subreq);
3400 subreq = cli_smb2_close_fnum_send(
3401 state, state->ev, state->cli, state->fnum);
3402 if (tevent_req_nomem(subreq, req)) {
3405 tevent_req_set_callback(subreq, cli_smb2_rename_closed, req);
3408 static void cli_smb2_rename_closed(struct tevent_req *subreq)
3410 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
3411 tevent_req_simple_finish_ntstatus(subreq, status);
3414 NTSTATUS cli_smb2_rename_recv(struct tevent_req *req)
3416 struct cli_smb2_rename_state *state = tevent_req_data(
3417 req, struct cli_smb2_rename_state);
3418 NTSTATUS status = NT_STATUS_OK;
3420 if (!tevent_req_is_nterror(req, &status)) {
3421 status = state->rename_status;
3423 tevent_req_received(req);
3427 /***************************************************************
3428 Wrapper that allows SMB2 to set an EA on a fnum.
3430 ***************************************************************/
3432 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
3434 const char *ea_name,
3439 DATA_BLOB inbuf = data_blob_null;
3441 char *ea_name_ascii = NULL;
3443 TALLOC_CTX *frame = talloc_stackframe();
3445 if (smbXcli_conn_has_async_calls(cli->conn)) {
3447 * Can't use sync call while an async call is in flight
3449 status = NT_STATUS_INVALID_PARAMETER;
3453 /* Marshall the SMB2 EA data. */
3454 if (ea_len > 0xFFFF) {
3455 status = NT_STATUS_INVALID_PARAMETER;
3459 if (!push_ascii_talloc(frame,
3463 status = NT_STATUS_INVALID_PARAMETER;
3467 if (namelen < 2 || namelen > 0xFF) {
3468 status = NT_STATUS_INVALID_PARAMETER;
3472 bloblen = 8 + ea_len + namelen;
3473 /* Round up to a 4 byte boundary. */
3474 bloblen = ((bloblen + 3)&~3);
3476 inbuf = data_blob_talloc_zero(frame, bloblen);
3477 if (inbuf.data == NULL) {
3478 status = NT_STATUS_NO_MEMORY;
3481 /* namelen doesn't include the NULL byte. */
3482 SCVAL(inbuf.data, 5, namelen - 1);
3483 SSVAL(inbuf.data, 6, ea_len);
3484 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
3485 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
3487 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3488 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3490 status = cli_smb2_set_info_fnum(
3493 1, /* in_info_type */
3494 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3495 &inbuf, /* in_input_buffer */
3496 0); /* in_additional_info */
3500 cli->raw_status = status;
3506 /***************************************************************
3507 Wrapper that allows SMB2 to set an EA on a pathname.
3509 ***************************************************************/
3511 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
3513 const char *ea_name,
3518 uint16_t fnum = 0xffff;
3520 if (smbXcli_conn_has_async_calls(cli->conn)) {
3522 * Can't use sync call while an async call is in flight
3524 status = NT_STATUS_INVALID_PARAMETER;
3528 status = get_fnum_from_path(cli,
3533 if (!NT_STATUS_IS_OK(status)) {
3537 status = cli_set_ea_fnum(cli,
3542 if (!NT_STATUS_IS_OK(status)) {
3548 if (fnum != 0xffff) {
3549 cli_smb2_close_fnum(cli, fnum);
3552 cli->raw_status = status;
3557 /***************************************************************
3558 Wrapper that allows SMB2 to get an EA list on a pathname.
3560 ***************************************************************/
3562 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
3566 struct ea_struct **pea_array)
3569 uint16_t fnum = 0xffff;
3570 DATA_BLOB outbuf = data_blob_null;
3571 struct ea_list *ea_list = NULL;
3572 struct ea_list *eal = NULL;
3573 size_t ea_count = 0;
3574 TALLOC_CTX *frame = talloc_stackframe();
3579 if (smbXcli_conn_has_async_calls(cli->conn)) {
3581 * Can't use sync call while an async call is in flight
3583 status = NT_STATUS_INVALID_PARAMETER;
3587 status = get_fnum_from_path(cli,
3592 if (!NT_STATUS_IS_OK(status)) {
3596 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3597 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3599 status = cli_smb2_query_info_fnum(
3602 1, /* in_info_type */
3603 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3604 0xFFFF, /* in_max_output_length */
3605 NULL, /* in_input_buffer */
3606 0, /* in_additional_info */
3611 if (!NT_STATUS_IS_OK(status)) {
3615 /* Parse the reply. */
3616 ea_list = read_nttrans_ea_list(ctx,
3617 (const char *)outbuf.data,
3619 if (ea_list == NULL) {
3620 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3624 /* Convert to an array. */
3625 for (eal = ea_list; eal; eal = eal->next) {
3630 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
3631 if (*pea_array == NULL) {
3632 status = NT_STATUS_NO_MEMORY;
3636 for (eal = ea_list; eal; eal = eal->next) {
3637 (*pea_array)[ea_count++] = eal->ea;
3639 *pnum_eas = ea_count;
3644 if (fnum != 0xffff) {
3645 cli_smb2_close_fnum(cli, fnum);
3648 cli->raw_status = status;
3654 /***************************************************************
3655 Wrapper that allows SMB2 to get user quota.
3657 ***************************************************************/
3659 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
3661 SMB_NTQUOTA_STRUCT *pqt)
3664 DATA_BLOB inbuf = data_blob_null;
3665 DATA_BLOB info_blob = data_blob_null;
3666 DATA_BLOB outbuf = data_blob_null;
3667 TALLOC_CTX *frame = talloc_stackframe();
3669 unsigned int offset;
3670 struct smb2_query_quota_info query = {0};
3671 struct file_get_quota_info info = {0};
3672 enum ndr_err_code err;
3673 struct ndr_push *ndr_push = NULL;
3675 if (smbXcli_conn_has_async_calls(cli->conn)) {
3677 * Can't use sync call while an async call is in flight
3679 status = NT_STATUS_INVALID_PARAMETER;
3683 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
3685 query.return_single = 1;
3687 info.next_entry_offset = 0;
3688 info.sid_length = sid_len;
3689 info.sid = pqt->sid;
3691 err = ndr_push_struct_blob(
3695 (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
3697 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3698 status = NT_STATUS_INTERNAL_ERROR;
3702 query.sid_list_length = info_blob.length;
3703 ndr_push = ndr_push_init_ctx(frame);
3705 status = NT_STATUS_NO_MEMORY;
3709 err = ndr_push_smb2_query_quota_info(ndr_push,
3710 NDR_SCALARS | NDR_BUFFERS,
3713 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3714 status = NT_STATUS_INTERNAL_ERROR;
3718 err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3721 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3722 status = NT_STATUS_INTERNAL_ERROR;
3725 inbuf.data = ndr_push->data;
3726 inbuf.length = ndr_push->offset;
3728 status = cli_smb2_query_info_fnum(
3731 4, /* in_info_type */
3732 0, /* in_file_info_class */
3733 0xFFFF, /* in_max_output_length */
3734 &inbuf, /* in_input_buffer */
3735 0, /* in_additional_info */
3740 if (!NT_STATUS_IS_OK(status)) {
3744 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3746 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3747 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3751 cli->raw_status = status;
3757 /***************************************************************
3758 Wrapper that allows SMB2 to list user quota.
3760 ***************************************************************/
3762 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3763 TALLOC_CTX *mem_ctx,
3765 SMB_NTQUOTA_LIST **pqt_list,
3769 DATA_BLOB inbuf = data_blob_null;
3770 DATA_BLOB outbuf = data_blob_null;
3771 TALLOC_CTX *frame = talloc_stackframe();
3772 struct smb2_query_quota_info info = {0};
3773 enum ndr_err_code err;
3775 if (smbXcli_conn_has_async_calls(cli->conn)) {
3777 * Can't use sync call while an async call is in flight
3779 status = NT_STATUS_INVALID_PARAMETER;
3783 info.restart_scan = first ? 1 : 0;
3785 err = ndr_push_struct_blob(
3789 (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3791 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3792 status = NT_STATUS_INTERNAL_ERROR;
3796 status = cli_smb2_query_info_fnum(
3799 4, /* in_info_type */
3800 0, /* in_file_info_class */
3801 0xFFFF, /* in_max_output_length */
3802 &inbuf, /* in_input_buffer */
3803 0, /* in_additional_info */
3809 * safeguard against panic from calling parse_user_quota_list with
3812 if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3813 status = NT_STATUS_NO_MORE_ENTRIES;
3816 if (!NT_STATUS_IS_OK(status)) {
3820 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3824 cli->raw_status = status;
3830 /***************************************************************
3831 Wrapper that allows SMB2 to get file system quota.
3833 ***************************************************************/
3835 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3837 SMB_NTQUOTA_STRUCT *pqt)
3840 DATA_BLOB outbuf = data_blob_null;
3841 TALLOC_CTX *frame = talloc_stackframe();
3843 if (smbXcli_conn_has_async_calls(cli->conn)) {
3845 * Can't use sync call while an async call is in flight
3847 status = NT_STATUS_INVALID_PARAMETER;
3851 status = cli_smb2_query_info_fnum(
3854 2, /* in_info_type */
3855 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3856 0xFFFF, /* in_max_output_length */
3857 NULL, /* in_input_buffer */
3858 0, /* in_additional_info */
3863 if (!NT_STATUS_IS_OK(status)) {
3867 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3870 cli->raw_status = status;
3876 /***************************************************************
3877 Wrapper that allows SMB2 to set user quota.
3879 ***************************************************************/
3881 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3883 SMB_NTQUOTA_LIST *qtl)
3886 DATA_BLOB inbuf = data_blob_null;
3887 TALLOC_CTX *frame = talloc_stackframe();
3889 if (smbXcli_conn_has_async_calls(cli->conn)) {
3891 * Can't use sync call while an async call is in flight
3893 status = NT_STATUS_INVALID_PARAMETER;
3897 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3898 if (!NT_STATUS_IS_OK(status)) {
3902 status = cli_smb2_set_info_fnum(
3905 4, /* in_info_type */
3906 0, /* in_file_info_class */
3907 &inbuf, /* in_input_buffer */
3908 0); /* in_additional_info */
3911 cli->raw_status = status;
3918 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3920 SMB_NTQUOTA_STRUCT *pqt)
3923 DATA_BLOB inbuf = data_blob_null;
3924 TALLOC_CTX *frame = talloc_stackframe();
3926 if (smbXcli_conn_has_async_calls(cli->conn)) {
3928 * Can't use sync call while an async call is in flight
3930 status = NT_STATUS_INVALID_PARAMETER;
3934 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3935 if (!NT_STATUS_IS_OK(status)) {
3939 status = cli_smb2_set_info_fnum(
3942 2, /* in_info_type */
3943 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3944 &inbuf, /* in_input_buffer */
3945 0); /* in_additional_info */
3947 cli->raw_status = status;
3953 struct cli_smb2_read_state {
3954 struct tevent_context *ev;
3955 struct cli_state *cli;
3956 struct smb2_hnd *ph;
3957 uint64_t start_offset;
3963 static void cli_smb2_read_done(struct tevent_req *subreq);
3965 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3966 struct tevent_context *ev,
3967 struct cli_state *cli,
3973 struct tevent_req *req, *subreq;
3974 struct cli_smb2_read_state *state;
3976 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3982 state->start_offset = (uint64_t)offset;
3983 state->size = (uint32_t)size;
3984 state->received = 0;
3987 status = map_fnum_to_smb2_handle(cli,
3990 if (tevent_req_nterror(req, status)) {
3991 return tevent_req_post(req, ev);
3994 subreq = smb2cli_read_send(state,
3997 state->cli->timeout,
3998 state->cli->smb2.session,
3999 state->cli->smb2.tcon,
4001 state->start_offset,
4002 state->ph->fid_persistent,
4003 state->ph->fid_volatile,
4004 0, /* minimum_count */
4005 0); /* remaining_bytes */
4007 if (tevent_req_nomem(subreq, req)) {
4008 return tevent_req_post(req, ev);
4010 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
4014 static void cli_smb2_read_done(struct tevent_req *subreq)
4016 struct tevent_req *req = tevent_req_callback_data(
4017 subreq, struct tevent_req);
4018 struct cli_smb2_read_state *state = tevent_req_data(
4019 req, struct cli_smb2_read_state);
4022 status = smb2cli_read_recv(subreq, state,
4023 &state->buf, &state->received);
4024 if (tevent_req_nterror(req, status)) {
4028 if (state->received > state->size) {
4029 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4033 tevent_req_done(req);
4036 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
4041 struct cli_smb2_read_state *state = tevent_req_data(
4042 req, struct cli_smb2_read_state);
4044 if (tevent_req_is_nterror(req, &status)) {
4045 state->cli->raw_status = status;
4049 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
4050 * better make sure that you copy it away before you talloc_free(req).
4051 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
4053 *received = (ssize_t)state->received;
4054 *rcvbuf = state->buf;
4055 state->cli->raw_status = NT_STATUS_OK;
4056 return NT_STATUS_OK;
4059 struct cli_smb2_write_state {
4060 struct tevent_context *ev;
4061 struct cli_state *cli;
4062 struct smb2_hnd *ph;
4070 static void cli_smb2_write_written(struct tevent_req *req);
4072 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
4073 struct tevent_context *ev,
4074 struct cli_state *cli,
4082 struct tevent_req *req, *subreq = NULL;
4083 struct cli_smb2_write_state *state = NULL;
4085 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
4091 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4092 state->flags = (uint32_t)mode;
4094 state->offset = (uint64_t)offset;
4095 state->size = (uint32_t)size;
4098 status = map_fnum_to_smb2_handle(cli,
4101 if (tevent_req_nterror(req, status)) {
4102 return tevent_req_post(req, ev);
4105 subreq = smb2cli_write_send(state,
4108 state->cli->timeout,
4109 state->cli->smb2.session,
4110 state->cli->smb2.tcon,
4113 state->ph->fid_persistent,
4114 state->ph->fid_volatile,
4115 0, /* remaining_bytes */
4116 state->flags, /* flags */
4119 if (tevent_req_nomem(subreq, req)) {
4120 return tevent_req_post(req, ev);
4122 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
4126 static void cli_smb2_write_written(struct tevent_req *subreq)
4128 struct tevent_req *req = tevent_req_callback_data(
4129 subreq, struct tevent_req);
4130 struct cli_smb2_write_state *state = tevent_req_data(
4131 req, struct cli_smb2_write_state);
4135 status = smb2cli_write_recv(subreq, &written);
4136 TALLOC_FREE(subreq);
4137 if (tevent_req_nterror(req, status)) {
4141 state->written = written;
4143 tevent_req_done(req);
4146 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
4149 struct cli_smb2_write_state *state = tevent_req_data(
4150 req, struct cli_smb2_write_state);
4153 if (tevent_req_is_nterror(req, &status)) {
4154 state->cli->raw_status = status;
4155 tevent_req_received(req);
4159 if (pwritten != NULL) {
4160 *pwritten = (size_t)state->written;
4162 state->cli->raw_status = NT_STATUS_OK;
4163 tevent_req_received(req);
4164 return NT_STATUS_OK;
4167 /***************************************************************
4168 Wrapper that allows SMB2 async write using an fnum.
4169 This is mostly cut-and-paste from Volker's code inside
4170 source3/libsmb/clireadwrite.c, adapted for SMB2.
4172 Done this way so I can reuse all the logic inside cli_push()
4174 ***************************************************************/
4176 struct cli_smb2_writeall_state {
4177 struct tevent_context *ev;
4178 struct cli_state *cli;
4179 struct smb2_hnd *ph;
4187 static void cli_smb2_writeall_written(struct tevent_req *req);
4189 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
4190 struct tevent_context *ev,
4191 struct cli_state *cli,
4199 struct tevent_req *req, *subreq = NULL;
4200 struct cli_smb2_writeall_state *state = NULL;
4205 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
4211 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4212 state->flags = (uint32_t)mode;
4214 state->offset = (uint64_t)offset;
4215 state->size = (uint32_t)size;
4218 status = map_fnum_to_smb2_handle(cli,
4221 if (tevent_req_nterror(req, status)) {
4222 return tevent_req_post(req, ev);
4225 to_write = state->size;
4226 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4227 to_write = MIN(max_size, to_write);
4228 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4230 to_write = MIN(max_size, to_write);
4233 subreq = smb2cli_write_send(state,
4236 state->cli->timeout,
4237 state->cli->smb2.session,
4238 state->cli->smb2.tcon,
4241 state->ph->fid_persistent,
4242 state->ph->fid_volatile,
4243 0, /* remaining_bytes */
4244 state->flags, /* flags */
4245 state->buf + state->written);
4247 if (tevent_req_nomem(subreq, req)) {
4248 return tevent_req_post(req, ev);
4250 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4254 static void cli_smb2_writeall_written(struct tevent_req *subreq)
4256 struct tevent_req *req = tevent_req_callback_data(
4257 subreq, struct tevent_req);
4258 struct cli_smb2_writeall_state *state = tevent_req_data(
4259 req, struct cli_smb2_writeall_state);
4261 uint32_t written, to_write;
4265 status = smb2cli_write_recv(subreq, &written);
4266 TALLOC_FREE(subreq);
4267 if (tevent_req_nterror(req, status)) {
4271 state->written += written;
4273 if (state->written > state->size) {
4274 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4278 to_write = state->size - state->written;
4280 if (to_write == 0) {
4281 tevent_req_done(req);
4285 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4286 to_write = MIN(max_size, to_write);
4287 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4289 to_write = MIN(max_size, to_write);
4292 subreq = smb2cli_write_send(state,
4295 state->cli->timeout,
4296 state->cli->smb2.session,
4297 state->cli->smb2.tcon,
4299 state->offset + state->written,
4300 state->ph->fid_persistent,
4301 state->ph->fid_volatile,
4302 0, /* remaining_bytes */
4303 state->flags, /* flags */
4304 state->buf + state->written);
4306 if (tevent_req_nomem(subreq, req)) {
4309 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4312 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
4315 struct cli_smb2_writeall_state *state = tevent_req_data(
4316 req, struct cli_smb2_writeall_state);
4319 if (tevent_req_is_nterror(req, &status)) {
4320 state->cli->raw_status = status;
4323 if (pwritten != NULL) {
4324 *pwritten = (size_t)state->written;
4326 state->cli->raw_status = NT_STATUS_OK;
4327 return NT_STATUS_OK;
4330 struct cli_smb2_splice_state {
4331 struct tevent_context *ev;
4332 struct cli_state *cli;
4333 struct smb2_hnd *src_ph;
4334 struct smb2_hnd *dst_ph;
4335 int (*splice_cb)(off_t n, void *priv);
4342 struct req_resume_key_rsp resume_rsp;
4343 struct srv_copychunk_copy cc_copy;
4346 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4347 struct tevent_req *req);
4349 static void cli_splice_copychunk_done(struct tevent_req *subreq)
4351 struct tevent_req *req = tevent_req_callback_data(
4352 subreq, struct tevent_req);
4353 struct cli_smb2_splice_state *state =
4354 tevent_req_data(req,
4355 struct cli_smb2_splice_state);
4356 struct smbXcli_conn *conn = state->cli->conn;
4357 DATA_BLOB out_input_buffer = data_blob_null;
4358 DATA_BLOB out_output_buffer = data_blob_null;
4359 struct srv_copychunk_rsp cc_copy_rsp;
4360 enum ndr_err_code ndr_ret;
4363 status = smb2cli_ioctl_recv(subreq, state,
4365 &out_output_buffer);
4366 TALLOC_FREE(subreq);
4367 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
4368 state->resized) && tevent_req_nterror(req, status)) {
4372 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
4373 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
4374 if (ndr_ret != NDR_ERR_SUCCESS) {
4375 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4376 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4380 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
4381 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
4382 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
4383 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
4384 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
4385 tevent_req_nterror(req, status)) {
4389 state->resized = true;
4390 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
4391 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
4393 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4394 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4395 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
4396 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4399 state->src_offset += cc_copy_rsp.total_bytes_written;
4400 state->dst_offset += cc_copy_rsp.total_bytes_written;
4401 state->written += cc_copy_rsp.total_bytes_written;
4402 if (!state->splice_cb(state->written, state->priv)) {
4403 tevent_req_nterror(req, NT_STATUS_CANCELLED);
4408 cli_splice_copychunk_send(state, req);
4411 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4412 struct tevent_req *req)
4414 struct tevent_req *subreq;
4415 enum ndr_err_code ndr_ret;
4416 struct smbXcli_conn *conn = state->cli->conn;
4417 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
4418 off_t src_offset = state->src_offset;
4419 off_t dst_offset = state->dst_offset;
4420 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
4421 state->size - state->written);
4422 DATA_BLOB in_input_buffer = data_blob_null;
4423 DATA_BLOB in_output_buffer = data_blob_null;
4425 if (state->size - state->written == 0) {
4426 tevent_req_done(req);
4430 cc_copy->chunk_count = 0;
4432 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
4433 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
4434 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
4435 smb2cli_conn_cc_chunk_len(conn));
4436 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
4437 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4440 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
4441 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
4442 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
4443 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4446 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4447 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4448 cc_copy->chunk_count++;
4451 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
4452 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
4453 if (ndr_ret != NDR_ERR_SUCCESS) {
4454 DEBUG(0, ("failed to marshall copy chunk req\n"));
4455 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4459 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
4460 state->cli->timeout,
4461 state->cli->smb2.session,
4462 state->cli->smb2.tcon,
4463 state->dst_ph->fid_persistent, /* in_fid_persistent */
4464 state->dst_ph->fid_volatile, /* in_fid_volatile */
4465 FSCTL_SRV_COPYCHUNK_WRITE,
4466 0, /* in_max_input_length */
4468 12, /* in_max_output_length */
4470 SMB2_IOCTL_FLAG_IS_FSCTL);
4471 if (tevent_req_nomem(subreq, req)) {
4474 tevent_req_set_callback(subreq,
4475 cli_splice_copychunk_done,
4479 static void cli_splice_key_done(struct tevent_req *subreq)
4481 struct tevent_req *req = tevent_req_callback_data(
4482 subreq, struct tevent_req);
4483 struct cli_smb2_splice_state *state =
4484 tevent_req_data(req,
4485 struct cli_smb2_splice_state);
4486 enum ndr_err_code ndr_ret;
4489 DATA_BLOB out_input_buffer = data_blob_null;
4490 DATA_BLOB out_output_buffer = data_blob_null;
4492 status = smb2cli_ioctl_recv(subreq, state,
4494 &out_output_buffer);
4495 TALLOC_FREE(subreq);
4496 if (tevent_req_nterror(req, status)) {
4500 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
4501 state, &state->resume_rsp,
4502 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
4503 if (ndr_ret != NDR_ERR_SUCCESS) {
4504 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4505 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4509 memcpy(&state->cc_copy.source_key,
4510 &state->resume_rsp.resume_key,
4511 sizeof state->resume_rsp.resume_key);
4513 cli_splice_copychunk_send(state, req);
4516 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
4517 struct tevent_context *ev,
4518 struct cli_state *cli,
4519 uint16_t src_fnum, uint16_t dst_fnum,
4520 off_t size, off_t src_offset, off_t dst_offset,
4521 int (*splice_cb)(off_t n, void *priv),
4524 struct tevent_req *req;
4525 struct tevent_req *subreq;
4526 struct cli_smb2_splice_state *state;
4528 DATA_BLOB in_input_buffer = data_blob_null;
4529 DATA_BLOB in_output_buffer = data_blob_null;
4531 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
4537 state->splice_cb = splice_cb;
4541 state->src_offset = src_offset;
4542 state->dst_offset = dst_offset;
4543 state->cc_copy.chunks = talloc_array(state,
4544 struct srv_copychunk,
4545 smb2cli_conn_cc_max_chunks(cli->conn));
4546 if (state->cc_copy.chunks == NULL) {
4550 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
4551 if (tevent_req_nterror(req, status))
4552 return tevent_req_post(req, ev);
4554 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
4555 if (tevent_req_nterror(req, status))
4556 return tevent_req_post(req, ev);
4558 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
4562 state->src_ph->fid_persistent, /* in_fid_persistent */
4563 state->src_ph->fid_volatile, /* in_fid_volatile */
4564 FSCTL_SRV_REQUEST_RESUME_KEY,
4565 0, /* in_max_input_length */
4567 32, /* in_max_output_length */
4569 SMB2_IOCTL_FLAG_IS_FSCTL);
4570 if (tevent_req_nomem(subreq, req)) {
4573 tevent_req_set_callback(subreq,
4574 cli_splice_key_done,
4580 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
4582 struct cli_smb2_splice_state *state = tevent_req_data(
4583 req, struct cli_smb2_splice_state);
4586 if (tevent_req_is_nterror(req, &status)) {
4587 state->cli->raw_status = status;
4588 tevent_req_received(req);
4591 if (written != NULL) {
4592 *written = state->written;
4594 state->cli->raw_status = NT_STATUS_OK;
4595 tevent_req_received(req);
4596 return NT_STATUS_OK;
4599 /***************************************************************
4600 SMB2 enum shadow copy data.
4601 ***************************************************************/
4603 struct cli_smb2_shadow_copy_data_fnum_state {
4604 struct cli_state *cli;
4606 struct smb2_hnd *ph;
4607 DATA_BLOB out_input_buffer;
4608 DATA_BLOB out_output_buffer;
4611 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
4613 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
4614 TALLOC_CTX *mem_ctx,
4615 struct tevent_context *ev,
4616 struct cli_state *cli,
4620 struct tevent_req *req, *subreq;
4621 struct cli_smb2_shadow_copy_data_fnum_state *state;
4624 req = tevent_req_create(mem_ctx, &state,
4625 struct cli_smb2_shadow_copy_data_fnum_state);
4633 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4634 if (tevent_req_nterror(req, status)) {
4635 return tevent_req_post(req, ev);
4639 * TODO. Under SMB2 we should send a zero max_output_length
4640 * ioctl to get the required size, then send another ioctl
4641 * to get the data, but the current SMB1 implementation just
4642 * does one roundtrip with a 64K buffer size. Do the same
4646 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4647 state->cli->timeout,
4648 state->cli->smb2.session,
4649 state->cli->smb2.tcon,
4650 state->ph->fid_persistent, /* in_fid_persistent */
4651 state->ph->fid_volatile, /* in_fid_volatile */
4652 FSCTL_GET_SHADOW_COPY_DATA,
4653 0, /* in_max_input_length */
4654 NULL, /* in_input_buffer */
4656 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
4657 NULL, /* in_output_buffer */
4658 SMB2_IOCTL_FLAG_IS_FSCTL);
4660 if (tevent_req_nomem(subreq, req)) {
4661 return tevent_req_post(req, ev);
4663 tevent_req_set_callback(subreq,
4664 cli_smb2_shadow_copy_data_fnum_done,
4670 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4672 struct tevent_req *req = tevent_req_callback_data(
4673 subreq, struct tevent_req);
4674 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4675 req, struct cli_smb2_shadow_copy_data_fnum_state);
4678 status = smb2cli_ioctl_recv(subreq, state,
4679 &state->out_input_buffer,
4680 &state->out_output_buffer);
4681 tevent_req_simple_finish_ntstatus(subreq, status);
4684 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4685 TALLOC_CTX *mem_ctx,
4690 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4691 req, struct cli_smb2_shadow_copy_data_fnum_state);
4692 char **names = NULL;
4693 uint32_t num_names = 0;
4694 uint32_t num_names_returned = 0;
4695 uint32_t dlength = 0;
4697 uint8_t *endp = NULL;
4700 if (tevent_req_is_nterror(req, &status)) {
4704 if (state->out_output_buffer.length < 16) {
4705 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4708 num_names = IVAL(state->out_output_buffer.data, 0);
4709 num_names_returned = IVAL(state->out_output_buffer.data, 4);
4710 dlength = IVAL(state->out_output_buffer.data, 8);
4712 if (num_names > 0x7FFFFFFF) {
4713 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4716 if (get_names == false) {
4717 *pnum_names = (int)num_names;
4718 return NT_STATUS_OK;
4720 if (num_names != num_names_returned) {
4721 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4723 if (dlength + 12 < 12) {
4724 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4727 * NB. The below is an allowable return if there are
4728 * more snapshots than the buffer size we told the
4729 * server we can receive. We currently don't support
4732 if (dlength + 12 > state->out_output_buffer.length) {
4733 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4735 if (state->out_output_buffer.length +
4736 (2 * sizeof(SHADOW_COPY_LABEL)) <
4737 state->out_output_buffer.length) {
4738 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4741 names = talloc_array(mem_ctx, char *, num_names_returned);
4742 if (names == NULL) {
4743 return NT_STATUS_NO_MEMORY;
4746 endp = state->out_output_buffer.data +
4747 state->out_output_buffer.length;
4749 for (i=0; i<num_names_returned; i++) {
4752 size_t converted_size;
4754 src = state->out_output_buffer.data + 12 +
4755 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4757 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4758 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4760 ret = convert_string_talloc(
4761 names, CH_UTF16LE, CH_UNIX,
4762 src, 2 * sizeof(SHADOW_COPY_LABEL),
4763 &names[i], &converted_size);
4766 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4769 *pnum_names = num_names;
4771 return NT_STATUS_OK;
4774 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4775 struct cli_state *cli,
4781 TALLOC_CTX *frame = talloc_stackframe();
4782 struct tevent_context *ev;
4783 struct tevent_req *req;
4784 NTSTATUS status = NT_STATUS_NO_MEMORY;
4786 if (smbXcli_conn_has_async_calls(cli->conn)) {
4788 * Can't use sync call while an async call is in flight
4790 status = NT_STATUS_INVALID_PARAMETER;
4793 ev = samba_tevent_context_init(frame);
4797 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4805 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4808 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4814 cli->raw_status = status;
4820 /***************************************************************
4821 Wrapper that allows SMB2 to truncate a file.
4823 ***************************************************************/
4825 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4830 uint8_t buf[8] = {0};
4831 DATA_BLOB inbuf = { .data = buf, .length = sizeof(buf) };
4832 TALLOC_CTX *frame = talloc_stackframe();
4834 if (smbXcli_conn_has_async_calls(cli->conn)) {
4836 * Can't use sync call while an async call is in flight
4838 status = NT_STATUS_INVALID_PARAMETER;
4842 SBVAL(buf, 0, newsize);
4844 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4845 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4847 status = cli_smb2_set_info_fnum(
4850 1, /* in_info_type */
4851 SMB_FILE_END_OF_FILE_INFORMATION-1000, /* in_file_info_class */
4852 &inbuf, /* in_input_buffer */
4857 cli->raw_status = status;
4863 struct cli_smb2_notify_state {
4864 struct tevent_req *subreq;
4865 struct notify_change *changes;
4869 static void cli_smb2_notify_done(struct tevent_req *subreq);
4870 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4872 struct tevent_req *cli_smb2_notify_send(
4873 TALLOC_CTX *mem_ctx,
4874 struct tevent_context *ev,
4875 struct cli_state *cli,
4877 uint32_t buffer_size,
4878 uint32_t completion_filter,
4881 struct tevent_req *req = NULL;
4882 struct cli_smb2_notify_state *state = NULL;
4883 struct smb2_hnd *ph = NULL;
4886 req = tevent_req_create(mem_ctx, &state,
4887 struct cli_smb2_notify_state);
4892 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4893 if (tevent_req_nterror(req, status)) {
4894 return tevent_req_post(req, ev);
4897 state->subreq = smb2cli_notify_send(
4909 if (tevent_req_nomem(state->subreq, req)) {
4910 return tevent_req_post(req, ev);
4912 tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4913 tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4917 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4919 struct cli_smb2_notify_state *state = tevent_req_data(
4920 req, struct cli_smb2_notify_state);
4923 ok = tevent_req_cancel(state->subreq);
4927 static void cli_smb2_notify_done(struct tevent_req *subreq)
4929 struct tevent_req *req = tevent_req_callback_data(
4930 subreq, struct tevent_req);
4931 struct cli_smb2_notify_state *state = tevent_req_data(
4932 req, struct cli_smb2_notify_state);
4938 status = smb2cli_notify_recv(subreq, state, &base, &len);
4939 TALLOC_FREE(subreq);
4941 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4942 tevent_req_done(req);
4945 if (tevent_req_nterror(req, status)) {
4951 while (len - ofs >= 12) {
4952 struct notify_change *tmp;
4953 struct notify_change *c;
4954 uint32_t next_ofs = IVAL(base, ofs);
4955 uint32_t file_name_length = IVAL(base, ofs+8);
4959 tmp = talloc_realloc(
4962 struct notify_change,
4963 state->num_changes + 1);
4964 if (tevent_req_nomem(tmp, req)) {
4967 state->changes = tmp;
4968 c = &state->changes[state->num_changes];
4969 state->num_changes += 1;
4971 if (smb_buffer_oob(len, ofs, next_ofs) ||
4972 smb_buffer_oob(len, ofs+12, file_name_length)) {
4974 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4978 c->action = IVAL(base, ofs+4);
4980 ok = convert_string_talloc(
4990 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4994 if (next_ofs == 0) {
5000 tevent_req_done(req);
5003 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
5004 TALLOC_CTX *mem_ctx,
5005 struct notify_change **pchanges,
5006 uint32_t *pnum_changes)
5008 struct cli_smb2_notify_state *state = tevent_req_data(
5009 req, struct cli_smb2_notify_state);
5012 if (tevent_req_is_nterror(req, &status)) {
5015 *pchanges = talloc_move(mem_ctx, &state->changes);
5016 *pnum_changes = state->num_changes;
5017 return NT_STATUS_OK;
5020 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
5021 uint32_t buffer_size, uint32_t completion_filter,
5022 bool recursive, TALLOC_CTX *mem_ctx,
5023 struct notify_change **pchanges,
5024 uint32_t *pnum_changes)
5026 TALLOC_CTX *frame = talloc_stackframe();
5027 struct tevent_context *ev;
5028 struct tevent_req *req;
5029 NTSTATUS status = NT_STATUS_NO_MEMORY;
5031 if (smbXcli_conn_has_async_calls(cli->conn)) {
5033 * Can't use sync call while an async call is in flight
5035 status = NT_STATUS_INVALID_PARAMETER;
5038 ev = samba_tevent_context_init(frame);
5042 req = cli_smb2_notify_send(
5053 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5056 status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
5062 struct cli_smb2_fsctl_state {
5066 static void cli_smb2_fsctl_done(struct tevent_req *subreq);
5068 struct tevent_req *cli_smb2_fsctl_send(
5069 TALLOC_CTX *mem_ctx,
5070 struct tevent_context *ev,
5071 struct cli_state *cli,
5074 const DATA_BLOB *in,
5077 struct tevent_req *req = NULL, *subreq = NULL;
5078 struct cli_smb2_fsctl_state *state = NULL;
5079 struct smb2_hnd *ph = NULL;
5082 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_fsctl_state);
5087 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
5088 if (tevent_req_nterror(req, status)) {
5089 return tevent_req_post(req, ev);
5092 subreq = smb2cli_ioctl_send(
5102 0, /* in_max_input_length */
5106 SMB2_IOCTL_FLAG_IS_FSCTL);
5108 if (tevent_req_nomem(subreq, req)) {
5109 return tevent_req_post(req, ev);
5111 tevent_req_set_callback(subreq, cli_smb2_fsctl_done, req);
5115 static void cli_smb2_fsctl_done(struct tevent_req *subreq)
5117 struct tevent_req *req = tevent_req_callback_data(
5118 subreq, struct tevent_req);
5119 struct cli_smb2_fsctl_state *state = tevent_req_data(
5120 req, struct cli_smb2_fsctl_state);
5123 status = smb2cli_ioctl_recv(subreq, state, NULL, &state->out);
5124 tevent_req_simple_finish_ntstatus(subreq, status);
5127 NTSTATUS cli_smb2_fsctl_recv(
5128 struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *out)
5130 struct cli_smb2_fsctl_state *state = tevent_req_data(
5131 req, struct cli_smb2_fsctl_state);
5132 NTSTATUS status = NT_STATUS_OK;
5134 if (tevent_req_is_nterror(req, &status)) {
5135 tevent_req_received(req);
5139 if (state->out.length == 0) {
5140 *out = (DATA_BLOB) { .data = NULL, };
5143 * Can't use talloc_move() here, the outblobs from
5144 * smb2cli_ioctl_recv() are not standalone talloc
5145 * objects but just peek into the larger buffers
5146 * received, hanging off "state".
5148 *out = data_blob_talloc(
5149 mem_ctx, state->out.data, state->out.length);
5150 if (out->data == NULL) {
5151 status = NT_STATUS_NO_MEMORY;
5155 tevent_req_received(req);
5156 return NT_STATUS_OK;