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.
1018 ***************************************************************/
1020 struct cli_smb2_unlink_state {
1021 struct tevent_context *ev;
1022 struct cli_state *cli;
1024 const struct smb2_create_blobs *in_cblobs;
1027 static void cli_smb2_unlink_opened1(struct tevent_req *subreq);
1028 static void cli_smb2_unlink_opened2(struct tevent_req *subreq);
1029 static void cli_smb2_unlink_closed(struct tevent_req *subreq);
1031 struct tevent_req *cli_smb2_unlink_send(
1032 TALLOC_CTX *mem_ctx,
1033 struct tevent_context *ev,
1034 struct cli_state *cli,
1036 const struct smb2_create_blobs *in_cblobs)
1038 struct tevent_req *req = NULL, *subreq = NULL;
1039 struct cli_smb2_unlink_state *state = NULL;
1041 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_unlink_state);
1047 state->fname = fname;
1048 state->in_cblobs = in_cblobs;
1050 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1051 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1052 return tevent_req_post(req, ev);
1055 subreq = cli_smb2_create_fnum_send(
1056 state, /* mem_ctx */
1057 state->ev, /* tevent_context */
1058 state->cli, /* cli_struct */
1059 state->fname, /* filename */
1060 0, /* create_flags */
1061 SMB2_IMPERSONATION_IMPERSONATION,
1062 DELETE_ACCESS, /* desired_access */
1063 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1066 FILE_SHARE_DELETE, /* share_access */
1067 FILE_OPEN, /* create_disposition */
1068 FILE_DELETE_ON_CLOSE, /* create_options */
1069 state->in_cblobs); /* in_cblobs */
1070 if (tevent_req_nomem(subreq, req)) {
1071 return tevent_req_post(req, ev);
1073 tevent_req_set_callback(subreq, cli_smb2_unlink_opened1, req);
1077 static void cli_smb2_unlink_opened1(struct tevent_req *subreq)
1079 struct tevent_req *req = tevent_req_callback_data(
1080 subreq, struct tevent_req);
1081 struct cli_smb2_unlink_state *state = tevent_req_data(
1082 req, struct cli_smb2_unlink_state);
1086 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1087 TALLOC_FREE(subreq);
1089 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1091 * Naive option to match our SMB1 code. Assume the
1092 * symlink path that tripped us up was the last
1093 * component and try again. Eventually we will have to
1094 * deal with the returned path unprocessed component. JRA.
1096 subreq = cli_smb2_create_fnum_send(
1097 state, /* mem_ctx */
1098 state->ev, /* tevent_context */
1099 state->cli, /* cli_struct */
1100 state->fname, /* filename */
1101 0, /* create_flags */
1102 SMB2_IMPERSONATION_IMPERSONATION,
1103 DELETE_ACCESS, /* desired_access */
1104 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1107 FILE_SHARE_DELETE, /* share_access */
1108 FILE_OPEN, /* create_disposition */
1109 FILE_DELETE_ON_CLOSE|
1110 FILE_OPEN_REPARSE_POINT, /* create_options */
1111 state->in_cblobs); /* in_cblobs */
1112 if (tevent_req_nomem(subreq, req)) {
1115 tevent_req_set_callback(subreq, cli_smb2_unlink_opened2, req);
1119 if (tevent_req_nterror(req, status)) {
1123 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1124 if (tevent_req_nomem(subreq, req)) {
1127 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1130 static void cli_smb2_unlink_opened2(struct tevent_req *subreq)
1132 struct tevent_req *req = tevent_req_callback_data(
1133 subreq, struct tevent_req);
1134 struct cli_smb2_unlink_state *state = tevent_req_data(
1135 req, struct cli_smb2_unlink_state);
1139 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1140 TALLOC_FREE(subreq);
1141 if (tevent_req_nterror(req, status)) {
1145 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1146 if (tevent_req_nomem(subreq, req)) {
1149 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1152 static void cli_smb2_unlink_closed(struct tevent_req *subreq)
1154 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1155 tevent_req_simple_finish_ntstatus(subreq, status);
1158 NTSTATUS cli_smb2_unlink_recv(struct tevent_req *req)
1160 return tevent_req_simple_recv_ntstatus(req);
1163 NTSTATUS cli_smb2_unlink(
1164 struct cli_state *cli,
1166 const struct smb2_create_blobs *in_cblobs)
1168 TALLOC_CTX *frame = talloc_stackframe();
1169 struct tevent_context *ev;
1170 struct tevent_req *req;
1171 NTSTATUS status = NT_STATUS_NO_MEMORY;
1174 if (smbXcli_conn_has_async_calls(cli->conn)) {
1176 * Can't use sync call while an async call is in flight
1178 status = NT_STATUS_INVALID_PARAMETER;
1181 ev = samba_tevent_context_init(frame);
1185 req = cli_smb2_unlink_send(frame, ev, cli, fname, in_cblobs);
1189 ok = tevent_req_poll_ntstatus(req, ev, &status);
1193 status = cli_smb2_unlink_recv(req);
1195 cli->raw_status = status;
1200 /***************************************************************
1201 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1202 ***************************************************************/
1204 static NTSTATUS parse_finfo_id_both_directory_info(const uint8_t *dir_data,
1205 uint32_t dir_data_length,
1206 struct file_info *finfo,
1207 uint32_t *next_offset)
1213 if (dir_data_length < 4) {
1214 return NT_STATUS_INFO_LENGTH_MISMATCH;
1217 *next_offset = IVAL(dir_data, 0);
1219 if (*next_offset > dir_data_length) {
1220 return NT_STATUS_INFO_LENGTH_MISMATCH;
1223 if (*next_offset != 0) {
1224 /* Ensure we only read what in this record. */
1225 dir_data_length = *next_offset;
1228 if (dir_data_length < 105) {
1229 return NT_STATUS_INFO_LENGTH_MISMATCH;
1232 finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
1233 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
1234 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
1235 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
1236 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
1237 finfo->allocated_size = IVAL2_TO_SMB_BIG_UINT(dir_data + 48, 0);
1238 finfo->mode = CVAL(dir_data + 56, 0);
1239 finfo->ino = IVAL2_TO_SMB_BIG_UINT(dir_data + 96, 0);
1240 namelen = IVAL(dir_data + 60,0);
1241 if (namelen > (dir_data_length - 104)) {
1242 return NT_STATUS_INFO_LENGTH_MISMATCH;
1244 slen = CVAL(dir_data + 68, 0);
1246 return NT_STATUS_INFO_LENGTH_MISMATCH;
1248 ret = pull_string_talloc(finfo,
1250 FLAGS2_UNICODE_STRINGS,
1255 if (ret == (size_t)-1) {
1256 /* Bad conversion. */
1257 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1260 ret = pull_string_talloc(finfo,
1262 FLAGS2_UNICODE_STRINGS,
1267 if (ret == (size_t)-1) {
1268 /* Bad conversion. */
1269 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1272 if (finfo->name == NULL) {
1273 /* Bad conversion. */
1274 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1277 return NT_STATUS_OK;
1280 /*******************************************************************
1281 Given a filename - get its directory name
1282 ********************************************************************/
1284 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
1292 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
1295 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
1306 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
1309 (*parent)[len] = '\0';
1317 /***************************************************************
1318 Wrapper that allows SMB2 to list a directory.
1320 ***************************************************************/
1322 NTSTATUS cli_smb2_list(struct cli_state *cli,
1323 const char *pathname,
1325 NTSTATUS (*fn)(const char *,
1332 uint16_t fnum = 0xffff;
1333 char *parent_dir = NULL;
1334 const char *mask = NULL;
1335 struct smb2_hnd *ph = NULL;
1336 bool processed_file = false;
1337 TALLOC_CTX *frame = talloc_stackframe();
1338 TALLOC_CTX *subframe = NULL;
1341 uint32_t max_avail_len;
1344 if (smbXcli_conn_has_async_calls(cli->conn)) {
1346 * Can't use sync call while an async call is in flight
1348 status = NT_STATUS_INVALID_PARAMETER;
1352 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1353 status = NT_STATUS_INVALID_PARAMETER;
1357 /* Get the directory name. */
1358 if (!windows_parent_dirname(frame,
1362 status = NT_STATUS_NO_MEMORY;
1366 mask_has_wild = ms_has_wild(mask);
1368 status = cli_smb2_create_fnum(cli,
1370 0, /* create_flags */
1371 SMB2_IMPERSONATION_IMPERSONATION,
1372 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
1373 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1374 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
1375 FILE_OPEN, /* create_disposition */
1376 FILE_DIRECTORY_FILE, /* create_options */
1383 if (!NT_STATUS_IS_OK(status)) {
1387 status = map_fnum_to_smb2_handle(cli,
1390 if (!NT_STATUS_IS_OK(status)) {
1395 * ideally, use the max transaction size, but don't send a request
1396 * bigger than we have credits available for
1398 max_trans = smb2cli_conn_max_trans_size(cli->conn);
1399 ok = smb2cli_conn_req_possible(cli->conn, &max_avail_len);
1401 max_trans = MIN(max_trans, max_avail_len);
1405 uint8_t *dir_data = NULL;
1406 uint32_t dir_data_length = 0;
1407 uint32_t next_offset = 0;
1408 subframe = talloc_stackframe();
1410 status = smb2cli_query_directory(cli->conn,
1414 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
1425 if (!NT_STATUS_IS_OK(status)) {
1426 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1433 struct file_info *finfo = talloc_zero(subframe,
1436 if (finfo == NULL) {
1437 status = NT_STATUS_NO_MEMORY;
1441 status = parse_finfo_id_both_directory_info(dir_data,
1446 if (!NT_STATUS_IS_OK(status)) {
1450 /* Protect against server attack. */
1451 status = is_bad_finfo_name(cli, finfo);
1452 if (!NT_STATUS_IS_OK(status)) {
1453 smbXcli_conn_disconnect(cli->conn, status);
1457 if (dir_check_ftype((uint32_t)finfo->mode,
1458 (uint32_t)attribute)) {
1460 * Only process if attributes match.
1461 * On SMB1 server does this, so on
1462 * SMB2 we need to emulate in the
1465 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1467 processed_file = true;
1469 status = fn(cli->dfs_mountpoint,
1474 if (!NT_STATUS_IS_OK(status)) {
1481 /* Move to next entry. */
1483 dir_data += next_offset;
1484 dir_data_length -= next_offset;
1486 } while (next_offset != 0);
1488 TALLOC_FREE(subframe);
1490 if (!mask_has_wild) {
1492 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1493 * when handed a non-wildcard path. Do it
1494 * for the server (with a non-wildcard path
1495 * there should only ever be one file returned.
1497 status = STATUS_NO_MORE_FILES;
1501 } while (NT_STATUS_IS_OK(status));
1503 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1504 status = NT_STATUS_OK;
1507 if (NT_STATUS_IS_OK(status) && !processed_file) {
1509 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1510 * if no files match. Emulate this in the client.
1512 status = NT_STATUS_NO_SUCH_FILE;
1517 if (fnum != 0xffff) {
1518 cli_smb2_close_fnum(cli, fnum);
1521 cli->raw_status = status;
1523 TALLOC_FREE(subframe);
1528 /***************************************************************
1529 Wrapper that allows SMB2 to query a path info (basic level).
1531 ***************************************************************/
1533 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1535 SMB_STRUCT_STAT *sbuf,
1536 uint32_t *attributes)
1539 struct smb_create_returns cr;
1540 uint16_t fnum = 0xffff;
1541 size_t namelen = strlen(name);
1543 if (smbXcli_conn_has_async_calls(cli->conn)) {
1545 * Can't use sync call while an async call is in flight
1547 return NT_STATUS_INVALID_PARAMETER;
1550 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1551 return NT_STATUS_INVALID_PARAMETER;
1554 /* SMB2 is pickier about pathnames. Ensure it doesn't
1556 if (namelen > 0 && name[namelen-1] == '\\') {
1557 char *modname = talloc_strndup(talloc_tos(), name, namelen-1);
1558 if (modname == NULL) {
1559 return NT_STATUS_NO_MEMORY;
1564 /* This is commonly used as a 'cd'. Try qpathinfo on
1565 a directory handle first. */
1567 status = cli_smb2_create_fnum(cli,
1569 0, /* create_flags */
1570 SMB2_IMPERSONATION_IMPERSONATION,
1571 FILE_READ_ATTRIBUTES, /* desired_access */
1572 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1573 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1574 FILE_OPEN, /* create_disposition */
1575 FILE_DIRECTORY_FILE, /* create_options */
1582 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1583 /* Maybe a file ? */
1584 status = cli_smb2_create_fnum(cli,
1586 0, /* create_flags */
1587 SMB2_IMPERSONATION_IMPERSONATION,
1588 FILE_READ_ATTRIBUTES, /* desired_access */
1589 0, /* file attributes */
1590 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1591 FILE_OPEN, /* create_disposition */
1592 0, /* create_options */
1600 if (!NT_STATUS_IS_OK(status)) {
1604 status = cli_smb2_close_fnum(cli, fnum);
1608 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1609 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1610 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1611 sbuf->st_ex_size = cr.end_of_file;
1612 *attributes = cr.file_attributes;
1617 /***************************************************************
1618 Wrapper that allows SMB2 to check if a path is a directory.
1620 ***************************************************************/
1622 NTSTATUS cli_smb2_chkpath(struct cli_state *cli,
1626 uint16_t fnum = 0xffff;
1628 if (smbXcli_conn_has_async_calls(cli->conn)) {
1630 * Can't use sync call while an async call is in flight
1632 return NT_STATUS_INVALID_PARAMETER;
1635 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1636 return NT_STATUS_INVALID_PARAMETER;
1639 /* Ensure this is a directory. */
1640 status = cli_smb2_create_fnum(cli,
1642 0, /* create_flags */
1643 SMB2_IMPERSONATION_IMPERSONATION,
1644 FILE_READ_ATTRIBUTES, /* desired_access */
1645 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1646 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1647 FILE_OPEN, /* create_disposition */
1648 FILE_DIRECTORY_FILE, /* create_options */
1655 if (!NT_STATUS_IS_OK(status)) {
1659 return cli_smb2_close_fnum(cli, fnum);
1662 struct cli_smb2_query_info_fnum_state {
1666 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq);
1668 struct tevent_req *cli_smb2_query_info_fnum_send(
1669 TALLOC_CTX *mem_ctx,
1670 struct tevent_context *ev,
1671 struct cli_state *cli,
1673 uint8_t in_info_type,
1674 uint8_t in_info_class,
1675 uint32_t in_max_output_length,
1676 const DATA_BLOB *in_input_buffer,
1677 uint32_t in_additional_info,
1680 struct tevent_req *req = NULL, *subreq = NULL;
1681 struct cli_smb2_query_info_fnum_state *state = NULL;
1682 struct smb2_hnd *ph = NULL;
1685 req = tevent_req_create(
1686 mem_ctx, &state, struct cli_smb2_query_info_fnum_state);
1691 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1692 if (tevent_req_nterror(req, status)) {
1693 return tevent_req_post(req, ev);
1696 subreq = smb2cli_query_info_send(
1705 in_max_output_length,
1711 if (tevent_req_nomem(subreq, req)) {
1712 return tevent_req_post(req, ev);
1714 tevent_req_set_callback(subreq, cli_smb2_query_info_fnum_done, req);
1718 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq)
1720 struct tevent_req *req = tevent_req_callback_data(
1721 subreq, struct tevent_req);
1722 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1723 req, struct cli_smb2_query_info_fnum_state);
1727 status = smb2cli_query_info_recv(subreq, state, &outbuf);
1728 TALLOC_FREE(subreq);
1729 if (tevent_req_nterror(req, status)) {
1734 * We have to dup the memory here because outbuf.data is not
1735 * returned as a talloc object by smb2cli_query_info_recv.
1736 * It's a pointer into the received buffer.
1738 state->outbuf = data_blob_dup_talloc(state, outbuf);
1740 if ((outbuf.length != 0) &&
1741 tevent_req_nomem(state->outbuf.data, req)) {
1744 tevent_req_done(req);
1747 NTSTATUS cli_smb2_query_info_fnum_recv(
1748 struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *outbuf)
1750 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1751 req, struct cli_smb2_query_info_fnum_state);
1754 if (tevent_req_is_nterror(req, &status)) {
1757 *outbuf = (DATA_BLOB) {
1758 .data = talloc_move(mem_ctx, &state->outbuf.data),
1759 .length = state->outbuf.length,
1761 return NT_STATUS_OK;
1764 NTSTATUS cli_smb2_query_info_fnum(
1765 struct cli_state *cli,
1767 uint8_t in_info_type,
1768 uint8_t in_info_class,
1769 uint32_t in_max_output_length,
1770 const DATA_BLOB *in_input_buffer,
1771 uint32_t in_additional_info,
1773 TALLOC_CTX *mem_ctx,
1776 TALLOC_CTX *frame = talloc_stackframe();
1777 struct tevent_context *ev = NULL;
1778 struct tevent_req *req = NULL;
1779 NTSTATUS status = NT_STATUS_NO_MEMORY;
1782 if (smbXcli_conn_has_async_calls(cli->conn)) {
1784 * Can't use sync call while an async call is in flight
1786 status = NT_STATUS_INVALID_PARAMETER;
1789 ev = samba_tevent_context_init(frame);
1793 req = cli_smb2_query_info_fnum_send(
1800 in_max_output_length,
1807 ok = tevent_req_poll_ntstatus(req, ev, &status);
1811 status = cli_smb2_query_info_fnum_recv(req, mem_ctx, outbuf);
1817 /***************************************************************
1818 Helper function for pathname operations.
1819 ***************************************************************/
1821 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1823 uint32_t desired_access,
1827 size_t namelen = strlen(name);
1828 TALLOC_CTX *frame = talloc_stackframe();
1829 uint32_t create_options = 0;
1831 /* SMB2 is pickier about pathnames. Ensure it doesn't
1833 if (namelen > 0 && name[namelen-1] == '\\') {
1834 char *modname = talloc_strdup(frame, name);
1835 if (modname == NULL) {
1836 status = NT_STATUS_NO_MEMORY;
1839 modname[namelen-1] = '\0';
1843 /* Try to open a file handle first. */
1844 status = cli_smb2_create_fnum(cli,
1846 0, /* create_flags */
1847 SMB2_IMPERSONATION_IMPERSONATION,
1849 0, /* file attributes */
1850 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1851 FILE_OPEN, /* create_disposition */
1859 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1861 * Naive option to match our SMB1 code. Assume the
1862 * symlink path that tripped us up was the last
1863 * component and try again. Eventually we will have to
1864 * deal with the returned path unprocessed component. JRA.
1866 create_options |= FILE_OPEN_REPARSE_POINT;
1867 status = cli_smb2_create_fnum(cli,
1869 0, /* create_flags */
1870 SMB2_IMPERSONATION_IMPERSONATION,
1872 0, /* file attributes */
1873 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1874 FILE_OPEN, /* create_disposition */
1883 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1884 create_options |= FILE_DIRECTORY_FILE;
1885 status = cli_smb2_create_fnum(cli,
1887 0, /* create_flags */
1888 SMB2_IMPERSONATION_IMPERSONATION,
1890 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1891 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1892 FILE_OPEN, /* create_disposition */
1893 create_options, /* create_options */
1907 /***************************************************************
1908 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1910 ***************************************************************/
1912 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1917 DATA_BLOB outbuf = data_blob_null;
1918 uint16_t fnum = 0xffff;
1919 uint32_t altnamelen = 0;
1920 TALLOC_CTX *frame = talloc_stackframe();
1922 if (smbXcli_conn_has_async_calls(cli->conn)) {
1924 * Can't use sync call while an async call is in flight
1926 status = NT_STATUS_INVALID_PARAMETER;
1930 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1931 status = NT_STATUS_INVALID_PARAMETER;
1935 status = get_fnum_from_path(cli,
1937 FILE_READ_ATTRIBUTES,
1940 if (!NT_STATUS_IS_OK(status)) {
1944 status = cli_smb2_query_info_fnum(
1947 1, /* in_info_type */
1948 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1949 0xFFFF, /* in_max_output_length */
1950 NULL, /* in_input_buffer */
1951 0, /* in_additional_info */
1956 if (!NT_STATUS_IS_OK(status)) {
1960 /* Parse the reply. */
1961 if (outbuf.length < 4) {
1962 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1966 altnamelen = IVAL(outbuf.data, 0);
1967 if (altnamelen > outbuf.length - 4) {
1968 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1972 if (altnamelen > 0) {
1974 char *short_name = NULL;
1975 ret = pull_string_talloc(frame,
1977 FLAGS2_UNICODE_STRINGS,
1982 if (ret == (size_t)-1) {
1983 /* Bad conversion. */
1984 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1988 fstrcpy(alt_name, short_name);
1993 status = NT_STATUS_OK;
1997 if (fnum != 0xffff) {
1998 cli_smb2_close_fnum(cli, fnum);
2001 cli->raw_status = status;
2008 /***************************************************************
2009 Wrapper that allows SMB2 to query a fnum info (basic level).
2011 ***************************************************************/
2013 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
2017 struct timespec *create_time,
2018 struct timespec *access_time,
2019 struct timespec *write_time,
2020 struct timespec *change_time,
2024 DATA_BLOB outbuf = data_blob_null;
2025 TALLOC_CTX *frame = talloc_stackframe();
2027 if (smbXcli_conn_has_async_calls(cli->conn)) {
2029 * Can't use sync call while an async call is in flight
2031 status = NT_STATUS_INVALID_PARAMETER;
2035 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2036 status = NT_STATUS_INVALID_PARAMETER;
2040 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2041 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
2043 status = cli_smb2_query_info_fnum(
2046 1, /* in_info_type */
2047 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
2048 0xFFFF, /* in_max_output_length */
2049 NULL, /* in_input_buffer */
2050 0, /* in_additional_info */
2054 if (!NT_STATUS_IS_OK(status)) {
2058 /* Parse the reply. */
2059 if (outbuf.length < 0x60) {
2060 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2065 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
2068 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
2071 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
2074 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
2077 uint32_t attr = IVAL(outbuf.data, 0x20);
2078 *mode = (uint16_t)attr;
2081 uint64_t file_size = BVAL(outbuf.data, 0x30);
2082 *size = (off_t)file_size;
2085 uint64_t file_index = BVAL(outbuf.data, 0x40);
2086 *ino = (SMB_INO_T)file_index;
2091 cli->raw_status = status;
2097 /***************************************************************
2098 Wrapper that allows SMB2 to query an fnum.
2099 Implement on top of cli_smb2_qfileinfo_basic().
2101 ***************************************************************/
2103 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
2107 time_t *change_time,
2108 time_t *access_time,
2111 struct timespec access_time_ts;
2112 struct timespec write_time_ts;
2113 struct timespec change_time_ts;
2114 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
2124 cli->raw_status = status;
2126 if (!NT_STATUS_IS_OK(status)) {
2131 *change_time = change_time_ts.tv_sec;
2134 *access_time = access_time_ts.tv_sec;
2137 *write_time = write_time_ts.tv_sec;
2139 return NT_STATUS_OK;
2142 /***************************************************************
2143 Wrapper that allows SMB2 to get pathname attributes.
2145 ***************************************************************/
2147 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
2154 uint16_t fnum = 0xffff;
2155 struct smb2_hnd *ph = NULL;
2156 TALLOC_CTX *frame = talloc_stackframe();
2158 if (smbXcli_conn_has_async_calls(cli->conn)) {
2160 * Can't use sync call while an async call is in flight
2162 status = NT_STATUS_INVALID_PARAMETER;
2166 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2167 status = NT_STATUS_INVALID_PARAMETER;
2171 status = get_fnum_from_path(cli,
2173 FILE_READ_ATTRIBUTES,
2176 if (!NT_STATUS_IS_OK(status)) {
2180 status = map_fnum_to_smb2_handle(cli,
2183 if (!NT_STATUS_IS_OK(status)) {
2186 status = cli_smb2_getattrE(cli,
2193 if (!NT_STATUS_IS_OK(status)) {
2199 if (fnum != 0xffff) {
2200 cli_smb2_close_fnum(cli, fnum);
2203 cli->raw_status = status;
2209 /***************************************************************
2210 Wrapper that allows SMB2 to query a pathname info (basic level).
2211 Implement on top of cli_smb2_qfileinfo_basic().
2213 ***************************************************************/
2215 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
2217 struct timespec *create_time,
2218 struct timespec *access_time,
2219 struct timespec *write_time,
2220 struct timespec *change_time,
2226 struct smb2_hnd *ph = NULL;
2227 uint16_t fnum = 0xffff;
2228 TALLOC_CTX *frame = talloc_stackframe();
2230 if (smbXcli_conn_has_async_calls(cli->conn)) {
2232 * Can't use sync call while an async call is in flight
2234 status = NT_STATUS_INVALID_PARAMETER;
2238 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2239 status = NT_STATUS_INVALID_PARAMETER;
2243 status = get_fnum_from_path(cli,
2245 FILE_READ_ATTRIBUTES,
2248 if (!NT_STATUS_IS_OK(status)) {
2252 status = map_fnum_to_smb2_handle(cli,
2255 if (!NT_STATUS_IS_OK(status)) {
2259 status = cli_smb2_qfileinfo_basic(cli,
2271 if (fnum != 0xffff) {
2272 cli_smb2_close_fnum(cli, fnum);
2275 cli->raw_status = status;
2281 /***************************************************************
2282 Wrapper that allows SMB2 to query pathname streams.
2284 ***************************************************************/
2286 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
2288 TALLOC_CTX *mem_ctx,
2289 unsigned int *pnum_streams,
2290 struct stream_struct **pstreams)
2293 uint16_t fnum = 0xffff;
2294 DATA_BLOB outbuf = data_blob_null;
2295 TALLOC_CTX *frame = talloc_stackframe();
2297 if (smbXcli_conn_has_async_calls(cli->conn)) {
2299 * Can't use sync call while an async call is in flight
2301 status = NT_STATUS_INVALID_PARAMETER;
2305 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2306 status = NT_STATUS_INVALID_PARAMETER;
2310 status = get_fnum_from_path(cli,
2312 FILE_READ_ATTRIBUTES,
2315 if (!NT_STATUS_IS_OK(status)) {
2319 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2320 level 22 (SMB2_FILE_STREAM_INFORMATION). */
2322 status = cli_smb2_query_info_fnum(
2325 1, /* in_info_type */
2326 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
2327 0xFFFF, /* in_max_output_length */
2328 NULL, /* in_input_buffer */
2329 0, /* in_additional_info */
2334 if (!NT_STATUS_IS_OK(status)) {
2338 /* Parse the reply. */
2339 if (!parse_streams_blob(mem_ctx,
2344 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2350 if (fnum != 0xffff) {
2351 cli_smb2_close_fnum(cli, fnum);
2354 cli->raw_status = status;
2360 /***************************************************************
2361 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2364 ***************************************************************/
2366 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
2368 uint8_t in_info_type,
2369 uint8_t in_file_info_class,
2370 const DATA_BLOB *p_in_data)
2373 uint16_t fnum = 0xffff;
2374 TALLOC_CTX *frame = talloc_stackframe();
2376 if (smbXcli_conn_has_async_calls(cli->conn)) {
2378 * Can't use sync call while an async call is in flight
2380 status = NT_STATUS_INVALID_PARAMETER;
2384 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2385 status = NT_STATUS_INVALID_PARAMETER;
2389 status = get_fnum_from_path(cli,
2391 FILE_WRITE_ATTRIBUTES,
2394 if (!NT_STATUS_IS_OK(status)) {
2398 status = cli_smb2_set_info_fnum(
2403 p_in_data, /* in_input_buffer */
2404 0); /* in_additional_info */
2407 if (fnum != 0xffff) {
2408 cli_smb2_close_fnum(cli, fnum);
2411 cli->raw_status = status;
2418 /***************************************************************
2419 Wrapper that allows SMB2 to set pathname attributes.
2421 ***************************************************************/
2423 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
2428 uint8_t inbuf_store[40];
2429 DATA_BLOB inbuf = data_blob_null;
2431 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2432 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2434 inbuf.data = inbuf_store;
2435 inbuf.length = sizeof(inbuf_store);
2436 data_blob_clear(&inbuf);
2439 * SMB1 uses attr == 0 to clear all attributes
2440 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2441 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2442 * request attribute change.
2444 * SMB2 uses exactly the reverse. Unfortunately as the
2445 * cli_setatr() ABI is exposed inside libsmbclient,
2446 * we must make the SMB2 cli_smb2_setatr() call
2447 * export the same ABI as the SMB1 cli_setatr()
2448 * which calls it. This means reversing the sense
2449 * of the requested attr argument if it's zero
2450 * or FILE_ATTRIBUTE_NORMAL.
2452 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2456 attr = FILE_ATTRIBUTE_NORMAL;
2457 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
2461 SSVAL(inbuf.data, 32, attr);
2463 put_long_date((char *)inbuf.data + 16,mtime);
2465 /* Set all the other times to -1. */
2466 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2467 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
2468 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
2470 return cli_smb2_setpathinfo(cli,
2472 1, /* in_info_type */
2473 /* in_file_info_class */
2474 SMB_FILE_BASIC_INFORMATION - 1000,
2479 /***************************************************************
2480 Wrapper that allows SMB2 to set file handle times.
2482 ***************************************************************/
2484 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
2490 uint8_t inbuf_store[40];
2491 DATA_BLOB inbuf = data_blob_null;
2493 if (smbXcli_conn_has_async_calls(cli->conn)) {
2495 * Can't use sync call while an async call is in flight
2497 return NT_STATUS_INVALID_PARAMETER;
2500 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2501 return NT_STATUS_INVALID_PARAMETER;
2504 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2505 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2507 inbuf.data = inbuf_store;
2508 inbuf.length = sizeof(inbuf_store);
2509 data_blob_clear(&inbuf);
2511 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2512 if (change_time != 0) {
2513 put_long_date((char *)inbuf.data + 24, change_time);
2515 if (access_time != 0) {
2516 put_long_date((char *)inbuf.data + 8, access_time);
2518 if (write_time != 0) {
2519 put_long_date((char *)inbuf.data + 16, write_time);
2522 cli->raw_status = cli_smb2_set_info_fnum(
2525 1, /* in_info_type */
2526 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
2527 &inbuf, /* in_input_buffer */
2528 0); /* in_additional_info */
2530 return cli->raw_status;
2533 /***************************************************************
2534 Wrapper that allows SMB2 to query disk attributes (size).
2536 ***************************************************************/
2538 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2539 uint64_t *bsize, uint64_t *total, uint64_t *avail)
2542 uint16_t fnum = 0xffff;
2543 DATA_BLOB outbuf = data_blob_null;
2544 uint32_t sectors_per_unit = 0;
2545 uint32_t bytes_per_sector = 0;
2546 uint64_t total_size = 0;
2547 uint64_t size_free = 0;
2548 TALLOC_CTX *frame = talloc_stackframe();
2550 if (smbXcli_conn_has_async_calls(cli->conn)) {
2552 * Can't use sync call while an async call is in flight
2554 status = NT_STATUS_INVALID_PARAMETER;
2558 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2559 status = NT_STATUS_INVALID_PARAMETER;
2563 /* First open the top level directory. */
2564 status = cli_smb2_create_fnum(cli,
2566 0, /* create_flags */
2567 SMB2_IMPERSONATION_IMPERSONATION,
2568 FILE_READ_ATTRIBUTES, /* desired_access */
2569 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2570 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2571 FILE_OPEN, /* create_disposition */
2572 FILE_DIRECTORY_FILE, /* create_options */
2579 if (!NT_STATUS_IS_OK(status)) {
2583 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2584 level 3 (SMB_FS_SIZE_INFORMATION). */
2586 status = cli_smb2_query_info_fnum(
2589 2, /* in_info_type */
2590 3, /* in_file_info_class */
2591 0xFFFF, /* in_max_output_length */
2592 NULL, /* in_input_buffer */
2593 0, /* in_additional_info */
2597 if (!NT_STATUS_IS_OK(status)) {
2601 /* Parse the reply. */
2602 if (outbuf.length != 24) {
2603 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2607 total_size = BVAL(outbuf.data, 0);
2608 size_free = BVAL(outbuf.data, 8);
2609 sectors_per_unit = IVAL(outbuf.data, 16);
2610 bytes_per_sector = IVAL(outbuf.data, 20);
2613 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2616 *total = total_size;
2622 status = NT_STATUS_OK;
2626 if (fnum != 0xffff) {
2627 cli_smb2_close_fnum(cli, fnum);
2630 cli->raw_status = status;
2636 /***************************************************************
2637 Wrapper that allows SMB2 to query file system sizes.
2639 ***************************************************************/
2641 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2642 uint64_t *total_allocation_units,
2643 uint64_t *caller_allocation_units,
2644 uint64_t *actual_allocation_units,
2645 uint64_t *sectors_per_allocation_unit,
2646 uint64_t *bytes_per_sector)
2649 uint16_t fnum = 0xffff;
2650 DATA_BLOB outbuf = data_blob_null;
2651 TALLOC_CTX *frame = talloc_stackframe();
2653 if (smbXcli_conn_has_async_calls(cli->conn)) {
2655 * Can't use sync call while an async call is in flight
2657 status = NT_STATUS_INVALID_PARAMETER;
2661 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2662 status = NT_STATUS_INVALID_PARAMETER;
2666 /* First open the top level directory. */
2668 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2669 SMB2_IMPERSONATION_IMPERSONATION,
2670 FILE_READ_ATTRIBUTES, /* desired_access */
2671 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2672 FILE_SHARE_READ | FILE_SHARE_WRITE |
2673 FILE_SHARE_DELETE, /* share_access */
2674 FILE_OPEN, /* create_disposition */
2675 FILE_DIRECTORY_FILE, /* create_options */
2682 if (!NT_STATUS_IS_OK(status)) {
2686 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2687 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2689 status = cli_smb2_query_info_fnum(
2692 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2693 SMB_FS_FULL_SIZE_INFORMATION - 1000, /* in_file_info_class */
2694 0xFFFF, /* in_max_output_length */
2695 NULL, /* in_input_buffer */
2696 0, /* in_additional_info */
2700 if (!NT_STATUS_IS_OK(status)) {
2704 if (outbuf.length < 32) {
2705 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2709 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2710 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2711 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2712 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2713 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2717 if (fnum != 0xffff) {
2718 cli_smb2_close_fnum(cli, fnum);
2721 cli->raw_status = status;
2727 /***************************************************************
2728 Wrapper that allows SMB2 to query file system attributes.
2730 ***************************************************************/
2732 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2735 uint16_t fnum = 0xffff;
2736 DATA_BLOB outbuf = data_blob_null;
2737 TALLOC_CTX *frame = talloc_stackframe();
2739 if (smbXcli_conn_has_async_calls(cli->conn)) {
2741 * Can't use sync call while an async call is in flight
2743 status = NT_STATUS_INVALID_PARAMETER;
2747 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2748 status = NT_STATUS_INVALID_PARAMETER;
2752 /* First open the top level directory. */
2754 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2755 SMB2_IMPERSONATION_IMPERSONATION,
2756 FILE_READ_ATTRIBUTES, /* desired_access */
2757 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2758 FILE_SHARE_READ | FILE_SHARE_WRITE |
2759 FILE_SHARE_DELETE, /* share_access */
2760 FILE_OPEN, /* create_disposition */
2761 FILE_DIRECTORY_FILE, /* create_options */
2768 if (!NT_STATUS_IS_OK(status)) {
2772 status = cli_smb2_query_info_fnum(
2775 2, /* in_info_type */
2776 5, /* in_file_info_class */
2777 0xFFFF, /* in_max_output_length */
2778 NULL, /* in_input_buffer */
2779 0, /* in_additional_info */
2783 if (!NT_STATUS_IS_OK(status)) {
2787 if (outbuf.length < 12) {
2788 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2792 *fs_attr = IVAL(outbuf.data, 0);
2796 if (fnum != 0xffff) {
2797 cli_smb2_close_fnum(cli, fnum);
2800 cli->raw_status = status;
2806 /***************************************************************
2807 Wrapper that allows SMB2 to query file system volume info.
2809 ***************************************************************/
2811 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2812 TALLOC_CTX *mem_ctx,
2813 char **_volume_name,
2814 uint32_t *pserial_number,
2818 uint16_t fnum = 0xffff;
2819 DATA_BLOB outbuf = data_blob_null;
2821 char *volume_name = NULL;
2822 TALLOC_CTX *frame = talloc_stackframe();
2824 if (smbXcli_conn_has_async_calls(cli->conn)) {
2826 * Can't use sync call while an async call is in flight
2828 status = NT_STATUS_INVALID_PARAMETER;
2832 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2833 status = NT_STATUS_INVALID_PARAMETER;
2837 /* First open the top level directory. */
2839 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2840 SMB2_IMPERSONATION_IMPERSONATION,
2841 FILE_READ_ATTRIBUTES, /* desired_access */
2842 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2843 FILE_SHARE_READ | FILE_SHARE_WRITE |
2844 FILE_SHARE_DELETE, /* share_access */
2845 FILE_OPEN, /* create_disposition */
2846 FILE_DIRECTORY_FILE, /* create_options */
2853 if (!NT_STATUS_IS_OK(status)) {
2857 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2858 level 1 (SMB_FS_VOLUME_INFORMATION). */
2860 status = cli_smb2_query_info_fnum(
2863 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2864 /* in_file_info_class */
2865 SMB_FS_VOLUME_INFORMATION - 1000,
2866 0xFFFF, /* in_max_output_length */
2867 NULL, /* in_input_buffer */
2868 0, /* in_additional_info */
2872 if (!NT_STATUS_IS_OK(status)) {
2876 if (outbuf.length < 24) {
2877 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2883 ts = interpret_long_date((char *)outbuf.data);
2886 if (pserial_number) {
2887 *pserial_number = IVAL(outbuf.data,8);
2889 nlen = IVAL(outbuf.data,12);
2890 if (nlen + 18 < 18) {
2892 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2896 * The next check is safe as we know outbuf.length >= 24
2899 if (nlen > (outbuf.length - 18)) {
2900 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2904 clistr_pull_talloc(mem_ctx,
2905 (const char *)outbuf.data,
2911 if (volume_name == NULL) {
2912 status = map_nt_error_from_unix(errno);
2916 *_volume_name = volume_name;
2920 if (fnum != 0xffff) {
2921 cli_smb2_close_fnum(cli, fnum);
2924 cli->raw_status = status;
2931 /***************************************************************
2932 Wrapper that allows SMB2 to query a security descriptor.
2934 ***************************************************************/
2936 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2939 TALLOC_CTX *mem_ctx,
2940 struct security_descriptor **ppsd)
2943 DATA_BLOB outbuf = data_blob_null;
2944 struct security_descriptor *lsd = NULL;
2945 TALLOC_CTX *frame = talloc_stackframe();
2947 if (smbXcli_conn_has_async_calls(cli->conn)) {
2949 * Can't use sync call while an async call is in flight
2951 status = NT_STATUS_INVALID_PARAMETER;
2955 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2956 status = NT_STATUS_INVALID_PARAMETER;
2960 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2962 status = cli_smb2_query_info_fnum(
2965 3, /* in_info_type */
2966 0, /* in_file_info_class */
2967 0xFFFF, /* in_max_output_length */
2968 NULL, /* in_input_buffer */
2969 sec_info, /* in_additional_info */
2974 if (!NT_STATUS_IS_OK(status)) {
2978 /* Parse the reply. */
2979 status = unmarshall_sec_desc(mem_ctx,
2984 if (!NT_STATUS_IS_OK(status)) {
2996 cli->raw_status = status;
3002 /***************************************************************
3003 Wrapper that allows SMB2 to set a security descriptor.
3005 ***************************************************************/
3007 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
3010 const struct security_descriptor *sd)
3013 DATA_BLOB inbuf = data_blob_null;
3014 TALLOC_CTX *frame = talloc_stackframe();
3016 if (smbXcli_conn_has_async_calls(cli->conn)) {
3018 * Can't use sync call while an async call is in flight
3020 status = NT_STATUS_INVALID_PARAMETER;
3024 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3025 status = NT_STATUS_INVALID_PARAMETER;
3029 status = marshall_sec_desc(frame,
3034 if (!NT_STATUS_IS_OK(status)) {
3038 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
3040 status = cli_smb2_set_info_fnum(
3043 3, /* in_info_type */
3044 0, /* in_file_info_class */
3045 &inbuf, /* in_input_buffer */
3046 sec_info); /* in_additional_info */
3050 cli->raw_status = status;
3056 /***************************************************************
3057 Wrapper that allows SMB2 to query a security descriptor.
3060 ***************************************************************/
3062 struct cli_smb2_mxac_state {
3063 struct tevent_context *ev;
3064 struct cli_state *cli;
3066 struct smb2_create_blobs in_cblobs;
3072 static void cli_smb2_mxac_opened(struct tevent_req *subreq);
3073 static void cli_smb2_mxac_closed(struct tevent_req *subreq);
3075 struct tevent_req *cli_smb2_query_mxac_send(TALLOC_CTX *mem_ctx,
3076 struct tevent_context *ev,
3077 struct cli_state *cli,
3080 struct tevent_req *req = NULL, *subreq = NULL;
3081 struct cli_smb2_mxac_state *state = NULL;
3084 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_mxac_state);
3088 *state = (struct cli_smb2_mxac_state) {
3094 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3095 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3096 return tevent_req_post(req, ev);
3099 status = smb2_create_blob_add(state,
3101 SMB2_CREATE_TAG_MXAC,
3102 data_blob(NULL, 0));
3103 if (tevent_req_nterror(req, status)) {
3104 return tevent_req_post(req, ev);
3107 subreq = cli_smb2_create_fnum_send(
3112 0, /* create_flags */
3113 SMB2_IMPERSONATION_IMPERSONATION,
3114 FILE_READ_ATTRIBUTES,
3115 0, /* file attributes */
3116 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
3118 0, /* create_options */
3120 if (tevent_req_nomem(subreq, req)) {
3121 return tevent_req_post(req, ev);
3123 tevent_req_set_callback(subreq, cli_smb2_mxac_opened, req);
3127 static void cli_smb2_mxac_opened(struct tevent_req *subreq)
3129 struct tevent_req *req = tevent_req_callback_data(
3130 subreq, struct tevent_req);
3131 struct cli_smb2_mxac_state *state = tevent_req_data(
3132 req, struct cli_smb2_mxac_state);
3133 struct smb2_create_blobs out_cblobs = {0};
3134 struct smb2_create_blob *mxac_blob = NULL;
3137 status = cli_smb2_create_fnum_recv(
3138 subreq, &state->fnum, NULL, state, &out_cblobs);
3139 TALLOC_FREE(subreq);
3141 if (tevent_req_nterror(req, status)) {
3145 mxac_blob = smb2_create_blob_find(&out_cblobs, SMB2_CREATE_TAG_MXAC);
3146 if (mxac_blob == NULL) {
3147 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3150 if (mxac_blob->data.length != 8) {
3151 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3155 state->status = NT_STATUS(IVAL(mxac_blob->data.data, 0));
3156 state->mxac = IVAL(mxac_blob->data.data, 4);
3159 subreq = cli_smb2_close_fnum_send(
3160 state, state->ev, state->cli, state->fnum);
3161 if (tevent_req_nomem(subreq, req)) {
3164 tevent_req_set_callback(subreq, cli_smb2_mxac_closed, req);
3169 static void cli_smb2_mxac_closed(struct tevent_req *subreq)
3171 struct tevent_req *req = tevent_req_callback_data(
3172 subreq, struct tevent_req);
3175 status = cli_smb2_close_fnum_recv(subreq);
3176 if (tevent_req_nterror(req, status)) {
3180 tevent_req_done(req);
3183 NTSTATUS cli_smb2_query_mxac_recv(struct tevent_req *req, uint32_t *mxac)
3185 struct cli_smb2_mxac_state *state = tevent_req_data(
3186 req, struct cli_smb2_mxac_state);
3189 if (tevent_req_is_nterror(req, &status)) {
3193 if (!NT_STATUS_IS_OK(state->status)) {
3194 return state->status;
3197 *mxac = state->mxac;
3198 return NT_STATUS_OK;
3201 NTSTATUS cli_smb2_query_mxac(struct cli_state *cli,
3205 TALLOC_CTX *frame = talloc_stackframe();
3206 struct tevent_context *ev = NULL;
3207 struct tevent_req *req = NULL;
3208 NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
3211 if (smbXcli_conn_has_async_calls(cli->conn)) {
3213 * Can't use sync call while an async call is in flight
3215 status = NT_STATUS_INVALID_PARAMETER;
3219 ev = samba_tevent_context_init(frame);
3223 req = cli_smb2_query_mxac_send(frame, ev, cli, fname);
3227 ok = tevent_req_poll_ntstatus(req, ev, &status);
3231 status = cli_smb2_query_mxac_recv(req, _mxac);
3234 cli->raw_status = status;
3239 /***************************************************************
3240 Wrapper that allows SMB2 to rename a file.
3242 ***************************************************************/
3244 NTSTATUS cli_smb2_rename(struct cli_state *cli,
3245 const char *fname_src,
3246 const char *fname_dst,
3250 DATA_BLOB inbuf = data_blob_null;
3251 uint16_t fnum = 0xffff;
3252 smb_ucs2_t *converted_str = NULL;
3253 size_t converted_size_bytes = 0;
3255 TALLOC_CTX *frame = talloc_stackframe();
3257 if (smbXcli_conn_has_async_calls(cli->conn)) {
3259 * Can't use sync call while an async call is in flight
3261 status = NT_STATUS_INVALID_PARAMETER;
3265 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3266 status = NT_STATUS_INVALID_PARAMETER;
3270 status = get_fnum_from_path(cli,
3275 if (!NT_STATUS_IS_OK(status)) {
3279 /* SMB2 is pickier about pathnames. Ensure it doesn't
3281 if (*fname_dst == '\\') {
3285 /* SMB2 is pickier about pathnames. Ensure it doesn't
3287 namelen = strlen(fname_dst);
3288 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
3289 char *modname = talloc_strdup(frame, fname_dst);
3290 modname[namelen-1] = '\0';
3291 fname_dst = modname;
3294 if (!push_ucs2_talloc(frame,
3297 &converted_size_bytes)) {
3298 status = NT_STATUS_INVALID_PARAMETER;
3302 /* W2K8 insists the dest name is not null
3303 terminated. Remove the last 2 zero bytes
3304 and reduce the name length. */
3306 if (converted_size_bytes < 2) {
3307 status = NT_STATUS_INVALID_PARAMETER;
3310 converted_size_bytes -= 2;
3312 inbuf = data_blob_talloc_zero(frame,
3313 20 + converted_size_bytes);
3314 if (inbuf.data == NULL) {
3315 status = NT_STATUS_NO_MEMORY;
3320 SCVAL(inbuf.data, 0, 1);
3323 SIVAL(inbuf.data, 16, converted_size_bytes);
3324 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
3326 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3327 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3329 status = cli_smb2_set_info_fnum(
3332 1, /* in_info_type */
3333 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
3334 &inbuf, /* in_input_buffer */
3335 0); /* in_additional_info */
3339 if (fnum != 0xffff) {
3340 cli_smb2_close_fnum(cli, fnum);
3343 cli->raw_status = status;
3349 /***************************************************************
3350 Wrapper that allows SMB2 to set an EA on a fnum.
3352 ***************************************************************/
3354 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
3356 const char *ea_name,
3361 DATA_BLOB inbuf = data_blob_null;
3363 char *ea_name_ascii = NULL;
3365 TALLOC_CTX *frame = talloc_stackframe();
3367 if (smbXcli_conn_has_async_calls(cli->conn)) {
3369 * Can't use sync call while an async call is in flight
3371 status = NT_STATUS_INVALID_PARAMETER;
3375 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3376 status = NT_STATUS_INVALID_PARAMETER;
3380 /* Marshall the SMB2 EA data. */
3381 if (ea_len > 0xFFFF) {
3382 status = NT_STATUS_INVALID_PARAMETER;
3386 if (!push_ascii_talloc(frame,
3390 status = NT_STATUS_INVALID_PARAMETER;
3394 if (namelen < 2 || namelen > 0xFF) {
3395 status = NT_STATUS_INVALID_PARAMETER;
3399 bloblen = 8 + ea_len + namelen;
3400 /* Round up to a 4 byte boundary. */
3401 bloblen = ((bloblen + 3)&~3);
3403 inbuf = data_blob_talloc_zero(frame, bloblen);
3404 if (inbuf.data == NULL) {
3405 status = NT_STATUS_NO_MEMORY;
3408 /* namelen doesn't include the NULL byte. */
3409 SCVAL(inbuf.data, 5, namelen - 1);
3410 SSVAL(inbuf.data, 6, ea_len);
3411 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
3412 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
3414 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3415 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3417 status = cli_smb2_set_info_fnum(
3420 1, /* in_info_type */
3421 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3422 &inbuf, /* in_input_buffer */
3423 0); /* in_additional_info */
3427 cli->raw_status = status;
3433 /***************************************************************
3434 Wrapper that allows SMB2 to set an EA on a pathname.
3436 ***************************************************************/
3438 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
3440 const char *ea_name,
3445 uint16_t fnum = 0xffff;
3447 if (smbXcli_conn_has_async_calls(cli->conn)) {
3449 * Can't use sync call while an async call is in flight
3451 status = NT_STATUS_INVALID_PARAMETER;
3455 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3456 status = NT_STATUS_INVALID_PARAMETER;
3460 status = get_fnum_from_path(cli,
3465 if (!NT_STATUS_IS_OK(status)) {
3469 status = cli_set_ea_fnum(cli,
3474 if (!NT_STATUS_IS_OK(status)) {
3480 if (fnum != 0xffff) {
3481 cli_smb2_close_fnum(cli, fnum);
3484 cli->raw_status = status;
3489 /***************************************************************
3490 Wrapper that allows SMB2 to get an EA list on a pathname.
3492 ***************************************************************/
3494 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
3498 struct ea_struct **pea_array)
3501 uint16_t fnum = 0xffff;
3502 DATA_BLOB outbuf = data_blob_null;
3503 struct ea_list *ea_list = NULL;
3504 struct ea_list *eal = NULL;
3505 size_t ea_count = 0;
3506 TALLOC_CTX *frame = talloc_stackframe();
3511 if (smbXcli_conn_has_async_calls(cli->conn)) {
3513 * Can't use sync call while an async call is in flight
3515 status = NT_STATUS_INVALID_PARAMETER;
3519 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3520 status = NT_STATUS_INVALID_PARAMETER;
3524 status = get_fnum_from_path(cli,
3529 if (!NT_STATUS_IS_OK(status)) {
3533 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3534 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3536 status = cli_smb2_query_info_fnum(
3539 1, /* in_info_type */
3540 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3541 0xFFFF, /* in_max_output_length */
3542 NULL, /* in_input_buffer */
3543 0, /* in_additional_info */
3548 if (!NT_STATUS_IS_OK(status)) {
3552 /* Parse the reply. */
3553 ea_list = read_nttrans_ea_list(ctx,
3554 (const char *)outbuf.data,
3556 if (ea_list == NULL) {
3557 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3561 /* Convert to an array. */
3562 for (eal = ea_list; eal; eal = eal->next) {
3567 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
3568 if (*pea_array == NULL) {
3569 status = NT_STATUS_NO_MEMORY;
3573 for (eal = ea_list; eal; eal = eal->next) {
3574 (*pea_array)[ea_count++] = eal->ea;
3576 *pnum_eas = ea_count;
3581 if (fnum != 0xffff) {
3582 cli_smb2_close_fnum(cli, fnum);
3585 cli->raw_status = status;
3591 /***************************************************************
3592 Wrapper that allows SMB2 to get user quota.
3594 ***************************************************************/
3596 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
3598 SMB_NTQUOTA_STRUCT *pqt)
3601 DATA_BLOB inbuf = data_blob_null;
3602 DATA_BLOB info_blob = data_blob_null;
3603 DATA_BLOB outbuf = data_blob_null;
3604 TALLOC_CTX *frame = talloc_stackframe();
3606 unsigned int offset;
3607 struct smb2_query_quota_info query = {0};
3608 struct file_get_quota_info info = {0};
3609 enum ndr_err_code err;
3610 struct ndr_push *ndr_push = NULL;
3612 if (smbXcli_conn_has_async_calls(cli->conn)) {
3614 * Can't use sync call while an async call is in flight
3616 status = NT_STATUS_INVALID_PARAMETER;
3620 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3621 status = NT_STATUS_INVALID_PARAMETER;
3625 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
3627 query.return_single = 1;
3629 info.next_entry_offset = 0;
3630 info.sid_length = sid_len;
3631 info.sid = pqt->sid;
3633 err = ndr_push_struct_blob(
3637 (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
3639 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3640 status = NT_STATUS_INTERNAL_ERROR;
3644 query.sid_list_length = info_blob.length;
3645 ndr_push = ndr_push_init_ctx(frame);
3647 status = NT_STATUS_NO_MEMORY;
3651 err = ndr_push_smb2_query_quota_info(ndr_push,
3652 NDR_SCALARS | NDR_BUFFERS,
3655 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3656 status = NT_STATUS_INTERNAL_ERROR;
3660 err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3663 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3664 status = NT_STATUS_INTERNAL_ERROR;
3667 inbuf.data = ndr_push->data;
3668 inbuf.length = ndr_push->offset;
3670 status = cli_smb2_query_info_fnum(
3673 4, /* in_info_type */
3674 0, /* in_file_info_class */
3675 0xFFFF, /* in_max_output_length */
3676 &inbuf, /* in_input_buffer */
3677 0, /* in_additional_info */
3682 if (!NT_STATUS_IS_OK(status)) {
3686 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3688 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3689 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3693 cli->raw_status = status;
3699 /***************************************************************
3700 Wrapper that allows SMB2 to list user quota.
3702 ***************************************************************/
3704 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3705 TALLOC_CTX *mem_ctx,
3707 SMB_NTQUOTA_LIST **pqt_list,
3711 DATA_BLOB inbuf = data_blob_null;
3712 DATA_BLOB outbuf = data_blob_null;
3713 TALLOC_CTX *frame = talloc_stackframe();
3714 struct smb2_query_quota_info info = {0};
3715 enum ndr_err_code err;
3717 if (smbXcli_conn_has_async_calls(cli->conn)) {
3719 * Can't use sync call while an async call is in flight
3721 status = NT_STATUS_INVALID_PARAMETER;
3725 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3726 status = NT_STATUS_INVALID_PARAMETER;
3730 info.restart_scan = first ? 1 : 0;
3732 err = ndr_push_struct_blob(
3736 (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3738 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3739 status = NT_STATUS_INTERNAL_ERROR;
3743 status = cli_smb2_query_info_fnum(
3746 4, /* in_info_type */
3747 0, /* in_file_info_class */
3748 0xFFFF, /* in_max_output_length */
3749 &inbuf, /* in_input_buffer */
3750 0, /* in_additional_info */
3756 * safeguard against panic from calling parse_user_quota_list with
3759 if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3760 status = NT_STATUS_NO_MORE_ENTRIES;
3763 if (!NT_STATUS_IS_OK(status)) {
3767 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3771 cli->raw_status = status;
3777 /***************************************************************
3778 Wrapper that allows SMB2 to get file system quota.
3780 ***************************************************************/
3782 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3784 SMB_NTQUOTA_STRUCT *pqt)
3787 DATA_BLOB outbuf = data_blob_null;
3788 TALLOC_CTX *frame = talloc_stackframe();
3790 if (smbXcli_conn_has_async_calls(cli->conn)) {
3792 * Can't use sync call while an async call is in flight
3794 status = NT_STATUS_INVALID_PARAMETER;
3798 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3799 status = NT_STATUS_INVALID_PARAMETER;
3803 status = cli_smb2_query_info_fnum(
3806 2, /* in_info_type */
3807 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3808 0xFFFF, /* in_max_output_length */
3809 NULL, /* in_input_buffer */
3810 0, /* in_additional_info */
3815 if (!NT_STATUS_IS_OK(status)) {
3819 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3822 cli->raw_status = status;
3828 /***************************************************************
3829 Wrapper that allows SMB2 to set user quota.
3831 ***************************************************************/
3833 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3835 SMB_NTQUOTA_LIST *qtl)
3838 DATA_BLOB inbuf = data_blob_null;
3839 TALLOC_CTX *frame = talloc_stackframe();
3841 if (smbXcli_conn_has_async_calls(cli->conn)) {
3843 * Can't use sync call while an async call is in flight
3845 status = NT_STATUS_INVALID_PARAMETER;
3849 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3850 status = NT_STATUS_INVALID_PARAMETER;
3854 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3855 if (!NT_STATUS_IS_OK(status)) {
3859 status = cli_smb2_set_info_fnum(
3862 4, /* in_info_type */
3863 0, /* in_file_info_class */
3864 &inbuf, /* in_input_buffer */
3865 0); /* in_additional_info */
3868 cli->raw_status = status;
3875 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3877 SMB_NTQUOTA_STRUCT *pqt)
3880 DATA_BLOB inbuf = data_blob_null;
3881 TALLOC_CTX *frame = talloc_stackframe();
3883 if (smbXcli_conn_has_async_calls(cli->conn)) {
3885 * Can't use sync call while an async call is in flight
3887 status = NT_STATUS_INVALID_PARAMETER;
3891 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3892 status = NT_STATUS_INVALID_PARAMETER;
3896 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3897 if (!NT_STATUS_IS_OK(status)) {
3901 status = cli_smb2_set_info_fnum(
3904 2, /* in_info_type */
3905 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3906 &inbuf, /* in_input_buffer */
3907 0); /* in_additional_info */
3909 cli->raw_status = status;
3915 struct cli_smb2_read_state {
3916 struct tevent_context *ev;
3917 struct cli_state *cli;
3918 struct smb2_hnd *ph;
3919 uint64_t start_offset;
3925 static void cli_smb2_read_done(struct tevent_req *subreq);
3927 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3928 struct tevent_context *ev,
3929 struct cli_state *cli,
3935 struct tevent_req *req, *subreq;
3936 struct cli_smb2_read_state *state;
3938 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3944 state->start_offset = (uint64_t)offset;
3945 state->size = (uint32_t)size;
3946 state->received = 0;
3949 status = map_fnum_to_smb2_handle(cli,
3952 if (tevent_req_nterror(req, status)) {
3953 return tevent_req_post(req, ev);
3956 subreq = smb2cli_read_send(state,
3959 state->cli->timeout,
3960 state->cli->smb2.session,
3961 state->cli->smb2.tcon,
3963 state->start_offset,
3964 state->ph->fid_persistent,
3965 state->ph->fid_volatile,
3966 0, /* minimum_count */
3967 0); /* remaining_bytes */
3969 if (tevent_req_nomem(subreq, req)) {
3970 return tevent_req_post(req, ev);
3972 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3976 static void cli_smb2_read_done(struct tevent_req *subreq)
3978 struct tevent_req *req = tevent_req_callback_data(
3979 subreq, struct tevent_req);
3980 struct cli_smb2_read_state *state = tevent_req_data(
3981 req, struct cli_smb2_read_state);
3984 status = smb2cli_read_recv(subreq, state,
3985 &state->buf, &state->received);
3986 if (tevent_req_nterror(req, status)) {
3990 if (state->received > state->size) {
3991 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3995 tevent_req_done(req);
3998 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
4003 struct cli_smb2_read_state *state = tevent_req_data(
4004 req, struct cli_smb2_read_state);
4006 if (tevent_req_is_nterror(req, &status)) {
4007 state->cli->raw_status = status;
4011 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
4012 * better make sure that you copy it away before you talloc_free(req).
4013 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
4015 *received = (ssize_t)state->received;
4016 *rcvbuf = state->buf;
4017 state->cli->raw_status = NT_STATUS_OK;
4018 return NT_STATUS_OK;
4021 struct cli_smb2_write_state {
4022 struct tevent_context *ev;
4023 struct cli_state *cli;
4024 struct smb2_hnd *ph;
4032 static void cli_smb2_write_written(struct tevent_req *req);
4034 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
4035 struct tevent_context *ev,
4036 struct cli_state *cli,
4044 struct tevent_req *req, *subreq = NULL;
4045 struct cli_smb2_write_state *state = NULL;
4047 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
4053 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4054 state->flags = (uint32_t)mode;
4056 state->offset = (uint64_t)offset;
4057 state->size = (uint32_t)size;
4060 status = map_fnum_to_smb2_handle(cli,
4063 if (tevent_req_nterror(req, status)) {
4064 return tevent_req_post(req, ev);
4067 subreq = smb2cli_write_send(state,
4070 state->cli->timeout,
4071 state->cli->smb2.session,
4072 state->cli->smb2.tcon,
4075 state->ph->fid_persistent,
4076 state->ph->fid_volatile,
4077 0, /* remaining_bytes */
4078 state->flags, /* flags */
4081 if (tevent_req_nomem(subreq, req)) {
4082 return tevent_req_post(req, ev);
4084 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
4088 static void cli_smb2_write_written(struct tevent_req *subreq)
4090 struct tevent_req *req = tevent_req_callback_data(
4091 subreq, struct tevent_req);
4092 struct cli_smb2_write_state *state = tevent_req_data(
4093 req, struct cli_smb2_write_state);
4097 status = smb2cli_write_recv(subreq, &written);
4098 TALLOC_FREE(subreq);
4099 if (tevent_req_nterror(req, status)) {
4103 state->written = written;
4105 tevent_req_done(req);
4108 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
4111 struct cli_smb2_write_state *state = tevent_req_data(
4112 req, struct cli_smb2_write_state);
4115 if (tevent_req_is_nterror(req, &status)) {
4116 state->cli->raw_status = status;
4117 tevent_req_received(req);
4121 if (pwritten != NULL) {
4122 *pwritten = (size_t)state->written;
4124 state->cli->raw_status = NT_STATUS_OK;
4125 tevent_req_received(req);
4126 return NT_STATUS_OK;
4129 /***************************************************************
4130 Wrapper that allows SMB2 async write using an fnum.
4131 This is mostly cut-and-paste from Volker's code inside
4132 source3/libsmb/clireadwrite.c, adapted for SMB2.
4134 Done this way so I can reuse all the logic inside cli_push()
4136 ***************************************************************/
4138 struct cli_smb2_writeall_state {
4139 struct tevent_context *ev;
4140 struct cli_state *cli;
4141 struct smb2_hnd *ph;
4149 static void cli_smb2_writeall_written(struct tevent_req *req);
4151 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
4152 struct tevent_context *ev,
4153 struct cli_state *cli,
4161 struct tevent_req *req, *subreq = NULL;
4162 struct cli_smb2_writeall_state *state = NULL;
4167 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
4173 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4174 state->flags = (uint32_t)mode;
4176 state->offset = (uint64_t)offset;
4177 state->size = (uint32_t)size;
4180 status = map_fnum_to_smb2_handle(cli,
4183 if (tevent_req_nterror(req, status)) {
4184 return tevent_req_post(req, ev);
4187 to_write = state->size;
4188 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4189 to_write = MIN(max_size, to_write);
4190 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4192 to_write = MIN(max_size, to_write);
4195 subreq = smb2cli_write_send(state,
4198 state->cli->timeout,
4199 state->cli->smb2.session,
4200 state->cli->smb2.tcon,
4203 state->ph->fid_persistent,
4204 state->ph->fid_volatile,
4205 0, /* remaining_bytes */
4206 state->flags, /* flags */
4207 state->buf + state->written);
4209 if (tevent_req_nomem(subreq, req)) {
4210 return tevent_req_post(req, ev);
4212 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4216 static void cli_smb2_writeall_written(struct tevent_req *subreq)
4218 struct tevent_req *req = tevent_req_callback_data(
4219 subreq, struct tevent_req);
4220 struct cli_smb2_writeall_state *state = tevent_req_data(
4221 req, struct cli_smb2_writeall_state);
4223 uint32_t written, to_write;
4227 status = smb2cli_write_recv(subreq, &written);
4228 TALLOC_FREE(subreq);
4229 if (tevent_req_nterror(req, status)) {
4233 state->written += written;
4235 if (state->written > state->size) {
4236 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4240 to_write = state->size - state->written;
4242 if (to_write == 0) {
4243 tevent_req_done(req);
4247 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4248 to_write = MIN(max_size, to_write);
4249 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4251 to_write = MIN(max_size, to_write);
4254 subreq = smb2cli_write_send(state,
4257 state->cli->timeout,
4258 state->cli->smb2.session,
4259 state->cli->smb2.tcon,
4261 state->offset + state->written,
4262 state->ph->fid_persistent,
4263 state->ph->fid_volatile,
4264 0, /* remaining_bytes */
4265 state->flags, /* flags */
4266 state->buf + state->written);
4268 if (tevent_req_nomem(subreq, req)) {
4271 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4274 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
4277 struct cli_smb2_writeall_state *state = tevent_req_data(
4278 req, struct cli_smb2_writeall_state);
4281 if (tevent_req_is_nterror(req, &status)) {
4282 state->cli->raw_status = status;
4285 if (pwritten != NULL) {
4286 *pwritten = (size_t)state->written;
4288 state->cli->raw_status = NT_STATUS_OK;
4289 return NT_STATUS_OK;
4292 struct cli_smb2_splice_state {
4293 struct tevent_context *ev;
4294 struct cli_state *cli;
4295 struct smb2_hnd *src_ph;
4296 struct smb2_hnd *dst_ph;
4297 int (*splice_cb)(off_t n, void *priv);
4304 struct req_resume_key_rsp resume_rsp;
4305 struct srv_copychunk_copy cc_copy;
4308 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4309 struct tevent_req *req);
4311 static void cli_splice_copychunk_done(struct tevent_req *subreq)
4313 struct tevent_req *req = tevent_req_callback_data(
4314 subreq, struct tevent_req);
4315 struct cli_smb2_splice_state *state =
4316 tevent_req_data(req,
4317 struct cli_smb2_splice_state);
4318 struct smbXcli_conn *conn = state->cli->conn;
4319 DATA_BLOB out_input_buffer = data_blob_null;
4320 DATA_BLOB out_output_buffer = data_blob_null;
4321 struct srv_copychunk_rsp cc_copy_rsp;
4322 enum ndr_err_code ndr_ret;
4325 status = smb2cli_ioctl_recv(subreq, state,
4327 &out_output_buffer);
4328 TALLOC_FREE(subreq);
4329 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
4330 state->resized) && tevent_req_nterror(req, status)) {
4334 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
4335 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
4336 if (ndr_ret != NDR_ERR_SUCCESS) {
4337 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4338 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4342 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
4343 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
4344 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
4345 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
4346 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
4347 tevent_req_nterror(req, status)) {
4351 state->resized = true;
4352 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
4353 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
4355 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4356 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4357 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
4358 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4361 state->src_offset += cc_copy_rsp.total_bytes_written;
4362 state->dst_offset += cc_copy_rsp.total_bytes_written;
4363 state->written += cc_copy_rsp.total_bytes_written;
4364 if (!state->splice_cb(state->written, state->priv)) {
4365 tevent_req_nterror(req, NT_STATUS_CANCELLED);
4370 cli_splice_copychunk_send(state, req);
4373 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4374 struct tevent_req *req)
4376 struct tevent_req *subreq;
4377 enum ndr_err_code ndr_ret;
4378 struct smbXcli_conn *conn = state->cli->conn;
4379 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
4380 off_t src_offset = state->src_offset;
4381 off_t dst_offset = state->dst_offset;
4382 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
4383 state->size - state->written);
4384 DATA_BLOB in_input_buffer = data_blob_null;
4385 DATA_BLOB in_output_buffer = data_blob_null;
4387 if (state->size - state->written == 0) {
4388 tevent_req_done(req);
4392 cc_copy->chunk_count = 0;
4394 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
4395 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
4396 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
4397 smb2cli_conn_cc_chunk_len(conn));
4398 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
4399 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4402 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
4403 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
4404 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
4405 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4408 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4409 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4410 cc_copy->chunk_count++;
4413 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
4414 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
4415 if (ndr_ret != NDR_ERR_SUCCESS) {
4416 DEBUG(0, ("failed to marshall copy chunk req\n"));
4417 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4421 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
4422 state->cli->timeout,
4423 state->cli->smb2.session,
4424 state->cli->smb2.tcon,
4425 state->dst_ph->fid_persistent, /* in_fid_persistent */
4426 state->dst_ph->fid_volatile, /* in_fid_volatile */
4427 FSCTL_SRV_COPYCHUNK_WRITE,
4428 0, /* in_max_input_length */
4430 12, /* in_max_output_length */
4432 SMB2_IOCTL_FLAG_IS_FSCTL);
4433 if (tevent_req_nomem(subreq, req)) {
4436 tevent_req_set_callback(subreq,
4437 cli_splice_copychunk_done,
4441 static void cli_splice_key_done(struct tevent_req *subreq)
4443 struct tevent_req *req = tevent_req_callback_data(
4444 subreq, struct tevent_req);
4445 struct cli_smb2_splice_state *state =
4446 tevent_req_data(req,
4447 struct cli_smb2_splice_state);
4448 enum ndr_err_code ndr_ret;
4451 DATA_BLOB out_input_buffer = data_blob_null;
4452 DATA_BLOB out_output_buffer = data_blob_null;
4454 status = smb2cli_ioctl_recv(subreq, state,
4456 &out_output_buffer);
4457 TALLOC_FREE(subreq);
4458 if (tevent_req_nterror(req, status)) {
4462 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
4463 state, &state->resume_rsp,
4464 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
4465 if (ndr_ret != NDR_ERR_SUCCESS) {
4466 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4467 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4471 memcpy(&state->cc_copy.source_key,
4472 &state->resume_rsp.resume_key,
4473 sizeof state->resume_rsp.resume_key);
4475 cli_splice_copychunk_send(state, req);
4478 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
4479 struct tevent_context *ev,
4480 struct cli_state *cli,
4481 uint16_t src_fnum, uint16_t dst_fnum,
4482 off_t size, off_t src_offset, off_t dst_offset,
4483 int (*splice_cb)(off_t n, void *priv),
4486 struct tevent_req *req;
4487 struct tevent_req *subreq;
4488 struct cli_smb2_splice_state *state;
4490 DATA_BLOB in_input_buffer = data_blob_null;
4491 DATA_BLOB in_output_buffer = data_blob_null;
4493 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
4499 state->splice_cb = splice_cb;
4503 state->src_offset = src_offset;
4504 state->dst_offset = dst_offset;
4505 state->cc_copy.chunks = talloc_array(state,
4506 struct srv_copychunk,
4507 smb2cli_conn_cc_max_chunks(cli->conn));
4508 if (state->cc_copy.chunks == NULL) {
4512 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
4513 if (tevent_req_nterror(req, status))
4514 return tevent_req_post(req, ev);
4516 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
4517 if (tevent_req_nterror(req, status))
4518 return tevent_req_post(req, ev);
4520 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
4524 state->src_ph->fid_persistent, /* in_fid_persistent */
4525 state->src_ph->fid_volatile, /* in_fid_volatile */
4526 FSCTL_SRV_REQUEST_RESUME_KEY,
4527 0, /* in_max_input_length */
4529 32, /* in_max_output_length */
4531 SMB2_IOCTL_FLAG_IS_FSCTL);
4532 if (tevent_req_nomem(subreq, req)) {
4535 tevent_req_set_callback(subreq,
4536 cli_splice_key_done,
4542 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
4544 struct cli_smb2_splice_state *state = tevent_req_data(
4545 req, struct cli_smb2_splice_state);
4548 if (tevent_req_is_nterror(req, &status)) {
4549 state->cli->raw_status = status;
4550 tevent_req_received(req);
4553 if (written != NULL) {
4554 *written = state->written;
4556 state->cli->raw_status = NT_STATUS_OK;
4557 tevent_req_received(req);
4558 return NT_STATUS_OK;
4561 /***************************************************************
4562 SMB2 enum shadow copy data.
4563 ***************************************************************/
4565 struct cli_smb2_shadow_copy_data_fnum_state {
4566 struct cli_state *cli;
4568 struct smb2_hnd *ph;
4569 DATA_BLOB out_input_buffer;
4570 DATA_BLOB out_output_buffer;
4573 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
4575 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
4576 TALLOC_CTX *mem_ctx,
4577 struct tevent_context *ev,
4578 struct cli_state *cli,
4582 struct tevent_req *req, *subreq;
4583 struct cli_smb2_shadow_copy_data_fnum_state *state;
4586 req = tevent_req_create(mem_ctx, &state,
4587 struct cli_smb2_shadow_copy_data_fnum_state);
4592 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4593 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4594 return tevent_req_post(req, ev);
4600 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4601 if (tevent_req_nterror(req, status)) {
4602 return tevent_req_post(req, ev);
4606 * TODO. Under SMB2 we should send a zero max_output_length
4607 * ioctl to get the required size, then send another ioctl
4608 * to get the data, but the current SMB1 implementation just
4609 * does one roundtrip with a 64K buffer size. Do the same
4613 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4614 state->cli->timeout,
4615 state->cli->smb2.session,
4616 state->cli->smb2.tcon,
4617 state->ph->fid_persistent, /* in_fid_persistent */
4618 state->ph->fid_volatile, /* in_fid_volatile */
4619 FSCTL_GET_SHADOW_COPY_DATA,
4620 0, /* in_max_input_length */
4621 NULL, /* in_input_buffer */
4623 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
4624 NULL, /* in_output_buffer */
4625 SMB2_IOCTL_FLAG_IS_FSCTL);
4627 if (tevent_req_nomem(subreq, req)) {
4628 return tevent_req_post(req, ev);
4630 tevent_req_set_callback(subreq,
4631 cli_smb2_shadow_copy_data_fnum_done,
4637 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4639 struct tevent_req *req = tevent_req_callback_data(
4640 subreq, struct tevent_req);
4641 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4642 req, struct cli_smb2_shadow_copy_data_fnum_state);
4645 status = smb2cli_ioctl_recv(subreq, state,
4646 &state->out_input_buffer,
4647 &state->out_output_buffer);
4648 tevent_req_simple_finish_ntstatus(subreq, status);
4651 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4652 TALLOC_CTX *mem_ctx,
4657 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4658 req, struct cli_smb2_shadow_copy_data_fnum_state);
4659 char **names = NULL;
4660 uint32_t num_names = 0;
4661 uint32_t num_names_returned = 0;
4662 uint32_t dlength = 0;
4664 uint8_t *endp = NULL;
4667 if (tevent_req_is_nterror(req, &status)) {
4671 if (state->out_output_buffer.length < 16) {
4672 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4675 num_names = IVAL(state->out_output_buffer.data, 0);
4676 num_names_returned = IVAL(state->out_output_buffer.data, 4);
4677 dlength = IVAL(state->out_output_buffer.data, 8);
4679 if (num_names > 0x7FFFFFFF) {
4680 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4683 if (get_names == false) {
4684 *pnum_names = (int)num_names;
4685 return NT_STATUS_OK;
4687 if (num_names != num_names_returned) {
4688 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4690 if (dlength + 12 < 12) {
4691 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4694 * NB. The below is an allowable return if there are
4695 * more snapshots than the buffer size we told the
4696 * server we can receive. We currently don't support
4699 if (dlength + 12 > state->out_output_buffer.length) {
4700 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4702 if (state->out_output_buffer.length +
4703 (2 * sizeof(SHADOW_COPY_LABEL)) <
4704 state->out_output_buffer.length) {
4705 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4708 names = talloc_array(mem_ctx, char *, num_names_returned);
4709 if (names == NULL) {
4710 return NT_STATUS_NO_MEMORY;
4713 endp = state->out_output_buffer.data +
4714 state->out_output_buffer.length;
4716 for (i=0; i<num_names_returned; i++) {
4719 size_t converted_size;
4721 src = state->out_output_buffer.data + 12 +
4722 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4724 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4725 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4727 ret = convert_string_talloc(
4728 names, CH_UTF16LE, CH_UNIX,
4729 src, 2 * sizeof(SHADOW_COPY_LABEL),
4730 &names[i], &converted_size);
4733 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4736 *pnum_names = num_names;
4738 return NT_STATUS_OK;
4741 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4742 struct cli_state *cli,
4748 TALLOC_CTX *frame = talloc_stackframe();
4749 struct tevent_context *ev;
4750 struct tevent_req *req;
4751 NTSTATUS status = NT_STATUS_NO_MEMORY;
4753 if (smbXcli_conn_has_async_calls(cli->conn)) {
4755 * Can't use sync call while an async call is in flight
4757 status = NT_STATUS_INVALID_PARAMETER;
4760 ev = samba_tevent_context_init(frame);
4764 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4772 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4775 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4781 cli->raw_status = status;
4787 /***************************************************************
4788 Wrapper that allows SMB2 to truncate a file.
4790 ***************************************************************/
4792 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4797 uint8_t buf[8] = {0};
4798 DATA_BLOB inbuf = { .data = buf, .length = sizeof(buf) };
4799 TALLOC_CTX *frame = talloc_stackframe();
4801 if (smbXcli_conn_has_async_calls(cli->conn)) {
4803 * Can't use sync call while an async call is in flight
4805 status = NT_STATUS_INVALID_PARAMETER;
4809 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4810 status = NT_STATUS_INVALID_PARAMETER;
4814 SBVAL(buf, 0, newsize);
4816 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4817 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4819 status = cli_smb2_set_info_fnum(
4822 1, /* in_info_type */
4823 SMB_FILE_END_OF_FILE_INFORMATION-1000, /* in_file_info_class */
4824 &inbuf, /* in_input_buffer */
4829 cli->raw_status = status;
4835 struct cli_smb2_notify_state {
4836 struct tevent_req *subreq;
4837 struct notify_change *changes;
4841 static void cli_smb2_notify_done(struct tevent_req *subreq);
4842 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4844 struct tevent_req *cli_smb2_notify_send(
4845 TALLOC_CTX *mem_ctx,
4846 struct tevent_context *ev,
4847 struct cli_state *cli,
4849 uint32_t buffer_size,
4850 uint32_t completion_filter,
4853 struct tevent_req *req = NULL;
4854 struct cli_smb2_notify_state *state = NULL;
4855 struct smb2_hnd *ph = NULL;
4858 req = tevent_req_create(mem_ctx, &state,
4859 struct cli_smb2_notify_state);
4864 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4865 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4866 return tevent_req_post(req, ev);
4869 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4870 if (tevent_req_nterror(req, status)) {
4871 return tevent_req_post(req, ev);
4874 state->subreq = smb2cli_notify_send(
4886 if (tevent_req_nomem(state->subreq, req)) {
4887 return tevent_req_post(req, ev);
4889 tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4890 tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4894 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4896 struct cli_smb2_notify_state *state = tevent_req_data(
4897 req, struct cli_smb2_notify_state);
4900 ok = tevent_req_cancel(state->subreq);
4904 static void cli_smb2_notify_done(struct tevent_req *subreq)
4906 struct tevent_req *req = tevent_req_callback_data(
4907 subreq, struct tevent_req);
4908 struct cli_smb2_notify_state *state = tevent_req_data(
4909 req, struct cli_smb2_notify_state);
4915 status = smb2cli_notify_recv(subreq, state, &base, &len);
4916 TALLOC_FREE(subreq);
4918 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4919 tevent_req_done(req);
4922 if (tevent_req_nterror(req, status)) {
4928 while (len - ofs >= 12) {
4929 struct notify_change *tmp;
4930 struct notify_change *c;
4931 uint32_t next_ofs = IVAL(base, ofs);
4932 uint32_t file_name_length = IVAL(base, ofs+8);
4936 tmp = talloc_realloc(
4939 struct notify_change,
4940 state->num_changes + 1);
4941 if (tevent_req_nomem(tmp, req)) {
4944 state->changes = tmp;
4945 c = &state->changes[state->num_changes];
4946 state->num_changes += 1;
4948 if (smb_buffer_oob(len, ofs, next_ofs) ||
4949 smb_buffer_oob(len, ofs+12, file_name_length)) {
4951 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4955 c->action = IVAL(base, ofs+4);
4957 ok = convert_string_talloc(
4967 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4971 if (next_ofs == 0) {
4977 tevent_req_done(req);
4980 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
4981 TALLOC_CTX *mem_ctx,
4982 struct notify_change **pchanges,
4983 uint32_t *pnum_changes)
4985 struct cli_smb2_notify_state *state = tevent_req_data(
4986 req, struct cli_smb2_notify_state);
4989 if (tevent_req_is_nterror(req, &status)) {
4992 *pchanges = talloc_move(mem_ctx, &state->changes);
4993 *pnum_changes = state->num_changes;
4994 return NT_STATUS_OK;
4997 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
4998 uint32_t buffer_size, uint32_t completion_filter,
4999 bool recursive, TALLOC_CTX *mem_ctx,
5000 struct notify_change **pchanges,
5001 uint32_t *pnum_changes)
5003 TALLOC_CTX *frame = talloc_stackframe();
5004 struct tevent_context *ev;
5005 struct tevent_req *req;
5006 NTSTATUS status = NT_STATUS_NO_MEMORY;
5008 if (smbXcli_conn_has_async_calls(cli->conn)) {
5010 * Can't use sync call while an async call is in flight
5012 status = NT_STATUS_INVALID_PARAMETER;
5015 ev = samba_tevent_context_init(frame);
5019 req = cli_smb2_notify_send(
5030 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5033 status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
5039 struct cli_smb2_set_reparse_point_fnum_state {
5040 struct cli_state *cli;
5042 struct smb2_hnd *ph;
5043 DATA_BLOB input_buffer;
5046 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
5048 struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
5049 TALLOC_CTX *mem_ctx,
5050 struct tevent_context *ev,
5051 struct cli_state *cli,
5055 struct tevent_req *req, *subreq;
5056 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
5059 req = tevent_req_create(mem_ctx, &state,
5060 struct cli_smb2_set_reparse_point_fnum_state);
5065 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5066 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
5067 return tevent_req_post(req, ev);
5073 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
5074 if (tevent_req_nterror(req, status)) {
5075 return tevent_req_post(req, ev);
5078 state->input_buffer = data_blob_talloc(state,
5081 if (state->input_buffer.data == NULL) {
5082 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
5083 return tevent_req_post(req, ev);
5086 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
5087 state->cli->timeout,
5088 state->cli->smb2.session,
5089 state->cli->smb2.tcon,
5090 state->ph->fid_persistent, /* in_fid_persistent */
5091 state->ph->fid_volatile, /* in_fid_volatile */
5092 FSCTL_SET_REPARSE_POINT,
5093 0, /* in_max_input_length */
5094 &state->input_buffer ,
5097 SMB2_IOCTL_FLAG_IS_FSCTL);
5099 if (tevent_req_nomem(subreq, req)) {
5100 return tevent_req_post(req, ev);
5102 tevent_req_set_callback(subreq,
5103 cli_smb2_set_reparse_point_fnum_done,
5109 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
5111 struct tevent_req *req = tevent_req_callback_data(
5112 subreq, struct tevent_req);
5113 struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
5114 req, struct cli_smb2_set_reparse_point_fnum_state);
5117 status = smb2cli_ioctl_recv(subreq, state,
5120 TALLOC_FREE(subreq);
5121 if (tevent_req_nterror(req, status)) {
5124 tevent_req_done(req);
5127 NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
5129 return tevent_req_simple_recv_ntstatus(req);
5132 struct cli_smb2_get_reparse_point_fnum_state {
5133 struct cli_state *cli;
5135 struct smb2_hnd *ph;
5136 DATA_BLOB output_buffer;
5139 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
5141 struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
5142 TALLOC_CTX *mem_ctx,
5143 struct tevent_context *ev,
5144 struct cli_state *cli,
5147 struct tevent_req *req, *subreq;
5148 struct cli_smb2_get_reparse_point_fnum_state *state = NULL;
5151 req = tevent_req_create(mem_ctx, &state,
5152 struct cli_smb2_get_reparse_point_fnum_state);
5157 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5158 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
5159 return tevent_req_post(req, ev);
5165 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
5166 if (tevent_req_nterror(req, status)) {
5167 return tevent_req_post(req, ev);
5170 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
5171 state->cli->timeout,
5172 state->cli->smb2.session,
5173 state->cli->smb2.tcon,
5174 state->ph->fid_persistent, /* in_fid_persistent */
5175 state->ph->fid_volatile, /* in_fid_volatile */
5176 FSCTL_GET_REPARSE_POINT,
5177 0, /* in_max_input_length */
5181 SMB2_IOCTL_FLAG_IS_FSCTL);
5183 if (tevent_req_nomem(subreq, req)) {
5184 return tevent_req_post(req, ev);
5186 tevent_req_set_callback(subreq,
5187 cli_smb2_get_reparse_point_fnum_done,
5193 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
5195 struct tevent_req *req = tevent_req_callback_data(
5196 subreq, struct tevent_req);
5197 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
5198 req, struct cli_smb2_get_reparse_point_fnum_state);
5199 struct cli_state *cli = state->cli;
5202 status = smb2cli_ioctl_recv(subreq, state,
5204 &state->output_buffer);
5205 TALLOC_FREE(subreq);
5206 if (tevent_req_nterror(req, status)) {
5207 cli->raw_status = status;
5210 tevent_req_done(req);
5213 NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
5214 TALLOC_CTX *mem_ctx,
5217 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
5218 req, struct cli_smb2_get_reparse_point_fnum_state);
5220 if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
5221 NTSTATUS status = state->cli->raw_status;
5222 tevent_req_received(req);
5225 *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
5226 if (output->data == NULL) {
5227 tevent_req_received(req);
5228 return NT_STATUS_NO_MEMORY;
5230 tevent_req_received(req);
5231 return NT_STATUS_OK;