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 TALLOC_CTX *frame = talloc_stackframe();
2362 if (smbXcli_conn_has_async_calls(cli->conn)) {
2364 * Can't use sync call while an async call is in flight
2366 status = NT_STATUS_INVALID_PARAMETER;
2370 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2371 status = NT_STATUS_INVALID_PARAMETER;
2375 status = get_fnum_from_path(cli,
2377 FILE_WRITE_ATTRIBUTES,
2380 if (!NT_STATUS_IS_OK(status)) {
2384 status = cli_smb2_set_info_fnum(
2389 p_in_data, /* in_input_buffer */
2390 0); /* in_additional_info */
2393 if (fnum != 0xffff) {
2394 cli_smb2_close_fnum(cli, fnum);
2397 cli->raw_status = status;
2404 /***************************************************************
2405 Wrapper that allows SMB2 to set pathname attributes.
2407 ***************************************************************/
2409 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
2414 uint8_t inbuf_store[40];
2415 DATA_BLOB inbuf = data_blob_null;
2417 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2418 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2420 inbuf.data = inbuf_store;
2421 inbuf.length = sizeof(inbuf_store);
2422 data_blob_clear(&inbuf);
2425 * SMB1 uses attr == 0 to clear all attributes
2426 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2427 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2428 * request attribute change.
2430 * SMB2 uses exactly the reverse. Unfortunately as the
2431 * cli_setatr() ABI is exposed inside libsmbclient,
2432 * we must make the SMB2 cli_smb2_setatr() call
2433 * export the same ABI as the SMB1 cli_setatr()
2434 * which calls it. This means reversing the sense
2435 * of the requested attr argument if it's zero
2436 * or FILE_ATTRIBUTE_NORMAL.
2438 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2442 attr = FILE_ATTRIBUTE_NORMAL;
2443 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
2447 SSVAL(inbuf.data, 32, attr);
2449 put_long_date((char *)inbuf.data + 16,mtime);
2451 /* Set all the other times to -1. */
2452 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2453 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
2454 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
2456 return cli_smb2_setpathinfo(cli,
2458 1, /* in_info_type */
2459 /* in_file_info_class */
2460 SMB_FILE_BASIC_INFORMATION - 1000,
2465 /***************************************************************
2466 Wrapper that allows SMB2 to set file handle times.
2468 ***************************************************************/
2470 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
2476 uint8_t inbuf_store[40];
2477 DATA_BLOB inbuf = data_blob_null;
2479 if (smbXcli_conn_has_async_calls(cli->conn)) {
2481 * Can't use sync call while an async call is in flight
2483 return NT_STATUS_INVALID_PARAMETER;
2486 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2487 return NT_STATUS_INVALID_PARAMETER;
2490 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2491 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2493 inbuf.data = inbuf_store;
2494 inbuf.length = sizeof(inbuf_store);
2495 data_blob_clear(&inbuf);
2497 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2498 if (change_time != 0) {
2499 put_long_date((char *)inbuf.data + 24, change_time);
2501 if (access_time != 0) {
2502 put_long_date((char *)inbuf.data + 8, access_time);
2504 if (write_time != 0) {
2505 put_long_date((char *)inbuf.data + 16, write_time);
2508 cli->raw_status = cli_smb2_set_info_fnum(
2511 1, /* in_info_type */
2512 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
2513 &inbuf, /* in_input_buffer */
2514 0); /* in_additional_info */
2516 return cli->raw_status;
2519 /***************************************************************
2520 Wrapper that allows SMB2 to query disk attributes (size).
2522 ***************************************************************/
2524 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2525 uint64_t *bsize, uint64_t *total, uint64_t *avail)
2528 uint16_t fnum = 0xffff;
2529 DATA_BLOB outbuf = data_blob_null;
2530 uint32_t sectors_per_unit = 0;
2531 uint32_t bytes_per_sector = 0;
2532 uint64_t total_size = 0;
2533 uint64_t size_free = 0;
2534 TALLOC_CTX *frame = talloc_stackframe();
2536 if (smbXcli_conn_has_async_calls(cli->conn)) {
2538 * Can't use sync call while an async call is in flight
2540 status = NT_STATUS_INVALID_PARAMETER;
2544 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2545 status = NT_STATUS_INVALID_PARAMETER;
2549 /* First open the top level directory. */
2550 status = cli_smb2_create_fnum(cli,
2552 0, /* create_flags */
2553 SMB2_IMPERSONATION_IMPERSONATION,
2554 FILE_READ_ATTRIBUTES, /* desired_access */
2555 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2556 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2557 FILE_OPEN, /* create_disposition */
2558 FILE_DIRECTORY_FILE, /* create_options */
2565 if (!NT_STATUS_IS_OK(status)) {
2569 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2570 level 3 (SMB_FS_SIZE_INFORMATION). */
2572 status = cli_smb2_query_info_fnum(
2575 2, /* in_info_type */
2576 3, /* in_file_info_class */
2577 0xFFFF, /* in_max_output_length */
2578 NULL, /* in_input_buffer */
2579 0, /* in_additional_info */
2583 if (!NT_STATUS_IS_OK(status)) {
2587 /* Parse the reply. */
2588 if (outbuf.length != 24) {
2589 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2593 total_size = BVAL(outbuf.data, 0);
2594 size_free = BVAL(outbuf.data, 8);
2595 sectors_per_unit = IVAL(outbuf.data, 16);
2596 bytes_per_sector = IVAL(outbuf.data, 20);
2599 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2602 *total = total_size;
2608 status = NT_STATUS_OK;
2612 if (fnum != 0xffff) {
2613 cli_smb2_close_fnum(cli, fnum);
2616 cli->raw_status = status;
2622 /***************************************************************
2623 Wrapper that allows SMB2 to query file system sizes.
2625 ***************************************************************/
2627 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2628 uint64_t *total_allocation_units,
2629 uint64_t *caller_allocation_units,
2630 uint64_t *actual_allocation_units,
2631 uint64_t *sectors_per_allocation_unit,
2632 uint64_t *bytes_per_sector)
2635 uint16_t fnum = 0xffff;
2636 DATA_BLOB outbuf = data_blob_null;
2637 TALLOC_CTX *frame = talloc_stackframe();
2639 if (smbXcli_conn_has_async_calls(cli->conn)) {
2641 * Can't use sync call while an async call is in flight
2643 status = NT_STATUS_INVALID_PARAMETER;
2647 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2648 status = NT_STATUS_INVALID_PARAMETER;
2652 /* First open the top level directory. */
2654 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2655 SMB2_IMPERSONATION_IMPERSONATION,
2656 FILE_READ_ATTRIBUTES, /* desired_access */
2657 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2658 FILE_SHARE_READ | FILE_SHARE_WRITE |
2659 FILE_SHARE_DELETE, /* share_access */
2660 FILE_OPEN, /* create_disposition */
2661 FILE_DIRECTORY_FILE, /* create_options */
2668 if (!NT_STATUS_IS_OK(status)) {
2672 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2673 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2675 status = cli_smb2_query_info_fnum(
2678 SMB2_GETINFO_FS, /* in_info_type */
2679 SMB_FS_FULL_SIZE_INFORMATION - 1000, /* in_file_info_class */
2680 0xFFFF, /* in_max_output_length */
2681 NULL, /* in_input_buffer */
2682 0, /* in_additional_info */
2686 if (!NT_STATUS_IS_OK(status)) {
2690 if (outbuf.length < 32) {
2691 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2695 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2696 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2697 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2698 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2699 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2703 if (fnum != 0xffff) {
2704 cli_smb2_close_fnum(cli, fnum);
2707 cli->raw_status = status;
2713 /***************************************************************
2714 Wrapper that allows SMB2 to query file system attributes.
2716 ***************************************************************/
2718 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2721 uint16_t fnum = 0xffff;
2722 DATA_BLOB outbuf = data_blob_null;
2723 TALLOC_CTX *frame = talloc_stackframe();
2725 if (smbXcli_conn_has_async_calls(cli->conn)) {
2727 * Can't use sync call while an async call is in flight
2729 status = NT_STATUS_INVALID_PARAMETER;
2733 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2734 status = NT_STATUS_INVALID_PARAMETER;
2738 /* First open the top level directory. */
2740 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2741 SMB2_IMPERSONATION_IMPERSONATION,
2742 FILE_READ_ATTRIBUTES, /* desired_access */
2743 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2744 FILE_SHARE_READ | FILE_SHARE_WRITE |
2745 FILE_SHARE_DELETE, /* share_access */
2746 FILE_OPEN, /* create_disposition */
2747 FILE_DIRECTORY_FILE, /* create_options */
2754 if (!NT_STATUS_IS_OK(status)) {
2758 status = cli_smb2_query_info_fnum(
2761 2, /* in_info_type */
2762 5, /* in_file_info_class */
2763 0xFFFF, /* in_max_output_length */
2764 NULL, /* in_input_buffer */
2765 0, /* in_additional_info */
2769 if (!NT_STATUS_IS_OK(status)) {
2773 if (outbuf.length < 12) {
2774 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2778 *fs_attr = IVAL(outbuf.data, 0);
2782 if (fnum != 0xffff) {
2783 cli_smb2_close_fnum(cli, fnum);
2786 cli->raw_status = status;
2792 /***************************************************************
2793 Wrapper that allows SMB2 to query file system volume info.
2795 ***************************************************************/
2797 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2798 TALLOC_CTX *mem_ctx,
2799 char **_volume_name,
2800 uint32_t *pserial_number,
2804 uint16_t fnum = 0xffff;
2805 DATA_BLOB outbuf = data_blob_null;
2807 char *volume_name = NULL;
2808 TALLOC_CTX *frame = talloc_stackframe();
2810 if (smbXcli_conn_has_async_calls(cli->conn)) {
2812 * Can't use sync call while an async call is in flight
2814 status = NT_STATUS_INVALID_PARAMETER;
2818 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2819 status = NT_STATUS_INVALID_PARAMETER;
2823 /* First open the top level directory. */
2825 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2826 SMB2_IMPERSONATION_IMPERSONATION,
2827 FILE_READ_ATTRIBUTES, /* desired_access */
2828 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2829 FILE_SHARE_READ | FILE_SHARE_WRITE |
2830 FILE_SHARE_DELETE, /* share_access */
2831 FILE_OPEN, /* create_disposition */
2832 FILE_DIRECTORY_FILE, /* create_options */
2839 if (!NT_STATUS_IS_OK(status)) {
2843 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2844 level 1 (SMB_FS_VOLUME_INFORMATION). */
2846 status = cli_smb2_query_info_fnum(
2849 SMB2_GETINFO_FS, /* in_info_type */
2850 /* in_file_info_class */
2851 SMB_FS_VOLUME_INFORMATION - 1000,
2852 0xFFFF, /* in_max_output_length */
2853 NULL, /* in_input_buffer */
2854 0, /* in_additional_info */
2858 if (!NT_STATUS_IS_OK(status)) {
2862 if (outbuf.length < 24) {
2863 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2869 ts = interpret_long_date((char *)outbuf.data);
2872 if (pserial_number) {
2873 *pserial_number = IVAL(outbuf.data,8);
2875 nlen = IVAL(outbuf.data,12);
2876 if (nlen + 18 < 18) {
2878 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2882 * The next check is safe as we know outbuf.length >= 24
2885 if (nlen > (outbuf.length - 18)) {
2886 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2890 clistr_pull_talloc(mem_ctx,
2891 (const char *)outbuf.data,
2897 if (volume_name == NULL) {
2898 status = map_nt_error_from_unix(errno);
2902 *_volume_name = volume_name;
2906 if (fnum != 0xffff) {
2907 cli_smb2_close_fnum(cli, fnum);
2910 cli->raw_status = status;
2917 /***************************************************************
2918 Wrapper that allows SMB2 to query a security descriptor.
2920 ***************************************************************/
2922 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2925 TALLOC_CTX *mem_ctx,
2926 struct security_descriptor **ppsd)
2929 DATA_BLOB outbuf = data_blob_null;
2930 struct security_descriptor *lsd = NULL;
2931 TALLOC_CTX *frame = talloc_stackframe();
2933 if (smbXcli_conn_has_async_calls(cli->conn)) {
2935 * Can't use sync call while an async call is in flight
2937 status = NT_STATUS_INVALID_PARAMETER;
2941 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2942 status = NT_STATUS_INVALID_PARAMETER;
2946 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2948 status = cli_smb2_query_info_fnum(
2951 3, /* in_info_type */
2952 0, /* in_file_info_class */
2953 0xFFFF, /* in_max_output_length */
2954 NULL, /* in_input_buffer */
2955 sec_info, /* in_additional_info */
2960 if (!NT_STATUS_IS_OK(status)) {
2964 /* Parse the reply. */
2965 status = unmarshall_sec_desc(mem_ctx,
2970 if (!NT_STATUS_IS_OK(status)) {
2982 cli->raw_status = status;
2988 /***************************************************************
2989 Wrapper that allows SMB2 to set a security descriptor.
2991 ***************************************************************/
2993 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
2996 const struct security_descriptor *sd)
2999 DATA_BLOB inbuf = data_blob_null;
3000 TALLOC_CTX *frame = talloc_stackframe();
3002 if (smbXcli_conn_has_async_calls(cli->conn)) {
3004 * Can't use sync call while an async call is in flight
3006 status = NT_STATUS_INVALID_PARAMETER;
3010 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3011 status = NT_STATUS_INVALID_PARAMETER;
3015 status = marshall_sec_desc(frame,
3020 if (!NT_STATUS_IS_OK(status)) {
3024 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
3026 status = cli_smb2_set_info_fnum(
3029 3, /* in_info_type */
3030 0, /* in_file_info_class */
3031 &inbuf, /* in_input_buffer */
3032 sec_info); /* in_additional_info */
3036 cli->raw_status = status;
3042 /***************************************************************
3043 Wrapper that allows SMB2 to query a security descriptor.
3046 ***************************************************************/
3048 struct cli_smb2_mxac_state {
3049 struct tevent_context *ev;
3050 struct cli_state *cli;
3052 struct smb2_create_blobs in_cblobs;
3058 static void cli_smb2_mxac_opened(struct tevent_req *subreq);
3059 static void cli_smb2_mxac_closed(struct tevent_req *subreq);
3061 struct tevent_req *cli_smb2_query_mxac_send(TALLOC_CTX *mem_ctx,
3062 struct tevent_context *ev,
3063 struct cli_state *cli,
3066 struct tevent_req *req = NULL, *subreq = NULL;
3067 struct cli_smb2_mxac_state *state = NULL;
3070 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_mxac_state);
3074 *state = (struct cli_smb2_mxac_state) {
3077 state->fname = fname,
3080 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3081 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3082 return tevent_req_post(req, ev);
3085 status = smb2_create_blob_add(state,
3087 SMB2_CREATE_TAG_MXAC,
3088 data_blob(NULL, 0));
3089 if (tevent_req_nterror(req, status)) {
3090 return tevent_req_post(req, ev);
3093 subreq = cli_smb2_create_fnum_send(
3098 0, /* create_flags */
3099 SMB2_IMPERSONATION_IMPERSONATION,
3100 FILE_READ_ATTRIBUTES,
3101 0, /* file attributes */
3102 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
3104 0, /* create_options */
3106 if (tevent_req_nomem(subreq, req)) {
3107 return tevent_req_post(req, ev);
3109 tevent_req_set_callback(subreq, cli_smb2_mxac_opened, req);
3113 static void cli_smb2_mxac_opened(struct tevent_req *subreq)
3115 struct tevent_req *req = tevent_req_callback_data(
3116 subreq, struct tevent_req);
3117 struct cli_smb2_mxac_state *state = tevent_req_data(
3118 req, struct cli_smb2_mxac_state);
3119 struct smb2_create_blobs out_cblobs = {0};
3120 struct smb2_create_blob *mxac_blob = NULL;
3123 status = cli_smb2_create_fnum_recv(
3124 subreq, &state->fnum, NULL, state, &out_cblobs);
3125 TALLOC_FREE(subreq);
3127 if (tevent_req_nterror(req, status)) {
3131 mxac_blob = smb2_create_blob_find(&out_cblobs, SMB2_CREATE_TAG_MXAC);
3132 if (mxac_blob == NULL) {
3133 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3136 if (mxac_blob->data.length != 8) {
3137 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3141 state->status = NT_STATUS(IVAL(mxac_blob->data.data, 0));
3142 state->mxac = IVAL(mxac_blob->data.data, 4);
3145 subreq = cli_smb2_close_fnum_send(
3146 state, state->ev, state->cli, state->fnum);
3147 if (tevent_req_nomem(subreq, req)) {
3150 tevent_req_set_callback(subreq, cli_smb2_mxac_closed, req);
3155 static void cli_smb2_mxac_closed(struct tevent_req *subreq)
3157 struct tevent_req *req = tevent_req_callback_data(
3158 subreq, struct tevent_req);
3161 status = cli_smb2_close_fnum_recv(subreq);
3162 if (tevent_req_nterror(req, status)) {
3166 tevent_req_done(req);
3169 NTSTATUS cli_smb2_query_mxac_recv(struct tevent_req *req, uint32_t *mxac)
3171 struct cli_smb2_mxac_state *state = tevent_req_data(
3172 req, struct cli_smb2_mxac_state);
3175 if (tevent_req_is_nterror(req, &status)) {
3179 if (!NT_STATUS_IS_OK(state->status)) {
3180 return state->status;
3183 *mxac = state->mxac;
3184 return NT_STATUS_OK;
3187 NTSTATUS cli_smb2_query_mxac(struct cli_state *cli,
3191 TALLOC_CTX *frame = talloc_stackframe();
3192 struct tevent_context *ev = NULL;
3193 struct tevent_req *req = NULL;
3194 NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
3197 if (smbXcli_conn_has_async_calls(cli->conn)) {
3199 * Can't use sync call while an async call is in flight
3201 status = NT_STATUS_INVALID_PARAMETER;
3205 ev = samba_tevent_context_init(frame);
3209 req = cli_smb2_query_mxac_send(frame, ev, cli, fname);
3213 ok = tevent_req_poll_ntstatus(req, ev, &status);
3217 status = cli_smb2_query_mxac_recv(req, _mxac);
3220 cli->raw_status = status;
3225 /***************************************************************
3226 Wrapper that allows SMB2 to rename a file.
3228 ***************************************************************/
3230 NTSTATUS cli_smb2_rename(struct cli_state *cli,
3231 const char *fname_src,
3232 const char *fname_dst,
3236 DATA_BLOB inbuf = data_blob_null;
3237 uint16_t fnum = 0xffff;
3238 smb_ucs2_t *converted_str = NULL;
3239 size_t converted_size_bytes = 0;
3241 TALLOC_CTX *frame = talloc_stackframe();
3243 if (smbXcli_conn_has_async_calls(cli->conn)) {
3245 * Can't use sync call while an async call is in flight
3247 status = NT_STATUS_INVALID_PARAMETER;
3251 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3252 status = NT_STATUS_INVALID_PARAMETER;
3256 status = get_fnum_from_path(cli,
3261 if (!NT_STATUS_IS_OK(status)) {
3265 /* SMB2 is pickier about pathnames. Ensure it doesn't
3267 if (*fname_dst == '\\') {
3271 /* SMB2 is pickier about pathnames. Ensure it doesn't
3273 namelen = strlen(fname_dst);
3274 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
3275 char *modname = talloc_strdup(frame, fname_dst);
3276 modname[namelen-1] = '\0';
3277 fname_dst = modname;
3280 if (!push_ucs2_talloc(frame,
3283 &converted_size_bytes)) {
3284 status = NT_STATUS_INVALID_PARAMETER;
3288 /* W2K8 insists the dest name is not null
3289 terminated. Remove the last 2 zero bytes
3290 and reduce the name length. */
3292 if (converted_size_bytes < 2) {
3293 status = NT_STATUS_INVALID_PARAMETER;
3296 converted_size_bytes -= 2;
3298 inbuf = data_blob_talloc_zero(frame,
3299 20 + converted_size_bytes);
3300 if (inbuf.data == NULL) {
3301 status = NT_STATUS_NO_MEMORY;
3306 SCVAL(inbuf.data, 0, 1);
3309 SIVAL(inbuf.data, 16, converted_size_bytes);
3310 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
3312 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3313 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3315 status = cli_smb2_set_info_fnum(
3318 1, /* in_info_type */
3319 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
3320 &inbuf, /* in_input_buffer */
3321 0); /* in_additional_info */
3325 if (fnum != 0xffff) {
3326 cli_smb2_close_fnum(cli, fnum);
3329 cli->raw_status = status;
3335 /***************************************************************
3336 Wrapper that allows SMB2 to set an EA on a fnum.
3338 ***************************************************************/
3340 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
3342 const char *ea_name,
3347 DATA_BLOB inbuf = data_blob_null;
3349 char *ea_name_ascii = NULL;
3351 TALLOC_CTX *frame = talloc_stackframe();
3353 if (smbXcli_conn_has_async_calls(cli->conn)) {
3355 * Can't use sync call while an async call is in flight
3357 status = NT_STATUS_INVALID_PARAMETER;
3361 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3362 status = NT_STATUS_INVALID_PARAMETER;
3366 /* Marshall the SMB2 EA data. */
3367 if (ea_len > 0xFFFF) {
3368 status = NT_STATUS_INVALID_PARAMETER;
3372 if (!push_ascii_talloc(frame,
3376 status = NT_STATUS_INVALID_PARAMETER;
3380 if (namelen < 2 || namelen > 0xFF) {
3381 status = NT_STATUS_INVALID_PARAMETER;
3385 bloblen = 8 + ea_len + namelen;
3386 /* Round up to a 4 byte boundary. */
3387 bloblen = ((bloblen + 3)&~3);
3389 inbuf = data_blob_talloc_zero(frame, bloblen);
3390 if (inbuf.data == NULL) {
3391 status = NT_STATUS_NO_MEMORY;
3394 /* namelen doesn't include the NULL byte. */
3395 SCVAL(inbuf.data, 5, namelen - 1);
3396 SSVAL(inbuf.data, 6, ea_len);
3397 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
3398 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
3400 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3401 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3403 status = cli_smb2_set_info_fnum(
3406 1, /* in_info_type */
3407 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3408 &inbuf, /* in_input_buffer */
3409 0); /* in_additional_info */
3413 cli->raw_status = status;
3419 /***************************************************************
3420 Wrapper that allows SMB2 to set an EA on a pathname.
3422 ***************************************************************/
3424 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
3426 const char *ea_name,
3431 uint16_t fnum = 0xffff;
3433 if (smbXcli_conn_has_async_calls(cli->conn)) {
3435 * Can't use sync call while an async call is in flight
3437 status = NT_STATUS_INVALID_PARAMETER;
3441 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3442 status = NT_STATUS_INVALID_PARAMETER;
3446 status = get_fnum_from_path(cli,
3451 if (!NT_STATUS_IS_OK(status)) {
3455 status = cli_set_ea_fnum(cli,
3460 if (!NT_STATUS_IS_OK(status)) {
3466 if (fnum != 0xffff) {
3467 cli_smb2_close_fnum(cli, fnum);
3470 cli->raw_status = status;
3475 /***************************************************************
3476 Wrapper that allows SMB2 to get an EA list on a pathname.
3478 ***************************************************************/
3480 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
3484 struct ea_struct **pea_array)
3487 uint16_t fnum = 0xffff;
3488 DATA_BLOB outbuf = data_blob_null;
3489 struct ea_list *ea_list = NULL;
3490 struct ea_list *eal = NULL;
3491 size_t ea_count = 0;
3492 TALLOC_CTX *frame = talloc_stackframe();
3497 if (smbXcli_conn_has_async_calls(cli->conn)) {
3499 * Can't use sync call while an async call is in flight
3501 status = NT_STATUS_INVALID_PARAMETER;
3505 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3506 status = NT_STATUS_INVALID_PARAMETER;
3510 status = get_fnum_from_path(cli,
3515 if (!NT_STATUS_IS_OK(status)) {
3519 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3520 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3522 status = cli_smb2_query_info_fnum(
3525 1, /* in_info_type */
3526 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3527 0xFFFF, /* in_max_output_length */
3528 NULL, /* in_input_buffer */
3529 0, /* in_additional_info */
3534 if (!NT_STATUS_IS_OK(status)) {
3538 /* Parse the reply. */
3539 ea_list = read_nttrans_ea_list(ctx,
3540 (const char *)outbuf.data,
3542 if (ea_list == NULL) {
3543 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3547 /* Convert to an array. */
3548 for (eal = ea_list; eal; eal = eal->next) {
3553 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
3554 if (*pea_array == NULL) {
3555 status = NT_STATUS_NO_MEMORY;
3559 for (eal = ea_list; eal; eal = eal->next) {
3560 (*pea_array)[ea_count++] = eal->ea;
3562 *pnum_eas = ea_count;
3567 if (fnum != 0xffff) {
3568 cli_smb2_close_fnum(cli, fnum);
3571 cli->raw_status = status;
3577 /***************************************************************
3578 Wrapper that allows SMB2 to get user quota.
3580 ***************************************************************/
3582 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
3584 SMB_NTQUOTA_STRUCT *pqt)
3587 DATA_BLOB inbuf = data_blob_null;
3588 DATA_BLOB info_blob = data_blob_null;
3589 DATA_BLOB outbuf = data_blob_null;
3590 TALLOC_CTX *frame = talloc_stackframe();
3592 unsigned int offset;
3593 struct smb2_query_quota_info query = {0};
3594 struct file_get_quota_info info = {0};
3595 enum ndr_err_code err;
3596 struct ndr_push *ndr_push = NULL;
3598 if (smbXcli_conn_has_async_calls(cli->conn)) {
3600 * Can't use sync call while an async call is in flight
3602 status = NT_STATUS_INVALID_PARAMETER;
3606 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3607 status = NT_STATUS_INVALID_PARAMETER;
3611 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
3613 query.return_single = 1;
3615 info.next_entry_offset = 0;
3616 info.sid_length = sid_len;
3617 info.sid = pqt->sid;
3619 err = ndr_push_struct_blob(
3623 (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
3625 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3626 status = NT_STATUS_INTERNAL_ERROR;
3630 query.sid_list_length = info_blob.length;
3631 ndr_push = ndr_push_init_ctx(frame);
3633 status = NT_STATUS_NO_MEMORY;
3637 err = ndr_push_smb2_query_quota_info(ndr_push,
3638 NDR_SCALARS | NDR_BUFFERS,
3641 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3642 status = NT_STATUS_INTERNAL_ERROR;
3646 err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3649 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3650 status = NT_STATUS_INTERNAL_ERROR;
3653 inbuf.data = ndr_push->data;
3654 inbuf.length = ndr_push->offset;
3656 status = cli_smb2_query_info_fnum(
3659 4, /* in_info_type */
3660 0, /* in_file_info_class */
3661 0xFFFF, /* in_max_output_length */
3662 &inbuf, /* in_input_buffer */
3663 0, /* in_additional_info */
3668 if (!NT_STATUS_IS_OK(status)) {
3672 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3674 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3675 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3679 cli->raw_status = status;
3685 /***************************************************************
3686 Wrapper that allows SMB2 to list user quota.
3688 ***************************************************************/
3690 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3691 TALLOC_CTX *mem_ctx,
3693 SMB_NTQUOTA_LIST **pqt_list,
3697 DATA_BLOB inbuf = data_blob_null;
3698 DATA_BLOB outbuf = data_blob_null;
3699 TALLOC_CTX *frame = talloc_stackframe();
3700 struct smb2_query_quota_info info = {0};
3701 enum ndr_err_code err;
3703 if (smbXcli_conn_has_async_calls(cli->conn)) {
3705 * Can't use sync call while an async call is in flight
3707 status = NT_STATUS_INVALID_PARAMETER;
3711 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3712 status = NT_STATUS_INVALID_PARAMETER;
3716 info.restart_scan = first ? 1 : 0;
3718 err = ndr_push_struct_blob(
3722 (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3724 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3725 status = NT_STATUS_INTERNAL_ERROR;
3729 status = cli_smb2_query_info_fnum(
3732 4, /* in_info_type */
3733 0, /* in_file_info_class */
3734 0xFFFF, /* in_max_output_length */
3735 &inbuf, /* in_input_buffer */
3736 0, /* in_additional_info */
3742 * safeguard against panic from calling parse_user_quota_list with
3745 if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3746 status = NT_STATUS_NO_MORE_ENTRIES;
3749 if (!NT_STATUS_IS_OK(status)) {
3753 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3757 cli->raw_status = status;
3763 /***************************************************************
3764 Wrapper that allows SMB2 to get file system quota.
3766 ***************************************************************/
3768 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3770 SMB_NTQUOTA_STRUCT *pqt)
3773 DATA_BLOB outbuf = data_blob_null;
3774 TALLOC_CTX *frame = talloc_stackframe();
3776 if (smbXcli_conn_has_async_calls(cli->conn)) {
3778 * Can't use sync call while an async call is in flight
3780 status = NT_STATUS_INVALID_PARAMETER;
3784 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3785 status = NT_STATUS_INVALID_PARAMETER;
3789 status = cli_smb2_query_info_fnum(
3792 2, /* in_info_type */
3793 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3794 0xFFFF, /* in_max_output_length */
3795 NULL, /* in_input_buffer */
3796 0, /* in_additional_info */
3801 if (!NT_STATUS_IS_OK(status)) {
3805 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3808 cli->raw_status = status;
3814 /***************************************************************
3815 Wrapper that allows SMB2 to set user quota.
3817 ***************************************************************/
3819 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3821 SMB_NTQUOTA_LIST *qtl)
3824 DATA_BLOB inbuf = data_blob_null;
3825 TALLOC_CTX *frame = talloc_stackframe();
3827 if (smbXcli_conn_has_async_calls(cli->conn)) {
3829 * Can't use sync call while an async call is in flight
3831 status = NT_STATUS_INVALID_PARAMETER;
3835 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3836 status = NT_STATUS_INVALID_PARAMETER;
3840 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3841 if (!NT_STATUS_IS_OK(status)) {
3845 status = cli_smb2_set_info_fnum(
3848 4, /* in_info_type */
3849 0, /* in_file_info_class */
3850 &inbuf, /* in_input_buffer */
3851 0); /* in_additional_info */
3854 cli->raw_status = status;
3861 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3863 SMB_NTQUOTA_STRUCT *pqt)
3866 DATA_BLOB inbuf = data_blob_null;
3867 TALLOC_CTX *frame = talloc_stackframe();
3869 if (smbXcli_conn_has_async_calls(cli->conn)) {
3871 * Can't use sync call while an async call is in flight
3873 status = NT_STATUS_INVALID_PARAMETER;
3877 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3878 status = NT_STATUS_INVALID_PARAMETER;
3882 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3883 if (!NT_STATUS_IS_OK(status)) {
3887 status = cli_smb2_set_info_fnum(
3890 2, /* in_info_type */
3891 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3892 &inbuf, /* in_input_buffer */
3893 0); /* in_additional_info */
3895 cli->raw_status = status;
3901 struct cli_smb2_read_state {
3902 struct tevent_context *ev;
3903 struct cli_state *cli;
3904 struct smb2_hnd *ph;
3905 uint64_t start_offset;
3911 static void cli_smb2_read_done(struct tevent_req *subreq);
3913 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3914 struct tevent_context *ev,
3915 struct cli_state *cli,
3921 struct tevent_req *req, *subreq;
3922 struct cli_smb2_read_state *state;
3924 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3930 state->start_offset = (uint64_t)offset;
3931 state->size = (uint32_t)size;
3932 state->received = 0;
3935 status = map_fnum_to_smb2_handle(cli,
3938 if (tevent_req_nterror(req, status)) {
3939 return tevent_req_post(req, ev);
3942 subreq = smb2cli_read_send(state,
3945 state->cli->timeout,
3946 state->cli->smb2.session,
3947 state->cli->smb2.tcon,
3949 state->start_offset,
3950 state->ph->fid_persistent,
3951 state->ph->fid_volatile,
3952 0, /* minimum_count */
3953 0); /* remaining_bytes */
3955 if (tevent_req_nomem(subreq, req)) {
3956 return tevent_req_post(req, ev);
3958 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3962 static void cli_smb2_read_done(struct tevent_req *subreq)
3964 struct tevent_req *req = tevent_req_callback_data(
3965 subreq, struct tevent_req);
3966 struct cli_smb2_read_state *state = tevent_req_data(
3967 req, struct cli_smb2_read_state);
3970 status = smb2cli_read_recv(subreq, state,
3971 &state->buf, &state->received);
3972 if (tevent_req_nterror(req, status)) {
3976 if (state->received > state->size) {
3977 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3981 tevent_req_done(req);
3984 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
3989 struct cli_smb2_read_state *state = tevent_req_data(
3990 req, struct cli_smb2_read_state);
3992 if (tevent_req_is_nterror(req, &status)) {
3993 state->cli->raw_status = status;
3997 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3998 * better make sure that you copy it away before you talloc_free(req).
3999 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
4001 *received = (ssize_t)state->received;
4002 *rcvbuf = state->buf;
4003 state->cli->raw_status = NT_STATUS_OK;
4004 return NT_STATUS_OK;
4007 struct cli_smb2_write_state {
4008 struct tevent_context *ev;
4009 struct cli_state *cli;
4010 struct smb2_hnd *ph;
4018 static void cli_smb2_write_written(struct tevent_req *req);
4020 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
4021 struct tevent_context *ev,
4022 struct cli_state *cli,
4030 struct tevent_req *req, *subreq = NULL;
4031 struct cli_smb2_write_state *state = NULL;
4033 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
4039 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4040 state->flags = (uint32_t)mode;
4042 state->offset = (uint64_t)offset;
4043 state->size = (uint32_t)size;
4046 status = map_fnum_to_smb2_handle(cli,
4049 if (tevent_req_nterror(req, status)) {
4050 return tevent_req_post(req, ev);
4053 subreq = smb2cli_write_send(state,
4056 state->cli->timeout,
4057 state->cli->smb2.session,
4058 state->cli->smb2.tcon,
4061 state->ph->fid_persistent,
4062 state->ph->fid_volatile,
4063 0, /* remaining_bytes */
4064 state->flags, /* flags */
4067 if (tevent_req_nomem(subreq, req)) {
4068 return tevent_req_post(req, ev);
4070 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
4074 static void cli_smb2_write_written(struct tevent_req *subreq)
4076 struct tevent_req *req = tevent_req_callback_data(
4077 subreq, struct tevent_req);
4078 struct cli_smb2_write_state *state = tevent_req_data(
4079 req, struct cli_smb2_write_state);
4083 status = smb2cli_write_recv(subreq, &written);
4084 TALLOC_FREE(subreq);
4085 if (tevent_req_nterror(req, status)) {
4089 state->written = written;
4091 tevent_req_done(req);
4094 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
4097 struct cli_smb2_write_state *state = tevent_req_data(
4098 req, struct cli_smb2_write_state);
4101 if (tevent_req_is_nterror(req, &status)) {
4102 state->cli->raw_status = status;
4103 tevent_req_received(req);
4107 if (pwritten != NULL) {
4108 *pwritten = (size_t)state->written;
4110 state->cli->raw_status = NT_STATUS_OK;
4111 tevent_req_received(req);
4112 return NT_STATUS_OK;
4115 /***************************************************************
4116 Wrapper that allows SMB2 async write using an fnum.
4117 This is mostly cut-and-paste from Volker's code inside
4118 source3/libsmb/clireadwrite.c, adapted for SMB2.
4120 Done this way so I can reuse all the logic inside cli_push()
4122 ***************************************************************/
4124 struct cli_smb2_writeall_state {
4125 struct tevent_context *ev;
4126 struct cli_state *cli;
4127 struct smb2_hnd *ph;
4135 static void cli_smb2_writeall_written(struct tevent_req *req);
4137 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
4138 struct tevent_context *ev,
4139 struct cli_state *cli,
4147 struct tevent_req *req, *subreq = NULL;
4148 struct cli_smb2_writeall_state *state = NULL;
4153 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
4159 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4160 state->flags = (uint32_t)mode;
4162 state->offset = (uint64_t)offset;
4163 state->size = (uint32_t)size;
4166 status = map_fnum_to_smb2_handle(cli,
4169 if (tevent_req_nterror(req, status)) {
4170 return tevent_req_post(req, ev);
4173 to_write = state->size;
4174 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4175 to_write = MIN(max_size, to_write);
4176 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4178 to_write = MIN(max_size, to_write);
4181 subreq = smb2cli_write_send(state,
4184 state->cli->timeout,
4185 state->cli->smb2.session,
4186 state->cli->smb2.tcon,
4189 state->ph->fid_persistent,
4190 state->ph->fid_volatile,
4191 0, /* remaining_bytes */
4192 state->flags, /* flags */
4193 state->buf + state->written);
4195 if (tevent_req_nomem(subreq, req)) {
4196 return tevent_req_post(req, ev);
4198 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4202 static void cli_smb2_writeall_written(struct tevent_req *subreq)
4204 struct tevent_req *req = tevent_req_callback_data(
4205 subreq, struct tevent_req);
4206 struct cli_smb2_writeall_state *state = tevent_req_data(
4207 req, struct cli_smb2_writeall_state);
4209 uint32_t written, to_write;
4213 status = smb2cli_write_recv(subreq, &written);
4214 TALLOC_FREE(subreq);
4215 if (tevent_req_nterror(req, status)) {
4219 state->written += written;
4221 if (state->written > state->size) {
4222 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4226 to_write = state->size - state->written;
4228 if (to_write == 0) {
4229 tevent_req_done(req);
4233 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4234 to_write = MIN(max_size, to_write);
4235 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4237 to_write = MIN(max_size, to_write);
4240 subreq = smb2cli_write_send(state,
4243 state->cli->timeout,
4244 state->cli->smb2.session,
4245 state->cli->smb2.tcon,
4247 state->offset + state->written,
4248 state->ph->fid_persistent,
4249 state->ph->fid_volatile,
4250 0, /* remaining_bytes */
4251 state->flags, /* flags */
4252 state->buf + state->written);
4254 if (tevent_req_nomem(subreq, req)) {
4257 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4260 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
4263 struct cli_smb2_writeall_state *state = tevent_req_data(
4264 req, struct cli_smb2_writeall_state);
4267 if (tevent_req_is_nterror(req, &status)) {
4268 state->cli->raw_status = status;
4271 if (pwritten != NULL) {
4272 *pwritten = (size_t)state->written;
4274 state->cli->raw_status = NT_STATUS_OK;
4275 return NT_STATUS_OK;
4278 struct cli_smb2_splice_state {
4279 struct tevent_context *ev;
4280 struct cli_state *cli;
4281 struct smb2_hnd *src_ph;
4282 struct smb2_hnd *dst_ph;
4283 int (*splice_cb)(off_t n, void *priv);
4290 struct req_resume_key_rsp resume_rsp;
4291 struct srv_copychunk_copy cc_copy;
4294 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4295 struct tevent_req *req);
4297 static void cli_splice_copychunk_done(struct tevent_req *subreq)
4299 struct tevent_req *req = tevent_req_callback_data(
4300 subreq, struct tevent_req);
4301 struct cli_smb2_splice_state *state =
4302 tevent_req_data(req,
4303 struct cli_smb2_splice_state);
4304 struct smbXcli_conn *conn = state->cli->conn;
4305 DATA_BLOB out_input_buffer = data_blob_null;
4306 DATA_BLOB out_output_buffer = data_blob_null;
4307 struct srv_copychunk_rsp cc_copy_rsp;
4308 enum ndr_err_code ndr_ret;
4311 status = smb2cli_ioctl_recv(subreq, state,
4313 &out_output_buffer);
4314 TALLOC_FREE(subreq);
4315 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
4316 state->resized) && tevent_req_nterror(req, status)) {
4320 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
4321 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
4322 if (ndr_ret != NDR_ERR_SUCCESS) {
4323 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4324 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4328 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
4329 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
4330 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
4331 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
4332 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
4333 tevent_req_nterror(req, status)) {
4337 state->resized = true;
4338 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
4339 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
4341 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4342 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4343 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
4344 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4347 state->src_offset += cc_copy_rsp.total_bytes_written;
4348 state->dst_offset += cc_copy_rsp.total_bytes_written;
4349 state->written += cc_copy_rsp.total_bytes_written;
4350 if (!state->splice_cb(state->written, state->priv)) {
4351 tevent_req_nterror(req, NT_STATUS_CANCELLED);
4356 cli_splice_copychunk_send(state, req);
4359 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4360 struct tevent_req *req)
4362 struct tevent_req *subreq;
4363 enum ndr_err_code ndr_ret;
4364 struct smbXcli_conn *conn = state->cli->conn;
4365 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
4366 off_t src_offset = state->src_offset;
4367 off_t dst_offset = state->dst_offset;
4368 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
4369 state->size - state->written);
4370 DATA_BLOB in_input_buffer = data_blob_null;
4371 DATA_BLOB in_output_buffer = data_blob_null;
4373 if (state->size - state->written == 0) {
4374 tevent_req_done(req);
4378 cc_copy->chunk_count = 0;
4380 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
4381 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
4382 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
4383 smb2cli_conn_cc_chunk_len(conn));
4384 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
4385 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4388 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
4389 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
4390 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
4391 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4394 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4395 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4396 cc_copy->chunk_count++;
4399 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
4400 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
4401 if (ndr_ret != NDR_ERR_SUCCESS) {
4402 DEBUG(0, ("failed to marshall copy chunk req\n"));
4403 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4407 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
4408 state->cli->timeout,
4409 state->cli->smb2.session,
4410 state->cli->smb2.tcon,
4411 state->dst_ph->fid_persistent, /* in_fid_persistent */
4412 state->dst_ph->fid_volatile, /* in_fid_volatile */
4413 FSCTL_SRV_COPYCHUNK_WRITE,
4414 0, /* in_max_input_length */
4416 12, /* in_max_output_length */
4418 SMB2_IOCTL_FLAG_IS_FSCTL);
4419 if (tevent_req_nomem(subreq, req)) {
4422 tevent_req_set_callback(subreq,
4423 cli_splice_copychunk_done,
4427 static void cli_splice_key_done(struct tevent_req *subreq)
4429 struct tevent_req *req = tevent_req_callback_data(
4430 subreq, struct tevent_req);
4431 struct cli_smb2_splice_state *state =
4432 tevent_req_data(req,
4433 struct cli_smb2_splice_state);
4434 enum ndr_err_code ndr_ret;
4437 DATA_BLOB out_input_buffer = data_blob_null;
4438 DATA_BLOB out_output_buffer = data_blob_null;
4440 status = smb2cli_ioctl_recv(subreq, state,
4442 &out_output_buffer);
4443 TALLOC_FREE(subreq);
4444 if (tevent_req_nterror(req, status)) {
4448 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
4449 state, &state->resume_rsp,
4450 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
4451 if (ndr_ret != NDR_ERR_SUCCESS) {
4452 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4453 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4457 memcpy(&state->cc_copy.source_key,
4458 &state->resume_rsp.resume_key,
4459 sizeof state->resume_rsp.resume_key);
4461 cli_splice_copychunk_send(state, req);
4464 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
4465 struct tevent_context *ev,
4466 struct cli_state *cli,
4467 uint16_t src_fnum, uint16_t dst_fnum,
4468 off_t size, off_t src_offset, off_t dst_offset,
4469 int (*splice_cb)(off_t n, void *priv),
4472 struct tevent_req *req;
4473 struct tevent_req *subreq;
4474 struct cli_smb2_splice_state *state;
4476 DATA_BLOB in_input_buffer = data_blob_null;
4477 DATA_BLOB in_output_buffer = data_blob_null;
4479 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
4485 state->splice_cb = splice_cb;
4489 state->src_offset = src_offset;
4490 state->dst_offset = dst_offset;
4491 state->cc_copy.chunks = talloc_array(state,
4492 struct srv_copychunk,
4493 smb2cli_conn_cc_max_chunks(cli->conn));
4494 if (state->cc_copy.chunks == NULL) {
4498 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
4499 if (tevent_req_nterror(req, status))
4500 return tevent_req_post(req, ev);
4502 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
4503 if (tevent_req_nterror(req, status))
4504 return tevent_req_post(req, ev);
4506 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
4510 state->src_ph->fid_persistent, /* in_fid_persistent */
4511 state->src_ph->fid_volatile, /* in_fid_volatile */
4512 FSCTL_SRV_REQUEST_RESUME_KEY,
4513 0, /* in_max_input_length */
4515 32, /* in_max_output_length */
4517 SMB2_IOCTL_FLAG_IS_FSCTL);
4518 if (tevent_req_nomem(subreq, req)) {
4521 tevent_req_set_callback(subreq,
4522 cli_splice_key_done,
4528 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
4530 struct cli_smb2_splice_state *state = tevent_req_data(
4531 req, struct cli_smb2_splice_state);
4534 if (tevent_req_is_nterror(req, &status)) {
4535 state->cli->raw_status = status;
4536 tevent_req_received(req);
4539 if (written != NULL) {
4540 *written = state->written;
4542 state->cli->raw_status = NT_STATUS_OK;
4543 tevent_req_received(req);
4544 return NT_STATUS_OK;
4547 /***************************************************************
4548 SMB2 enum shadow copy data.
4549 ***************************************************************/
4551 struct cli_smb2_shadow_copy_data_fnum_state {
4552 struct cli_state *cli;
4554 struct smb2_hnd *ph;
4555 DATA_BLOB out_input_buffer;
4556 DATA_BLOB out_output_buffer;
4559 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
4561 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
4562 TALLOC_CTX *mem_ctx,
4563 struct tevent_context *ev,
4564 struct cli_state *cli,
4568 struct tevent_req *req, *subreq;
4569 struct cli_smb2_shadow_copy_data_fnum_state *state;
4572 req = tevent_req_create(mem_ctx, &state,
4573 struct cli_smb2_shadow_copy_data_fnum_state);
4578 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4579 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4580 return tevent_req_post(req, ev);
4586 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4587 if (tevent_req_nterror(req, status)) {
4588 return tevent_req_post(req, ev);
4592 * TODO. Under SMB2 we should send a zero max_output_length
4593 * ioctl to get the required size, then send another ioctl
4594 * to get the data, but the current SMB1 implementation just
4595 * does one roundtrip with a 64K buffer size. Do the same
4599 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4600 state->cli->timeout,
4601 state->cli->smb2.session,
4602 state->cli->smb2.tcon,
4603 state->ph->fid_persistent, /* in_fid_persistent */
4604 state->ph->fid_volatile, /* in_fid_volatile */
4605 FSCTL_GET_SHADOW_COPY_DATA,
4606 0, /* in_max_input_length */
4607 NULL, /* in_input_buffer */
4609 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
4610 NULL, /* in_output_buffer */
4611 SMB2_IOCTL_FLAG_IS_FSCTL);
4613 if (tevent_req_nomem(subreq, req)) {
4614 return tevent_req_post(req, ev);
4616 tevent_req_set_callback(subreq,
4617 cli_smb2_shadow_copy_data_fnum_done,
4623 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4625 struct tevent_req *req = tevent_req_callback_data(
4626 subreq, struct tevent_req);
4627 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4628 req, struct cli_smb2_shadow_copy_data_fnum_state);
4631 status = smb2cli_ioctl_recv(subreq, state,
4632 &state->out_input_buffer,
4633 &state->out_output_buffer);
4634 tevent_req_simple_finish_ntstatus(subreq, status);
4637 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4638 TALLOC_CTX *mem_ctx,
4643 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4644 req, struct cli_smb2_shadow_copy_data_fnum_state);
4645 char **names = NULL;
4646 uint32_t num_names = 0;
4647 uint32_t num_names_returned = 0;
4648 uint32_t dlength = 0;
4650 uint8_t *endp = NULL;
4653 if (tevent_req_is_nterror(req, &status)) {
4657 if (state->out_output_buffer.length < 16) {
4658 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4661 num_names = IVAL(state->out_output_buffer.data, 0);
4662 num_names_returned = IVAL(state->out_output_buffer.data, 4);
4663 dlength = IVAL(state->out_output_buffer.data, 8);
4665 if (num_names > 0x7FFFFFFF) {
4666 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4669 if (get_names == false) {
4670 *pnum_names = (int)num_names;
4671 return NT_STATUS_OK;
4673 if (num_names != num_names_returned) {
4674 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4676 if (dlength + 12 < 12) {
4677 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4680 * NB. The below is an allowable return if there are
4681 * more snapshots than the buffer size we told the
4682 * server we can receive. We currently don't support
4685 if (dlength + 12 > state->out_output_buffer.length) {
4686 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4688 if (state->out_output_buffer.length +
4689 (2 * sizeof(SHADOW_COPY_LABEL)) <
4690 state->out_output_buffer.length) {
4691 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4694 names = talloc_array(mem_ctx, char *, num_names_returned);
4695 if (names == NULL) {
4696 return NT_STATUS_NO_MEMORY;
4699 endp = state->out_output_buffer.data +
4700 state->out_output_buffer.length;
4702 for (i=0; i<num_names_returned; i++) {
4705 size_t converted_size;
4707 src = state->out_output_buffer.data + 12 +
4708 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4710 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4711 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4713 ret = convert_string_talloc(
4714 names, CH_UTF16LE, CH_UNIX,
4715 src, 2 * sizeof(SHADOW_COPY_LABEL),
4716 &names[i], &converted_size);
4719 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4722 *pnum_names = num_names;
4724 return NT_STATUS_OK;
4727 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4728 struct cli_state *cli,
4734 TALLOC_CTX *frame = talloc_stackframe();
4735 struct tevent_context *ev;
4736 struct tevent_req *req;
4737 NTSTATUS status = NT_STATUS_NO_MEMORY;
4739 if (smbXcli_conn_has_async_calls(cli->conn)) {
4741 * Can't use sync call while an async call is in flight
4743 status = NT_STATUS_INVALID_PARAMETER;
4746 ev = samba_tevent_context_init(frame);
4750 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4758 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4761 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4767 cli->raw_status = status;
4773 /***************************************************************
4774 Wrapper that allows SMB2 to truncate a file.
4776 ***************************************************************/
4778 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4783 uint8_t buf[8] = {0};
4784 DATA_BLOB inbuf = { .data = buf, .length = sizeof(buf) };
4785 TALLOC_CTX *frame = talloc_stackframe();
4787 if (smbXcli_conn_has_async_calls(cli->conn)) {
4789 * Can't use sync call while an async call is in flight
4791 status = NT_STATUS_INVALID_PARAMETER;
4795 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4796 status = NT_STATUS_INVALID_PARAMETER;
4800 SBVAL(buf, 0, newsize);
4802 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4803 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4805 status = cli_smb2_set_info_fnum(
4808 1, /* in_info_type */
4809 SMB_FILE_END_OF_FILE_INFORMATION-1000, /* in_file_info_class */
4810 &inbuf, /* in_input_buffer */
4815 cli->raw_status = status;
4821 struct cli_smb2_notify_state {
4822 struct tevent_req *subreq;
4823 struct notify_change *changes;
4827 static void cli_smb2_notify_done(struct tevent_req *subreq);
4828 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4830 struct tevent_req *cli_smb2_notify_send(
4831 TALLOC_CTX *mem_ctx,
4832 struct tevent_context *ev,
4833 struct cli_state *cli,
4835 uint32_t buffer_size,
4836 uint32_t completion_filter,
4839 struct tevent_req *req = NULL;
4840 struct cli_smb2_notify_state *state = NULL;
4841 struct smb2_hnd *ph = NULL;
4844 req = tevent_req_create(mem_ctx, &state,
4845 struct cli_smb2_notify_state);
4850 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4851 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4852 return tevent_req_post(req, ev);
4855 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4856 if (tevent_req_nterror(req, status)) {
4857 return tevent_req_post(req, ev);
4860 state->subreq = smb2cli_notify_send(
4872 if (tevent_req_nomem(state->subreq, req)) {
4873 return tevent_req_post(req, ev);
4875 tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4876 tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4880 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4882 struct cli_smb2_notify_state *state = tevent_req_data(
4883 req, struct cli_smb2_notify_state);
4886 ok = tevent_req_cancel(state->subreq);
4890 static void cli_smb2_notify_done(struct tevent_req *subreq)
4892 struct tevent_req *req = tevent_req_callback_data(
4893 subreq, struct tevent_req);
4894 struct cli_smb2_notify_state *state = tevent_req_data(
4895 req, struct cli_smb2_notify_state);
4901 status = smb2cli_notify_recv(subreq, state, &base, &len);
4902 TALLOC_FREE(subreq);
4904 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4905 tevent_req_done(req);
4908 if (tevent_req_nterror(req, status)) {
4914 while (len - ofs >= 12) {
4915 struct notify_change *tmp;
4916 struct notify_change *c;
4917 uint32_t next_ofs = IVAL(base, ofs);
4918 uint32_t file_name_length = IVAL(base, ofs+8);
4922 tmp = talloc_realloc(
4925 struct notify_change,
4926 state->num_changes + 1);
4927 if (tevent_req_nomem(tmp, req)) {
4930 state->changes = tmp;
4931 c = &state->changes[state->num_changes];
4932 state->num_changes += 1;
4934 if (smb_buffer_oob(len, ofs, next_ofs) ||
4935 smb_buffer_oob(len, ofs+12, file_name_length)) {
4937 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4941 c->action = IVAL(base, ofs+4);
4943 ok = convert_string_talloc(
4953 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4957 if (next_ofs == 0) {
4963 tevent_req_done(req);
4966 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
4967 TALLOC_CTX *mem_ctx,
4968 struct notify_change **pchanges,
4969 uint32_t *pnum_changes)
4971 struct cli_smb2_notify_state *state = tevent_req_data(
4972 req, struct cli_smb2_notify_state);
4975 if (tevent_req_is_nterror(req, &status)) {
4978 *pchanges = talloc_move(mem_ctx, &state->changes);
4979 *pnum_changes = state->num_changes;
4980 return NT_STATUS_OK;
4983 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
4984 uint32_t buffer_size, uint32_t completion_filter,
4985 bool recursive, TALLOC_CTX *mem_ctx,
4986 struct notify_change **pchanges,
4987 uint32_t *pnum_changes)
4989 TALLOC_CTX *frame = talloc_stackframe();
4990 struct tevent_context *ev;
4991 struct tevent_req *req;
4992 NTSTATUS status = NT_STATUS_NO_MEMORY;
4994 if (smbXcli_conn_has_async_calls(cli->conn)) {
4996 * Can't use sync call while an async call is in flight
4998 status = NT_STATUS_INVALID_PARAMETER;
5001 ev = samba_tevent_context_init(frame);
5005 req = cli_smb2_notify_send(
5016 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5019 status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
5025 struct cli_smb2_set_reparse_point_fnum_state {
5026 struct cli_state *cli;
5028 struct smb2_hnd *ph;
5029 DATA_BLOB input_buffer;
5032 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
5034 struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
5035 TALLOC_CTX *mem_ctx,
5036 struct tevent_context *ev,
5037 struct cli_state *cli,
5041 struct tevent_req *req, *subreq;
5042 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
5045 req = tevent_req_create(mem_ctx, &state,
5046 struct cli_smb2_set_reparse_point_fnum_state);
5051 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5052 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
5053 return tevent_req_post(req, ev);
5059 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
5060 if (tevent_req_nterror(req, status)) {
5061 return tevent_req_post(req, ev);
5064 state->input_buffer = data_blob_talloc(state,
5067 if (state->input_buffer.data == NULL) {
5068 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
5069 return tevent_req_post(req, ev);
5072 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
5073 state->cli->timeout,
5074 state->cli->smb2.session,
5075 state->cli->smb2.tcon,
5076 state->ph->fid_persistent, /* in_fid_persistent */
5077 state->ph->fid_volatile, /* in_fid_volatile */
5078 FSCTL_SET_REPARSE_POINT,
5079 0, /* in_max_input_length */
5080 &state->input_buffer ,
5083 SMB2_IOCTL_FLAG_IS_FSCTL);
5085 if (tevent_req_nomem(subreq, req)) {
5086 return tevent_req_post(req, ev);
5088 tevent_req_set_callback(subreq,
5089 cli_smb2_set_reparse_point_fnum_done,
5095 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
5097 struct tevent_req *req = tevent_req_callback_data(
5098 subreq, struct tevent_req);
5099 struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
5100 req, struct cli_smb2_set_reparse_point_fnum_state);
5103 status = smb2cli_ioctl_recv(subreq, state,
5106 TALLOC_FREE(subreq);
5107 if (tevent_req_nterror(req, status)) {
5110 tevent_req_done(req);
5113 NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
5115 return tevent_req_simple_recv_ntstatus(req);
5118 struct cli_smb2_get_reparse_point_fnum_state {
5119 struct cli_state *cli;
5121 struct smb2_hnd *ph;
5122 DATA_BLOB output_buffer;
5125 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
5127 struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
5128 TALLOC_CTX *mem_ctx,
5129 struct tevent_context *ev,
5130 struct cli_state *cli,
5133 struct tevent_req *req, *subreq;
5134 struct cli_smb2_get_reparse_point_fnum_state *state = NULL;
5137 req = tevent_req_create(mem_ctx, &state,
5138 struct cli_smb2_get_reparse_point_fnum_state);
5143 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5144 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
5145 return tevent_req_post(req, ev);
5151 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
5152 if (tevent_req_nterror(req, status)) {
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_GET_REPARSE_POINT,
5163 0, /* in_max_input_length */
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_get_reparse_point_fnum_done,
5179 static void cli_smb2_get_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_get_reparse_point_fnum_state *state = tevent_req_data(
5184 req, struct cli_smb2_get_reparse_point_fnum_state);
5185 struct cli_state *cli = state->cli;
5188 status = smb2cli_ioctl_recv(subreq, state,
5190 &state->output_buffer);
5191 TALLOC_FREE(subreq);
5192 if (tevent_req_nterror(req, status)) {
5193 cli->raw_status = status;
5196 tevent_req_done(req);
5199 NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
5200 TALLOC_CTX *mem_ctx,
5203 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
5204 req, struct cli_smb2_get_reparse_point_fnum_state);
5206 if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
5207 NTSTATUS status = state->cli->raw_status;
5208 tevent_req_received(req);
5211 *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
5212 if (output->data == NULL) {
5213 tevent_req_received(req);
5214 return NT_STATUS_NO_MEMORY;
5216 tevent_req_received(req);
5217 return NT_STATUS_OK;