2 Unix SMB/CIFS implementation.
4 Copyright (C) Jeremy Allison 2013
5 Copyright (C) Volker Lendecke 2013
6 Copyright (C) Stefan Metzmacher 2013
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This code is a thin wrapper around the existing
24 cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c,
25 but allows the handles to be mapped to uint16_t fnums,
26 which are easier for smbclient to use.
31 #include "async_smb.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "cli_smb2_fnum.h"
36 #include "../libcli/smb/smb2_create_blob.h"
37 #include "libsmb/proto.h"
38 #include "lib/util/tevent_ntstatus.h"
39 #include "../libcli/security/security.h"
40 #include "../librpc/gen_ndr/ndr_security.h"
41 #include "lib/util_ea.h"
42 #include "librpc/gen_ndr/ndr_ioctl.h"
44 #include "librpc/gen_ndr/ndr_quota.h"
47 uint64_t fid_persistent;
48 uint64_t fid_volatile;
52 * Handle mapping code.
55 /***************************************************************
56 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
57 Ensures handle is owned by cli struct.
58 ***************************************************************/
60 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
61 const struct smb2_hnd *ph, /* In */
62 uint16_t *pfnum) /* Out */
65 struct idr_context *idp = cli->smb2.open_handles;
66 struct smb2_hnd *owned_h = talloc_memdup(cli,
68 sizeof(struct smb2_hnd));
70 if (owned_h == NULL) {
71 return NT_STATUS_NO_MEMORY;
76 cli->smb2.open_handles = idr_init(cli);
77 if (cli->smb2.open_handles == NULL) {
79 return NT_STATUS_NO_MEMORY;
81 idp = cli->smb2.open_handles;
84 ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
87 return NT_STATUS_NO_MEMORY;
90 *pfnum = (uint16_t)ret;
94 /***************************************************************
95 Return the smb2_hnd pointer associated with the given fnum.
96 ***************************************************************/
98 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
99 uint16_t fnum, /* In */
100 struct smb2_hnd **pph) /* Out */
102 struct idr_context *idp = cli->smb2.open_handles;
105 return NT_STATUS_INVALID_PARAMETER;
107 *pph = (struct smb2_hnd *)idr_find(idp, fnum);
109 return NT_STATUS_INVALID_HANDLE;
114 /***************************************************************
115 Delete the fnum to smb2_hnd mapping. Zeros out handle on
117 ***************************************************************/
119 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
120 struct smb2_hnd **pph, /* In */
121 uint16_t fnum) /* In */
123 struct idr_context *idp = cli->smb2.open_handles;
127 return NT_STATUS_INVALID_PARAMETER;
130 ph = (struct smb2_hnd *)idr_find(idp, fnum);
132 return NT_STATUS_INVALID_PARAMETER;
134 idr_remove(idp, fnum);
139 /***************************************************************
141 ***************************************************************/
143 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
145 if (create_flags & REQUEST_BATCH_OPLOCK) {
146 return SMB2_OPLOCK_LEVEL_BATCH;
147 } else if (create_flags & REQUEST_OPLOCK) {
148 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
151 /* create_flags doesn't do a level2 request. */
152 return SMB2_OPLOCK_LEVEL_NONE;
155 /***************************************************************
156 Small wrapper that allows SMB2 create to return a uint16_t fnum.
157 ***************************************************************/
159 struct cli_smb2_create_fnum_state {
160 struct cli_state *cli;
161 struct smb2_create_blobs in_cblobs;
162 struct smb2_create_blobs out_cblobs;
163 struct smb_create_returns cr;
165 struct tevent_req *subreq;
168 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
169 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
171 struct tevent_req *cli_smb2_create_fnum_send(
173 struct tevent_context *ev,
174 struct cli_state *cli,
176 uint32_t create_flags,
177 uint32_t impersonation_level,
178 uint32_t desired_access,
179 uint32_t file_attributes,
180 uint32_t share_access,
181 uint32_t create_disposition,
182 uint32_t create_options,
183 const struct smb2_create_blobs *in_cblobs)
185 struct tevent_req *req, *subreq;
186 struct cli_smb2_create_fnum_state *state;
187 size_t fname_len = 0;
188 const char *startp = NULL;
189 const char *endp = NULL;
190 time_t tstamp = (time_t)0;
193 req = tevent_req_create(mem_ctx, &state,
194 struct cli_smb2_create_fnum_state);
200 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
201 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
202 return tevent_req_post(req, ev);
205 if (cli->backup_intent) {
206 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
209 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
210 fname_len = strlen(fname);
211 if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
212 size_t len_before_gmt = startp - fname;
213 size_t len_after_gmt = fname + fname_len - endp;
217 char *new_fname = talloc_array(state, char,
218 len_before_gmt + len_after_gmt + 1);
220 if (tevent_req_nomem(new_fname, req)) {
221 return tevent_req_post(req, ev);
224 memcpy(new_fname, fname, len_before_gmt);
225 memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
227 fname_len = len_before_gmt + len_after_gmt;
229 unix_to_nt_time(&ntt, tstamp);
230 twrp_blob = data_blob_const((const void *)&ntt, 8);
232 status = smb2_create_blob_add(
235 SMB2_CREATE_TAG_TWRP,
237 if (!NT_STATUS_IS_OK(status)) {
238 tevent_req_nterror(req, status);
239 return tevent_req_post(req, ev);
243 if (in_cblobs != NULL) {
245 for (i=0; i<in_cblobs->num_blobs; i++) {
246 struct smb2_create_blob *b = &in_cblobs->blobs[i];
247 status = smb2_create_blob_add(
248 state, &state->in_cblobs, b->tag, b->data);
249 if (!NT_STATUS_IS_OK(status)) {
250 tevent_req_nterror(req, status);
251 return tevent_req_post(req, ev);
256 /* SMB2 is pickier about pathnames. Ensure it doesn't
258 if (*fname == '\\') {
263 /* Or end in a '\' */
264 if (fname_len > 0 && fname[fname_len-1] == '\\') {
265 char *new_fname = talloc_strdup(state, fname);
266 if (tevent_req_nomem(new_fname, req)) {
267 return tevent_req_post(req, ev);
269 new_fname[fname_len-1] = '\0';
273 subreq = smb2cli_create_send(state, ev,
279 flags_to_smb2_oplock(create_flags),
287 if (tevent_req_nomem(subreq, req)) {
288 return tevent_req_post(req, ev);
290 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
292 state->subreq = subreq;
293 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
298 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
300 struct tevent_req *req = tevent_req_callback_data(
301 subreq, struct tevent_req);
302 struct cli_smb2_create_fnum_state *state = tevent_req_data(
303 req, struct cli_smb2_create_fnum_state);
307 status = smb2cli_create_recv(
310 &h.fid_volatile, &state->cr,
314 if (tevent_req_nterror(req, status)) {
318 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
319 if (tevent_req_nterror(req, status)) {
322 tevent_req_done(req);
325 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
327 struct cli_smb2_create_fnum_state *state = tevent_req_data(
328 req, struct cli_smb2_create_fnum_state);
329 return tevent_req_cancel(state->subreq);
332 NTSTATUS cli_smb2_create_fnum_recv(
333 struct tevent_req *req,
335 struct smb_create_returns *cr,
337 struct smb2_create_blobs *out_cblobs)
339 struct cli_smb2_create_fnum_state *state = tevent_req_data(
340 req, struct cli_smb2_create_fnum_state);
343 if (tevent_req_is_nterror(req, &status)) {
344 state->cli->raw_status = status;
348 *pfnum = state->fnum;
353 if (out_cblobs != NULL) {
354 *out_cblobs = (struct smb2_create_blobs) {
355 .num_blobs = state->out_cblobs.num_blobs,
356 .blobs = talloc_move(
357 mem_ctx, &state->out_cblobs.blobs),
360 state->cli->raw_status = NT_STATUS_OK;
364 NTSTATUS cli_smb2_create_fnum(
365 struct cli_state *cli,
367 uint32_t create_flags,
368 uint32_t impersonation_level,
369 uint32_t desired_access,
370 uint32_t file_attributes,
371 uint32_t share_access,
372 uint32_t create_disposition,
373 uint32_t create_options,
374 const struct smb2_create_blobs *in_cblobs,
376 struct smb_create_returns *cr,
378 struct smb2_create_blobs *out_cblobs)
380 TALLOC_CTX *frame = talloc_stackframe();
381 struct tevent_context *ev;
382 struct tevent_req *req;
383 NTSTATUS status = NT_STATUS_NO_MEMORY;
385 if (smbXcli_conn_has_async_calls(cli->conn)) {
387 * Can't use sync call while an async call is in flight
389 status = NT_STATUS_INVALID_PARAMETER;
392 ev = samba_tevent_context_init(frame);
396 req = cli_smb2_create_fnum_send(
412 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
415 status = cli_smb2_create_fnum_recv(req, pfid, cr, mem_ctx, out_cblobs);
421 /***************************************************************
422 Small wrapper that allows SMB2 close to use a uint16_t fnum.
423 ***************************************************************/
425 struct cli_smb2_close_fnum_state {
426 struct cli_state *cli;
431 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
433 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
434 struct tevent_context *ev,
435 struct cli_state *cli,
438 struct tevent_req *req, *subreq;
439 struct cli_smb2_close_fnum_state *state;
442 req = tevent_req_create(mem_ctx, &state,
443 struct cli_smb2_close_fnum_state);
450 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
451 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
452 return tevent_req_post(req, ev);
455 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
456 if (tevent_req_nterror(req, status)) {
457 return tevent_req_post(req, ev);
460 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
461 cli->smb2.session, cli->smb2.tcon,
462 0, state->ph->fid_persistent,
463 state->ph->fid_volatile);
464 if (tevent_req_nomem(subreq, req)) {
465 return tevent_req_post(req, ev);
467 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
471 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
473 struct tevent_req *req = tevent_req_callback_data(
474 subreq, struct tevent_req);
475 struct cli_smb2_close_fnum_state *state = tevent_req_data(
476 req, struct cli_smb2_close_fnum_state);
479 status = smb2cli_close_recv(subreq);
480 if (tevent_req_nterror(req, status)) {
484 /* Delete the fnum -> handle mapping. */
485 status = delete_smb2_handle_mapping(state->cli, &state->ph,
487 if (tevent_req_nterror(req, status)) {
490 tevent_req_done(req);
493 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
495 struct cli_smb2_close_fnum_state *state = tevent_req_data(
496 req, struct cli_smb2_close_fnum_state);
497 NTSTATUS status = NT_STATUS_OK;
499 if (tevent_req_is_nterror(req, &status)) {
500 state->cli->raw_status = status;
502 tevent_req_received(req);
506 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
508 TALLOC_CTX *frame = talloc_stackframe();
509 struct tevent_context *ev;
510 struct tevent_req *req;
511 NTSTATUS status = NT_STATUS_NO_MEMORY;
513 if (smbXcli_conn_has_async_calls(cli->conn)) {
515 * Can't use sync call while an async call is in flight
517 status = NT_STATUS_INVALID_PARAMETER;
520 ev = samba_tevent_context_init(frame);
524 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
528 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
531 status = cli_smb2_close_fnum_recv(req);
537 struct cli_smb2_set_info_fnum_state {
541 static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq);
543 struct tevent_req *cli_smb2_set_info_fnum_send(
545 struct tevent_context *ev,
546 struct cli_state *cli,
548 uint8_t in_info_type,
549 uint8_t in_info_class,
550 const DATA_BLOB *in_input_buffer,
551 uint32_t in_additional_info)
553 struct tevent_req *req = NULL, *subreq = NULL;
554 struct cli_smb2_set_info_fnum_state *state = NULL;
555 struct smb2_hnd *ph = NULL;
558 req = tevent_req_create(
559 mem_ctx, &state, struct cli_smb2_set_info_fnum_state);
564 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
565 if (tevent_req_nterror(req, status)) {
566 return tevent_req_post(req, ev);
569 subreq = smb2cli_set_info_send(
582 if (tevent_req_nomem(subreq, req)) {
583 return tevent_req_post(req, ev);
585 tevent_req_set_callback(subreq, cli_smb2_set_info_fnum_done, req);
589 static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq)
591 NTSTATUS status = smb2cli_set_info_recv(subreq);
592 tevent_req_simple_finish_ntstatus(subreq, status);
595 NTSTATUS cli_smb2_set_info_fnum_recv(struct tevent_req *req)
597 return tevent_req_simple_recv_ntstatus(req);
600 NTSTATUS cli_smb2_set_info_fnum(
601 struct cli_state *cli,
603 uint8_t in_info_type,
604 uint8_t in_info_class,
605 const DATA_BLOB *in_input_buffer,
606 uint32_t in_additional_info)
608 TALLOC_CTX *frame = talloc_stackframe();
609 struct tevent_context *ev = NULL;
610 struct tevent_req *req = NULL;
611 NTSTATUS status = NT_STATUS_NO_MEMORY;
614 if (smbXcli_conn_has_async_calls(cli->conn)) {
616 * Can't use sync call while an async call is in flight
618 status = NT_STATUS_INVALID_PARAMETER;
621 ev = samba_tevent_context_init(frame);
625 req = cli_smb2_set_info_fnum_send(
637 ok = tevent_req_poll_ntstatus(req, ev, &status);
641 status = cli_smb2_set_info_fnum_recv(req);
647 struct cli_smb2_delete_on_close_state {
648 struct cli_state *cli;
653 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
655 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
656 struct tevent_context *ev,
657 struct cli_state *cli,
661 struct tevent_req *req = NULL;
662 struct cli_smb2_delete_on_close_state *state = NULL;
663 struct tevent_req *subreq = NULL;
664 uint8_t in_info_type;
665 uint8_t in_file_info_class;
667 req = tevent_req_create(mem_ctx, &state,
668 struct cli_smb2_delete_on_close_state);
674 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
675 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
676 return tevent_req_post(req, ev);
680 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
681 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
684 in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
685 /* Setup data array. */
686 SCVAL(&state->data[0], 0, flag ? 1 : 0);
687 state->inbuf.data = &state->data[0];
688 state->inbuf.length = 1;
690 subreq = cli_smb2_set_info_fnum_send(
699 if (tevent_req_nomem(subreq, req)) {
700 return tevent_req_post(req, ev);
702 tevent_req_set_callback(subreq,
703 cli_smb2_delete_on_close_done,
708 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
710 NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
711 tevent_req_simple_finish_ntstatus(subreq, status);
714 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
716 struct cli_smb2_delete_on_close_state *state =
718 struct cli_smb2_delete_on_close_state);
721 if (tevent_req_is_nterror(req, &status)) {
722 state->cli->raw_status = status;
723 tevent_req_received(req);
727 state->cli->raw_status = NT_STATUS_OK;
728 tevent_req_received(req);
732 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
734 TALLOC_CTX *frame = talloc_stackframe();
735 struct tevent_context *ev;
736 struct tevent_req *req;
737 NTSTATUS status = NT_STATUS_NO_MEMORY;
739 if (smbXcli_conn_has_async_calls(cli->conn)) {
741 * Can't use sync call while an async call is in flight
743 status = NT_STATUS_INVALID_PARAMETER;
746 ev = samba_tevent_context_init(frame);
750 req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
754 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
757 status = cli_smb2_delete_on_close_recv(req);
763 /***************************************************************
764 Small wrapper that allows SMB2 to create a directory
766 ***************************************************************/
768 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
773 if (smbXcli_conn_has_async_calls(cli->conn)) {
775 * Can't use sync call while an async call is in flight
777 return NT_STATUS_INVALID_PARAMETER;
780 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
781 return NT_STATUS_INVALID_PARAMETER;
784 status = cli_smb2_create_fnum(cli,
786 0, /* create_flags */
787 SMB2_IMPERSONATION_IMPERSONATION,
788 FILE_READ_ATTRIBUTES, /* desired_access */
789 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
790 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
791 FILE_CREATE, /* create_disposition */
792 FILE_DIRECTORY_FILE, /* create_options */
799 if (!NT_STATUS_IS_OK(status)) {
802 return cli_smb2_close_fnum(cli, fnum);
805 struct cli_smb2_rmdir_state {
806 struct tevent_context *ev;
807 struct cli_state *cli;
809 const struct smb2_create_blobs *in_cblobs;
814 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq);
815 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq);
816 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq);
817 static void cli_smb2_rmdir_closed(struct tevent_req *subreq);
819 struct tevent_req *cli_smb2_rmdir_send(
821 struct tevent_context *ev,
822 struct cli_state *cli,
824 const struct smb2_create_blobs *in_cblobs)
826 struct tevent_req *req = NULL, *subreq = NULL;
827 struct cli_smb2_rmdir_state *state = NULL;
829 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_rmdir_state);
835 state->dname = dname;
836 state->in_cblobs = in_cblobs;
838 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
839 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
840 return tevent_req_post(req, ev);
843 subreq = cli_smb2_create_fnum_send(
848 0, /* create_flags */
849 SMB2_IMPERSONATION_IMPERSONATION,
850 DELETE_ACCESS, /* desired_access */
851 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
852 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
853 FILE_OPEN, /* create_disposition */
854 FILE_DIRECTORY_FILE, /* create_options */
855 state->in_cblobs); /* in_cblobs */
856 if (tevent_req_nomem(subreq, req)) {
857 return tevent_req_post(req, ev);
859 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened1, req);
863 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq)
865 struct tevent_req *req = tevent_req_callback_data(
866 subreq, struct tevent_req);
867 struct cli_smb2_rmdir_state *state = tevent_req_data(
868 req, struct cli_smb2_rmdir_state);
871 status = cli_smb2_create_fnum_recv(
872 subreq, &state->fnum, NULL, NULL, NULL);
875 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
877 * Naive option to match our SMB1 code. Assume the
878 * symlink path that tripped us up was the last
879 * component and try again. Eventually we will have to
880 * deal with the returned path unprocessed component. JRA.
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,
892 FILE_OPEN, /* create_disposition */
894 FILE_DELETE_ON_CLOSE|
895 FILE_OPEN_REPARSE_POINT, /* create_options */
896 state->in_cblobs); /* in_cblobs */
897 if (tevent_req_nomem(subreq, req)) {
900 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened2, req);
904 if (tevent_req_nterror(req, status)) {
908 subreq = cli_smb2_delete_on_close_send(
909 state, state->ev, state->cli, state->fnum, true);
910 if (tevent_req_nomem(subreq, req)) {
913 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
916 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq)
918 struct tevent_req *req = tevent_req_callback_data(
919 subreq, struct tevent_req);
920 struct cli_smb2_rmdir_state *state = tevent_req_data(
921 req, struct cli_smb2_rmdir_state);
924 status = cli_smb2_create_fnum_recv(
925 subreq, &state->fnum, NULL, NULL, NULL);
927 if (tevent_req_nterror(req, status)) {
931 subreq = cli_smb2_delete_on_close_send(
932 state, state->ev, state->cli, state->fnum, true);
933 if (tevent_req_nomem(subreq, req)) {
936 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
939 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq)
941 struct tevent_req *req = tevent_req_callback_data(
942 subreq, struct tevent_req);
943 struct cli_smb2_rmdir_state *state = tevent_req_data(
944 req, struct cli_smb2_rmdir_state);
946 state->status = cli_smb2_delete_on_close_recv(subreq);
950 * Close the fd even if the set_disp failed
953 subreq = cli_smb2_close_fnum_send(
954 state, state->ev, state->cli, state->fnum);
955 if (tevent_req_nomem(subreq, req)) {
958 tevent_req_set_callback(subreq, cli_smb2_rmdir_closed, req);
961 static void cli_smb2_rmdir_closed(struct tevent_req *subreq)
963 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
964 tevent_req_simple_finish_ntstatus(subreq, status);
967 NTSTATUS cli_smb2_rmdir_recv(struct tevent_req *req)
969 struct cli_smb2_rmdir_state *state = tevent_req_data(
970 req, struct cli_smb2_rmdir_state);
973 if (tevent_req_is_nterror(req, &status)) {
976 return state->status;
979 NTSTATUS cli_smb2_rmdir(
980 struct cli_state *cli,
982 const struct smb2_create_blobs *in_cblobs)
984 TALLOC_CTX *frame = talloc_stackframe();
985 struct tevent_context *ev;
986 struct tevent_req *req;
987 NTSTATUS status = NT_STATUS_NO_MEMORY;
990 if (smbXcli_conn_has_async_calls(cli->conn)) {
992 * Can't use sync call while an async call is in flight
994 status = NT_STATUS_INVALID_PARAMETER;
997 ev = samba_tevent_context_init(frame);
1001 req = cli_smb2_rmdir_send(frame, ev, cli, dname, in_cblobs);
1005 ok = tevent_req_poll_ntstatus(req, ev, &status);
1009 status = cli_smb2_rmdir_recv(req);
1011 cli->raw_status = status;
1016 /***************************************************************
1017 Small wrapper that allows SMB2 to unlink a pathname.
1019 ***************************************************************/
1021 struct cli_smb2_unlink_state {
1022 struct tevent_context *ev;
1023 struct cli_state *cli;
1025 const struct smb2_create_blobs *in_cblobs;
1028 static void cli_smb2_unlink_opened1(struct tevent_req *subreq);
1029 static void cli_smb2_unlink_opened2(struct tevent_req *subreq);
1030 static void cli_smb2_unlink_closed(struct tevent_req *subreq);
1032 struct tevent_req *cli_smb2_unlink_send(
1033 TALLOC_CTX *mem_ctx,
1034 struct tevent_context *ev,
1035 struct cli_state *cli,
1037 const struct smb2_create_blobs *in_cblobs)
1039 struct tevent_req *req = NULL, *subreq = NULL;
1040 struct cli_smb2_unlink_state *state = NULL;
1042 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_unlink_state);
1048 state->fname = fname;
1049 state->in_cblobs = in_cblobs;
1051 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1052 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1053 return tevent_req_post(req, ev);
1056 subreq = cli_smb2_create_fnum_send(
1057 state, /* mem_ctx */
1058 state->ev, /* tevent_context */
1059 state->cli, /* cli_struct */
1060 state->fname, /* filename */
1061 0, /* create_flags */
1062 SMB2_IMPERSONATION_IMPERSONATION,
1063 DELETE_ACCESS, /* desired_access */
1064 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1067 FILE_SHARE_DELETE, /* share_access */
1068 FILE_OPEN, /* create_disposition */
1069 FILE_DELETE_ON_CLOSE, /* create_options */
1070 state->in_cblobs); /* in_cblobs */
1071 if (tevent_req_nomem(subreq, req)) {
1072 return tevent_req_post(req, ev);
1074 tevent_req_set_callback(subreq, cli_smb2_unlink_opened1, req);
1078 static void cli_smb2_unlink_opened1(struct tevent_req *subreq)
1080 struct tevent_req *req = tevent_req_callback_data(
1081 subreq, struct tevent_req);
1082 struct cli_smb2_unlink_state *state = tevent_req_data(
1083 req, struct cli_smb2_unlink_state);
1087 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1088 TALLOC_FREE(subreq);
1090 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1092 * Naive option to match our SMB1 code. Assume the
1093 * symlink path that tripped us up was the last
1094 * component and try again. Eventually we will have to
1095 * deal with the returned path unprocessed component. JRA.
1097 subreq = cli_smb2_create_fnum_send(
1098 state, /* mem_ctx */
1099 state->ev, /* tevent_context */
1100 state->cli, /* cli_struct */
1101 state->fname, /* filename */
1102 0, /* create_flags */
1103 SMB2_IMPERSONATION_IMPERSONATION,
1104 DELETE_ACCESS, /* desired_access */
1105 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1108 FILE_SHARE_DELETE, /* share_access */
1109 FILE_OPEN, /* create_disposition */
1110 FILE_DELETE_ON_CLOSE|
1111 FILE_OPEN_REPARSE_POINT, /* create_options */
1112 state->in_cblobs); /* in_cblobs */
1113 if (tevent_req_nomem(subreq, req)) {
1116 tevent_req_set_callback(subreq, cli_smb2_unlink_opened2, req);
1120 if (tevent_req_nterror(req, status)) {
1124 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1125 if (tevent_req_nomem(subreq, req)) {
1128 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1131 static void cli_smb2_unlink_opened2(struct tevent_req *subreq)
1133 struct tevent_req *req = tevent_req_callback_data(
1134 subreq, struct tevent_req);
1135 struct cli_smb2_unlink_state *state = tevent_req_data(
1136 req, struct cli_smb2_unlink_state);
1140 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1141 TALLOC_FREE(subreq);
1142 if (tevent_req_nterror(req, status)) {
1146 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1147 if (tevent_req_nomem(subreq, req)) {
1150 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1153 static void cli_smb2_unlink_closed(struct tevent_req *subreq)
1155 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1156 tevent_req_simple_finish_ntstatus(subreq, status);
1159 NTSTATUS cli_smb2_unlink_recv(struct tevent_req *req)
1161 return tevent_req_simple_recv_ntstatus(req);
1164 NTSTATUS cli_smb2_unlink(
1165 struct cli_state *cli,
1167 const struct smb2_create_blobs *in_cblobs)
1169 TALLOC_CTX *frame = talloc_stackframe();
1170 struct tevent_context *ev;
1171 struct tevent_req *req;
1172 NTSTATUS status = NT_STATUS_NO_MEMORY;
1175 if (smbXcli_conn_has_async_calls(cli->conn)) {
1177 * Can't use sync call while an async call is in flight
1179 status = NT_STATUS_INVALID_PARAMETER;
1182 ev = samba_tevent_context_init(frame);
1186 req = cli_smb2_unlink_send(frame, ev, cli, fname, in_cblobs);
1190 ok = tevent_req_poll_ntstatus(req, ev, &status);
1194 status = cli_smb2_unlink_recv(req);
1196 cli->raw_status = status;
1201 /***************************************************************
1202 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1203 ***************************************************************/
1205 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
1206 uint32_t dir_data_length,
1207 struct file_info *finfo,
1208 uint32_t *next_offset)
1214 if (dir_data_length < 4) {
1215 return NT_STATUS_INFO_LENGTH_MISMATCH;
1218 *next_offset = IVAL(dir_data, 0);
1220 if (*next_offset > dir_data_length) {
1221 return NT_STATUS_INFO_LENGTH_MISMATCH;
1224 if (*next_offset != 0) {
1225 /* Ensure we only read what in this record. */
1226 dir_data_length = *next_offset;
1229 if (dir_data_length < 105) {
1230 return NT_STATUS_INFO_LENGTH_MISMATCH;
1233 finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
1234 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
1235 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
1236 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
1237 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
1238 finfo->allocated_size = IVAL2_TO_SMB_BIG_UINT(dir_data + 48, 0);
1239 finfo->mode = CVAL(dir_data + 56, 0);
1240 finfo->ino = IVAL2_TO_SMB_BIG_UINT(dir_data + 96, 0);
1241 namelen = IVAL(dir_data + 60,0);
1242 if (namelen > (dir_data_length - 104)) {
1243 return NT_STATUS_INFO_LENGTH_MISMATCH;
1245 slen = CVAL(dir_data + 68, 0);
1247 return NT_STATUS_INFO_LENGTH_MISMATCH;
1249 ret = pull_string_talloc(finfo,
1251 FLAGS2_UNICODE_STRINGS,
1256 if (ret == (size_t)-1) {
1257 /* Bad conversion. */
1258 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1261 ret = pull_string_talloc(finfo,
1263 FLAGS2_UNICODE_STRINGS,
1268 if (ret == (size_t)-1) {
1269 /* Bad conversion. */
1270 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1272 return NT_STATUS_OK;
1275 /*******************************************************************
1276 Given a filename - get its directory name
1277 ********************************************************************/
1279 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
1287 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
1290 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
1301 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
1304 (*parent)[len] = '\0';
1312 /***************************************************************
1313 Wrapper that allows SMB2 to list a directory.
1315 ***************************************************************/
1317 NTSTATUS cli_smb2_list(struct cli_state *cli,
1318 const char *pathname,
1320 NTSTATUS (*fn)(const char *,
1327 uint16_t fnum = 0xffff;
1328 char *parent_dir = NULL;
1329 const char *mask = NULL;
1330 struct smb2_hnd *ph = NULL;
1331 bool processed_file = false;
1332 TALLOC_CTX *frame = talloc_stackframe();
1333 TALLOC_CTX *subframe = NULL;
1336 uint32_t max_avail_len;
1339 if (smbXcli_conn_has_async_calls(cli->conn)) {
1341 * Can't use sync call while an async call is in flight
1343 status = NT_STATUS_INVALID_PARAMETER;
1347 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1348 status = NT_STATUS_INVALID_PARAMETER;
1352 /* Get the directory name. */
1353 if (!windows_parent_dirname(frame,
1357 status = NT_STATUS_NO_MEMORY;
1361 mask_has_wild = ms_has_wild(mask);
1363 status = cli_smb2_create_fnum(cli,
1365 0, /* create_flags */
1366 SMB2_IMPERSONATION_IMPERSONATION,
1367 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
1368 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1369 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
1370 FILE_OPEN, /* create_disposition */
1371 FILE_DIRECTORY_FILE, /* create_options */
1378 if (!NT_STATUS_IS_OK(status)) {
1382 status = map_fnum_to_smb2_handle(cli,
1385 if (!NT_STATUS_IS_OK(status)) {
1390 * ideally, use the max transaction size, but don't send a request
1391 * bigger than we have credits available for
1393 max_trans = smb2cli_conn_max_trans_size(cli->conn);
1394 ok = smb2cli_conn_req_possible(cli->conn, &max_avail_len);
1396 max_trans = MIN(max_trans, max_avail_len);
1400 uint8_t *dir_data = NULL;
1401 uint32_t dir_data_length = 0;
1402 uint32_t next_offset = 0;
1403 subframe = talloc_stackframe();
1405 status = smb2cli_query_directory(cli->conn,
1409 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
1420 if (!NT_STATUS_IS_OK(status)) {
1421 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1428 struct file_info *finfo = talloc_zero(subframe,
1431 if (finfo == NULL) {
1432 status = NT_STATUS_NO_MEMORY;
1436 status = parse_finfo_id_both_directory_info(dir_data,
1441 if (!NT_STATUS_IS_OK(status)) {
1445 if (dir_check_ftype((uint32_t)finfo->mode,
1446 (uint32_t)attribute)) {
1448 * Only process if attributes match.
1449 * On SMB1 server does this, so on
1450 * SMB2 we need to emulate in the
1453 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1455 processed_file = true;
1457 status = fn(cli->dfs_mountpoint,
1462 if (!NT_STATUS_IS_OK(status)) {
1469 /* Move to next entry. */
1471 dir_data += next_offset;
1472 dir_data_length -= next_offset;
1474 } while (next_offset != 0);
1476 TALLOC_FREE(subframe);
1478 if (!mask_has_wild) {
1480 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1481 * when handed a non-wildcard path. Do it
1482 * for the server (with a non-wildcard path
1483 * there should only ever be one file returned.
1485 status = STATUS_NO_MORE_FILES;
1489 } while (NT_STATUS_IS_OK(status));
1491 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1492 status = NT_STATUS_OK;
1495 if (NT_STATUS_IS_OK(status) && !processed_file) {
1497 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1498 * if no files match. Emulate this in the client.
1500 status = NT_STATUS_NO_SUCH_FILE;
1505 if (fnum != 0xffff) {
1506 cli_smb2_close_fnum(cli, fnum);
1509 cli->raw_status = status;
1511 TALLOC_FREE(subframe);
1516 /***************************************************************
1517 Wrapper that allows SMB2 to query a path info (basic level).
1519 ***************************************************************/
1521 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1523 SMB_STRUCT_STAT *sbuf,
1524 uint32_t *attributes)
1527 struct smb_create_returns cr;
1528 uint16_t fnum = 0xffff;
1529 size_t namelen = strlen(name);
1531 if (smbXcli_conn_has_async_calls(cli->conn)) {
1533 * Can't use sync call while an async call is in flight
1535 return NT_STATUS_INVALID_PARAMETER;
1538 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1539 return NT_STATUS_INVALID_PARAMETER;
1542 /* SMB2 is pickier about pathnames. Ensure it doesn't
1544 if (namelen > 0 && name[namelen-1] == '\\') {
1545 char *modname = talloc_strdup(talloc_tos(), name);
1546 modname[namelen-1] = '\0';
1550 /* This is commonly used as a 'cd'. Try qpathinfo on
1551 a directory handle first. */
1553 status = cli_smb2_create_fnum(cli,
1555 0, /* create_flags */
1556 SMB2_IMPERSONATION_IMPERSONATION,
1557 FILE_READ_ATTRIBUTES, /* desired_access */
1558 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1559 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1560 FILE_OPEN, /* create_disposition */
1561 FILE_DIRECTORY_FILE, /* create_options */
1568 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1569 /* Maybe a file ? */
1570 status = cli_smb2_create_fnum(cli,
1572 0, /* create_flags */
1573 SMB2_IMPERSONATION_IMPERSONATION,
1574 FILE_READ_ATTRIBUTES, /* desired_access */
1575 0, /* file attributes */
1576 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1577 FILE_OPEN, /* create_disposition */
1578 0, /* create_options */
1586 if (!NT_STATUS_IS_OK(status)) {
1590 status = cli_smb2_close_fnum(cli, fnum);
1594 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1595 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1596 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1597 sbuf->st_ex_size = cr.end_of_file;
1598 *attributes = cr.file_attributes;
1603 /***************************************************************
1604 Wrapper that allows SMB2 to check if a path is a directory.
1606 ***************************************************************/
1608 NTSTATUS cli_smb2_chkpath(struct cli_state *cli,
1612 uint16_t fnum = 0xffff;
1614 if (smbXcli_conn_has_async_calls(cli->conn)) {
1616 * Can't use sync call while an async call is in flight
1618 return NT_STATUS_INVALID_PARAMETER;
1621 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1622 return NT_STATUS_INVALID_PARAMETER;
1625 /* Ensure this is a directory. */
1626 status = cli_smb2_create_fnum(cli,
1628 0, /* create_flags */
1629 SMB2_IMPERSONATION_IMPERSONATION,
1630 FILE_READ_ATTRIBUTES, /* desired_access */
1631 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1632 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1633 FILE_OPEN, /* create_disposition */
1634 FILE_DIRECTORY_FILE, /* create_options */
1641 if (!NT_STATUS_IS_OK(status)) {
1645 return cli_smb2_close_fnum(cli, fnum);
1648 struct cli_smb2_query_info_fnum_state {
1652 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq);
1654 struct tevent_req *cli_smb2_query_info_fnum_send(
1655 TALLOC_CTX *mem_ctx,
1656 struct tevent_context *ev,
1657 struct cli_state *cli,
1659 uint8_t in_info_type,
1660 uint8_t in_info_class,
1661 uint32_t in_max_output_length,
1662 const DATA_BLOB *in_input_buffer,
1663 uint32_t in_additional_info,
1666 struct tevent_req *req = NULL, *subreq = NULL;
1667 struct cli_smb2_query_info_fnum_state *state = NULL;
1668 struct smb2_hnd *ph = NULL;
1671 req = tevent_req_create(
1672 mem_ctx, &state, struct cli_smb2_query_info_fnum_state);
1677 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1678 if (tevent_req_nterror(req, status)) {
1679 return tevent_req_post(req, ev);
1682 subreq = smb2cli_query_info_send(
1691 in_max_output_length,
1697 if (tevent_req_nomem(subreq, req)) {
1698 return tevent_req_post(req, ev);
1700 tevent_req_set_callback(subreq, cli_smb2_query_info_fnum_done, req);
1704 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq)
1706 struct tevent_req *req = tevent_req_callback_data(
1707 subreq, struct tevent_req);
1708 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1709 req, struct cli_smb2_query_info_fnum_state);
1713 status = smb2cli_query_info_recv(subreq, state, &outbuf);
1714 TALLOC_FREE(subreq);
1715 if (tevent_req_nterror(req, status)) {
1720 * We have to dup the memory here because outbuf.data is not
1721 * returned as a talloc object by smb2cli_query_info_recv.
1722 * It's a pointer into the received buffer.
1724 state->outbuf = data_blob_dup_talloc(state, outbuf);
1726 if ((outbuf.length != 0) &&
1727 tevent_req_nomem(state->outbuf.data, req)) {
1730 tevent_req_done(req);
1733 NTSTATUS cli_smb2_query_info_fnum_recv(
1734 struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *outbuf)
1736 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1737 req, struct cli_smb2_query_info_fnum_state);
1740 if (tevent_req_is_nterror(req, &status)) {
1743 *outbuf = (DATA_BLOB) {
1744 .data = talloc_move(mem_ctx, &state->outbuf.data),
1745 .length = state->outbuf.length,
1747 return NT_STATUS_OK;
1750 NTSTATUS cli_smb2_query_info_fnum(
1751 struct cli_state *cli,
1753 uint8_t in_info_type,
1754 uint8_t in_info_class,
1755 uint32_t in_max_output_length,
1756 const DATA_BLOB *in_input_buffer,
1757 uint32_t in_additional_info,
1759 TALLOC_CTX *mem_ctx,
1762 TALLOC_CTX *frame = talloc_stackframe();
1763 struct tevent_context *ev = NULL;
1764 struct tevent_req *req = NULL;
1765 NTSTATUS status = NT_STATUS_NO_MEMORY;
1768 if (smbXcli_conn_has_async_calls(cli->conn)) {
1770 * Can't use sync call while an async call is in flight
1772 status = NT_STATUS_INVALID_PARAMETER;
1775 ev = samba_tevent_context_init(frame);
1779 req = cli_smb2_query_info_fnum_send(
1786 in_max_output_length,
1793 ok = tevent_req_poll_ntstatus(req, ev, &status);
1797 status = cli_smb2_query_info_fnum_recv(req, mem_ctx, outbuf);
1803 /***************************************************************
1804 Helper function for pathname operations.
1805 ***************************************************************/
1807 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1809 uint32_t desired_access,
1813 size_t namelen = strlen(name);
1814 TALLOC_CTX *frame = talloc_stackframe();
1815 uint32_t create_options = 0;
1817 /* SMB2 is pickier about pathnames. Ensure it doesn't
1819 if (namelen > 0 && name[namelen-1] == '\\') {
1820 char *modname = talloc_strdup(frame, name);
1821 if (modname == NULL) {
1822 status = NT_STATUS_NO_MEMORY;
1825 modname[namelen-1] = '\0';
1829 /* Try to open a file handle first. */
1830 status = cli_smb2_create_fnum(cli,
1832 0, /* create_flags */
1833 SMB2_IMPERSONATION_IMPERSONATION,
1835 0, /* file attributes */
1836 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1837 FILE_OPEN, /* create_disposition */
1845 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1847 * Naive option to match our SMB1 code. Assume the
1848 * symlink path that tripped us up was the last
1849 * component and try again. Eventually we will have to
1850 * deal with the returned path unprocessed component. JRA.
1852 create_options |= FILE_OPEN_REPARSE_POINT;
1853 status = cli_smb2_create_fnum(cli,
1855 0, /* create_flags */
1856 SMB2_IMPERSONATION_IMPERSONATION,
1858 0, /* file attributes */
1859 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1860 FILE_OPEN, /* create_disposition */
1869 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1870 create_options |= FILE_DIRECTORY_FILE;
1871 status = cli_smb2_create_fnum(cli,
1873 0, /* create_flags */
1874 SMB2_IMPERSONATION_IMPERSONATION,
1876 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1877 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1878 FILE_OPEN, /* create_disposition */
1879 FILE_DIRECTORY_FILE, /* create_options */
1893 /***************************************************************
1894 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1896 ***************************************************************/
1898 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1903 DATA_BLOB outbuf = data_blob_null;
1904 uint16_t fnum = 0xffff;
1905 uint32_t altnamelen = 0;
1906 TALLOC_CTX *frame = talloc_stackframe();
1908 if (smbXcli_conn_has_async_calls(cli->conn)) {
1910 * Can't use sync call while an async call is in flight
1912 status = NT_STATUS_INVALID_PARAMETER;
1916 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1917 status = NT_STATUS_INVALID_PARAMETER;
1921 status = get_fnum_from_path(cli,
1923 FILE_READ_ATTRIBUTES,
1926 if (!NT_STATUS_IS_OK(status)) {
1930 status = cli_smb2_query_info_fnum(
1933 1, /* in_info_type */
1934 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1935 0xFFFF, /* in_max_output_length */
1936 NULL, /* in_input_buffer */
1937 0, /* in_additional_info */
1942 if (!NT_STATUS_IS_OK(status)) {
1946 /* Parse the reply. */
1947 if (outbuf.length < 4) {
1948 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1952 altnamelen = IVAL(outbuf.data, 0);
1953 if (altnamelen > outbuf.length - 4) {
1954 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1958 if (altnamelen > 0) {
1960 char *short_name = NULL;
1961 ret = pull_string_talloc(frame,
1963 FLAGS2_UNICODE_STRINGS,
1968 if (ret == (size_t)-1) {
1969 /* Bad conversion. */
1970 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1974 fstrcpy(alt_name, short_name);
1979 status = NT_STATUS_OK;
1983 if (fnum != 0xffff) {
1984 cli_smb2_close_fnum(cli, fnum);
1987 cli->raw_status = status;
1994 /***************************************************************
1995 Wrapper that allows SMB2 to query a fnum info (basic level).
1997 ***************************************************************/
1999 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
2003 struct timespec *create_time,
2004 struct timespec *access_time,
2005 struct timespec *write_time,
2006 struct timespec *change_time,
2010 DATA_BLOB outbuf = data_blob_null;
2011 TALLOC_CTX *frame = talloc_stackframe();
2013 if (smbXcli_conn_has_async_calls(cli->conn)) {
2015 * Can't use sync call while an async call is in flight
2017 status = NT_STATUS_INVALID_PARAMETER;
2021 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2022 status = NT_STATUS_INVALID_PARAMETER;
2026 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2027 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
2029 status = cli_smb2_query_info_fnum(
2032 1, /* in_info_type */
2033 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
2034 0xFFFF, /* in_max_output_length */
2035 NULL, /* in_input_buffer */
2036 0, /* in_additional_info */
2040 if (!NT_STATUS_IS_OK(status)) {
2044 /* Parse the reply. */
2045 if (outbuf.length < 0x60) {
2046 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2051 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
2054 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
2057 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
2060 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
2063 uint32_t attr = IVAL(outbuf.data, 0x20);
2064 *mode = (uint16_t)attr;
2067 uint64_t file_size = BVAL(outbuf.data, 0x30);
2068 *size = (off_t)file_size;
2071 uint64_t file_index = BVAL(outbuf.data, 0x40);
2072 *ino = (SMB_INO_T)file_index;
2077 cli->raw_status = status;
2083 /***************************************************************
2084 Wrapper that allows SMB2 to query an fnum.
2085 Implement on top of cli_smb2_qfileinfo_basic().
2087 ***************************************************************/
2089 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
2093 time_t *change_time,
2094 time_t *access_time,
2097 struct timespec access_time_ts;
2098 struct timespec write_time_ts;
2099 struct timespec change_time_ts;
2100 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
2110 cli->raw_status = status;
2112 if (!NT_STATUS_IS_OK(status)) {
2117 *change_time = change_time_ts.tv_sec;
2120 *access_time = access_time_ts.tv_sec;
2123 *write_time = write_time_ts.tv_sec;
2125 return NT_STATUS_OK;
2128 /***************************************************************
2129 Wrapper that allows SMB2 to get pathname attributes.
2131 ***************************************************************/
2133 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
2140 uint16_t fnum = 0xffff;
2141 struct smb2_hnd *ph = NULL;
2142 TALLOC_CTX *frame = talloc_stackframe();
2144 if (smbXcli_conn_has_async_calls(cli->conn)) {
2146 * Can't use sync call while an async call is in flight
2148 status = NT_STATUS_INVALID_PARAMETER;
2152 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2153 status = NT_STATUS_INVALID_PARAMETER;
2157 status = get_fnum_from_path(cli,
2159 FILE_READ_ATTRIBUTES,
2162 if (!NT_STATUS_IS_OK(status)) {
2166 status = map_fnum_to_smb2_handle(cli,
2169 if (!NT_STATUS_IS_OK(status)) {
2172 status = cli_smb2_getattrE(cli,
2179 if (!NT_STATUS_IS_OK(status)) {
2185 if (fnum != 0xffff) {
2186 cli_smb2_close_fnum(cli, fnum);
2189 cli->raw_status = status;
2195 /***************************************************************
2196 Wrapper that allows SMB2 to query a pathname info (basic level).
2197 Implement on top of cli_smb2_qfileinfo_basic().
2199 ***************************************************************/
2201 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
2203 struct timespec *create_time,
2204 struct timespec *access_time,
2205 struct timespec *write_time,
2206 struct timespec *change_time,
2212 struct smb2_hnd *ph = NULL;
2213 uint16_t fnum = 0xffff;
2214 TALLOC_CTX *frame = talloc_stackframe();
2216 if (smbXcli_conn_has_async_calls(cli->conn)) {
2218 * Can't use sync call while an async call is in flight
2220 status = NT_STATUS_INVALID_PARAMETER;
2224 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2225 status = NT_STATUS_INVALID_PARAMETER;
2229 status = get_fnum_from_path(cli,
2231 FILE_READ_ATTRIBUTES,
2234 if (!NT_STATUS_IS_OK(status)) {
2238 status = map_fnum_to_smb2_handle(cli,
2241 if (!NT_STATUS_IS_OK(status)) {
2245 status = cli_smb2_qfileinfo_basic(cli,
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 struct smb2_hnd *ph = NULL;
2361 TALLOC_CTX *frame = talloc_stackframe();
2363 if (smbXcli_conn_has_async_calls(cli->conn)) {
2365 * Can't use sync call while an async call is in flight
2367 status = NT_STATUS_INVALID_PARAMETER;
2371 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2372 status = NT_STATUS_INVALID_PARAMETER;
2376 status = get_fnum_from_path(cli,
2378 FILE_WRITE_ATTRIBUTES,
2381 if (!NT_STATUS_IS_OK(status)) {
2385 status = map_fnum_to_smb2_handle(cli,
2388 if (!NT_STATUS_IS_OK(status)) {
2392 status = smb2cli_set_info(cli->conn,
2398 p_in_data, /* in_input_buffer */
2399 0, /* in_additional_info */
2404 if (fnum != 0xffff) {
2405 cli_smb2_close_fnum(cli, fnum);
2408 cli->raw_status = status;
2415 /***************************************************************
2416 Wrapper that allows SMB2 to set pathname attributes.
2418 ***************************************************************/
2420 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
2425 uint8_t inbuf_store[40];
2426 DATA_BLOB inbuf = data_blob_null;
2428 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2429 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2431 inbuf.data = inbuf_store;
2432 inbuf.length = sizeof(inbuf_store);
2433 data_blob_clear(&inbuf);
2436 * SMB1 uses attr == 0 to clear all attributes
2437 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2438 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2439 * request attribute change.
2441 * SMB2 uses exactly the reverse. Unfortunately as the
2442 * cli_setatr() ABI is exposed inside libsmbclient,
2443 * we must make the SMB2 cli_smb2_setatr() call
2444 * export the same ABI as the SMB1 cli_setatr()
2445 * which calls it. This means reversing the sense
2446 * of the requested attr argument if it's zero
2447 * or FILE_ATTRIBUTE_NORMAL.
2449 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2453 attr = FILE_ATTRIBUTE_NORMAL;
2454 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
2458 SSVAL(inbuf.data, 32, attr);
2460 put_long_date((char *)inbuf.data + 16,mtime);
2462 /* Set all the other times to -1. */
2463 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2464 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
2465 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
2467 return cli_smb2_setpathinfo(cli,
2469 1, /* in_info_type */
2470 /* in_file_info_class */
2471 SMB_FILE_BASIC_INFORMATION - 1000,
2476 /***************************************************************
2477 Wrapper that allows SMB2 to set file handle times.
2479 ***************************************************************/
2481 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
2488 struct smb2_hnd *ph = NULL;
2489 uint8_t inbuf_store[40];
2490 DATA_BLOB inbuf = data_blob_null;
2492 if (smbXcli_conn_has_async_calls(cli->conn)) {
2494 * Can't use sync call while an async call is in flight
2496 return NT_STATUS_INVALID_PARAMETER;
2499 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2500 return NT_STATUS_INVALID_PARAMETER;
2503 status = map_fnum_to_smb2_handle(cli,
2506 if (!NT_STATUS_IS_OK(status)) {
2510 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2511 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2513 inbuf.data = inbuf_store;
2514 inbuf.length = sizeof(inbuf_store);
2515 data_blob_clear(&inbuf);
2517 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2518 if (change_time != 0) {
2519 put_long_date((char *)inbuf.data + 24, change_time);
2521 if (access_time != 0) {
2522 put_long_date((char *)inbuf.data + 8, access_time);
2524 if (write_time != 0) {
2525 put_long_date((char *)inbuf.data + 16, write_time);
2528 cli->raw_status = smb2cli_set_info(cli->conn,
2532 1, /* in_info_type */
2533 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
2534 &inbuf, /* in_input_buffer */
2535 0, /* in_additional_info */
2539 return cli->raw_status;
2542 /***************************************************************
2543 Wrapper that allows SMB2 to query disk attributes (size).
2545 ***************************************************************/
2547 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2548 uint64_t *bsize, uint64_t *total, uint64_t *avail)
2551 uint16_t fnum = 0xffff;
2552 DATA_BLOB outbuf = data_blob_null;
2553 uint32_t sectors_per_unit = 0;
2554 uint32_t bytes_per_sector = 0;
2555 uint64_t total_size = 0;
2556 uint64_t size_free = 0;
2557 TALLOC_CTX *frame = talloc_stackframe();
2559 if (smbXcli_conn_has_async_calls(cli->conn)) {
2561 * Can't use sync call while an async call is in flight
2563 status = NT_STATUS_INVALID_PARAMETER;
2567 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2568 status = NT_STATUS_INVALID_PARAMETER;
2572 /* First open the top level directory. */
2573 status = cli_smb2_create_fnum(cli,
2575 0, /* create_flags */
2576 SMB2_IMPERSONATION_IMPERSONATION,
2577 FILE_READ_ATTRIBUTES, /* desired_access */
2578 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2579 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2580 FILE_OPEN, /* create_disposition */
2581 FILE_DIRECTORY_FILE, /* create_options */
2588 if (!NT_STATUS_IS_OK(status)) {
2592 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2593 level 3 (SMB_FS_SIZE_INFORMATION). */
2595 status = cli_smb2_query_info_fnum(
2598 2, /* in_info_type */
2599 3, /* in_file_info_class */
2600 0xFFFF, /* in_max_output_length */
2601 NULL, /* in_input_buffer */
2602 0, /* in_additional_info */
2606 if (!NT_STATUS_IS_OK(status)) {
2610 /* Parse the reply. */
2611 if (outbuf.length != 24) {
2612 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2616 total_size = BVAL(outbuf.data, 0);
2617 size_free = BVAL(outbuf.data, 8);
2618 sectors_per_unit = IVAL(outbuf.data, 16);
2619 bytes_per_sector = IVAL(outbuf.data, 20);
2622 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2625 *total = total_size;
2631 status = NT_STATUS_OK;
2635 if (fnum != 0xffff) {
2636 cli_smb2_close_fnum(cli, fnum);
2639 cli->raw_status = status;
2645 /***************************************************************
2646 Wrapper that allows SMB2 to query file system sizes.
2648 ***************************************************************/
2650 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2651 uint64_t *total_allocation_units,
2652 uint64_t *caller_allocation_units,
2653 uint64_t *actual_allocation_units,
2654 uint64_t *sectors_per_allocation_unit,
2655 uint64_t *bytes_per_sector)
2658 uint16_t fnum = 0xffff;
2659 DATA_BLOB outbuf = data_blob_null;
2660 TALLOC_CTX *frame = talloc_stackframe();
2662 if (smbXcli_conn_has_async_calls(cli->conn)) {
2664 * Can't use sync call while an async call is in flight
2666 status = NT_STATUS_INVALID_PARAMETER;
2670 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2671 status = NT_STATUS_INVALID_PARAMETER;
2675 /* First open the top level directory. */
2677 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2678 SMB2_IMPERSONATION_IMPERSONATION,
2679 FILE_READ_ATTRIBUTES, /* desired_access */
2680 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2681 FILE_SHARE_READ | FILE_SHARE_WRITE |
2682 FILE_SHARE_DELETE, /* share_access */
2683 FILE_OPEN, /* create_disposition */
2684 FILE_DIRECTORY_FILE, /* create_options */
2691 if (!NT_STATUS_IS_OK(status)) {
2695 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2696 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2698 status = cli_smb2_query_info_fnum(
2701 SMB2_GETINFO_FS, /* in_info_type */
2702 SMB_FS_FULL_SIZE_INFORMATION - 1000, /* in_file_info_class */
2703 0xFFFF, /* in_max_output_length */
2704 NULL, /* in_input_buffer */
2705 0, /* in_additional_info */
2709 if (!NT_STATUS_IS_OK(status)) {
2713 if (outbuf.length < 32) {
2714 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2718 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2719 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2720 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2721 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2722 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2726 if (fnum != 0xffff) {
2727 cli_smb2_close_fnum(cli, fnum);
2730 cli->raw_status = status;
2736 /***************************************************************
2737 Wrapper that allows SMB2 to query file system attributes.
2739 ***************************************************************/
2741 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2744 uint16_t fnum = 0xffff;
2745 DATA_BLOB outbuf = data_blob_null;
2746 TALLOC_CTX *frame = talloc_stackframe();
2748 if (smbXcli_conn_has_async_calls(cli->conn)) {
2750 * Can't use sync call while an async call is in flight
2752 status = NT_STATUS_INVALID_PARAMETER;
2756 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2757 status = NT_STATUS_INVALID_PARAMETER;
2761 /* First open the top level directory. */
2763 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2764 SMB2_IMPERSONATION_IMPERSONATION,
2765 FILE_READ_ATTRIBUTES, /* desired_access */
2766 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2767 FILE_SHARE_READ | FILE_SHARE_WRITE |
2768 FILE_SHARE_DELETE, /* share_access */
2769 FILE_OPEN, /* create_disposition */
2770 FILE_DIRECTORY_FILE, /* create_options */
2777 if (!NT_STATUS_IS_OK(status)) {
2781 status = cli_smb2_query_info_fnum(
2784 2, /* in_info_type */
2785 5, /* in_file_info_class */
2786 0xFFFF, /* in_max_output_length */
2787 NULL, /* in_input_buffer */
2788 0, /* in_additional_info */
2792 if (!NT_STATUS_IS_OK(status)) {
2796 if (outbuf.length < 12) {
2797 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2801 *fs_attr = IVAL(outbuf.data, 0);
2805 if (fnum != 0xffff) {
2806 cli_smb2_close_fnum(cli, fnum);
2809 cli->raw_status = status;
2815 /***************************************************************
2816 Wrapper that allows SMB2 to query file system volume info.
2818 ***************************************************************/
2820 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2821 TALLOC_CTX *mem_ctx,
2822 char **_volume_name,
2823 uint32_t *pserial_number,
2827 uint16_t fnum = 0xffff;
2828 DATA_BLOB outbuf = data_blob_null;
2830 char *volume_name = NULL;
2831 TALLOC_CTX *frame = talloc_stackframe();
2833 if (smbXcli_conn_has_async_calls(cli->conn)) {
2835 * Can't use sync call while an async call is in flight
2837 status = NT_STATUS_INVALID_PARAMETER;
2841 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2842 status = NT_STATUS_INVALID_PARAMETER;
2846 /* First open the top level directory. */
2848 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2849 SMB2_IMPERSONATION_IMPERSONATION,
2850 FILE_READ_ATTRIBUTES, /* desired_access */
2851 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2852 FILE_SHARE_READ | FILE_SHARE_WRITE |
2853 FILE_SHARE_DELETE, /* share_access */
2854 FILE_OPEN, /* create_disposition */
2855 FILE_DIRECTORY_FILE, /* create_options */
2862 if (!NT_STATUS_IS_OK(status)) {
2866 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2867 level 1 (SMB_FS_VOLUME_INFORMATION). */
2869 status = cli_smb2_query_info_fnum(
2872 SMB2_GETINFO_FS, /* in_info_type */
2873 /* in_file_info_class */
2874 SMB_FS_VOLUME_INFORMATION - 1000,
2875 0xFFFF, /* in_max_output_length */
2876 NULL, /* in_input_buffer */
2877 0, /* in_additional_info */
2881 if (!NT_STATUS_IS_OK(status)) {
2885 if (outbuf.length < 24) {
2886 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2892 ts = interpret_long_date((char *)outbuf.data);
2895 if (pserial_number) {
2896 *pserial_number = IVAL(outbuf.data,8);
2898 nlen = IVAL(outbuf.data,12);
2899 if (nlen + 18 < 18) {
2901 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2905 * The next check is safe as we know outbuf.length >= 24
2908 if (nlen > (outbuf.length - 18)) {
2909 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2913 clistr_pull_talloc(mem_ctx,
2914 (const char *)outbuf.data,
2920 if (volume_name == NULL) {
2921 status = map_nt_error_from_unix(errno);
2925 *_volume_name = volume_name;
2929 if (fnum != 0xffff) {
2930 cli_smb2_close_fnum(cli, fnum);
2933 cli->raw_status = status;
2940 /***************************************************************
2941 Wrapper that allows SMB2 to query a security descriptor.
2943 ***************************************************************/
2945 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2948 TALLOC_CTX *mem_ctx,
2949 struct security_descriptor **ppsd)
2952 DATA_BLOB outbuf = data_blob_null;
2953 struct security_descriptor *lsd = NULL;
2954 TALLOC_CTX *frame = talloc_stackframe();
2956 if (smbXcli_conn_has_async_calls(cli->conn)) {
2958 * Can't use sync call while an async call is in flight
2960 status = NT_STATUS_INVALID_PARAMETER;
2964 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2965 status = NT_STATUS_INVALID_PARAMETER;
2969 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2971 status = cli_smb2_query_info_fnum(
2974 3, /* in_info_type */
2975 0, /* in_file_info_class */
2976 0xFFFF, /* in_max_output_length */
2977 NULL, /* in_input_buffer */
2978 sec_info, /* in_additional_info */
2983 if (!NT_STATUS_IS_OK(status)) {
2987 /* Parse the reply. */
2988 status = unmarshall_sec_desc(mem_ctx,
2993 if (!NT_STATUS_IS_OK(status)) {
3005 cli->raw_status = status;
3011 /***************************************************************
3012 Wrapper that allows SMB2 to set a security descriptor.
3014 ***************************************************************/
3016 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
3019 const struct security_descriptor *sd)
3022 DATA_BLOB inbuf = data_blob_null;
3023 struct smb2_hnd *ph = NULL;
3024 TALLOC_CTX *frame = talloc_stackframe();
3026 if (smbXcli_conn_has_async_calls(cli->conn)) {
3028 * Can't use sync call while an async call is in flight
3030 status = NT_STATUS_INVALID_PARAMETER;
3034 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3035 status = NT_STATUS_INVALID_PARAMETER;
3039 status = map_fnum_to_smb2_handle(cli,
3042 if (!NT_STATUS_IS_OK(status)) {
3046 status = marshall_sec_desc(frame,
3051 if (!NT_STATUS_IS_OK(status)) {
3055 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
3057 status = smb2cli_set_info(cli->conn,
3061 3, /* in_info_type */
3062 0, /* in_file_info_class */
3063 &inbuf, /* in_input_buffer */
3064 sec_info, /* in_additional_info */
3070 cli->raw_status = status;
3076 /***************************************************************
3077 Wrapper that allows SMB2 to query a security descriptor.
3080 ***************************************************************/
3082 struct cli_smb2_mxac_state {
3083 struct tevent_context *ev;
3084 struct cli_state *cli;
3086 struct smb2_create_blobs in_cblobs;
3092 static void cli_smb2_mxac_opened(struct tevent_req *subreq);
3093 static void cli_smb2_mxac_closed(struct tevent_req *subreq);
3095 struct tevent_req *cli_smb2_query_mxac_send(TALLOC_CTX *mem_ctx,
3096 struct tevent_context *ev,
3097 struct cli_state *cli,
3100 struct tevent_req *req = NULL, *subreq = NULL;
3101 struct cli_smb2_mxac_state *state = NULL;
3104 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_mxac_state);
3108 *state = (struct cli_smb2_mxac_state) {
3111 state->fname = fname,
3114 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3115 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3116 return tevent_req_post(req, ev);
3119 status = smb2_create_blob_add(state,
3121 SMB2_CREATE_TAG_MXAC,
3122 data_blob(NULL, 0));
3123 if (tevent_req_nterror(req, status)) {
3124 return tevent_req_post(req, ev);
3127 subreq = cli_smb2_create_fnum_send(
3132 0, /* create_flags */
3133 SMB2_IMPERSONATION_IMPERSONATION,
3134 FILE_READ_ATTRIBUTES,
3135 0, /* file attributes */
3136 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
3138 0, /* create_options */
3140 if (tevent_req_nomem(subreq, req)) {
3141 return tevent_req_post(req, ev);
3143 tevent_req_set_callback(subreq, cli_smb2_mxac_opened, req);
3147 static void cli_smb2_mxac_opened(struct tevent_req *subreq)
3149 struct tevent_req *req = tevent_req_callback_data(
3150 subreq, struct tevent_req);
3151 struct cli_smb2_mxac_state *state = tevent_req_data(
3152 req, struct cli_smb2_mxac_state);
3153 struct smb2_create_blobs out_cblobs = {0};
3154 struct smb2_create_blob *mxac_blob = NULL;
3157 status = cli_smb2_create_fnum_recv(
3158 subreq, &state->fnum, NULL, state, &out_cblobs);
3159 TALLOC_FREE(subreq);
3161 if (tevent_req_nterror(req, status)) {
3165 mxac_blob = smb2_create_blob_find(&out_cblobs, SMB2_CREATE_TAG_MXAC);
3166 if (mxac_blob == NULL) {
3167 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3170 if (mxac_blob->data.length != 8) {
3171 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3175 state->status = NT_STATUS(IVAL(mxac_blob->data.data, 0));
3176 state->mxac = IVAL(mxac_blob->data.data, 4);
3179 subreq = cli_smb2_close_fnum_send(
3180 state, state->ev, state->cli, state->fnum);
3181 if (tevent_req_nomem(subreq, req)) {
3184 tevent_req_set_callback(subreq, cli_smb2_mxac_closed, req);
3189 static void cli_smb2_mxac_closed(struct tevent_req *subreq)
3191 struct tevent_req *req = tevent_req_callback_data(
3192 subreq, struct tevent_req);
3195 status = cli_smb2_close_fnum_recv(subreq);
3196 if (tevent_req_nterror(req, status)) {
3200 tevent_req_done(req);
3203 NTSTATUS cli_smb2_query_mxac_recv(struct tevent_req *req, uint32_t *mxac)
3205 struct cli_smb2_mxac_state *state = tevent_req_data(
3206 req, struct cli_smb2_mxac_state);
3209 if (tevent_req_is_nterror(req, &status)) {
3213 if (!NT_STATUS_IS_OK(state->status)) {
3214 return state->status;
3217 *mxac = state->mxac;
3218 return NT_STATUS_OK;
3221 NTSTATUS cli_smb2_query_mxac(struct cli_state *cli,
3225 TALLOC_CTX *frame = talloc_stackframe();
3226 struct tevent_context *ev = NULL;
3227 struct tevent_req *req = NULL;
3228 NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
3231 if (smbXcli_conn_has_async_calls(cli->conn)) {
3233 * Can't use sync call while an async call is in flight
3235 status = NT_STATUS_INVALID_PARAMETER;
3239 ev = samba_tevent_context_init(frame);
3243 req = cli_smb2_query_mxac_send(frame, ev, cli, fname);
3247 ok = tevent_req_poll_ntstatus(req, ev, &status);
3251 status = cli_smb2_query_mxac_recv(req, _mxac);
3254 cli->raw_status = status;
3259 /***************************************************************
3260 Wrapper that allows SMB2 to rename a file.
3262 ***************************************************************/
3264 NTSTATUS cli_smb2_rename(struct cli_state *cli,
3265 const char *fname_src,
3266 const char *fname_dst,
3270 DATA_BLOB inbuf = data_blob_null;
3271 uint16_t fnum = 0xffff;
3272 struct smb2_hnd *ph = NULL;
3273 smb_ucs2_t *converted_str = NULL;
3274 size_t converted_size_bytes = 0;
3276 TALLOC_CTX *frame = talloc_stackframe();
3278 if (smbXcli_conn_has_async_calls(cli->conn)) {
3280 * Can't use sync call while an async call is in flight
3282 status = NT_STATUS_INVALID_PARAMETER;
3286 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3287 status = NT_STATUS_INVALID_PARAMETER;
3291 status = get_fnum_from_path(cli,
3296 if (!NT_STATUS_IS_OK(status)) {
3300 status = map_fnum_to_smb2_handle(cli,
3303 if (!NT_STATUS_IS_OK(status)) {
3307 /* SMB2 is pickier about pathnames. Ensure it doesn't
3309 if (*fname_dst == '\\') {
3313 /* SMB2 is pickier about pathnames. Ensure it doesn't
3315 namelen = strlen(fname_dst);
3316 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
3317 char *modname = talloc_strdup(frame, fname_dst);
3318 modname[namelen-1] = '\0';
3319 fname_dst = modname;
3322 if (!push_ucs2_talloc(frame,
3325 &converted_size_bytes)) {
3326 status = NT_STATUS_INVALID_PARAMETER;
3330 /* W2K8 insists the dest name is not null
3331 terminated. Remove the last 2 zero bytes
3332 and reduce the name length. */
3334 if (converted_size_bytes < 2) {
3335 status = NT_STATUS_INVALID_PARAMETER;
3338 converted_size_bytes -= 2;
3340 inbuf = data_blob_talloc_zero(frame,
3341 20 + converted_size_bytes);
3342 if (inbuf.data == NULL) {
3343 status = NT_STATUS_NO_MEMORY;
3348 SCVAL(inbuf.data, 0, 1);
3351 SIVAL(inbuf.data, 16, converted_size_bytes);
3352 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
3354 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3355 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3357 status = smb2cli_set_info(cli->conn,
3361 1, /* in_info_type */
3362 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
3363 &inbuf, /* in_input_buffer */
3364 0, /* in_additional_info */
3370 if (fnum != 0xffff) {
3371 cli_smb2_close_fnum(cli, fnum);
3374 cli->raw_status = status;
3380 /***************************************************************
3381 Wrapper that allows SMB2 to set an EA on a fnum.
3383 ***************************************************************/
3385 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
3387 const char *ea_name,
3392 DATA_BLOB inbuf = data_blob_null;
3394 char *ea_name_ascii = NULL;
3396 struct smb2_hnd *ph = NULL;
3397 TALLOC_CTX *frame = talloc_stackframe();
3399 if (smbXcli_conn_has_async_calls(cli->conn)) {
3401 * Can't use sync call while an async call is in flight
3403 status = NT_STATUS_INVALID_PARAMETER;
3407 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3408 status = NT_STATUS_INVALID_PARAMETER;
3412 status = map_fnum_to_smb2_handle(cli,
3415 if (!NT_STATUS_IS_OK(status)) {
3419 /* Marshall the SMB2 EA data. */
3420 if (ea_len > 0xFFFF) {
3421 status = NT_STATUS_INVALID_PARAMETER;
3425 if (!push_ascii_talloc(frame,
3429 status = NT_STATUS_INVALID_PARAMETER;
3433 if (namelen < 2 || namelen > 0xFF) {
3434 status = NT_STATUS_INVALID_PARAMETER;
3438 bloblen = 8 + ea_len + namelen;
3439 /* Round up to a 4 byte boundary. */
3440 bloblen = ((bloblen + 3)&~3);
3442 inbuf = data_blob_talloc_zero(frame, bloblen);
3443 if (inbuf.data == NULL) {
3444 status = NT_STATUS_NO_MEMORY;
3447 /* namelen doesn't include the NULL byte. */
3448 SCVAL(inbuf.data, 5, namelen - 1);
3449 SSVAL(inbuf.data, 6, ea_len);
3450 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
3451 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
3453 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3454 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3456 status = smb2cli_set_info(cli->conn,
3460 1, /* in_info_type */
3461 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3462 &inbuf, /* in_input_buffer */
3463 0, /* in_additional_info */
3469 cli->raw_status = status;
3475 /***************************************************************
3476 Wrapper that allows SMB2 to set an EA on a pathname.
3478 ***************************************************************/
3480 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
3482 const char *ea_name,
3487 uint16_t fnum = 0xffff;
3489 if (smbXcli_conn_has_async_calls(cli->conn)) {
3491 * Can't use sync call while an async call is in flight
3493 status = NT_STATUS_INVALID_PARAMETER;
3497 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3498 status = NT_STATUS_INVALID_PARAMETER;
3502 status = get_fnum_from_path(cli,
3507 if (!NT_STATUS_IS_OK(status)) {
3511 status = cli_set_ea_fnum(cli,
3516 if (!NT_STATUS_IS_OK(status)) {
3522 if (fnum != 0xffff) {
3523 cli_smb2_close_fnum(cli, fnum);
3526 cli->raw_status = status;
3531 /***************************************************************
3532 Wrapper that allows SMB2 to get an EA list on a pathname.
3534 ***************************************************************/
3536 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
3540 struct ea_struct **pea_array)
3543 uint16_t fnum = 0xffff;
3544 DATA_BLOB outbuf = data_blob_null;
3545 struct ea_list *ea_list = NULL;
3546 struct ea_list *eal = NULL;
3547 size_t ea_count = 0;
3548 TALLOC_CTX *frame = talloc_stackframe();
3553 if (smbXcli_conn_has_async_calls(cli->conn)) {
3555 * Can't use sync call while an async call is in flight
3557 status = NT_STATUS_INVALID_PARAMETER;
3561 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3562 status = NT_STATUS_INVALID_PARAMETER;
3566 status = get_fnum_from_path(cli,
3571 if (!NT_STATUS_IS_OK(status)) {
3575 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3576 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3578 status = cli_smb2_query_info_fnum(
3581 1, /* in_info_type */
3582 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3583 0xFFFF, /* in_max_output_length */
3584 NULL, /* in_input_buffer */
3585 0, /* in_additional_info */
3590 if (!NT_STATUS_IS_OK(status)) {
3594 /* Parse the reply. */
3595 ea_list = read_nttrans_ea_list(ctx,
3596 (const char *)outbuf.data,
3598 if (ea_list == NULL) {
3599 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3603 /* Convert to an array. */
3604 for (eal = ea_list; eal; eal = eal->next) {
3609 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
3610 if (*pea_array == NULL) {
3611 status = NT_STATUS_NO_MEMORY;
3615 for (eal = ea_list; eal; eal = eal->next) {
3616 (*pea_array)[ea_count++] = eal->ea;
3618 *pnum_eas = ea_count;
3623 if (fnum != 0xffff) {
3624 cli_smb2_close_fnum(cli, fnum);
3627 cli->raw_status = status;
3633 /***************************************************************
3634 Wrapper that allows SMB2 to get user quota.
3636 ***************************************************************/
3638 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
3640 SMB_NTQUOTA_STRUCT *pqt)
3643 DATA_BLOB inbuf = data_blob_null;
3644 DATA_BLOB info_blob = data_blob_null;
3645 DATA_BLOB outbuf = data_blob_null;
3646 TALLOC_CTX *frame = talloc_stackframe();
3648 unsigned int offset;
3649 struct smb2_query_quota_info query = {0};
3650 struct file_get_quota_info info = {0};
3651 enum ndr_err_code err;
3652 struct ndr_push *ndr_push = NULL;
3654 if (smbXcli_conn_has_async_calls(cli->conn)) {
3656 * Can't use sync call while an async call is in flight
3658 status = NT_STATUS_INVALID_PARAMETER;
3662 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3663 status = NT_STATUS_INVALID_PARAMETER;
3667 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
3669 query.return_single = 1;
3671 info.next_entry_offset = 0;
3672 info.sid_length = sid_len;
3673 info.sid = pqt->sid;
3675 err = ndr_push_struct_blob(
3679 (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
3681 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3682 status = NT_STATUS_INTERNAL_ERROR;
3686 query.sid_list_length = info_blob.length;
3687 ndr_push = ndr_push_init_ctx(frame);
3689 status = NT_STATUS_NO_MEMORY;
3693 err = ndr_push_smb2_query_quota_info(ndr_push,
3694 NDR_SCALARS | NDR_BUFFERS,
3697 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3698 status = NT_STATUS_INTERNAL_ERROR;
3702 err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3705 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3706 status = NT_STATUS_INTERNAL_ERROR;
3709 inbuf.data = ndr_push->data;
3710 inbuf.length = ndr_push->offset;
3712 status = cli_smb2_query_info_fnum(
3715 4, /* in_info_type */
3716 0, /* in_file_info_class */
3717 0xFFFF, /* in_max_output_length */
3718 &inbuf, /* in_input_buffer */
3719 0, /* in_additional_info */
3724 if (!NT_STATUS_IS_OK(status)) {
3728 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3730 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3731 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3735 cli->raw_status = status;
3741 /***************************************************************
3742 Wrapper that allows SMB2 to list user quota.
3744 ***************************************************************/
3746 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3747 TALLOC_CTX *mem_ctx,
3749 SMB_NTQUOTA_LIST **pqt_list,
3753 DATA_BLOB inbuf = data_blob_null;
3754 DATA_BLOB outbuf = data_blob_null;
3755 TALLOC_CTX *frame = talloc_stackframe();
3756 struct smb2_query_quota_info info = {0};
3757 enum ndr_err_code err;
3759 if (smbXcli_conn_has_async_calls(cli->conn)) {
3761 * Can't use sync call while an async call is in flight
3763 status = NT_STATUS_INVALID_PARAMETER;
3767 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3768 status = NT_STATUS_INVALID_PARAMETER;
3772 info.restart_scan = first ? 1 : 0;
3774 err = ndr_push_struct_blob(
3778 (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3780 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3781 status = NT_STATUS_INTERNAL_ERROR;
3785 status = cli_smb2_query_info_fnum(
3788 4, /* in_info_type */
3789 0, /* in_file_info_class */
3790 0xFFFF, /* in_max_output_length */
3791 &inbuf, /* in_input_buffer */
3792 0, /* in_additional_info */
3798 * safeguard against panic from calling parse_user_quota_list with
3801 if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3802 status = NT_STATUS_NO_MORE_ENTRIES;
3805 if (!NT_STATUS_IS_OK(status)) {
3809 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3813 cli->raw_status = status;
3819 /***************************************************************
3820 Wrapper that allows SMB2 to get file system quota.
3822 ***************************************************************/
3824 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3826 SMB_NTQUOTA_STRUCT *pqt)
3829 DATA_BLOB outbuf = data_blob_null;
3830 TALLOC_CTX *frame = talloc_stackframe();
3832 if (smbXcli_conn_has_async_calls(cli->conn)) {
3834 * Can't use sync call while an async call is in flight
3836 status = NT_STATUS_INVALID_PARAMETER;
3840 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3841 status = NT_STATUS_INVALID_PARAMETER;
3845 status = cli_smb2_query_info_fnum(
3848 2, /* in_info_type */
3849 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3850 0xFFFF, /* in_max_output_length */
3851 NULL, /* in_input_buffer */
3852 0, /* in_additional_info */
3857 if (!NT_STATUS_IS_OK(status)) {
3861 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3864 cli->raw_status = status;
3870 /***************************************************************
3871 Wrapper that allows SMB2 to set user quota.
3873 ***************************************************************/
3875 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3877 SMB_NTQUOTA_LIST *qtl)
3880 DATA_BLOB inbuf = data_blob_null;
3881 struct smb2_hnd *ph = NULL;
3882 TALLOC_CTX *frame = talloc_stackframe();
3884 if (smbXcli_conn_has_async_calls(cli->conn)) {
3886 * Can't use sync call while an async call is in flight
3888 status = NT_STATUS_INVALID_PARAMETER;
3892 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3893 status = NT_STATUS_INVALID_PARAMETER;
3897 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3898 if (!NT_STATUS_IS_OK(status)) {
3902 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3903 if (!NT_STATUS_IS_OK(status)) {
3907 status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
3908 cli->smb2.tcon, 4, /* in_info_type */
3909 0, /* in_file_info_class */
3910 &inbuf, /* in_input_buffer */
3911 0, /* in_additional_info */
3912 ph->fid_persistent, ph->fid_volatile);
3915 cli->raw_status = status;
3922 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3924 SMB_NTQUOTA_STRUCT *pqt)
3927 DATA_BLOB inbuf = data_blob_null;
3928 struct smb2_hnd *ph = NULL;
3929 TALLOC_CTX *frame = talloc_stackframe();
3931 if (smbXcli_conn_has_async_calls(cli->conn)) {
3933 * Can't use sync call while an async call is in flight
3935 status = NT_STATUS_INVALID_PARAMETER;
3939 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3940 status = NT_STATUS_INVALID_PARAMETER;
3944 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3945 if (!NT_STATUS_IS_OK(status)) {
3949 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3950 if (!NT_STATUS_IS_OK(status)) {
3954 status = smb2cli_set_info(
3955 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3956 2, /* in_info_type */
3957 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3958 &inbuf, /* in_input_buffer */
3959 0, /* in_additional_info */
3960 ph->fid_persistent, ph->fid_volatile);
3962 cli->raw_status = status;
3968 struct cli_smb2_read_state {
3969 struct tevent_context *ev;
3970 struct cli_state *cli;
3971 struct smb2_hnd *ph;
3972 uint64_t start_offset;
3978 static void cli_smb2_read_done(struct tevent_req *subreq);
3980 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3981 struct tevent_context *ev,
3982 struct cli_state *cli,
3988 struct tevent_req *req, *subreq;
3989 struct cli_smb2_read_state *state;
3991 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3997 state->start_offset = (uint64_t)offset;
3998 state->size = (uint32_t)size;
3999 state->received = 0;
4002 status = map_fnum_to_smb2_handle(cli,
4005 if (tevent_req_nterror(req, status)) {
4006 return tevent_req_post(req, ev);
4009 subreq = smb2cli_read_send(state,
4012 state->cli->timeout,
4013 state->cli->smb2.session,
4014 state->cli->smb2.tcon,
4016 state->start_offset,
4017 state->ph->fid_persistent,
4018 state->ph->fid_volatile,
4019 0, /* minimum_count */
4020 0); /* remaining_bytes */
4022 if (tevent_req_nomem(subreq, req)) {
4023 return tevent_req_post(req, ev);
4025 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
4029 static void cli_smb2_read_done(struct tevent_req *subreq)
4031 struct tevent_req *req = tevent_req_callback_data(
4032 subreq, struct tevent_req);
4033 struct cli_smb2_read_state *state = tevent_req_data(
4034 req, struct cli_smb2_read_state);
4037 status = smb2cli_read_recv(subreq, state,
4038 &state->buf, &state->received);
4039 if (tevent_req_nterror(req, status)) {
4043 if (state->received > state->size) {
4044 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4048 tevent_req_done(req);
4051 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
4056 struct cli_smb2_read_state *state = tevent_req_data(
4057 req, struct cli_smb2_read_state);
4059 if (tevent_req_is_nterror(req, &status)) {
4060 state->cli->raw_status = status;
4064 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
4065 * better make sure that you copy it away before you talloc_free(req).
4066 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
4068 *received = (ssize_t)state->received;
4069 *rcvbuf = state->buf;
4070 state->cli->raw_status = NT_STATUS_OK;
4071 return NT_STATUS_OK;
4074 struct cli_smb2_write_state {
4075 struct tevent_context *ev;
4076 struct cli_state *cli;
4077 struct smb2_hnd *ph;
4085 static void cli_smb2_write_written(struct tevent_req *req);
4087 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
4088 struct tevent_context *ev,
4089 struct cli_state *cli,
4097 struct tevent_req *req, *subreq = NULL;
4098 struct cli_smb2_write_state *state = NULL;
4100 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
4106 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4107 state->flags = (uint32_t)mode;
4109 state->offset = (uint64_t)offset;
4110 state->size = (uint32_t)size;
4113 status = map_fnum_to_smb2_handle(cli,
4116 if (tevent_req_nterror(req, status)) {
4117 return tevent_req_post(req, ev);
4120 subreq = smb2cli_write_send(state,
4123 state->cli->timeout,
4124 state->cli->smb2.session,
4125 state->cli->smb2.tcon,
4128 state->ph->fid_persistent,
4129 state->ph->fid_volatile,
4130 0, /* remaining_bytes */
4131 state->flags, /* flags */
4134 if (tevent_req_nomem(subreq, req)) {
4135 return tevent_req_post(req, ev);
4137 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
4141 static void cli_smb2_write_written(struct tevent_req *subreq)
4143 struct tevent_req *req = tevent_req_callback_data(
4144 subreq, struct tevent_req);
4145 struct cli_smb2_write_state *state = tevent_req_data(
4146 req, struct cli_smb2_write_state);
4150 status = smb2cli_write_recv(subreq, &written);
4151 TALLOC_FREE(subreq);
4152 if (tevent_req_nterror(req, status)) {
4156 state->written = written;
4158 tevent_req_done(req);
4161 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
4164 struct cli_smb2_write_state *state = tevent_req_data(
4165 req, struct cli_smb2_write_state);
4168 if (tevent_req_is_nterror(req, &status)) {
4169 state->cli->raw_status = status;
4170 tevent_req_received(req);
4174 if (pwritten != NULL) {
4175 *pwritten = (size_t)state->written;
4177 state->cli->raw_status = NT_STATUS_OK;
4178 tevent_req_received(req);
4179 return NT_STATUS_OK;
4182 /***************************************************************
4183 Wrapper that allows SMB2 async write using an fnum.
4184 This is mostly cut-and-paste from Volker's code inside
4185 source3/libsmb/clireadwrite.c, adapted for SMB2.
4187 Done this way so I can reuse all the logic inside cli_push()
4189 ***************************************************************/
4191 struct cli_smb2_writeall_state {
4192 struct tevent_context *ev;
4193 struct cli_state *cli;
4194 struct smb2_hnd *ph;
4202 static void cli_smb2_writeall_written(struct tevent_req *req);
4204 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
4205 struct tevent_context *ev,
4206 struct cli_state *cli,
4214 struct tevent_req *req, *subreq = NULL;
4215 struct cli_smb2_writeall_state *state = NULL;
4220 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
4226 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4227 state->flags = (uint32_t)mode;
4229 state->offset = (uint64_t)offset;
4230 state->size = (uint32_t)size;
4233 status = map_fnum_to_smb2_handle(cli,
4236 if (tevent_req_nterror(req, status)) {
4237 return tevent_req_post(req, ev);
4240 to_write = state->size;
4241 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4242 to_write = MIN(max_size, to_write);
4243 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4245 to_write = MIN(max_size, to_write);
4248 subreq = smb2cli_write_send(state,
4251 state->cli->timeout,
4252 state->cli->smb2.session,
4253 state->cli->smb2.tcon,
4256 state->ph->fid_persistent,
4257 state->ph->fid_volatile,
4258 0, /* remaining_bytes */
4259 state->flags, /* flags */
4260 state->buf + state->written);
4262 if (tevent_req_nomem(subreq, req)) {
4263 return tevent_req_post(req, ev);
4265 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4269 static void cli_smb2_writeall_written(struct tevent_req *subreq)
4271 struct tevent_req *req = tevent_req_callback_data(
4272 subreq, struct tevent_req);
4273 struct cli_smb2_writeall_state *state = tevent_req_data(
4274 req, struct cli_smb2_writeall_state);
4276 uint32_t written, to_write;
4280 status = smb2cli_write_recv(subreq, &written);
4281 TALLOC_FREE(subreq);
4282 if (tevent_req_nterror(req, status)) {
4286 state->written += written;
4288 if (state->written > state->size) {
4289 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4293 to_write = state->size - state->written;
4295 if (to_write == 0) {
4296 tevent_req_done(req);
4300 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4301 to_write = MIN(max_size, to_write);
4302 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4304 to_write = MIN(max_size, to_write);
4307 subreq = smb2cli_write_send(state,
4310 state->cli->timeout,
4311 state->cli->smb2.session,
4312 state->cli->smb2.tcon,
4314 state->offset + state->written,
4315 state->ph->fid_persistent,
4316 state->ph->fid_volatile,
4317 0, /* remaining_bytes */
4318 state->flags, /* flags */
4319 state->buf + state->written);
4321 if (tevent_req_nomem(subreq, req)) {
4324 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4327 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
4330 struct cli_smb2_writeall_state *state = tevent_req_data(
4331 req, struct cli_smb2_writeall_state);
4334 if (tevent_req_is_nterror(req, &status)) {
4335 state->cli->raw_status = status;
4338 if (pwritten != NULL) {
4339 *pwritten = (size_t)state->written;
4341 state->cli->raw_status = NT_STATUS_OK;
4342 return NT_STATUS_OK;
4345 struct cli_smb2_splice_state {
4346 struct tevent_context *ev;
4347 struct cli_state *cli;
4348 struct smb2_hnd *src_ph;
4349 struct smb2_hnd *dst_ph;
4350 int (*splice_cb)(off_t n, void *priv);
4357 struct req_resume_key_rsp resume_rsp;
4358 struct srv_copychunk_copy cc_copy;
4361 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4362 struct tevent_req *req);
4364 static void cli_splice_copychunk_done(struct tevent_req *subreq)
4366 struct tevent_req *req = tevent_req_callback_data(
4367 subreq, struct tevent_req);
4368 struct cli_smb2_splice_state *state =
4369 tevent_req_data(req,
4370 struct cli_smb2_splice_state);
4371 struct smbXcli_conn *conn = state->cli->conn;
4372 DATA_BLOB out_input_buffer = data_blob_null;
4373 DATA_BLOB out_output_buffer = data_blob_null;
4374 struct srv_copychunk_rsp cc_copy_rsp;
4375 enum ndr_err_code ndr_ret;
4378 status = smb2cli_ioctl_recv(subreq, state,
4380 &out_output_buffer);
4381 TALLOC_FREE(subreq);
4382 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
4383 state->resized) && tevent_req_nterror(req, status)) {
4387 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
4388 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
4389 if (ndr_ret != NDR_ERR_SUCCESS) {
4390 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4391 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4395 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
4396 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
4397 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
4398 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
4399 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
4400 tevent_req_nterror(req, status)) {
4404 state->resized = true;
4405 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
4406 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
4408 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4409 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4410 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
4411 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4414 state->src_offset += cc_copy_rsp.total_bytes_written;
4415 state->dst_offset += cc_copy_rsp.total_bytes_written;
4416 state->written += cc_copy_rsp.total_bytes_written;
4417 if (!state->splice_cb(state->written, state->priv)) {
4418 tevent_req_nterror(req, NT_STATUS_CANCELLED);
4423 cli_splice_copychunk_send(state, req);
4426 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4427 struct tevent_req *req)
4429 struct tevent_req *subreq;
4430 enum ndr_err_code ndr_ret;
4431 struct smbXcli_conn *conn = state->cli->conn;
4432 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
4433 off_t src_offset = state->src_offset;
4434 off_t dst_offset = state->dst_offset;
4435 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
4436 state->size - state->written);
4437 DATA_BLOB in_input_buffer = data_blob_null;
4438 DATA_BLOB in_output_buffer = data_blob_null;
4440 if (state->size - state->written == 0) {
4441 tevent_req_done(req);
4445 cc_copy->chunk_count = 0;
4447 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
4448 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
4449 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
4450 smb2cli_conn_cc_chunk_len(conn));
4451 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
4452 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4455 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
4456 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
4457 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
4458 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4461 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4462 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4463 cc_copy->chunk_count++;
4466 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
4467 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
4468 if (ndr_ret != NDR_ERR_SUCCESS) {
4469 DEBUG(0, ("failed to marshall copy chunk req\n"));
4470 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4474 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
4475 state->cli->timeout,
4476 state->cli->smb2.session,
4477 state->cli->smb2.tcon,
4478 state->dst_ph->fid_persistent, /* in_fid_persistent */
4479 state->dst_ph->fid_volatile, /* in_fid_volatile */
4480 FSCTL_SRV_COPYCHUNK_WRITE,
4481 0, /* in_max_input_length */
4483 12, /* in_max_output_length */
4485 SMB2_IOCTL_FLAG_IS_FSCTL);
4486 if (tevent_req_nomem(subreq, req)) {
4489 tevent_req_set_callback(subreq,
4490 cli_splice_copychunk_done,
4494 static void cli_splice_key_done(struct tevent_req *subreq)
4496 struct tevent_req *req = tevent_req_callback_data(
4497 subreq, struct tevent_req);
4498 struct cli_smb2_splice_state *state =
4499 tevent_req_data(req,
4500 struct cli_smb2_splice_state);
4501 enum ndr_err_code ndr_ret;
4504 DATA_BLOB out_input_buffer = data_blob_null;
4505 DATA_BLOB out_output_buffer = data_blob_null;
4507 status = smb2cli_ioctl_recv(subreq, state,
4509 &out_output_buffer);
4510 TALLOC_FREE(subreq);
4511 if (tevent_req_nterror(req, status)) {
4515 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
4516 state, &state->resume_rsp,
4517 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
4518 if (ndr_ret != NDR_ERR_SUCCESS) {
4519 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4520 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4524 memcpy(&state->cc_copy.source_key,
4525 &state->resume_rsp.resume_key,
4526 sizeof state->resume_rsp.resume_key);
4528 cli_splice_copychunk_send(state, req);
4531 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
4532 struct tevent_context *ev,
4533 struct cli_state *cli,
4534 uint16_t src_fnum, uint16_t dst_fnum,
4535 off_t size, off_t src_offset, off_t dst_offset,
4536 int (*splice_cb)(off_t n, void *priv),
4539 struct tevent_req *req;
4540 struct tevent_req *subreq;
4541 struct cli_smb2_splice_state *state;
4543 DATA_BLOB in_input_buffer = data_blob_null;
4544 DATA_BLOB in_output_buffer = data_blob_null;
4546 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
4552 state->splice_cb = splice_cb;
4556 state->src_offset = src_offset;
4557 state->dst_offset = dst_offset;
4558 state->cc_copy.chunks = talloc_array(state,
4559 struct srv_copychunk,
4560 smb2cli_conn_cc_max_chunks(cli->conn));
4561 if (state->cc_copy.chunks == NULL) {
4565 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
4566 if (tevent_req_nterror(req, status))
4567 return tevent_req_post(req, ev);
4569 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
4570 if (tevent_req_nterror(req, status))
4571 return tevent_req_post(req, ev);
4573 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
4577 state->src_ph->fid_persistent, /* in_fid_persistent */
4578 state->src_ph->fid_volatile, /* in_fid_volatile */
4579 FSCTL_SRV_REQUEST_RESUME_KEY,
4580 0, /* in_max_input_length */
4582 32, /* in_max_output_length */
4584 SMB2_IOCTL_FLAG_IS_FSCTL);
4585 if (tevent_req_nomem(subreq, req)) {
4588 tevent_req_set_callback(subreq,
4589 cli_splice_key_done,
4595 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
4597 struct cli_smb2_splice_state *state = tevent_req_data(
4598 req, struct cli_smb2_splice_state);
4601 if (tevent_req_is_nterror(req, &status)) {
4602 state->cli->raw_status = status;
4603 tevent_req_received(req);
4606 if (written != NULL) {
4607 *written = state->written;
4609 state->cli->raw_status = NT_STATUS_OK;
4610 tevent_req_received(req);
4611 return NT_STATUS_OK;
4614 /***************************************************************
4615 SMB2 enum shadow copy data.
4616 ***************************************************************/
4618 struct cli_smb2_shadow_copy_data_fnum_state {
4619 struct cli_state *cli;
4621 struct smb2_hnd *ph;
4622 DATA_BLOB out_input_buffer;
4623 DATA_BLOB out_output_buffer;
4626 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
4628 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
4629 TALLOC_CTX *mem_ctx,
4630 struct tevent_context *ev,
4631 struct cli_state *cli,
4635 struct tevent_req *req, *subreq;
4636 struct cli_smb2_shadow_copy_data_fnum_state *state;
4639 req = tevent_req_create(mem_ctx, &state,
4640 struct cli_smb2_shadow_copy_data_fnum_state);
4645 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4646 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4647 return tevent_req_post(req, ev);
4653 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4654 if (tevent_req_nterror(req, status)) {
4655 return tevent_req_post(req, ev);
4659 * TODO. Under SMB2 we should send a zero max_output_length
4660 * ioctl to get the required size, then send another ioctl
4661 * to get the data, but the current SMB1 implementation just
4662 * does one roundtrip with a 64K buffer size. Do the same
4666 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4667 state->cli->timeout,
4668 state->cli->smb2.session,
4669 state->cli->smb2.tcon,
4670 state->ph->fid_persistent, /* in_fid_persistent */
4671 state->ph->fid_volatile, /* in_fid_volatile */
4672 FSCTL_GET_SHADOW_COPY_DATA,
4673 0, /* in_max_input_length */
4674 NULL, /* in_input_buffer */
4676 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
4677 NULL, /* in_output_buffer */
4678 SMB2_IOCTL_FLAG_IS_FSCTL);
4680 if (tevent_req_nomem(subreq, req)) {
4681 return tevent_req_post(req, ev);
4683 tevent_req_set_callback(subreq,
4684 cli_smb2_shadow_copy_data_fnum_done,
4690 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4692 struct tevent_req *req = tevent_req_callback_data(
4693 subreq, struct tevent_req);
4694 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4695 req, struct cli_smb2_shadow_copy_data_fnum_state);
4698 status = smb2cli_ioctl_recv(subreq, state,
4699 &state->out_input_buffer,
4700 &state->out_output_buffer);
4701 tevent_req_simple_finish_ntstatus(subreq, status);
4704 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4705 TALLOC_CTX *mem_ctx,
4710 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4711 req, struct cli_smb2_shadow_copy_data_fnum_state);
4712 char **names = NULL;
4713 uint32_t num_names = 0;
4714 uint32_t num_names_returned = 0;
4715 uint32_t dlength = 0;
4717 uint8_t *endp = NULL;
4720 if (tevent_req_is_nterror(req, &status)) {
4724 if (state->out_output_buffer.length < 16) {
4725 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4728 num_names = IVAL(state->out_output_buffer.data, 0);
4729 num_names_returned = IVAL(state->out_output_buffer.data, 4);
4730 dlength = IVAL(state->out_output_buffer.data, 8);
4732 if (num_names > 0x7FFFFFFF) {
4733 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4736 if (get_names == false) {
4737 *pnum_names = (int)num_names;
4738 return NT_STATUS_OK;
4740 if (num_names != num_names_returned) {
4741 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4743 if (dlength + 12 < 12) {
4744 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4747 * NB. The below is an allowable return if there are
4748 * more snapshots than the buffer size we told the
4749 * server we can receive. We currently don't support
4752 if (dlength + 12 > state->out_output_buffer.length) {
4753 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4755 if (state->out_output_buffer.length +
4756 (2 * sizeof(SHADOW_COPY_LABEL)) <
4757 state->out_output_buffer.length) {
4758 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4761 names = talloc_array(mem_ctx, char *, num_names_returned);
4762 if (names == NULL) {
4763 return NT_STATUS_NO_MEMORY;
4766 endp = state->out_output_buffer.data +
4767 state->out_output_buffer.length;
4769 for (i=0; i<num_names_returned; i++) {
4772 size_t converted_size;
4774 src = state->out_output_buffer.data + 12 +
4775 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4777 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4778 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4780 ret = convert_string_talloc(
4781 names, CH_UTF16LE, CH_UNIX,
4782 src, 2 * sizeof(SHADOW_COPY_LABEL),
4783 &names[i], &converted_size);
4786 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4789 *pnum_names = num_names;
4791 return NT_STATUS_OK;
4794 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4795 struct cli_state *cli,
4801 TALLOC_CTX *frame = talloc_stackframe();
4802 struct tevent_context *ev;
4803 struct tevent_req *req;
4804 NTSTATUS status = NT_STATUS_NO_MEMORY;
4806 if (smbXcli_conn_has_async_calls(cli->conn)) {
4808 * Can't use sync call while an async call is in flight
4810 status = NT_STATUS_INVALID_PARAMETER;
4813 ev = samba_tevent_context_init(frame);
4817 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4825 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4828 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4834 cli->raw_status = status;
4840 /***************************************************************
4841 Wrapper that allows SMB2 to truncate a file.
4843 ***************************************************************/
4845 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4850 DATA_BLOB inbuf = data_blob_null;
4851 struct smb2_hnd *ph = NULL;
4852 TALLOC_CTX *frame = talloc_stackframe();
4854 if (smbXcli_conn_has_async_calls(cli->conn)) {
4856 * Can't use sync call while an async call is in flight
4858 status = NT_STATUS_INVALID_PARAMETER;
4862 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4863 status = NT_STATUS_INVALID_PARAMETER;
4867 status = map_fnum_to_smb2_handle(cli,
4870 if (!NT_STATUS_IS_OK(status)) {
4874 inbuf = data_blob_talloc_zero(frame, 8);
4875 if (inbuf.data == NULL) {
4876 status = NT_STATUS_NO_MEMORY;
4880 SBVAL(inbuf.data, 0, newsize);
4882 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4883 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4885 status = smb2cli_set_info(cli->conn,
4889 1, /* in_info_type */
4890 /* in_file_info_class */
4891 SMB_FILE_END_OF_FILE_INFORMATION - 1000,
4892 &inbuf, /* in_input_buffer */
4893 0, /* in_additional_info */
4899 cli->raw_status = status;
4905 struct cli_smb2_notify_state {
4906 struct tevent_req *subreq;
4907 struct notify_change *changes;
4911 static void cli_smb2_notify_done(struct tevent_req *subreq);
4912 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4914 struct tevent_req *cli_smb2_notify_send(
4915 TALLOC_CTX *mem_ctx,
4916 struct tevent_context *ev,
4917 struct cli_state *cli,
4919 uint32_t buffer_size,
4920 uint32_t completion_filter,
4923 struct tevent_req *req = NULL;
4924 struct cli_smb2_notify_state *state = NULL;
4925 struct smb2_hnd *ph = NULL;
4928 req = tevent_req_create(mem_ctx, &state,
4929 struct cli_smb2_notify_state);
4934 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4935 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4936 return tevent_req_post(req, ev);
4939 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4940 if (tevent_req_nterror(req, status)) {
4941 return tevent_req_post(req, ev);
4944 state->subreq = smb2cli_notify_send(
4956 if (tevent_req_nomem(state->subreq, req)) {
4957 return tevent_req_post(req, ev);
4959 tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4960 tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4964 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4966 struct cli_smb2_notify_state *state = tevent_req_data(
4967 req, struct cli_smb2_notify_state);
4970 ok = tevent_req_cancel(state->subreq);
4974 static void cli_smb2_notify_done(struct tevent_req *subreq)
4976 struct tevent_req *req = tevent_req_callback_data(
4977 subreq, struct tevent_req);
4978 struct cli_smb2_notify_state *state = tevent_req_data(
4979 req, struct cli_smb2_notify_state);
4985 status = smb2cli_notify_recv(subreq, state, &base, &len);
4986 TALLOC_FREE(subreq);
4988 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4989 tevent_req_done(req);
4992 if (tevent_req_nterror(req, status)) {
4998 while (len - ofs >= 12) {
4999 struct notify_change *tmp;
5000 struct notify_change *c;
5001 uint32_t next_ofs = IVAL(base, ofs);
5002 uint32_t file_name_length = IVAL(base, ofs+8);
5006 tmp = talloc_realloc(
5009 struct notify_change,
5010 state->num_changes + 1);
5011 if (tevent_req_nomem(tmp, req)) {
5014 state->changes = tmp;
5015 c = &state->changes[state->num_changes];
5016 state->num_changes += 1;
5018 if (smb_buffer_oob(len, ofs, next_ofs) ||
5019 smb_buffer_oob(len, ofs+12, file_name_length)) {
5021 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
5025 c->action = IVAL(base, ofs+4);
5027 ok = convert_string_talloc(
5037 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
5041 if (next_ofs == 0) {
5047 tevent_req_done(req);
5050 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
5051 TALLOC_CTX *mem_ctx,
5052 struct notify_change **pchanges,
5053 uint32_t *pnum_changes)
5055 struct cli_smb2_notify_state *state = tevent_req_data(
5056 req, struct cli_smb2_notify_state);
5059 if (tevent_req_is_nterror(req, &status)) {
5062 *pchanges = talloc_move(mem_ctx, &state->changes);
5063 *pnum_changes = state->num_changes;
5064 return NT_STATUS_OK;
5067 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
5068 uint32_t buffer_size, uint32_t completion_filter,
5069 bool recursive, TALLOC_CTX *mem_ctx,
5070 struct notify_change **pchanges,
5071 uint32_t *pnum_changes)
5073 TALLOC_CTX *frame = talloc_stackframe();
5074 struct tevent_context *ev;
5075 struct tevent_req *req;
5076 NTSTATUS status = NT_STATUS_NO_MEMORY;
5078 if (smbXcli_conn_has_async_calls(cli->conn)) {
5080 * Can't use sync call while an async call is in flight
5082 status = NT_STATUS_INVALID_PARAMETER;
5085 ev = samba_tevent_context_init(frame);
5089 req = cli_smb2_notify_send(
5100 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5103 status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
5109 struct cli_smb2_set_reparse_point_fnum_state {
5110 struct cli_state *cli;
5112 struct smb2_hnd *ph;
5113 DATA_BLOB input_buffer;
5116 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
5118 struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
5119 TALLOC_CTX *mem_ctx,
5120 struct tevent_context *ev,
5121 struct cli_state *cli,
5125 struct tevent_req *req, *subreq;
5126 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
5129 req = tevent_req_create(mem_ctx, &state,
5130 struct cli_smb2_set_reparse_point_fnum_state);
5135 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5136 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
5137 return tevent_req_post(req, ev);
5143 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
5144 if (tevent_req_nterror(req, status)) {
5145 return tevent_req_post(req, ev);
5148 state->input_buffer = data_blob_talloc(state,
5151 if (state->input_buffer.data == NULL) {
5152 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
5153 return tevent_req_post(req, ev);
5156 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
5157 state->cli->timeout,
5158 state->cli->smb2.session,
5159 state->cli->smb2.tcon,
5160 state->ph->fid_persistent, /* in_fid_persistent */
5161 state->ph->fid_volatile, /* in_fid_volatile */
5162 FSCTL_SET_REPARSE_POINT,
5163 0, /* in_max_input_length */
5164 &state->input_buffer ,
5167 SMB2_IOCTL_FLAG_IS_FSCTL);
5169 if (tevent_req_nomem(subreq, req)) {
5170 return tevent_req_post(req, ev);
5172 tevent_req_set_callback(subreq,
5173 cli_smb2_set_reparse_point_fnum_done,
5179 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
5181 struct tevent_req *req = tevent_req_callback_data(
5182 subreq, struct tevent_req);
5183 struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
5184 req, struct cli_smb2_set_reparse_point_fnum_state);
5187 status = smb2cli_ioctl_recv(subreq, state,
5190 TALLOC_FREE(subreq);
5191 if (tevent_req_nterror(req, status)) {
5194 tevent_req_done(req);
5197 NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
5199 return tevent_req_simple_recv_ntstatus(req);
5202 struct cli_smb2_get_reparse_point_fnum_state {
5203 struct cli_state *cli;
5205 struct smb2_hnd *ph;
5206 DATA_BLOB output_buffer;
5209 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
5211 struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
5212 TALLOC_CTX *mem_ctx,
5213 struct tevent_context *ev,
5214 struct cli_state *cli,
5217 struct tevent_req *req, *subreq;
5218 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
5221 req = tevent_req_create(mem_ctx, &state,
5222 struct cli_smb2_get_reparse_point_fnum_state);
5227 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5228 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
5229 return tevent_req_post(req, ev);
5235 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
5236 if (tevent_req_nterror(req, status)) {
5237 return tevent_req_post(req, ev);
5240 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
5241 state->cli->timeout,
5242 state->cli->smb2.session,
5243 state->cli->smb2.tcon,
5244 state->ph->fid_persistent, /* in_fid_persistent */
5245 state->ph->fid_volatile, /* in_fid_volatile */
5246 FSCTL_GET_REPARSE_POINT,
5247 0, /* in_max_input_length */
5251 SMB2_IOCTL_FLAG_IS_FSCTL);
5253 if (tevent_req_nomem(subreq, req)) {
5254 return tevent_req_post(req, ev);
5256 tevent_req_set_callback(subreq,
5257 cli_smb2_get_reparse_point_fnum_done,
5263 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
5265 struct tevent_req *req = tevent_req_callback_data(
5266 subreq, struct tevent_req);
5267 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
5268 req, struct cli_smb2_get_reparse_point_fnum_state);
5271 status = smb2cli_ioctl_recv(subreq, state,
5273 &state->output_buffer);
5274 TALLOC_FREE(subreq);
5275 if (tevent_req_nterror(req, status)) {
5276 state->cli->raw_status = status;
5279 tevent_req_done(req);
5282 NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
5283 TALLOC_CTX *mem_ctx,
5286 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
5287 req, struct cli_smb2_get_reparse_point_fnum_state);
5289 if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
5290 tevent_req_received(req);
5291 return state->cli->raw_status;
5293 *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
5294 if (output->data == NULL) {
5295 tevent_req_received(req);
5296 return NT_STATUS_NO_MEMORY;
5298 tevent_req_received(req);
5299 return NT_STATUS_OK;