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 Small wrapper that allows SMB2 create to return a uint16_t fnum.
158 ***************************************************************/
160 struct cli_smb2_create_fnum_state {
161 struct cli_state *cli;
162 struct smb2_create_blobs in_cblobs;
163 struct smb2_create_blobs out_cblobs;
164 struct smb_create_returns cr;
166 struct tevent_req *subreq;
169 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
170 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
172 struct tevent_req *cli_smb2_create_fnum_send(
174 struct tevent_context *ev,
175 struct cli_state *cli,
177 uint32_t create_flags,
178 uint32_t impersonation_level,
179 uint32_t desired_access,
180 uint32_t file_attributes,
181 uint32_t share_access,
182 uint32_t create_disposition,
183 uint32_t create_options,
184 const struct smb2_create_blobs *in_cblobs)
186 struct tevent_req *req, *subreq;
187 struct cli_smb2_create_fnum_state *state;
188 size_t fname_len = 0;
189 const char *startp = NULL;
190 const char *endp = NULL;
191 time_t tstamp = (time_t)0;
194 req = tevent_req_create(mem_ctx, &state,
195 struct cli_smb2_create_fnum_state);
201 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
202 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
203 return tevent_req_post(req, ev);
206 if (cli->backup_intent) {
207 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
210 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
211 fname_len = strlen(fname);
212 if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
213 size_t len_before_gmt = startp - fname;
214 size_t len_after_gmt = fname + fname_len - endp;
218 char *new_fname = talloc_array(state, char,
219 len_before_gmt + len_after_gmt + 1);
221 if (tevent_req_nomem(new_fname, req)) {
222 return tevent_req_post(req, ev);
225 memcpy(new_fname, fname, len_before_gmt);
226 memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
228 fname_len = len_before_gmt + len_after_gmt;
230 unix_to_nt_time(&ntt, tstamp);
231 twrp_blob = data_blob_const((const void *)&ntt, 8);
233 status = smb2_create_blob_add(
236 SMB2_CREATE_TAG_TWRP,
238 if (!NT_STATUS_IS_OK(status)) {
239 tevent_req_nterror(req, status);
240 return tevent_req_post(req, ev);
244 if (in_cblobs != NULL) {
246 for (i=0; i<in_cblobs->num_blobs; i++) {
247 struct smb2_create_blob *b = &in_cblobs->blobs[i];
248 status = smb2_create_blob_add(
249 state, &state->in_cblobs, b->tag, b->data);
250 if (!NT_STATUS_IS_OK(status)) {
251 tevent_req_nterror(req, status);
252 return tevent_req_post(req, ev);
257 /* SMB2 is pickier about pathnames. Ensure it doesn't
259 if (*fname == '\\') {
264 /* Or end in a '\' */
265 if (fname_len > 0 && fname[fname_len-1] == '\\') {
266 char *new_fname = talloc_strdup(state, fname);
267 if (tevent_req_nomem(new_fname, req)) {
268 return tevent_req_post(req, ev);
270 new_fname[fname_len-1] = '\0';
274 subreq = smb2cli_create_send(state, ev,
280 flags_to_smb2_oplock(create_flags),
288 if (tevent_req_nomem(subreq, req)) {
289 return tevent_req_post(req, ev);
291 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
293 state->subreq = subreq;
294 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
299 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
301 struct tevent_req *req = tevent_req_callback_data(
302 subreq, struct tevent_req);
303 struct cli_smb2_create_fnum_state *state = tevent_req_data(
304 req, struct cli_smb2_create_fnum_state);
308 status = smb2cli_create_recv(
311 &h.fid_volatile, &state->cr,
315 if (tevent_req_nterror(req, status)) {
319 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
320 if (tevent_req_nterror(req, status)) {
323 tevent_req_done(req);
326 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
328 struct cli_smb2_create_fnum_state *state = tevent_req_data(
329 req, struct cli_smb2_create_fnum_state);
330 return tevent_req_cancel(state->subreq);
333 NTSTATUS cli_smb2_create_fnum_recv(
334 struct tevent_req *req,
336 struct smb_create_returns *cr,
338 struct smb2_create_blobs *out_cblobs)
340 struct cli_smb2_create_fnum_state *state = tevent_req_data(
341 req, struct cli_smb2_create_fnum_state);
344 if (tevent_req_is_nterror(req, &status)) {
345 state->cli->raw_status = status;
349 *pfnum = state->fnum;
354 if (out_cblobs != NULL) {
355 *out_cblobs = (struct smb2_create_blobs) {
356 .num_blobs = state->out_cblobs.num_blobs,
357 .blobs = talloc_move(
358 mem_ctx, &state->out_cblobs.blobs),
361 state->cli->raw_status = NT_STATUS_OK;
365 NTSTATUS cli_smb2_create_fnum(
366 struct cli_state *cli,
368 uint32_t create_flags,
369 uint32_t impersonation_level,
370 uint32_t desired_access,
371 uint32_t file_attributes,
372 uint32_t share_access,
373 uint32_t create_disposition,
374 uint32_t create_options,
375 const struct smb2_create_blobs *in_cblobs,
377 struct smb_create_returns *cr,
379 struct smb2_create_blobs *out_cblobs)
381 TALLOC_CTX *frame = talloc_stackframe();
382 struct tevent_context *ev;
383 struct tevent_req *req;
384 NTSTATUS status = NT_STATUS_NO_MEMORY;
386 if (smbXcli_conn_has_async_calls(cli->conn)) {
388 * Can't use sync call while an async call is in flight
390 status = NT_STATUS_INVALID_PARAMETER;
393 ev = samba_tevent_context_init(frame);
397 req = cli_smb2_create_fnum_send(
413 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
416 status = cli_smb2_create_fnum_recv(req, pfid, cr, mem_ctx, out_cblobs);
422 /***************************************************************
423 Small wrapper that allows SMB2 close to use a uint16_t fnum.
424 ***************************************************************/
426 struct cli_smb2_close_fnum_state {
427 struct cli_state *cli;
432 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
434 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
435 struct tevent_context *ev,
436 struct cli_state *cli,
439 struct tevent_req *req, *subreq;
440 struct cli_smb2_close_fnum_state *state;
443 req = tevent_req_create(mem_ctx, &state,
444 struct cli_smb2_close_fnum_state);
451 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
452 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
453 return tevent_req_post(req, ev);
456 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
457 if (tevent_req_nterror(req, status)) {
458 return tevent_req_post(req, ev);
461 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
462 cli->smb2.session, cli->smb2.tcon,
463 0, state->ph->fid_persistent,
464 state->ph->fid_volatile);
465 if (tevent_req_nomem(subreq, req)) {
466 return tevent_req_post(req, ev);
468 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
472 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
474 struct tevent_req *req = tevent_req_callback_data(
475 subreq, struct tevent_req);
476 struct cli_smb2_close_fnum_state *state = tevent_req_data(
477 req, struct cli_smb2_close_fnum_state);
480 status = smb2cli_close_recv(subreq);
481 if (tevent_req_nterror(req, status)) {
485 /* Delete the fnum -> handle mapping. */
486 status = delete_smb2_handle_mapping(state->cli, &state->ph,
488 if (tevent_req_nterror(req, status)) {
491 tevent_req_done(req);
494 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
496 struct cli_smb2_close_fnum_state *state = tevent_req_data(
497 req, struct cli_smb2_close_fnum_state);
498 NTSTATUS status = NT_STATUS_OK;
500 if (tevent_req_is_nterror(req, &status)) {
501 state->cli->raw_status = status;
503 tevent_req_received(req);
507 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
509 TALLOC_CTX *frame = talloc_stackframe();
510 struct tevent_context *ev;
511 struct tevent_req *req;
512 NTSTATUS status = NT_STATUS_NO_MEMORY;
514 if (smbXcli_conn_has_async_calls(cli->conn)) {
516 * Can't use sync call while an async call is in flight
518 status = NT_STATUS_INVALID_PARAMETER;
521 ev = samba_tevent_context_init(frame);
525 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
529 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
532 status = cli_smb2_close_fnum_recv(req);
538 struct cli_smb2_set_info_fnum_state {
542 static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq);
544 struct tevent_req *cli_smb2_set_info_fnum_send(
546 struct tevent_context *ev,
547 struct cli_state *cli,
549 uint8_t in_info_type,
550 uint8_t in_info_class,
551 const DATA_BLOB *in_input_buffer,
552 uint32_t in_additional_info)
554 struct tevent_req *req = NULL, *subreq = NULL;
555 struct cli_smb2_set_info_fnum_state *state = NULL;
556 struct smb2_hnd *ph = NULL;
559 req = tevent_req_create(
560 mem_ctx, &state, struct cli_smb2_set_info_fnum_state);
565 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
566 if (tevent_req_nterror(req, status)) {
567 return tevent_req_post(req, ev);
570 subreq = smb2cli_set_info_send(
583 if (tevent_req_nomem(subreq, req)) {
584 return tevent_req_post(req, ev);
586 tevent_req_set_callback(subreq, cli_smb2_set_info_fnum_done, req);
590 static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq)
592 NTSTATUS status = smb2cli_set_info_recv(subreq);
593 tevent_req_simple_finish_ntstatus(subreq, status);
596 NTSTATUS cli_smb2_set_info_fnum_recv(struct tevent_req *req)
598 return tevent_req_simple_recv_ntstatus(req);
601 NTSTATUS cli_smb2_set_info_fnum(
602 struct cli_state *cli,
604 uint8_t in_info_type,
605 uint8_t in_info_class,
606 const DATA_BLOB *in_input_buffer,
607 uint32_t in_additional_info)
609 TALLOC_CTX *frame = talloc_stackframe();
610 struct tevent_context *ev = NULL;
611 struct tevent_req *req = NULL;
612 NTSTATUS status = NT_STATUS_NO_MEMORY;
615 if (smbXcli_conn_has_async_calls(cli->conn)) {
617 * Can't use sync call while an async call is in flight
619 status = NT_STATUS_INVALID_PARAMETER;
622 ev = samba_tevent_context_init(frame);
626 req = cli_smb2_set_info_fnum_send(
638 ok = tevent_req_poll_ntstatus(req, ev, &status);
642 status = cli_smb2_set_info_fnum_recv(req);
648 struct cli_smb2_delete_on_close_state {
649 struct cli_state *cli;
654 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
656 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
657 struct tevent_context *ev,
658 struct cli_state *cli,
662 struct tevent_req *req = NULL;
663 struct cli_smb2_delete_on_close_state *state = NULL;
664 struct tevent_req *subreq = NULL;
665 uint8_t in_info_type;
666 uint8_t in_file_info_class;
668 req = tevent_req_create(mem_ctx, &state,
669 struct cli_smb2_delete_on_close_state);
675 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
676 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
677 return tevent_req_post(req, ev);
681 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
682 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
685 in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
686 /* Setup data array. */
687 SCVAL(&state->data[0], 0, flag ? 1 : 0);
688 state->inbuf.data = &state->data[0];
689 state->inbuf.length = 1;
691 subreq = cli_smb2_set_info_fnum_send(
700 if (tevent_req_nomem(subreq, req)) {
701 return tevent_req_post(req, ev);
703 tevent_req_set_callback(subreq,
704 cli_smb2_delete_on_close_done,
709 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
711 NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
712 tevent_req_simple_finish_ntstatus(subreq, status);
715 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
717 struct cli_smb2_delete_on_close_state *state =
719 struct cli_smb2_delete_on_close_state);
722 if (tevent_req_is_nterror(req, &status)) {
723 state->cli->raw_status = status;
724 tevent_req_received(req);
728 state->cli->raw_status = NT_STATUS_OK;
729 tevent_req_received(req);
733 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
735 TALLOC_CTX *frame = talloc_stackframe();
736 struct tevent_context *ev;
737 struct tevent_req *req;
738 NTSTATUS status = NT_STATUS_NO_MEMORY;
740 if (smbXcli_conn_has_async_calls(cli->conn)) {
742 * Can't use sync call while an async call is in flight
744 status = NT_STATUS_INVALID_PARAMETER;
747 ev = samba_tevent_context_init(frame);
751 req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
755 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
758 status = cli_smb2_delete_on_close_recv(req);
764 struct cli_smb2_mkdir_state {
765 struct tevent_context *ev;
766 struct cli_state *cli;
769 static void cli_smb2_mkdir_opened(struct tevent_req *subreq);
770 static void cli_smb2_mkdir_closed(struct tevent_req *subreq);
772 struct tevent_req *cli_smb2_mkdir_send(
774 struct tevent_context *ev,
775 struct cli_state *cli,
778 struct tevent_req *req = NULL, *subreq = NULL;
779 struct cli_smb2_mkdir_state *state = NULL;
781 req = tevent_req_create(
782 mem_ctx, &state, struct cli_smb2_mkdir_state);
789 /* Ensure this is a directory. */
790 subreq = cli_smb2_create_fnum_send(
795 0, /* create_flags */
796 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level */
797 FILE_READ_ATTRIBUTES, /* desired_access */
798 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
800 FILE_SHARE_WRITE, /* share_access */
801 FILE_CREATE, /* create_disposition */
802 FILE_DIRECTORY_FILE, /* create_options */
803 NULL); /* in_cblobs */
804 if (tevent_req_nomem(subreq, req)) {
805 return tevent_req_post(req, ev);
807 tevent_req_set_callback(subreq, cli_smb2_mkdir_opened, req);
811 static void cli_smb2_mkdir_opened(struct tevent_req *subreq)
813 struct tevent_req *req = tevent_req_callback_data(
814 subreq, struct tevent_req);
815 struct cli_smb2_mkdir_state *state = tevent_req_data(
816 req, struct cli_smb2_mkdir_state);
820 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
822 if (tevent_req_nterror(req, status)) {
826 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
827 if (tevent_req_nomem(subreq, req)) {
830 tevent_req_set_callback(subreq, cli_smb2_mkdir_closed, req);
833 static void cli_smb2_mkdir_closed(struct tevent_req *subreq)
835 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
836 tevent_req_simple_finish_ntstatus(subreq, status);
839 NTSTATUS cli_smb2_mkdir_recv(struct tevent_req *req)
841 return tevent_req_simple_recv_ntstatus(req);
844 struct cli_smb2_rmdir_state {
845 struct tevent_context *ev;
846 struct cli_state *cli;
848 const struct smb2_create_blobs *in_cblobs;
853 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq);
854 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq);
855 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq);
856 static void cli_smb2_rmdir_closed(struct tevent_req *subreq);
858 struct tevent_req *cli_smb2_rmdir_send(
860 struct tevent_context *ev,
861 struct cli_state *cli,
863 const struct smb2_create_blobs *in_cblobs)
865 struct tevent_req *req = NULL, *subreq = NULL;
866 struct cli_smb2_rmdir_state *state = NULL;
868 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_rmdir_state);
874 state->dname = dname;
875 state->in_cblobs = in_cblobs;
877 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
878 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
879 return tevent_req_post(req, ev);
882 subreq = cli_smb2_create_fnum_send(
887 0, /* create_flags */
888 SMB2_IMPERSONATION_IMPERSONATION,
889 DELETE_ACCESS, /* desired_access */
890 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
891 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
892 FILE_OPEN, /* create_disposition */
893 FILE_DIRECTORY_FILE, /* create_options */
894 state->in_cblobs); /* in_cblobs */
895 if (tevent_req_nomem(subreq, req)) {
896 return tevent_req_post(req, ev);
898 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened1, req);
902 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq)
904 struct tevent_req *req = tevent_req_callback_data(
905 subreq, struct tevent_req);
906 struct cli_smb2_rmdir_state *state = tevent_req_data(
907 req, struct cli_smb2_rmdir_state);
910 status = cli_smb2_create_fnum_recv(
911 subreq, &state->fnum, NULL, NULL, NULL);
914 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
916 * Naive option to match our SMB1 code. Assume the
917 * symlink path that tripped us up was the last
918 * component and try again. Eventually we will have to
919 * deal with the returned path unprocessed component. JRA.
921 subreq = cli_smb2_create_fnum_send(
926 0, /* create_flags */
927 SMB2_IMPERSONATION_IMPERSONATION,
928 DELETE_ACCESS, /* desired_access */
929 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
930 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
931 FILE_OPEN, /* create_disposition */
933 FILE_DELETE_ON_CLOSE|
934 FILE_OPEN_REPARSE_POINT, /* create_options */
935 state->in_cblobs); /* in_cblobs */
936 if (tevent_req_nomem(subreq, req)) {
939 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened2, req);
943 if (tevent_req_nterror(req, status)) {
947 subreq = cli_smb2_delete_on_close_send(
948 state, state->ev, state->cli, state->fnum, true);
949 if (tevent_req_nomem(subreq, req)) {
952 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
955 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq)
957 struct tevent_req *req = tevent_req_callback_data(
958 subreq, struct tevent_req);
959 struct cli_smb2_rmdir_state *state = tevent_req_data(
960 req, struct cli_smb2_rmdir_state);
963 status = cli_smb2_create_fnum_recv(
964 subreq, &state->fnum, NULL, NULL, NULL);
966 if (tevent_req_nterror(req, status)) {
970 subreq = cli_smb2_delete_on_close_send(
971 state, state->ev, state->cli, state->fnum, true);
972 if (tevent_req_nomem(subreq, req)) {
975 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
978 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq)
980 struct tevent_req *req = tevent_req_callback_data(
981 subreq, struct tevent_req);
982 struct cli_smb2_rmdir_state *state = tevent_req_data(
983 req, struct cli_smb2_rmdir_state);
985 state->status = cli_smb2_delete_on_close_recv(subreq);
989 * Close the fd even if the set_disp failed
992 subreq = cli_smb2_close_fnum_send(
993 state, state->ev, state->cli, state->fnum);
994 if (tevent_req_nomem(subreq, req)) {
997 tevent_req_set_callback(subreq, cli_smb2_rmdir_closed, req);
1000 static void cli_smb2_rmdir_closed(struct tevent_req *subreq)
1002 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1003 tevent_req_simple_finish_ntstatus(subreq, status);
1006 NTSTATUS cli_smb2_rmdir_recv(struct tevent_req *req)
1008 struct cli_smb2_rmdir_state *state = tevent_req_data(
1009 req, struct cli_smb2_rmdir_state);
1012 if (tevent_req_is_nterror(req, &status)) {
1015 return state->status;
1018 /***************************************************************
1019 Small wrapper that allows SMB2 to unlink a pathname.
1020 ***************************************************************/
1022 struct cli_smb2_unlink_state {
1023 struct tevent_context *ev;
1024 struct cli_state *cli;
1026 const struct smb2_create_blobs *in_cblobs;
1029 static void cli_smb2_unlink_opened1(struct tevent_req *subreq);
1030 static void cli_smb2_unlink_opened2(struct tevent_req *subreq);
1031 static void cli_smb2_unlink_closed(struct tevent_req *subreq);
1033 struct tevent_req *cli_smb2_unlink_send(
1034 TALLOC_CTX *mem_ctx,
1035 struct tevent_context *ev,
1036 struct cli_state *cli,
1038 const struct smb2_create_blobs *in_cblobs)
1040 struct tevent_req *req = NULL, *subreq = NULL;
1041 struct cli_smb2_unlink_state *state = NULL;
1043 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_unlink_state);
1049 state->fname = fname;
1050 state->in_cblobs = in_cblobs;
1052 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1053 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1054 return tevent_req_post(req, ev);
1057 subreq = cli_smb2_create_fnum_send(
1058 state, /* mem_ctx */
1059 state->ev, /* tevent_context */
1060 state->cli, /* cli_struct */
1061 state->fname, /* filename */
1062 0, /* create_flags */
1063 SMB2_IMPERSONATION_IMPERSONATION,
1064 DELETE_ACCESS, /* desired_access */
1065 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1068 FILE_SHARE_DELETE, /* share_access */
1069 FILE_OPEN, /* create_disposition */
1070 FILE_DELETE_ON_CLOSE, /* create_options */
1071 state->in_cblobs); /* in_cblobs */
1072 if (tevent_req_nomem(subreq, req)) {
1073 return tevent_req_post(req, ev);
1075 tevent_req_set_callback(subreq, cli_smb2_unlink_opened1, req);
1079 static void cli_smb2_unlink_opened1(struct tevent_req *subreq)
1081 struct tevent_req *req = tevent_req_callback_data(
1082 subreq, struct tevent_req);
1083 struct cli_smb2_unlink_state *state = tevent_req_data(
1084 req, struct cli_smb2_unlink_state);
1088 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1089 TALLOC_FREE(subreq);
1091 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1093 * Naive option to match our SMB1 code. Assume the
1094 * symlink path that tripped us up was the last
1095 * component and try again. Eventually we will have to
1096 * deal with the returned path unprocessed component. JRA.
1098 subreq = cli_smb2_create_fnum_send(
1099 state, /* mem_ctx */
1100 state->ev, /* tevent_context */
1101 state->cli, /* cli_struct */
1102 state->fname, /* filename */
1103 0, /* create_flags */
1104 SMB2_IMPERSONATION_IMPERSONATION,
1105 DELETE_ACCESS, /* desired_access */
1106 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1109 FILE_SHARE_DELETE, /* share_access */
1110 FILE_OPEN, /* create_disposition */
1111 FILE_DELETE_ON_CLOSE|
1112 FILE_OPEN_REPARSE_POINT, /* create_options */
1113 state->in_cblobs); /* in_cblobs */
1114 if (tevent_req_nomem(subreq, req)) {
1117 tevent_req_set_callback(subreq, cli_smb2_unlink_opened2, req);
1121 if (tevent_req_nterror(req, status)) {
1125 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1126 if (tevent_req_nomem(subreq, req)) {
1129 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1132 static void cli_smb2_unlink_opened2(struct tevent_req *subreq)
1134 struct tevent_req *req = tevent_req_callback_data(
1135 subreq, struct tevent_req);
1136 struct cli_smb2_unlink_state *state = tevent_req_data(
1137 req, struct cli_smb2_unlink_state);
1141 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1142 TALLOC_FREE(subreq);
1143 if (tevent_req_nterror(req, status)) {
1147 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1148 if (tevent_req_nomem(subreq, req)) {
1151 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1154 static void cli_smb2_unlink_closed(struct tevent_req *subreq)
1156 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1157 tevent_req_simple_finish_ntstatus(subreq, status);
1160 NTSTATUS cli_smb2_unlink_recv(struct tevent_req *req)
1162 return tevent_req_simple_recv_ntstatus(req);
1165 /***************************************************************
1166 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1167 ***************************************************************/
1169 static NTSTATUS parse_finfo_id_both_directory_info(const uint8_t *dir_data,
1170 uint32_t dir_data_length,
1171 struct file_info *finfo,
1172 uint32_t *next_offset)
1178 if (dir_data_length < 4) {
1179 return NT_STATUS_INFO_LENGTH_MISMATCH;
1182 *next_offset = IVAL(dir_data, 0);
1184 if (*next_offset > dir_data_length) {
1185 return NT_STATUS_INFO_LENGTH_MISMATCH;
1188 if (*next_offset != 0) {
1189 /* Ensure we only read what in this record. */
1190 dir_data_length = *next_offset;
1193 if (dir_data_length < 105) {
1194 return NT_STATUS_INFO_LENGTH_MISMATCH;
1197 finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
1198 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
1199 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
1200 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
1201 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
1202 finfo->allocated_size = IVAL2_TO_SMB_BIG_UINT(dir_data + 48, 0);
1203 finfo->attr = IVAL(dir_data + 56, 0);
1204 finfo->ino = IVAL2_TO_SMB_BIG_UINT(dir_data + 96, 0);
1205 namelen = IVAL(dir_data + 60,0);
1206 if (namelen > (dir_data_length - 104)) {
1207 return NT_STATUS_INFO_LENGTH_MISMATCH;
1209 slen = CVAL(dir_data + 68, 0);
1211 return NT_STATUS_INFO_LENGTH_MISMATCH;
1213 ret = pull_string_talloc(finfo,
1215 FLAGS2_UNICODE_STRINGS,
1220 if (ret == (size_t)-1) {
1221 /* Bad conversion. */
1222 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1225 ret = pull_string_talloc(finfo,
1227 FLAGS2_UNICODE_STRINGS,
1232 if (ret == (size_t)-1) {
1233 /* Bad conversion. */
1234 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1237 if (finfo->name == NULL) {
1238 /* Bad conversion. */
1239 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1242 return NT_STATUS_OK;
1245 /*******************************************************************
1246 Given a filename - get its directory name
1247 ********************************************************************/
1249 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
1257 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
1260 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
1271 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
1274 (*parent)[len] = '\0';
1282 /***************************************************************
1283 Wrapper that allows SMB2 to list a directory.
1285 ***************************************************************/
1287 NTSTATUS cli_smb2_list(struct cli_state *cli,
1288 const char *pathname,
1290 NTSTATUS (*fn)(struct file_info *finfo,
1292 void *private_data),
1296 uint16_t fnum = 0xffff;
1297 char *parent_dir = NULL;
1298 const char *mask = NULL;
1299 struct smb2_hnd *ph = NULL;
1300 bool processed_file = false;
1301 TALLOC_CTX *frame = talloc_stackframe();
1302 TALLOC_CTX *subframe = NULL;
1305 uint32_t max_avail_len;
1308 if (smbXcli_conn_has_async_calls(cli->conn)) {
1310 * Can't use sync call while an async call is in flight
1312 status = NT_STATUS_INVALID_PARAMETER;
1316 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1317 status = NT_STATUS_INVALID_PARAMETER;
1321 /* Get the directory name. */
1322 if (!windows_parent_dirname(frame,
1326 status = NT_STATUS_NO_MEMORY;
1330 mask_has_wild = ms_has_wild(mask);
1332 status = cli_smb2_create_fnum(cli,
1334 0, /* create_flags */
1335 SMB2_IMPERSONATION_IMPERSONATION,
1336 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
1337 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1338 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
1339 FILE_OPEN, /* create_disposition */
1340 FILE_DIRECTORY_FILE, /* create_options */
1347 if (!NT_STATUS_IS_OK(status)) {
1351 status = map_fnum_to_smb2_handle(cli,
1354 if (!NT_STATUS_IS_OK(status)) {
1359 * ideally, use the max transaction size, but don't send a request
1360 * bigger than we have credits available for
1362 max_trans = smb2cli_conn_max_trans_size(cli->conn);
1363 ok = smb2cli_conn_req_possible(cli->conn, &max_avail_len);
1365 max_trans = MIN(max_trans, max_avail_len);
1369 uint8_t *dir_data = NULL;
1370 uint32_t dir_data_length = 0;
1371 uint32_t next_offset = 0;
1372 subframe = talloc_stackframe();
1374 status = smb2cli_query_directory(cli->conn,
1378 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
1389 if (!NT_STATUS_IS_OK(status)) {
1390 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1397 struct file_info *finfo = talloc_zero(subframe,
1400 if (finfo == NULL) {
1401 status = NT_STATUS_NO_MEMORY;
1405 status = parse_finfo_id_both_directory_info(dir_data,
1410 if (!NT_STATUS_IS_OK(status)) {
1414 /* Protect against server attack. */
1415 status = is_bad_finfo_name(cli, finfo);
1416 if (!NT_STATUS_IS_OK(status)) {
1417 smbXcli_conn_disconnect(cli->conn, status);
1421 if (dir_check_ftype(finfo->attr, attribute)) {
1423 * Only process if attributes match.
1424 * SMB1 servers do the filtering, so
1425 * with SMB2 we need to emulate it in
1428 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1430 processed_file = true;
1437 if (!NT_STATUS_IS_OK(status)) {
1444 /* Move to next entry. */
1446 dir_data += next_offset;
1447 dir_data_length -= next_offset;
1449 } while (next_offset != 0);
1451 TALLOC_FREE(subframe);
1453 if (!mask_has_wild) {
1455 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1456 * when handed a non-wildcard path. Do it
1457 * for the server (with a non-wildcard path
1458 * there should only ever be one file returned.
1460 status = STATUS_NO_MORE_FILES;
1464 } while (NT_STATUS_IS_OK(status));
1466 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1467 status = NT_STATUS_OK;
1470 if (NT_STATUS_IS_OK(status) && !processed_file) {
1472 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1473 * if no files match. Emulate this in the client.
1475 status = NT_STATUS_NO_SUCH_FILE;
1480 if (fnum != 0xffff) {
1481 cli_smb2_close_fnum(cli, fnum);
1484 cli->raw_status = status;
1486 TALLOC_FREE(subframe);
1491 /***************************************************************
1492 Wrapper that allows SMB2 to query a path info (basic level).
1494 ***************************************************************/
1496 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1498 SMB_STRUCT_STAT *sbuf,
1499 uint32_t *attributes)
1502 struct smb_create_returns cr;
1503 uint16_t fnum = 0xffff;
1504 size_t namelen = strlen(name);
1506 if (smbXcli_conn_has_async_calls(cli->conn)) {
1508 * Can't use sync call while an async call is in flight
1510 return NT_STATUS_INVALID_PARAMETER;
1513 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1514 return NT_STATUS_INVALID_PARAMETER;
1517 /* SMB2 is pickier about pathnames. Ensure it doesn't
1519 if (namelen > 0 && name[namelen-1] == '\\') {
1520 char *modname = talloc_strndup(talloc_tos(), name, namelen-1);
1521 if (modname == NULL) {
1522 return NT_STATUS_NO_MEMORY;
1527 /* This is commonly used as a 'cd'. Try qpathinfo on
1528 a directory handle first. */
1530 status = cli_smb2_create_fnum(cli,
1532 0, /* create_flags */
1533 SMB2_IMPERSONATION_IMPERSONATION,
1534 FILE_READ_ATTRIBUTES, /* desired_access */
1535 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1536 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1537 FILE_OPEN, /* create_disposition */
1538 FILE_DIRECTORY_FILE, /* create_options */
1545 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1546 /* Maybe a file ? */
1547 status = cli_smb2_create_fnum(cli,
1549 0, /* create_flags */
1550 SMB2_IMPERSONATION_IMPERSONATION,
1551 FILE_READ_ATTRIBUTES, /* desired_access */
1552 0, /* file attributes */
1553 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1554 FILE_OPEN, /* create_disposition */
1555 0, /* create_options */
1563 if (!NT_STATUS_IS_OK(status)) {
1567 status = cli_smb2_close_fnum(cli, fnum);
1571 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1572 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1573 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1574 sbuf->st_ex_size = cr.end_of_file;
1575 *attributes = cr.file_attributes;
1580 struct cli_smb2_chkpath_state {
1581 struct tevent_context *ev;
1582 struct cli_state *cli;
1585 static void cli_smb2_chkpath_opened(struct tevent_req *subreq);
1586 static void cli_smb2_chkpath_closed(struct tevent_req *subreq);
1588 struct tevent_req *cli_smb2_chkpath_send(
1589 TALLOC_CTX *mem_ctx,
1590 struct tevent_context *ev,
1591 struct cli_state *cli,
1594 struct tevent_req *req = NULL, *subreq = NULL;
1595 struct cli_smb2_chkpath_state *state = NULL;
1597 req = tevent_req_create(
1598 mem_ctx, &state, struct cli_smb2_chkpath_state);
1605 /* Ensure this is a directory. */
1606 subreq = cli_smb2_create_fnum_send(
1607 state, /* mem_ctx */
1611 0, /* create_flags */
1612 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level */
1613 FILE_READ_ATTRIBUTES, /* desired_access */
1614 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
1617 FILE_SHARE_DELETE, /* share_access */
1618 FILE_OPEN, /* create_disposition */
1619 FILE_DIRECTORY_FILE, /* create_options */
1620 NULL); /* in_cblobs */
1621 if (tevent_req_nomem(subreq, req)) {
1622 return tevent_req_post(req, ev);
1624 tevent_req_set_callback(subreq, cli_smb2_chkpath_opened, req);
1628 static void cli_smb2_chkpath_opened(struct tevent_req *subreq)
1630 struct tevent_req *req = tevent_req_callback_data(
1631 subreq, struct tevent_req);
1632 struct cli_smb2_chkpath_state *state = tevent_req_data(
1633 req, struct cli_smb2_chkpath_state);
1637 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1638 TALLOC_FREE(subreq);
1639 if (tevent_req_nterror(req, status)) {
1643 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1644 if (tevent_req_nomem(subreq, req)) {
1647 tevent_req_set_callback(subreq, cli_smb2_chkpath_closed, req);
1650 static void cli_smb2_chkpath_closed(struct tevent_req *subreq)
1652 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1653 tevent_req_simple_finish_ntstatus(subreq, status);
1656 NTSTATUS cli_smb2_chkpath_recv(struct tevent_req *req)
1658 return tevent_req_simple_recv_ntstatus(req);
1661 struct cli_smb2_query_info_fnum_state {
1665 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq);
1667 struct tevent_req *cli_smb2_query_info_fnum_send(
1668 TALLOC_CTX *mem_ctx,
1669 struct tevent_context *ev,
1670 struct cli_state *cli,
1672 uint8_t in_info_type,
1673 uint8_t in_info_class,
1674 uint32_t in_max_output_length,
1675 const DATA_BLOB *in_input_buffer,
1676 uint32_t in_additional_info,
1679 struct tevent_req *req = NULL, *subreq = NULL;
1680 struct cli_smb2_query_info_fnum_state *state = NULL;
1681 struct smb2_hnd *ph = NULL;
1684 req = tevent_req_create(
1685 mem_ctx, &state, struct cli_smb2_query_info_fnum_state);
1690 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1691 if (tevent_req_nterror(req, status)) {
1692 return tevent_req_post(req, ev);
1695 subreq = smb2cli_query_info_send(
1704 in_max_output_length,
1710 if (tevent_req_nomem(subreq, req)) {
1711 return tevent_req_post(req, ev);
1713 tevent_req_set_callback(subreq, cli_smb2_query_info_fnum_done, req);
1717 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq)
1719 struct tevent_req *req = tevent_req_callback_data(
1720 subreq, struct tevent_req);
1721 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1722 req, struct cli_smb2_query_info_fnum_state);
1726 status = smb2cli_query_info_recv(subreq, state, &outbuf);
1727 TALLOC_FREE(subreq);
1728 if (tevent_req_nterror(req, status)) {
1733 * We have to dup the memory here because outbuf.data is not
1734 * returned as a talloc object by smb2cli_query_info_recv.
1735 * It's a pointer into the received buffer.
1737 state->outbuf = data_blob_dup_talloc(state, outbuf);
1739 if ((outbuf.length != 0) &&
1740 tevent_req_nomem(state->outbuf.data, req)) {
1743 tevent_req_done(req);
1746 NTSTATUS cli_smb2_query_info_fnum_recv(
1747 struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *outbuf)
1749 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1750 req, struct cli_smb2_query_info_fnum_state);
1753 if (tevent_req_is_nterror(req, &status)) {
1756 *outbuf = (DATA_BLOB) {
1757 .data = talloc_move(mem_ctx, &state->outbuf.data),
1758 .length = state->outbuf.length,
1760 return NT_STATUS_OK;
1763 NTSTATUS cli_smb2_query_info_fnum(
1764 struct cli_state *cli,
1766 uint8_t in_info_type,
1767 uint8_t in_info_class,
1768 uint32_t in_max_output_length,
1769 const DATA_BLOB *in_input_buffer,
1770 uint32_t in_additional_info,
1772 TALLOC_CTX *mem_ctx,
1775 TALLOC_CTX *frame = talloc_stackframe();
1776 struct tevent_context *ev = NULL;
1777 struct tevent_req *req = NULL;
1778 NTSTATUS status = NT_STATUS_NO_MEMORY;
1781 if (smbXcli_conn_has_async_calls(cli->conn)) {
1783 * Can't use sync call while an async call is in flight
1785 status = NT_STATUS_INVALID_PARAMETER;
1788 ev = samba_tevent_context_init(frame);
1792 req = cli_smb2_query_info_fnum_send(
1799 in_max_output_length,
1806 ok = tevent_req_poll_ntstatus(req, ev, &status);
1810 status = cli_smb2_query_info_fnum_recv(req, mem_ctx, outbuf);
1816 /***************************************************************
1817 Helper function for pathname operations.
1818 ***************************************************************/
1820 struct get_fnum_from_path_state {
1821 struct tevent_context *ev;
1822 struct cli_state *cli;
1824 uint32_t desired_access;
1828 static void get_fnum_from_path_opened_file(struct tevent_req *subreq);
1829 static void get_fnum_from_path_opened_reparse(struct tevent_req *subreq);
1830 static void get_fnum_from_path_opened_dir(struct tevent_req *subreq);
1832 static struct tevent_req *get_fnum_from_path_send(
1833 TALLOC_CTX *mem_ctx,
1834 struct tevent_context *ev,
1835 struct cli_state *cli,
1837 uint32_t desired_access)
1839 struct tevent_req *req = NULL, *subreq = NULL;
1840 struct get_fnum_from_path_state *state = NULL;
1841 size_t namelen = strlen(name);
1843 req = tevent_req_create(
1844 mem_ctx, &state, struct get_fnum_from_path_state);
1851 state->desired_access = desired_access;
1854 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
1857 if (namelen > 0 && name[namelen-1] == '\\') {
1858 state->name = talloc_strndup(state, name, namelen-1);
1859 if (tevent_req_nomem(state->name, req)) {
1860 return tevent_req_post(req, ev);
1864 subreq = cli_smb2_create_fnum_send(
1865 state, /* mem_ctx, */
1868 state->name, /* fname */
1869 0, /* create_flags */
1870 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level */
1871 desired_access, /* desired_access */
1872 0, /* file_attributes */
1875 FILE_SHARE_DELETE, /* share_access */
1876 FILE_OPEN, /* create_disposition */
1877 0, /* create_options */
1878 NULL); /* in_cblobs */
1879 if (tevent_req_nomem(subreq, req)) {
1880 return tevent_req_post(req, ev);
1882 tevent_req_set_callback(subreq, get_fnum_from_path_opened_file, req);
1886 static void get_fnum_from_path_opened_file(struct tevent_req *subreq)
1888 struct tevent_req *req = tevent_req_callback_data(
1889 subreq, struct tevent_req);
1890 struct get_fnum_from_path_state *state = tevent_req_data(
1891 req, struct get_fnum_from_path_state);
1894 status = cli_smb2_create_fnum_recv(
1895 subreq, &state->fnum, NULL, NULL, NULL);
1896 TALLOC_FREE(subreq);
1898 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1900 * Naive option to match our SMB1 code. Assume the
1901 * symlink path that tripped us up was the last
1902 * component and try again. Eventually we will have to
1903 * deal with the returned path unprocessed component. JRA.
1905 subreq = cli_smb2_create_fnum_send(
1906 state, /* mem_ctx, */
1908 state->cli, /* cli */
1909 state->name, /* fname */
1910 0, /* create_flags */
1911 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation */
1912 state->desired_access, /* desired_access */
1913 0, /* file_attributes */
1916 FILE_SHARE_DELETE, /* share_access */
1917 FILE_OPEN, /* create_disposition */
1918 FILE_OPEN_REPARSE_POINT, /* create_options */
1919 NULL); /* in_cblobs */
1920 if (tevent_req_nomem(subreq, req)) {
1923 tevent_req_set_callback(
1924 subreq, get_fnum_from_path_opened_reparse, req);
1928 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1929 subreq = cli_smb2_create_fnum_send(
1930 state, /* mem_ctx, */
1932 state->cli, /* cli */
1933 state->name, /* fname */
1934 0, /* create_flags */
1935 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation */
1936 state->desired_access, /* desired_access */
1937 0, /* file_attributes */
1940 FILE_SHARE_DELETE, /* share_access */
1941 FILE_OPEN, /* create_disposition */
1942 FILE_DIRECTORY_FILE, /* create_options */
1943 NULL); /* in_cblobs */
1944 if (tevent_req_nomem(subreq, req)) {
1947 tevent_req_set_callback(
1948 subreq, get_fnum_from_path_opened_dir, req);
1952 if (tevent_req_nterror(req, status)) {
1955 tevent_req_done(req);
1958 static void get_fnum_from_path_opened_reparse(struct tevent_req *subreq)
1960 struct tevent_req *req = tevent_req_callback_data(
1961 subreq, struct tevent_req);
1962 struct get_fnum_from_path_state *state = tevent_req_data(
1963 req, struct get_fnum_from_path_state);
1964 NTSTATUS status = cli_smb2_create_fnum_recv(
1965 subreq, &state->fnum, NULL, NULL, NULL);
1966 tevent_req_simple_finish_ntstatus(subreq, status);
1969 static void get_fnum_from_path_opened_dir(struct tevent_req *subreq)
1971 /* Abstraction violation, but these two are just the same... */
1972 get_fnum_from_path_opened_reparse(subreq);
1975 static NTSTATUS get_fnum_from_path_recv(
1976 struct tevent_req *req, uint16_t *pfnum)
1978 struct get_fnum_from_path_state *state = tevent_req_data(
1979 req, struct get_fnum_from_path_state);
1980 NTSTATUS status = NT_STATUS_OK;
1982 if (!tevent_req_is_nterror(req, &status)) {
1983 *pfnum = state->fnum;
1985 tevent_req_received(req);
1989 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1991 uint32_t desired_access,
1994 TALLOC_CTX *frame = talloc_stackframe();
1995 struct tevent_context *ev = NULL;
1996 struct tevent_req *req = NULL;
1997 NTSTATUS status = NT_STATUS_NO_MEMORY;
1999 if (smbXcli_conn_has_async_calls(cli->conn)) {
2000 status = NT_STATUS_INVALID_PARAMETER;
2003 ev = samba_tevent_context_init(frame);
2007 req = get_fnum_from_path_send(frame, ev, cli, name, desired_access);
2011 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2014 status = get_fnum_from_path_recv(req, pfnum);
2020 /***************************************************************
2021 Wrapper that allows SMB2 to query a path info (ALTNAME level).
2023 ***************************************************************/
2025 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
2030 DATA_BLOB outbuf = data_blob_null;
2031 uint16_t fnum = 0xffff;
2032 uint32_t altnamelen = 0;
2033 TALLOC_CTX *frame = talloc_stackframe();
2035 if (smbXcli_conn_has_async_calls(cli->conn)) {
2037 * Can't use sync call while an async call is in flight
2039 status = NT_STATUS_INVALID_PARAMETER;
2043 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2044 status = NT_STATUS_INVALID_PARAMETER;
2048 status = get_fnum_from_path(cli,
2050 FILE_READ_ATTRIBUTES,
2053 if (!NT_STATUS_IS_OK(status)) {
2057 status = cli_smb2_query_info_fnum(
2060 1, /* in_info_type */
2061 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
2062 0xFFFF, /* in_max_output_length */
2063 NULL, /* in_input_buffer */
2064 0, /* in_additional_info */
2069 if (!NT_STATUS_IS_OK(status)) {
2073 /* Parse the reply. */
2074 if (outbuf.length < 4) {
2075 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2079 altnamelen = IVAL(outbuf.data, 0);
2080 if (altnamelen > outbuf.length - 4) {
2081 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2085 if (altnamelen > 0) {
2087 char *short_name = NULL;
2088 ret = pull_string_talloc(frame,
2090 FLAGS2_UNICODE_STRINGS,
2095 if (ret == (size_t)-1) {
2096 /* Bad conversion. */
2097 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2101 fstrcpy(alt_name, short_name);
2106 status = NT_STATUS_OK;
2110 if (fnum != 0xffff) {
2111 cli_smb2_close_fnum(cli, fnum);
2114 cli->raw_status = status;
2120 /***************************************************************
2121 Wrapper that allows SMB2 to get pathname attributes.
2123 ***************************************************************/
2125 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
2132 uint16_t fnum = 0xffff;
2133 struct smb2_hnd *ph = NULL;
2134 struct timespec write_time_ts;
2135 TALLOC_CTX *frame = talloc_stackframe();
2137 if (smbXcli_conn_has_async_calls(cli->conn)) {
2139 * Can't use sync call while an async call is in flight
2141 status = NT_STATUS_INVALID_PARAMETER;
2145 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2146 status = NT_STATUS_INVALID_PARAMETER;
2150 status = get_fnum_from_path(cli,
2152 FILE_READ_ATTRIBUTES,
2155 if (!NT_STATUS_IS_OK(status)) {
2159 status = map_fnum_to_smb2_handle(cli,
2162 if (!NT_STATUS_IS_OK(status)) {
2165 status = cli_qfileinfo_basic(
2170 NULL, /* create_time */
2171 NULL, /* access_time */
2173 NULL, /* change_time */
2175 if (!NT_STATUS_IS_OK(status)) {
2178 if (write_time != NULL) {
2179 *write_time = write_time_ts.tv_sec;
2184 if (fnum != 0xffff) {
2185 cli_smb2_close_fnum(cli, fnum);
2188 cli->raw_status = status;
2194 /***************************************************************
2195 Wrapper that allows SMB2 to query a pathname info (basic level).
2196 Implement on top of cli_qfileinfo_basic().
2198 ***************************************************************/
2200 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
2202 struct timespec *create_time,
2203 struct timespec *access_time,
2204 struct timespec *write_time,
2205 struct timespec *change_time,
2211 struct smb2_hnd *ph = NULL;
2212 uint16_t fnum = 0xffff;
2213 TALLOC_CTX *frame = talloc_stackframe();
2215 if (smbXcli_conn_has_async_calls(cli->conn)) {
2217 * Can't use sync call while an async call is in flight
2219 status = NT_STATUS_INVALID_PARAMETER;
2223 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2224 status = NT_STATUS_INVALID_PARAMETER;
2228 status = get_fnum_from_path(cli,
2230 FILE_READ_ATTRIBUTES,
2233 if (!NT_STATUS_IS_OK(status)) {
2237 status = map_fnum_to_smb2_handle(cli,
2240 if (!NT_STATUS_IS_OK(status)) {
2244 status = cli_qfileinfo_basic(
2257 if (fnum != 0xffff) {
2258 cli_smb2_close_fnum(cli, fnum);
2261 cli->raw_status = status;
2267 /***************************************************************
2268 Wrapper that allows SMB2 to query pathname streams.
2270 ***************************************************************/
2272 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
2274 TALLOC_CTX *mem_ctx,
2275 unsigned int *pnum_streams,
2276 struct stream_struct **pstreams)
2279 uint16_t fnum = 0xffff;
2280 DATA_BLOB outbuf = data_blob_null;
2281 TALLOC_CTX *frame = talloc_stackframe();
2283 if (smbXcli_conn_has_async_calls(cli->conn)) {
2285 * Can't use sync call while an async call is in flight
2287 status = NT_STATUS_INVALID_PARAMETER;
2291 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2292 status = NT_STATUS_INVALID_PARAMETER;
2296 status = get_fnum_from_path(cli,
2298 FILE_READ_ATTRIBUTES,
2301 if (!NT_STATUS_IS_OK(status)) {
2305 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2306 level 22 (SMB2_FILE_STREAM_INFORMATION). */
2308 status = cli_smb2_query_info_fnum(
2311 1, /* in_info_type */
2312 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
2313 0xFFFF, /* in_max_output_length */
2314 NULL, /* in_input_buffer */
2315 0, /* in_additional_info */
2320 if (!NT_STATUS_IS_OK(status)) {
2324 /* Parse the reply. */
2325 if (!parse_streams_blob(mem_ctx,
2330 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2336 if (fnum != 0xffff) {
2337 cli_smb2_close_fnum(cli, fnum);
2340 cli->raw_status = status;
2346 /***************************************************************
2347 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2350 ***************************************************************/
2352 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
2354 uint8_t in_info_type,
2355 uint8_t in_file_info_class,
2356 const DATA_BLOB *p_in_data)
2359 uint16_t fnum = 0xffff;
2360 TALLOC_CTX *frame = talloc_stackframe();
2362 if (smbXcli_conn_has_async_calls(cli->conn)) {
2364 * Can't use sync call while an async call is in flight
2366 status = NT_STATUS_INVALID_PARAMETER;
2370 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2371 status = NT_STATUS_INVALID_PARAMETER;
2375 status = get_fnum_from_path(cli,
2377 FILE_WRITE_ATTRIBUTES,
2380 if (!NT_STATUS_IS_OK(status)) {
2384 status = cli_smb2_set_info_fnum(
2389 p_in_data, /* in_input_buffer */
2390 0); /* in_additional_info */
2393 if (fnum != 0xffff) {
2394 cli_smb2_close_fnum(cli, fnum);
2397 cli->raw_status = status;
2404 /***************************************************************
2405 Wrapper that allows SMB2 to set pathname attributes.
2407 ***************************************************************/
2409 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
2414 uint8_t inbuf_store[40];
2415 DATA_BLOB inbuf = data_blob_null;
2417 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2418 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2420 inbuf.data = inbuf_store;
2421 inbuf.length = sizeof(inbuf_store);
2422 data_blob_clear(&inbuf);
2425 * SMB1 uses attr == 0 to clear all attributes
2426 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2427 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2428 * request attribute change.
2430 * SMB2 uses exactly the reverse. Unfortunately as the
2431 * cli_setatr() ABI is exposed inside libsmbclient,
2432 * we must make the SMB2 cli_smb2_setatr() call
2433 * export the same ABI as the SMB1 cli_setatr()
2434 * which calls it. This means reversing the sense
2435 * of the requested attr argument if it's zero
2436 * or FILE_ATTRIBUTE_NORMAL.
2438 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2442 attr = FILE_ATTRIBUTE_NORMAL;
2443 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
2447 SIVAL(inbuf.data, 32, attr);
2449 put_long_date((char *)inbuf.data + 16,mtime);
2451 /* Set all the other times to -1. */
2452 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2453 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
2454 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
2456 return cli_smb2_setpathinfo(cli,
2458 1, /* in_info_type */
2459 /* in_file_info_class */
2460 SMB_FILE_BASIC_INFORMATION - 1000,
2465 /***************************************************************
2466 Wrapper that allows SMB2 to set file handle times.
2468 ***************************************************************/
2470 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
2476 uint8_t inbuf_store[40];
2477 DATA_BLOB inbuf = data_blob_null;
2479 if (smbXcli_conn_has_async_calls(cli->conn)) {
2481 * Can't use sync call while an async call is in flight
2483 return NT_STATUS_INVALID_PARAMETER;
2486 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2487 return NT_STATUS_INVALID_PARAMETER;
2490 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2491 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2493 inbuf.data = inbuf_store;
2494 inbuf.length = sizeof(inbuf_store);
2495 data_blob_clear(&inbuf);
2497 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2498 if (change_time != 0) {
2499 put_long_date((char *)inbuf.data + 24, change_time);
2501 if (access_time != 0) {
2502 put_long_date((char *)inbuf.data + 8, access_time);
2504 if (write_time != 0) {
2505 put_long_date((char *)inbuf.data + 16, write_time);
2508 cli->raw_status = cli_smb2_set_info_fnum(
2511 1, /* in_info_type */
2512 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
2513 &inbuf, /* in_input_buffer */
2514 0); /* in_additional_info */
2516 return cli->raw_status;
2519 /***************************************************************
2520 Wrapper that allows SMB2 to query disk attributes (size).
2522 ***************************************************************/
2524 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2525 uint64_t *bsize, uint64_t *total, uint64_t *avail)
2528 uint16_t fnum = 0xffff;
2529 DATA_BLOB outbuf = data_blob_null;
2530 uint32_t sectors_per_unit = 0;
2531 uint32_t bytes_per_sector = 0;
2532 uint64_t total_size = 0;
2533 uint64_t size_free = 0;
2534 TALLOC_CTX *frame = talloc_stackframe();
2536 if (smbXcli_conn_has_async_calls(cli->conn)) {
2538 * Can't use sync call while an async call is in flight
2540 status = NT_STATUS_INVALID_PARAMETER;
2544 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2545 status = NT_STATUS_INVALID_PARAMETER;
2549 /* First open the top level directory. */
2550 status = cli_smb2_create_fnum(cli,
2552 0, /* create_flags */
2553 SMB2_IMPERSONATION_IMPERSONATION,
2554 FILE_READ_ATTRIBUTES, /* desired_access */
2555 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2556 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2557 FILE_OPEN, /* create_disposition */
2558 FILE_DIRECTORY_FILE, /* create_options */
2565 if (!NT_STATUS_IS_OK(status)) {
2569 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2570 level 3 (SMB_FS_SIZE_INFORMATION). */
2572 status = cli_smb2_query_info_fnum(
2575 2, /* in_info_type */
2576 3, /* in_file_info_class */
2577 0xFFFF, /* in_max_output_length */
2578 NULL, /* in_input_buffer */
2579 0, /* in_additional_info */
2583 if (!NT_STATUS_IS_OK(status)) {
2587 /* Parse the reply. */
2588 if (outbuf.length != 24) {
2589 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2593 total_size = BVAL(outbuf.data, 0);
2594 size_free = BVAL(outbuf.data, 8);
2595 sectors_per_unit = IVAL(outbuf.data, 16);
2596 bytes_per_sector = IVAL(outbuf.data, 20);
2599 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2602 *total = total_size;
2608 status = NT_STATUS_OK;
2612 if (fnum != 0xffff) {
2613 cli_smb2_close_fnum(cli, fnum);
2616 cli->raw_status = status;
2622 /***************************************************************
2623 Wrapper that allows SMB2 to query file system sizes.
2625 ***************************************************************/
2627 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2628 uint64_t *total_allocation_units,
2629 uint64_t *caller_allocation_units,
2630 uint64_t *actual_allocation_units,
2631 uint64_t *sectors_per_allocation_unit,
2632 uint64_t *bytes_per_sector)
2635 uint16_t fnum = 0xffff;
2636 DATA_BLOB outbuf = data_blob_null;
2637 TALLOC_CTX *frame = talloc_stackframe();
2639 if (smbXcli_conn_has_async_calls(cli->conn)) {
2641 * Can't use sync call while an async call is in flight
2643 status = NT_STATUS_INVALID_PARAMETER;
2647 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2648 status = NT_STATUS_INVALID_PARAMETER;
2652 /* First open the top level directory. */
2654 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2655 SMB2_IMPERSONATION_IMPERSONATION,
2656 FILE_READ_ATTRIBUTES, /* desired_access */
2657 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2658 FILE_SHARE_READ | FILE_SHARE_WRITE |
2659 FILE_SHARE_DELETE, /* share_access */
2660 FILE_OPEN, /* create_disposition */
2661 FILE_DIRECTORY_FILE, /* create_options */
2668 if (!NT_STATUS_IS_OK(status)) {
2672 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2673 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2675 status = cli_smb2_query_info_fnum(
2678 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2679 SMB_FS_FULL_SIZE_INFORMATION - 1000, /* in_file_info_class */
2680 0xFFFF, /* in_max_output_length */
2681 NULL, /* in_input_buffer */
2682 0, /* in_additional_info */
2686 if (!NT_STATUS_IS_OK(status)) {
2690 if (outbuf.length < 32) {
2691 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2695 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2696 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2697 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2698 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2699 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2703 if (fnum != 0xffff) {
2704 cli_smb2_close_fnum(cli, fnum);
2707 cli->raw_status = status;
2713 /***************************************************************
2714 Wrapper that allows SMB2 to query file system attributes.
2716 ***************************************************************/
2718 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2721 uint16_t fnum = 0xffff;
2722 DATA_BLOB outbuf = data_blob_null;
2723 TALLOC_CTX *frame = talloc_stackframe();
2725 if (smbXcli_conn_has_async_calls(cli->conn)) {
2727 * Can't use sync call while an async call is in flight
2729 status = NT_STATUS_INVALID_PARAMETER;
2733 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2734 status = NT_STATUS_INVALID_PARAMETER;
2738 /* First open the top level directory. */
2740 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2741 SMB2_IMPERSONATION_IMPERSONATION,
2742 FILE_READ_ATTRIBUTES, /* desired_access */
2743 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2744 FILE_SHARE_READ | FILE_SHARE_WRITE |
2745 FILE_SHARE_DELETE, /* share_access */
2746 FILE_OPEN, /* create_disposition */
2747 FILE_DIRECTORY_FILE, /* create_options */
2754 if (!NT_STATUS_IS_OK(status)) {
2758 status = cli_smb2_query_info_fnum(
2761 2, /* in_info_type */
2762 5, /* in_file_info_class */
2763 0xFFFF, /* in_max_output_length */
2764 NULL, /* in_input_buffer */
2765 0, /* in_additional_info */
2769 if (!NT_STATUS_IS_OK(status)) {
2773 if (outbuf.length < 12) {
2774 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2778 *fs_attr = IVAL(outbuf.data, 0);
2782 if (fnum != 0xffff) {
2783 cli_smb2_close_fnum(cli, fnum);
2786 cli->raw_status = status;
2792 /***************************************************************
2793 Wrapper that allows SMB2 to query file system volume info.
2795 ***************************************************************/
2797 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2798 TALLOC_CTX *mem_ctx,
2799 char **_volume_name,
2800 uint32_t *pserial_number,
2804 uint16_t fnum = 0xffff;
2805 DATA_BLOB outbuf = data_blob_null;
2807 char *volume_name = NULL;
2808 TALLOC_CTX *frame = talloc_stackframe();
2810 if (smbXcli_conn_has_async_calls(cli->conn)) {
2812 * Can't use sync call while an async call is in flight
2814 status = NT_STATUS_INVALID_PARAMETER;
2818 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2819 status = NT_STATUS_INVALID_PARAMETER;
2823 /* First open the top level directory. */
2825 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2826 SMB2_IMPERSONATION_IMPERSONATION,
2827 FILE_READ_ATTRIBUTES, /* desired_access */
2828 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2829 FILE_SHARE_READ | FILE_SHARE_WRITE |
2830 FILE_SHARE_DELETE, /* share_access */
2831 FILE_OPEN, /* create_disposition */
2832 FILE_DIRECTORY_FILE, /* create_options */
2839 if (!NT_STATUS_IS_OK(status)) {
2843 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2844 level 1 (SMB_FS_VOLUME_INFORMATION). */
2846 status = cli_smb2_query_info_fnum(
2849 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2850 /* in_file_info_class */
2851 SMB_FS_VOLUME_INFORMATION - 1000,
2852 0xFFFF, /* in_max_output_length */
2853 NULL, /* in_input_buffer */
2854 0, /* in_additional_info */
2858 if (!NT_STATUS_IS_OK(status)) {
2862 if (outbuf.length < 24) {
2863 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2869 ts = interpret_long_date((char *)outbuf.data);
2872 if (pserial_number) {
2873 *pserial_number = IVAL(outbuf.data,8);
2875 nlen = IVAL(outbuf.data,12);
2876 if (nlen + 18 < 18) {
2878 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2882 * The next check is safe as we know outbuf.length >= 24
2885 if (nlen > (outbuf.length - 18)) {
2886 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2890 pull_string_talloc(mem_ctx,
2891 (const char *)outbuf.data,
2897 if (volume_name == NULL) {
2898 status = map_nt_error_from_unix(errno);
2902 *_volume_name = volume_name;
2906 if (fnum != 0xffff) {
2907 cli_smb2_close_fnum(cli, fnum);
2910 cli->raw_status = status;
2916 struct cli_smb2_mxac_state {
2917 struct tevent_context *ev;
2918 struct cli_state *cli;
2920 struct smb2_create_blobs in_cblobs;
2926 static void cli_smb2_mxac_opened(struct tevent_req *subreq);
2927 static void cli_smb2_mxac_closed(struct tevent_req *subreq);
2929 struct tevent_req *cli_smb2_query_mxac_send(TALLOC_CTX *mem_ctx,
2930 struct tevent_context *ev,
2931 struct cli_state *cli,
2934 struct tevent_req *req = NULL, *subreq = NULL;
2935 struct cli_smb2_mxac_state *state = NULL;
2938 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_mxac_state);
2942 *state = (struct cli_smb2_mxac_state) {
2948 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2949 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2950 return tevent_req_post(req, ev);
2953 status = smb2_create_blob_add(state,
2955 SMB2_CREATE_TAG_MXAC,
2956 data_blob(NULL, 0));
2957 if (tevent_req_nterror(req, status)) {
2958 return tevent_req_post(req, ev);
2961 subreq = cli_smb2_create_fnum_send(
2966 0, /* create_flags */
2967 SMB2_IMPERSONATION_IMPERSONATION,
2968 FILE_READ_ATTRIBUTES,
2969 0, /* file attributes */
2970 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
2972 0, /* create_options */
2974 if (tevent_req_nomem(subreq, req)) {
2975 return tevent_req_post(req, ev);
2977 tevent_req_set_callback(subreq, cli_smb2_mxac_opened, req);
2981 static void cli_smb2_mxac_opened(struct tevent_req *subreq)
2983 struct tevent_req *req = tevent_req_callback_data(
2984 subreq, struct tevent_req);
2985 struct cli_smb2_mxac_state *state = tevent_req_data(
2986 req, struct cli_smb2_mxac_state);
2987 struct smb2_create_blobs out_cblobs = {0};
2988 struct smb2_create_blob *mxac_blob = NULL;
2991 status = cli_smb2_create_fnum_recv(
2992 subreq, &state->fnum, NULL, state, &out_cblobs);
2993 TALLOC_FREE(subreq);
2995 if (tevent_req_nterror(req, status)) {
2999 mxac_blob = smb2_create_blob_find(&out_cblobs, SMB2_CREATE_TAG_MXAC);
3000 if (mxac_blob == NULL) {
3001 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3004 if (mxac_blob->data.length != 8) {
3005 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3009 state->status = NT_STATUS(IVAL(mxac_blob->data.data, 0));
3010 state->mxac = IVAL(mxac_blob->data.data, 4);
3013 subreq = cli_smb2_close_fnum_send(
3014 state, state->ev, state->cli, state->fnum);
3015 if (tevent_req_nomem(subreq, req)) {
3018 tevent_req_set_callback(subreq, cli_smb2_mxac_closed, req);
3023 static void cli_smb2_mxac_closed(struct tevent_req *subreq)
3025 struct tevent_req *req = tevent_req_callback_data(
3026 subreq, struct tevent_req);
3029 status = cli_smb2_close_fnum_recv(subreq);
3030 if (tevent_req_nterror(req, status)) {
3034 tevent_req_done(req);
3037 NTSTATUS cli_smb2_query_mxac_recv(struct tevent_req *req, uint32_t *mxac)
3039 struct cli_smb2_mxac_state *state = tevent_req_data(
3040 req, struct cli_smb2_mxac_state);
3043 if (tevent_req_is_nterror(req, &status)) {
3047 if (!NT_STATUS_IS_OK(state->status)) {
3048 return state->status;
3051 *mxac = state->mxac;
3052 return NT_STATUS_OK;
3055 NTSTATUS cli_smb2_query_mxac(struct cli_state *cli,
3059 TALLOC_CTX *frame = talloc_stackframe();
3060 struct tevent_context *ev = NULL;
3061 struct tevent_req *req = NULL;
3062 NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
3065 if (smbXcli_conn_has_async_calls(cli->conn)) {
3067 * Can't use sync call while an async call is in flight
3069 status = NT_STATUS_INVALID_PARAMETER;
3073 ev = samba_tevent_context_init(frame);
3077 req = cli_smb2_query_mxac_send(frame, ev, cli, fname);
3081 ok = tevent_req_poll_ntstatus(req, ev, &status);
3085 status = cli_smb2_query_mxac_recv(req, _mxac);
3088 cli->raw_status = status;
3093 struct cli_smb2_rename_fnum_state {
3097 static void cli_smb2_rename_fnum_done(struct tevent_req *subreq);
3099 static struct tevent_req *cli_smb2_rename_fnum_send(
3100 TALLOC_CTX *mem_ctx,
3101 struct tevent_context *ev,
3102 struct cli_state *cli,
3104 const char *fname_dst,
3107 struct tevent_req *req = NULL, *subreq = NULL;
3108 struct cli_smb2_rename_fnum_state *state = NULL;
3109 size_t namelen = strlen(fname_dst);
3110 smb_ucs2_t *converted_str = NULL;
3111 size_t converted_size_bytes = 0;
3115 req = tevent_req_create(
3116 mem_ctx, &state, struct cli_smb2_rename_fnum_state);
3122 * SMB2 is pickier about pathnames. Ensure it doesn't start in
3125 if (*fname_dst == '\\') {
3130 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
3133 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
3134 fname_dst = talloc_strndup(state, fname_dst, namelen-1);
3135 if (tevent_req_nomem(fname_dst, req)) {
3136 return tevent_req_post(req, ev);
3140 ok = push_ucs2_talloc(
3141 state, &converted_str, fname_dst, &converted_size_bytes);
3143 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3144 return tevent_req_post(req, ev);
3148 * W2K8 insists the dest name is not null terminated. Remove
3149 * the last 2 zero bytes and reduce the name length.
3151 if (converted_size_bytes < 2) {
3152 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3153 return tevent_req_post(req, ev);
3155 converted_size_bytes -= 2;
3157 inbuf_size = 20 + converted_size_bytes;
3158 if (inbuf_size < 20) {
3159 /* Integer wrap check. */
3160 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3161 return tevent_req_post(req, ev);
3165 * The Windows 10 SMB2 server has a minimum length
3166 * for a SMB2_FILE_RENAME_INFORMATION buffer of
3167 * 24 bytes. It returns NT_STATUS_INFO_LENGTH_MISMATCH
3168 * if the length is less. This isn't an alignment
3169 * issue as Windows client happily 2-byte align
3170 * for larget target name sizes. Also the Windows 10
3171 * SMB1 server doesn't have this restriction.
3173 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14403
3175 inbuf_size = MAX(inbuf_size, 24);
3177 state->inbuf = data_blob_talloc_zero(state, inbuf_size);
3178 if (tevent_req_nomem(state->inbuf.data, req)) {
3179 return tevent_req_post(req, ev);
3183 SCVAL(state->inbuf.data, 0, 1);
3186 SIVAL(state->inbuf.data, 16, converted_size_bytes);
3187 memcpy(state->inbuf.data + 20, converted_str, converted_size_bytes);
3189 TALLOC_FREE(converted_str);
3191 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3192 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3194 subreq = cli_smb2_set_info_fnum_send(
3195 state, /* mem_ctx */
3199 1, /* in_info_type */
3200 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
3201 &state->inbuf, /* in_input_buffer */
3202 0); /* in_additional_info */
3203 if (tevent_req_nomem(subreq, req)) {
3204 return tevent_req_post(req, ev);
3206 tevent_req_set_callback(subreq, cli_smb2_rename_fnum_done, req);
3210 static void cli_smb2_rename_fnum_done(struct tevent_req *subreq)
3212 NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
3213 tevent_req_simple_finish_ntstatus(subreq, status);
3216 static NTSTATUS cli_smb2_rename_fnum_recv(struct tevent_req *req)
3218 return tevent_req_simple_recv_ntstatus(req);
3221 /***************************************************************
3222 Wrapper that allows SMB2 to rename a file.
3223 ***************************************************************/
3225 struct cli_smb2_rename_state {
3226 struct tevent_context *ev;
3227 struct cli_state *cli;
3228 const char *fname_dst;
3232 NTSTATUS rename_status;
3235 static void cli_smb2_rename_opened(struct tevent_req *subreq);
3236 static void cli_smb2_rename_renamed(struct tevent_req *subreq);
3237 static void cli_smb2_rename_closed(struct tevent_req *subreq);
3239 struct tevent_req *cli_smb2_rename_send(
3240 TALLOC_CTX *mem_ctx,
3241 struct tevent_context *ev,
3242 struct cli_state *cli,
3243 const char *fname_src,
3244 const char *fname_dst,
3247 struct tevent_req *req = NULL, *subreq = NULL;
3248 struct cli_smb2_rename_state *state = NULL;
3250 req = tevent_req_create(
3251 mem_ctx, &state, struct cli_smb2_rename_state);
3257 state->fname_dst = fname_dst;
3258 state->replace = replace;
3260 subreq = get_fnum_from_path_send(
3261 state, ev, cli, fname_src, DELETE_ACCESS);
3262 if (tevent_req_nomem(subreq, req)) {
3263 return tevent_req_post(req, ev);
3265 tevent_req_set_callback(subreq, cli_smb2_rename_opened, req);
3269 static void cli_smb2_rename_opened(struct tevent_req *subreq)
3271 struct tevent_req *req = tevent_req_callback_data(
3272 subreq, struct tevent_req);
3273 struct cli_smb2_rename_state *state = tevent_req_data(
3274 req, struct cli_smb2_rename_state);
3277 status = get_fnum_from_path_recv(subreq, &state->fnum);
3278 TALLOC_FREE(subreq);
3279 if (tevent_req_nterror(req, status)) {
3283 subreq = cli_smb2_rename_fnum_send(
3290 if (tevent_req_nomem(subreq, req)) {
3293 tevent_req_set_callback(subreq, cli_smb2_rename_renamed, req);
3296 static void cli_smb2_rename_renamed(struct tevent_req *subreq)
3298 struct tevent_req *req = tevent_req_callback_data(
3299 subreq, struct tevent_req);
3300 struct cli_smb2_rename_state *state = tevent_req_data(
3301 req, struct cli_smb2_rename_state);
3303 state->rename_status = cli_smb2_rename_fnum_recv(subreq);
3304 TALLOC_FREE(subreq);
3306 subreq = cli_smb2_close_fnum_send(
3307 state, state->ev, state->cli, state->fnum);
3308 if (tevent_req_nomem(subreq, req)) {
3311 tevent_req_set_callback(subreq, cli_smb2_rename_closed, req);
3314 static void cli_smb2_rename_closed(struct tevent_req *subreq)
3316 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
3317 tevent_req_simple_finish_ntstatus(subreq, status);
3320 NTSTATUS cli_smb2_rename_recv(struct tevent_req *req)
3322 struct cli_smb2_rename_state *state = tevent_req_data(
3323 req, struct cli_smb2_rename_state);
3324 NTSTATUS status = NT_STATUS_OK;
3326 if (!tevent_req_is_nterror(req, &status)) {
3327 status = state->rename_status;
3329 tevent_req_received(req);
3333 NTSTATUS cli_smb2_rename(struct cli_state *cli,
3334 const char *fname_src,
3335 const char *fname_dst,
3338 TALLOC_CTX *frame = talloc_stackframe();
3339 struct tevent_context *ev = NULL;
3340 struct tevent_req *req = NULL;
3341 NTSTATUS status = NT_STATUS_NO_MEMORY;
3343 if (smbXcli_conn_has_async_calls(cli->conn)) {
3344 status = NT_STATUS_INVALID_PARAMETER;
3347 ev = samba_tevent_context_init(frame);
3351 req = cli_smb2_rename_send(
3352 frame, ev, cli, fname_src, fname_dst, replace);
3356 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3359 status = cli_smb2_rename_recv(req);
3365 /***************************************************************
3366 Wrapper that allows SMB2 to set an EA on a fnum.
3368 ***************************************************************/
3370 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
3372 const char *ea_name,
3377 DATA_BLOB inbuf = data_blob_null;
3379 char *ea_name_ascii = NULL;
3381 TALLOC_CTX *frame = talloc_stackframe();
3383 if (smbXcli_conn_has_async_calls(cli->conn)) {
3385 * Can't use sync call while an async call is in flight
3387 status = NT_STATUS_INVALID_PARAMETER;
3391 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3392 status = NT_STATUS_INVALID_PARAMETER;
3396 /* Marshall the SMB2 EA data. */
3397 if (ea_len > 0xFFFF) {
3398 status = NT_STATUS_INVALID_PARAMETER;
3402 if (!push_ascii_talloc(frame,
3406 status = NT_STATUS_INVALID_PARAMETER;
3410 if (namelen < 2 || namelen > 0xFF) {
3411 status = NT_STATUS_INVALID_PARAMETER;
3415 bloblen = 8 + ea_len + namelen;
3416 /* Round up to a 4 byte boundary. */
3417 bloblen = ((bloblen + 3)&~3);
3419 inbuf = data_blob_talloc_zero(frame, bloblen);
3420 if (inbuf.data == NULL) {
3421 status = NT_STATUS_NO_MEMORY;
3424 /* namelen doesn't include the NULL byte. */
3425 SCVAL(inbuf.data, 5, namelen - 1);
3426 SSVAL(inbuf.data, 6, ea_len);
3427 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
3428 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
3430 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3431 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3433 status = cli_smb2_set_info_fnum(
3436 1, /* in_info_type */
3437 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3438 &inbuf, /* in_input_buffer */
3439 0); /* in_additional_info */
3443 cli->raw_status = status;
3449 /***************************************************************
3450 Wrapper that allows SMB2 to set an EA on a pathname.
3452 ***************************************************************/
3454 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
3456 const char *ea_name,
3461 uint16_t fnum = 0xffff;
3463 if (smbXcli_conn_has_async_calls(cli->conn)) {
3465 * Can't use sync call while an async call is in flight
3467 status = NT_STATUS_INVALID_PARAMETER;
3471 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3472 status = NT_STATUS_INVALID_PARAMETER;
3476 status = get_fnum_from_path(cli,
3481 if (!NT_STATUS_IS_OK(status)) {
3485 status = cli_set_ea_fnum(cli,
3490 if (!NT_STATUS_IS_OK(status)) {
3496 if (fnum != 0xffff) {
3497 cli_smb2_close_fnum(cli, fnum);
3500 cli->raw_status = status;
3505 /***************************************************************
3506 Wrapper that allows SMB2 to get an EA list on a pathname.
3508 ***************************************************************/
3510 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
3514 struct ea_struct **pea_array)
3517 uint16_t fnum = 0xffff;
3518 DATA_BLOB outbuf = data_blob_null;
3519 struct ea_list *ea_list = NULL;
3520 struct ea_list *eal = NULL;
3521 size_t ea_count = 0;
3522 TALLOC_CTX *frame = talloc_stackframe();
3527 if (smbXcli_conn_has_async_calls(cli->conn)) {
3529 * Can't use sync call while an async call is in flight
3531 status = NT_STATUS_INVALID_PARAMETER;
3535 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3536 status = NT_STATUS_INVALID_PARAMETER;
3540 status = get_fnum_from_path(cli,
3545 if (!NT_STATUS_IS_OK(status)) {
3549 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3550 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3552 status = cli_smb2_query_info_fnum(
3555 1, /* in_info_type */
3556 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3557 0xFFFF, /* in_max_output_length */
3558 NULL, /* in_input_buffer */
3559 0, /* in_additional_info */
3564 if (!NT_STATUS_IS_OK(status)) {
3568 /* Parse the reply. */
3569 ea_list = read_nttrans_ea_list(ctx,
3570 (const char *)outbuf.data,
3572 if (ea_list == NULL) {
3573 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3577 /* Convert to an array. */
3578 for (eal = ea_list; eal; eal = eal->next) {
3583 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
3584 if (*pea_array == NULL) {
3585 status = NT_STATUS_NO_MEMORY;
3589 for (eal = ea_list; eal; eal = eal->next) {
3590 (*pea_array)[ea_count++] = eal->ea;
3592 *pnum_eas = ea_count;
3597 if (fnum != 0xffff) {
3598 cli_smb2_close_fnum(cli, fnum);
3601 cli->raw_status = status;
3607 /***************************************************************
3608 Wrapper that allows SMB2 to get user quota.
3610 ***************************************************************/
3612 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
3614 SMB_NTQUOTA_STRUCT *pqt)
3617 DATA_BLOB inbuf = data_blob_null;
3618 DATA_BLOB info_blob = data_blob_null;
3619 DATA_BLOB outbuf = data_blob_null;
3620 TALLOC_CTX *frame = talloc_stackframe();
3622 unsigned int offset;
3623 struct smb2_query_quota_info query = {0};
3624 struct file_get_quota_info info = {0};
3625 enum ndr_err_code err;
3626 struct ndr_push *ndr_push = NULL;
3628 if (smbXcli_conn_has_async_calls(cli->conn)) {
3630 * Can't use sync call while an async call is in flight
3632 status = NT_STATUS_INVALID_PARAMETER;
3636 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3637 status = NT_STATUS_INVALID_PARAMETER;
3641 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
3643 query.return_single = 1;
3645 info.next_entry_offset = 0;
3646 info.sid_length = sid_len;
3647 info.sid = pqt->sid;
3649 err = ndr_push_struct_blob(
3653 (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
3655 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3656 status = NT_STATUS_INTERNAL_ERROR;
3660 query.sid_list_length = info_blob.length;
3661 ndr_push = ndr_push_init_ctx(frame);
3663 status = NT_STATUS_NO_MEMORY;
3667 err = ndr_push_smb2_query_quota_info(ndr_push,
3668 NDR_SCALARS | NDR_BUFFERS,
3671 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3672 status = NT_STATUS_INTERNAL_ERROR;
3676 err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3679 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3680 status = NT_STATUS_INTERNAL_ERROR;
3683 inbuf.data = ndr_push->data;
3684 inbuf.length = ndr_push->offset;
3686 status = cli_smb2_query_info_fnum(
3689 4, /* in_info_type */
3690 0, /* in_file_info_class */
3691 0xFFFF, /* in_max_output_length */
3692 &inbuf, /* in_input_buffer */
3693 0, /* in_additional_info */
3698 if (!NT_STATUS_IS_OK(status)) {
3702 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3704 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3705 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3709 cli->raw_status = status;
3715 /***************************************************************
3716 Wrapper that allows SMB2 to list user quota.
3718 ***************************************************************/
3720 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3721 TALLOC_CTX *mem_ctx,
3723 SMB_NTQUOTA_LIST **pqt_list,
3727 DATA_BLOB inbuf = data_blob_null;
3728 DATA_BLOB outbuf = data_blob_null;
3729 TALLOC_CTX *frame = talloc_stackframe();
3730 struct smb2_query_quota_info info = {0};
3731 enum ndr_err_code err;
3733 if (smbXcli_conn_has_async_calls(cli->conn)) {
3735 * Can't use sync call while an async call is in flight
3737 status = NT_STATUS_INVALID_PARAMETER;
3741 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3742 status = NT_STATUS_INVALID_PARAMETER;
3746 info.restart_scan = first ? 1 : 0;
3748 err = ndr_push_struct_blob(
3752 (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3754 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3755 status = NT_STATUS_INTERNAL_ERROR;
3759 status = cli_smb2_query_info_fnum(
3762 4, /* in_info_type */
3763 0, /* in_file_info_class */
3764 0xFFFF, /* in_max_output_length */
3765 &inbuf, /* in_input_buffer */
3766 0, /* in_additional_info */
3772 * safeguard against panic from calling parse_user_quota_list with
3775 if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3776 status = NT_STATUS_NO_MORE_ENTRIES;
3779 if (!NT_STATUS_IS_OK(status)) {
3783 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3787 cli->raw_status = status;
3793 /***************************************************************
3794 Wrapper that allows SMB2 to get file system quota.
3796 ***************************************************************/
3798 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3800 SMB_NTQUOTA_STRUCT *pqt)
3803 DATA_BLOB outbuf = data_blob_null;
3804 TALLOC_CTX *frame = talloc_stackframe();
3806 if (smbXcli_conn_has_async_calls(cli->conn)) {
3808 * Can't use sync call while an async call is in flight
3810 status = NT_STATUS_INVALID_PARAMETER;
3814 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3815 status = NT_STATUS_INVALID_PARAMETER;
3819 status = cli_smb2_query_info_fnum(
3822 2, /* in_info_type */
3823 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3824 0xFFFF, /* in_max_output_length */
3825 NULL, /* in_input_buffer */
3826 0, /* in_additional_info */
3831 if (!NT_STATUS_IS_OK(status)) {
3835 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3838 cli->raw_status = status;
3844 /***************************************************************
3845 Wrapper that allows SMB2 to set user quota.
3847 ***************************************************************/
3849 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3851 SMB_NTQUOTA_LIST *qtl)
3854 DATA_BLOB inbuf = data_blob_null;
3855 TALLOC_CTX *frame = talloc_stackframe();
3857 if (smbXcli_conn_has_async_calls(cli->conn)) {
3859 * Can't use sync call while an async call is in flight
3861 status = NT_STATUS_INVALID_PARAMETER;
3865 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3866 status = NT_STATUS_INVALID_PARAMETER;
3870 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3871 if (!NT_STATUS_IS_OK(status)) {
3875 status = cli_smb2_set_info_fnum(
3878 4, /* in_info_type */
3879 0, /* in_file_info_class */
3880 &inbuf, /* in_input_buffer */
3881 0); /* in_additional_info */
3884 cli->raw_status = status;
3891 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3893 SMB_NTQUOTA_STRUCT *pqt)
3896 DATA_BLOB inbuf = data_blob_null;
3897 TALLOC_CTX *frame = talloc_stackframe();
3899 if (smbXcli_conn_has_async_calls(cli->conn)) {
3901 * Can't use sync call while an async call is in flight
3903 status = NT_STATUS_INVALID_PARAMETER;
3907 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3908 status = NT_STATUS_INVALID_PARAMETER;
3912 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3913 if (!NT_STATUS_IS_OK(status)) {
3917 status = cli_smb2_set_info_fnum(
3920 2, /* in_info_type */
3921 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3922 &inbuf, /* in_input_buffer */
3923 0); /* in_additional_info */
3925 cli->raw_status = status;
3931 struct cli_smb2_read_state {
3932 struct tevent_context *ev;
3933 struct cli_state *cli;
3934 struct smb2_hnd *ph;
3935 uint64_t start_offset;
3941 static void cli_smb2_read_done(struct tevent_req *subreq);
3943 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3944 struct tevent_context *ev,
3945 struct cli_state *cli,
3951 struct tevent_req *req, *subreq;
3952 struct cli_smb2_read_state *state;
3954 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3960 state->start_offset = (uint64_t)offset;
3961 state->size = (uint32_t)size;
3962 state->received = 0;
3965 status = map_fnum_to_smb2_handle(cli,
3968 if (tevent_req_nterror(req, status)) {
3969 return tevent_req_post(req, ev);
3972 subreq = smb2cli_read_send(state,
3975 state->cli->timeout,
3976 state->cli->smb2.session,
3977 state->cli->smb2.tcon,
3979 state->start_offset,
3980 state->ph->fid_persistent,
3981 state->ph->fid_volatile,
3982 0, /* minimum_count */
3983 0); /* remaining_bytes */
3985 if (tevent_req_nomem(subreq, req)) {
3986 return tevent_req_post(req, ev);
3988 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3992 static void cli_smb2_read_done(struct tevent_req *subreq)
3994 struct tevent_req *req = tevent_req_callback_data(
3995 subreq, struct tevent_req);
3996 struct cli_smb2_read_state *state = tevent_req_data(
3997 req, struct cli_smb2_read_state);
4000 status = smb2cli_read_recv(subreq, state,
4001 &state->buf, &state->received);
4002 if (tevent_req_nterror(req, status)) {
4006 if (state->received > state->size) {
4007 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4011 tevent_req_done(req);
4014 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
4019 struct cli_smb2_read_state *state = tevent_req_data(
4020 req, struct cli_smb2_read_state);
4022 if (tevent_req_is_nterror(req, &status)) {
4023 state->cli->raw_status = status;
4027 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
4028 * better make sure that you copy it away before you talloc_free(req).
4029 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
4031 *received = (ssize_t)state->received;
4032 *rcvbuf = state->buf;
4033 state->cli->raw_status = NT_STATUS_OK;
4034 return NT_STATUS_OK;
4037 struct cli_smb2_write_state {
4038 struct tevent_context *ev;
4039 struct cli_state *cli;
4040 struct smb2_hnd *ph;
4048 static void cli_smb2_write_written(struct tevent_req *req);
4050 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
4051 struct tevent_context *ev,
4052 struct cli_state *cli,
4060 struct tevent_req *req, *subreq = NULL;
4061 struct cli_smb2_write_state *state = NULL;
4063 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
4069 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4070 state->flags = (uint32_t)mode;
4072 state->offset = (uint64_t)offset;
4073 state->size = (uint32_t)size;
4076 status = map_fnum_to_smb2_handle(cli,
4079 if (tevent_req_nterror(req, status)) {
4080 return tevent_req_post(req, ev);
4083 subreq = smb2cli_write_send(state,
4086 state->cli->timeout,
4087 state->cli->smb2.session,
4088 state->cli->smb2.tcon,
4091 state->ph->fid_persistent,
4092 state->ph->fid_volatile,
4093 0, /* remaining_bytes */
4094 state->flags, /* flags */
4097 if (tevent_req_nomem(subreq, req)) {
4098 return tevent_req_post(req, ev);
4100 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
4104 static void cli_smb2_write_written(struct tevent_req *subreq)
4106 struct tevent_req *req = tevent_req_callback_data(
4107 subreq, struct tevent_req);
4108 struct cli_smb2_write_state *state = tevent_req_data(
4109 req, struct cli_smb2_write_state);
4113 status = smb2cli_write_recv(subreq, &written);
4114 TALLOC_FREE(subreq);
4115 if (tevent_req_nterror(req, status)) {
4119 state->written = written;
4121 tevent_req_done(req);
4124 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
4127 struct cli_smb2_write_state *state = tevent_req_data(
4128 req, struct cli_smb2_write_state);
4131 if (tevent_req_is_nterror(req, &status)) {
4132 state->cli->raw_status = status;
4133 tevent_req_received(req);
4137 if (pwritten != NULL) {
4138 *pwritten = (size_t)state->written;
4140 state->cli->raw_status = NT_STATUS_OK;
4141 tevent_req_received(req);
4142 return NT_STATUS_OK;
4145 /***************************************************************
4146 Wrapper that allows SMB2 async write using an fnum.
4147 This is mostly cut-and-paste from Volker's code inside
4148 source3/libsmb/clireadwrite.c, adapted for SMB2.
4150 Done this way so I can reuse all the logic inside cli_push()
4152 ***************************************************************/
4154 struct cli_smb2_writeall_state {
4155 struct tevent_context *ev;
4156 struct cli_state *cli;
4157 struct smb2_hnd *ph;
4165 static void cli_smb2_writeall_written(struct tevent_req *req);
4167 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
4168 struct tevent_context *ev,
4169 struct cli_state *cli,
4177 struct tevent_req *req, *subreq = NULL;
4178 struct cli_smb2_writeall_state *state = NULL;
4183 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
4189 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4190 state->flags = (uint32_t)mode;
4192 state->offset = (uint64_t)offset;
4193 state->size = (uint32_t)size;
4196 status = map_fnum_to_smb2_handle(cli,
4199 if (tevent_req_nterror(req, status)) {
4200 return tevent_req_post(req, ev);
4203 to_write = state->size;
4204 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4205 to_write = MIN(max_size, to_write);
4206 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4208 to_write = MIN(max_size, to_write);
4211 subreq = smb2cli_write_send(state,
4214 state->cli->timeout,
4215 state->cli->smb2.session,
4216 state->cli->smb2.tcon,
4219 state->ph->fid_persistent,
4220 state->ph->fid_volatile,
4221 0, /* remaining_bytes */
4222 state->flags, /* flags */
4223 state->buf + state->written);
4225 if (tevent_req_nomem(subreq, req)) {
4226 return tevent_req_post(req, ev);
4228 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4232 static void cli_smb2_writeall_written(struct tevent_req *subreq)
4234 struct tevent_req *req = tevent_req_callback_data(
4235 subreq, struct tevent_req);
4236 struct cli_smb2_writeall_state *state = tevent_req_data(
4237 req, struct cli_smb2_writeall_state);
4239 uint32_t written, to_write;
4243 status = smb2cli_write_recv(subreq, &written);
4244 TALLOC_FREE(subreq);
4245 if (tevent_req_nterror(req, status)) {
4249 state->written += written;
4251 if (state->written > state->size) {
4252 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4256 to_write = state->size - state->written;
4258 if (to_write == 0) {
4259 tevent_req_done(req);
4263 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4264 to_write = MIN(max_size, to_write);
4265 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4267 to_write = MIN(max_size, to_write);
4270 subreq = smb2cli_write_send(state,
4273 state->cli->timeout,
4274 state->cli->smb2.session,
4275 state->cli->smb2.tcon,
4277 state->offset + state->written,
4278 state->ph->fid_persistent,
4279 state->ph->fid_volatile,
4280 0, /* remaining_bytes */
4281 state->flags, /* flags */
4282 state->buf + state->written);
4284 if (tevent_req_nomem(subreq, req)) {
4287 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4290 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
4293 struct cli_smb2_writeall_state *state = tevent_req_data(
4294 req, struct cli_smb2_writeall_state);
4297 if (tevent_req_is_nterror(req, &status)) {
4298 state->cli->raw_status = status;
4301 if (pwritten != NULL) {
4302 *pwritten = (size_t)state->written;
4304 state->cli->raw_status = NT_STATUS_OK;
4305 return NT_STATUS_OK;
4308 struct cli_smb2_splice_state {
4309 struct tevent_context *ev;
4310 struct cli_state *cli;
4311 struct smb2_hnd *src_ph;
4312 struct smb2_hnd *dst_ph;
4313 int (*splice_cb)(off_t n, void *priv);
4320 struct req_resume_key_rsp resume_rsp;
4321 struct srv_copychunk_copy cc_copy;
4324 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4325 struct tevent_req *req);
4327 static void cli_splice_copychunk_done(struct tevent_req *subreq)
4329 struct tevent_req *req = tevent_req_callback_data(
4330 subreq, struct tevent_req);
4331 struct cli_smb2_splice_state *state =
4332 tevent_req_data(req,
4333 struct cli_smb2_splice_state);
4334 struct smbXcli_conn *conn = state->cli->conn;
4335 DATA_BLOB out_input_buffer = data_blob_null;
4336 DATA_BLOB out_output_buffer = data_blob_null;
4337 struct srv_copychunk_rsp cc_copy_rsp;
4338 enum ndr_err_code ndr_ret;
4341 status = smb2cli_ioctl_recv(subreq, state,
4343 &out_output_buffer);
4344 TALLOC_FREE(subreq);
4345 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
4346 state->resized) && tevent_req_nterror(req, status)) {
4350 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
4351 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
4352 if (ndr_ret != NDR_ERR_SUCCESS) {
4353 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4354 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4358 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
4359 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
4360 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
4361 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
4362 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
4363 tevent_req_nterror(req, status)) {
4367 state->resized = true;
4368 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
4369 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
4371 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4372 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4373 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
4374 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4377 state->src_offset += cc_copy_rsp.total_bytes_written;
4378 state->dst_offset += cc_copy_rsp.total_bytes_written;
4379 state->written += cc_copy_rsp.total_bytes_written;
4380 if (!state->splice_cb(state->written, state->priv)) {
4381 tevent_req_nterror(req, NT_STATUS_CANCELLED);
4386 cli_splice_copychunk_send(state, req);
4389 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4390 struct tevent_req *req)
4392 struct tevent_req *subreq;
4393 enum ndr_err_code ndr_ret;
4394 struct smbXcli_conn *conn = state->cli->conn;
4395 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
4396 off_t src_offset = state->src_offset;
4397 off_t dst_offset = state->dst_offset;
4398 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
4399 state->size - state->written);
4400 DATA_BLOB in_input_buffer = data_blob_null;
4401 DATA_BLOB in_output_buffer = data_blob_null;
4403 if (state->size - state->written == 0) {
4404 tevent_req_done(req);
4408 cc_copy->chunk_count = 0;
4410 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
4411 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
4412 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
4413 smb2cli_conn_cc_chunk_len(conn));
4414 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
4415 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4418 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
4419 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
4420 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
4421 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4424 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4425 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4426 cc_copy->chunk_count++;
4429 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
4430 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
4431 if (ndr_ret != NDR_ERR_SUCCESS) {
4432 DEBUG(0, ("failed to marshall copy chunk req\n"));
4433 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4437 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
4438 state->cli->timeout,
4439 state->cli->smb2.session,
4440 state->cli->smb2.tcon,
4441 state->dst_ph->fid_persistent, /* in_fid_persistent */
4442 state->dst_ph->fid_volatile, /* in_fid_volatile */
4443 FSCTL_SRV_COPYCHUNK_WRITE,
4444 0, /* in_max_input_length */
4446 12, /* in_max_output_length */
4448 SMB2_IOCTL_FLAG_IS_FSCTL);
4449 if (tevent_req_nomem(subreq, req)) {
4452 tevent_req_set_callback(subreq,
4453 cli_splice_copychunk_done,
4457 static void cli_splice_key_done(struct tevent_req *subreq)
4459 struct tevent_req *req = tevent_req_callback_data(
4460 subreq, struct tevent_req);
4461 struct cli_smb2_splice_state *state =
4462 tevent_req_data(req,
4463 struct cli_smb2_splice_state);
4464 enum ndr_err_code ndr_ret;
4467 DATA_BLOB out_input_buffer = data_blob_null;
4468 DATA_BLOB out_output_buffer = data_blob_null;
4470 status = smb2cli_ioctl_recv(subreq, state,
4472 &out_output_buffer);
4473 TALLOC_FREE(subreq);
4474 if (tevent_req_nterror(req, status)) {
4478 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
4479 state, &state->resume_rsp,
4480 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
4481 if (ndr_ret != NDR_ERR_SUCCESS) {
4482 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4483 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4487 memcpy(&state->cc_copy.source_key,
4488 &state->resume_rsp.resume_key,
4489 sizeof state->resume_rsp.resume_key);
4491 cli_splice_copychunk_send(state, req);
4494 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
4495 struct tevent_context *ev,
4496 struct cli_state *cli,
4497 uint16_t src_fnum, uint16_t dst_fnum,
4498 off_t size, off_t src_offset, off_t dst_offset,
4499 int (*splice_cb)(off_t n, void *priv),
4502 struct tevent_req *req;
4503 struct tevent_req *subreq;
4504 struct cli_smb2_splice_state *state;
4506 DATA_BLOB in_input_buffer = data_blob_null;
4507 DATA_BLOB in_output_buffer = data_blob_null;
4509 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
4515 state->splice_cb = splice_cb;
4519 state->src_offset = src_offset;
4520 state->dst_offset = dst_offset;
4521 state->cc_copy.chunks = talloc_array(state,
4522 struct srv_copychunk,
4523 smb2cli_conn_cc_max_chunks(cli->conn));
4524 if (state->cc_copy.chunks == NULL) {
4528 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
4529 if (tevent_req_nterror(req, status))
4530 return tevent_req_post(req, ev);
4532 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
4533 if (tevent_req_nterror(req, status))
4534 return tevent_req_post(req, ev);
4536 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
4540 state->src_ph->fid_persistent, /* in_fid_persistent */
4541 state->src_ph->fid_volatile, /* in_fid_volatile */
4542 FSCTL_SRV_REQUEST_RESUME_KEY,
4543 0, /* in_max_input_length */
4545 32, /* in_max_output_length */
4547 SMB2_IOCTL_FLAG_IS_FSCTL);
4548 if (tevent_req_nomem(subreq, req)) {
4551 tevent_req_set_callback(subreq,
4552 cli_splice_key_done,
4558 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
4560 struct cli_smb2_splice_state *state = tevent_req_data(
4561 req, struct cli_smb2_splice_state);
4564 if (tevent_req_is_nterror(req, &status)) {
4565 state->cli->raw_status = status;
4566 tevent_req_received(req);
4569 if (written != NULL) {
4570 *written = state->written;
4572 state->cli->raw_status = NT_STATUS_OK;
4573 tevent_req_received(req);
4574 return NT_STATUS_OK;
4577 /***************************************************************
4578 SMB2 enum shadow copy data.
4579 ***************************************************************/
4581 struct cli_smb2_shadow_copy_data_fnum_state {
4582 struct cli_state *cli;
4584 struct smb2_hnd *ph;
4585 DATA_BLOB out_input_buffer;
4586 DATA_BLOB out_output_buffer;
4589 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
4591 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
4592 TALLOC_CTX *mem_ctx,
4593 struct tevent_context *ev,
4594 struct cli_state *cli,
4598 struct tevent_req *req, *subreq;
4599 struct cli_smb2_shadow_copy_data_fnum_state *state;
4602 req = tevent_req_create(mem_ctx, &state,
4603 struct cli_smb2_shadow_copy_data_fnum_state);
4608 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4609 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4610 return tevent_req_post(req, ev);
4616 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4617 if (tevent_req_nterror(req, status)) {
4618 return tevent_req_post(req, ev);
4622 * TODO. Under SMB2 we should send a zero max_output_length
4623 * ioctl to get the required size, then send another ioctl
4624 * to get the data, but the current SMB1 implementation just
4625 * does one roundtrip with a 64K buffer size. Do the same
4629 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4630 state->cli->timeout,
4631 state->cli->smb2.session,
4632 state->cli->smb2.tcon,
4633 state->ph->fid_persistent, /* in_fid_persistent */
4634 state->ph->fid_volatile, /* in_fid_volatile */
4635 FSCTL_GET_SHADOW_COPY_DATA,
4636 0, /* in_max_input_length */
4637 NULL, /* in_input_buffer */
4639 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
4640 NULL, /* in_output_buffer */
4641 SMB2_IOCTL_FLAG_IS_FSCTL);
4643 if (tevent_req_nomem(subreq, req)) {
4644 return tevent_req_post(req, ev);
4646 tevent_req_set_callback(subreq,
4647 cli_smb2_shadow_copy_data_fnum_done,
4653 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4655 struct tevent_req *req = tevent_req_callback_data(
4656 subreq, struct tevent_req);
4657 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4658 req, struct cli_smb2_shadow_copy_data_fnum_state);
4661 status = smb2cli_ioctl_recv(subreq, state,
4662 &state->out_input_buffer,
4663 &state->out_output_buffer);
4664 tevent_req_simple_finish_ntstatus(subreq, status);
4667 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4668 TALLOC_CTX *mem_ctx,
4673 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4674 req, struct cli_smb2_shadow_copy_data_fnum_state);
4675 char **names = NULL;
4676 uint32_t num_names = 0;
4677 uint32_t num_names_returned = 0;
4678 uint32_t dlength = 0;
4680 uint8_t *endp = NULL;
4683 if (tevent_req_is_nterror(req, &status)) {
4687 if (state->out_output_buffer.length < 16) {
4688 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4691 num_names = IVAL(state->out_output_buffer.data, 0);
4692 num_names_returned = IVAL(state->out_output_buffer.data, 4);
4693 dlength = IVAL(state->out_output_buffer.data, 8);
4695 if (num_names > 0x7FFFFFFF) {
4696 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4699 if (get_names == false) {
4700 *pnum_names = (int)num_names;
4701 return NT_STATUS_OK;
4703 if (num_names != num_names_returned) {
4704 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4706 if (dlength + 12 < 12) {
4707 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4710 * NB. The below is an allowable return if there are
4711 * more snapshots than the buffer size we told the
4712 * server we can receive. We currently don't support
4715 if (dlength + 12 > state->out_output_buffer.length) {
4716 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4718 if (state->out_output_buffer.length +
4719 (2 * sizeof(SHADOW_COPY_LABEL)) <
4720 state->out_output_buffer.length) {
4721 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4724 names = talloc_array(mem_ctx, char *, num_names_returned);
4725 if (names == NULL) {
4726 return NT_STATUS_NO_MEMORY;
4729 endp = state->out_output_buffer.data +
4730 state->out_output_buffer.length;
4732 for (i=0; i<num_names_returned; i++) {
4735 size_t converted_size;
4737 src = state->out_output_buffer.data + 12 +
4738 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4740 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4741 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4743 ret = convert_string_talloc(
4744 names, CH_UTF16LE, CH_UNIX,
4745 src, 2 * sizeof(SHADOW_COPY_LABEL),
4746 &names[i], &converted_size);
4749 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4752 *pnum_names = num_names;
4754 return NT_STATUS_OK;
4757 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4758 struct cli_state *cli,
4764 TALLOC_CTX *frame = talloc_stackframe();
4765 struct tevent_context *ev;
4766 struct tevent_req *req;
4767 NTSTATUS status = NT_STATUS_NO_MEMORY;
4769 if (smbXcli_conn_has_async_calls(cli->conn)) {
4771 * Can't use sync call while an async call is in flight
4773 status = NT_STATUS_INVALID_PARAMETER;
4776 ev = samba_tevent_context_init(frame);
4780 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4788 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4791 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4797 cli->raw_status = status;
4803 /***************************************************************
4804 Wrapper that allows SMB2 to truncate a file.
4806 ***************************************************************/
4808 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4813 uint8_t buf[8] = {0};
4814 DATA_BLOB inbuf = { .data = buf, .length = sizeof(buf) };
4815 TALLOC_CTX *frame = talloc_stackframe();
4817 if (smbXcli_conn_has_async_calls(cli->conn)) {
4819 * Can't use sync call while an async call is in flight
4821 status = NT_STATUS_INVALID_PARAMETER;
4825 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4826 status = NT_STATUS_INVALID_PARAMETER;
4830 SBVAL(buf, 0, newsize);
4832 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4833 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4835 status = cli_smb2_set_info_fnum(
4838 1, /* in_info_type */
4839 SMB_FILE_END_OF_FILE_INFORMATION-1000, /* in_file_info_class */
4840 &inbuf, /* in_input_buffer */
4845 cli->raw_status = status;
4851 struct cli_smb2_notify_state {
4852 struct tevent_req *subreq;
4853 struct notify_change *changes;
4857 static void cli_smb2_notify_done(struct tevent_req *subreq);
4858 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4860 struct tevent_req *cli_smb2_notify_send(
4861 TALLOC_CTX *mem_ctx,
4862 struct tevent_context *ev,
4863 struct cli_state *cli,
4865 uint32_t buffer_size,
4866 uint32_t completion_filter,
4869 struct tevent_req *req = NULL;
4870 struct cli_smb2_notify_state *state = NULL;
4871 struct smb2_hnd *ph = NULL;
4874 req = tevent_req_create(mem_ctx, &state,
4875 struct cli_smb2_notify_state);
4880 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4881 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4882 return tevent_req_post(req, ev);
4885 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4886 if (tevent_req_nterror(req, status)) {
4887 return tevent_req_post(req, ev);
4890 state->subreq = smb2cli_notify_send(
4902 if (tevent_req_nomem(state->subreq, req)) {
4903 return tevent_req_post(req, ev);
4905 tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4906 tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4910 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4912 struct cli_smb2_notify_state *state = tevent_req_data(
4913 req, struct cli_smb2_notify_state);
4916 ok = tevent_req_cancel(state->subreq);
4920 static void cli_smb2_notify_done(struct tevent_req *subreq)
4922 struct tevent_req *req = tevent_req_callback_data(
4923 subreq, struct tevent_req);
4924 struct cli_smb2_notify_state *state = tevent_req_data(
4925 req, struct cli_smb2_notify_state);
4931 status = smb2cli_notify_recv(subreq, state, &base, &len);
4932 TALLOC_FREE(subreq);
4934 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4935 tevent_req_done(req);
4938 if (tevent_req_nterror(req, status)) {
4944 while (len - ofs >= 12) {
4945 struct notify_change *tmp;
4946 struct notify_change *c;
4947 uint32_t next_ofs = IVAL(base, ofs);
4948 uint32_t file_name_length = IVAL(base, ofs+8);
4952 tmp = talloc_realloc(
4955 struct notify_change,
4956 state->num_changes + 1);
4957 if (tevent_req_nomem(tmp, req)) {
4960 state->changes = tmp;
4961 c = &state->changes[state->num_changes];
4962 state->num_changes += 1;
4964 if (smb_buffer_oob(len, ofs, next_ofs) ||
4965 smb_buffer_oob(len, ofs+12, file_name_length)) {
4967 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4971 c->action = IVAL(base, ofs+4);
4973 ok = convert_string_talloc(
4983 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4987 if (next_ofs == 0) {
4993 tevent_req_done(req);
4996 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
4997 TALLOC_CTX *mem_ctx,
4998 struct notify_change **pchanges,
4999 uint32_t *pnum_changes)
5001 struct cli_smb2_notify_state *state = tevent_req_data(
5002 req, struct cli_smb2_notify_state);
5005 if (tevent_req_is_nterror(req, &status)) {
5008 *pchanges = talloc_move(mem_ctx, &state->changes);
5009 *pnum_changes = state->num_changes;
5010 return NT_STATUS_OK;
5013 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
5014 uint32_t buffer_size, uint32_t completion_filter,
5015 bool recursive, TALLOC_CTX *mem_ctx,
5016 struct notify_change **pchanges,
5017 uint32_t *pnum_changes)
5019 TALLOC_CTX *frame = talloc_stackframe();
5020 struct tevent_context *ev;
5021 struct tevent_req *req;
5022 NTSTATUS status = NT_STATUS_NO_MEMORY;
5024 if (smbXcli_conn_has_async_calls(cli->conn)) {
5026 * Can't use sync call while an async call is in flight
5028 status = NT_STATUS_INVALID_PARAMETER;
5031 ev = samba_tevent_context_init(frame);
5035 req = cli_smb2_notify_send(
5046 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5049 status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
5055 struct cli_smb2_set_reparse_point_fnum_state {
5056 struct cli_state *cli;
5058 struct smb2_hnd *ph;
5059 DATA_BLOB input_buffer;
5062 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
5064 struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
5065 TALLOC_CTX *mem_ctx,
5066 struct tevent_context *ev,
5067 struct cli_state *cli,
5071 struct tevent_req *req, *subreq;
5072 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
5075 req = tevent_req_create(mem_ctx, &state,
5076 struct cli_smb2_set_reparse_point_fnum_state);
5081 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5082 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
5083 return tevent_req_post(req, ev);
5089 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
5090 if (tevent_req_nterror(req, status)) {
5091 return tevent_req_post(req, ev);
5094 state->input_buffer = data_blob_talloc(state,
5097 if (state->input_buffer.data == NULL) {
5098 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
5099 return tevent_req_post(req, ev);
5102 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
5103 state->cli->timeout,
5104 state->cli->smb2.session,
5105 state->cli->smb2.tcon,
5106 state->ph->fid_persistent, /* in_fid_persistent */
5107 state->ph->fid_volatile, /* in_fid_volatile */
5108 FSCTL_SET_REPARSE_POINT,
5109 0, /* in_max_input_length */
5110 &state->input_buffer ,
5113 SMB2_IOCTL_FLAG_IS_FSCTL);
5115 if (tevent_req_nomem(subreq, req)) {
5116 return tevent_req_post(req, ev);
5118 tevent_req_set_callback(subreq,
5119 cli_smb2_set_reparse_point_fnum_done,
5125 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
5127 struct tevent_req *req = tevent_req_callback_data(
5128 subreq, struct tevent_req);
5129 struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
5130 req, struct cli_smb2_set_reparse_point_fnum_state);
5133 status = smb2cli_ioctl_recv(subreq, state,
5136 TALLOC_FREE(subreq);
5137 if (tevent_req_nterror(req, status)) {
5140 tevent_req_done(req);
5143 NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
5145 return tevent_req_simple_recv_ntstatus(req);
5148 struct cli_smb2_get_reparse_point_fnum_state {
5149 struct cli_state *cli;
5151 struct smb2_hnd *ph;
5152 DATA_BLOB output_buffer;
5155 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
5157 struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
5158 TALLOC_CTX *mem_ctx,
5159 struct tevent_context *ev,
5160 struct cli_state *cli,
5163 struct tevent_req *req, *subreq;
5164 struct cli_smb2_get_reparse_point_fnum_state *state = NULL;
5167 req = tevent_req_create(mem_ctx, &state,
5168 struct cli_smb2_get_reparse_point_fnum_state);
5173 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5174 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
5175 return tevent_req_post(req, ev);
5181 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
5182 if (tevent_req_nterror(req, status)) {
5183 return tevent_req_post(req, ev);
5186 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
5187 state->cli->timeout,
5188 state->cli->smb2.session,
5189 state->cli->smb2.tcon,
5190 state->ph->fid_persistent, /* in_fid_persistent */
5191 state->ph->fid_volatile, /* in_fid_volatile */
5192 FSCTL_GET_REPARSE_POINT,
5193 0, /* in_max_input_length */
5197 SMB2_IOCTL_FLAG_IS_FSCTL);
5199 if (tevent_req_nomem(subreq, req)) {
5200 return tevent_req_post(req, ev);
5202 tevent_req_set_callback(subreq,
5203 cli_smb2_get_reparse_point_fnum_done,
5209 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
5211 struct tevent_req *req = tevent_req_callback_data(
5212 subreq, struct tevent_req);
5213 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
5214 req, struct cli_smb2_get_reparse_point_fnum_state);
5215 struct cli_state *cli = state->cli;
5218 status = smb2cli_ioctl_recv(subreq, state,
5220 &state->output_buffer);
5221 TALLOC_FREE(subreq);
5222 if (tevent_req_nterror(req, status)) {
5223 cli->raw_status = status;
5226 tevent_req_done(req);
5229 NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
5230 TALLOC_CTX *mem_ctx,
5233 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
5234 req, struct cli_smb2_get_reparse_point_fnum_state);
5236 if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
5237 NTSTATUS status = state->cli->raw_status;
5238 tevent_req_received(req);
5241 *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
5242 if (output->data == NULL) {
5243 tevent_req_received(req);
5244 return NT_STATUS_NO_MEMORY;
5246 tevent_req_received(req);
5247 return NT_STATUS_OK;