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;
655 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
657 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
658 struct tevent_context *ev,
659 struct cli_state *cli,
663 struct tevent_req *req = NULL;
664 struct cli_smb2_delete_on_close_state *state = NULL;
665 struct tevent_req *subreq = NULL;
666 uint8_t in_info_type;
667 uint8_t in_file_info_class;
670 req = tevent_req_create(mem_ctx, &state,
671 struct cli_smb2_delete_on_close_state);
678 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
679 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
680 return tevent_req_post(req, ev);
683 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
684 if (tevent_req_nterror(req, status)) {
685 return tevent_req_post(req, ev);
689 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
690 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
693 in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
694 /* Setup data array. */
695 SCVAL(&state->data[0], 0, flag ? 1 : 0);
696 state->inbuf.data = &state->data[0];
697 state->inbuf.length = 1;
699 subreq = smb2cli_set_info_send(state, ev,
706 &state->inbuf, /* in_input_buffer */
707 0, /* in_additional_info */
708 state->ph->fid_persistent,
709 state->ph->fid_volatile);
710 if (tevent_req_nomem(subreq, req)) {
711 return tevent_req_post(req, ev);
713 tevent_req_set_callback(subreq,
714 cli_smb2_delete_on_close_done,
719 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
721 NTSTATUS status = smb2cli_set_info_recv(subreq);
722 tevent_req_simple_finish_ntstatus(subreq, status);
725 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
727 struct cli_smb2_delete_on_close_state *state =
729 struct cli_smb2_delete_on_close_state);
732 if (tevent_req_is_nterror(req, &status)) {
733 state->cli->raw_status = status;
734 tevent_req_received(req);
738 state->cli->raw_status = NT_STATUS_OK;
739 tevent_req_received(req);
743 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
745 TALLOC_CTX *frame = talloc_stackframe();
746 struct tevent_context *ev;
747 struct tevent_req *req;
748 NTSTATUS status = NT_STATUS_NO_MEMORY;
750 if (smbXcli_conn_has_async_calls(cli->conn)) {
752 * Can't use sync call while an async call is in flight
754 status = NT_STATUS_INVALID_PARAMETER;
757 ev = samba_tevent_context_init(frame);
761 req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
765 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
768 status = cli_smb2_delete_on_close_recv(req);
774 /***************************************************************
775 Small wrapper that allows SMB2 to create a directory
777 ***************************************************************/
779 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
784 if (smbXcli_conn_has_async_calls(cli->conn)) {
786 * Can't use sync call while an async call is in flight
788 return NT_STATUS_INVALID_PARAMETER;
791 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
792 return NT_STATUS_INVALID_PARAMETER;
795 status = cli_smb2_create_fnum(cli,
797 0, /* create_flags */
798 SMB2_IMPERSONATION_IMPERSONATION,
799 FILE_READ_ATTRIBUTES, /* desired_access */
800 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
801 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
802 FILE_CREATE, /* create_disposition */
803 FILE_DIRECTORY_FILE, /* create_options */
810 if (!NT_STATUS_IS_OK(status)) {
813 return cli_smb2_close_fnum(cli, fnum);
816 struct cli_smb2_rmdir_state {
817 struct tevent_context *ev;
818 struct cli_state *cli;
820 const struct smb2_create_blobs *in_cblobs;
825 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq);
826 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq);
827 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq);
828 static void cli_smb2_rmdir_closed(struct tevent_req *subreq);
830 struct tevent_req *cli_smb2_rmdir_send(
832 struct tevent_context *ev,
833 struct cli_state *cli,
835 const struct smb2_create_blobs *in_cblobs)
837 struct tevent_req *req = NULL, *subreq = NULL;
838 struct cli_smb2_rmdir_state *state = NULL;
840 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_rmdir_state);
846 state->dname = dname;
847 state->in_cblobs = in_cblobs;
849 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
850 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
851 return tevent_req_post(req, ev);
854 subreq = cli_smb2_create_fnum_send(
859 0, /* create_flags */
860 SMB2_IMPERSONATION_IMPERSONATION,
861 DELETE_ACCESS, /* desired_access */
862 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
863 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
864 FILE_OPEN, /* create_disposition */
865 FILE_DIRECTORY_FILE, /* create_options */
866 state->in_cblobs); /* in_cblobs */
867 if (tevent_req_nomem(subreq, req)) {
868 return tevent_req_post(req, ev);
870 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened1, req);
874 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq)
876 struct tevent_req *req = tevent_req_callback_data(
877 subreq, struct tevent_req);
878 struct cli_smb2_rmdir_state *state = tevent_req_data(
879 req, struct cli_smb2_rmdir_state);
882 status = cli_smb2_create_fnum_recv(
883 subreq, &state->fnum, NULL, NULL, NULL);
886 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
888 * Naive option to match our SMB1 code. Assume the
889 * symlink path that tripped us up was the last
890 * component and try again. Eventually we will have to
891 * deal with the returned path unprocessed component. JRA.
893 subreq = cli_smb2_create_fnum_send(
898 0, /* create_flags */
899 SMB2_IMPERSONATION_IMPERSONATION,
900 DELETE_ACCESS, /* desired_access */
901 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
902 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
903 FILE_OPEN, /* create_disposition */
905 FILE_DELETE_ON_CLOSE|
906 FILE_OPEN_REPARSE_POINT, /* create_options */
907 state->in_cblobs); /* in_cblobs */
908 if (tevent_req_nomem(subreq, req)) {
911 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened2, req);
915 if (tevent_req_nterror(req, status)) {
919 subreq = cli_smb2_delete_on_close_send(
920 state, state->ev, state->cli, state->fnum, true);
921 if (tevent_req_nomem(subreq, req)) {
924 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
927 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq)
929 struct tevent_req *req = tevent_req_callback_data(
930 subreq, struct tevent_req);
931 struct cli_smb2_rmdir_state *state = tevent_req_data(
932 req, struct cli_smb2_rmdir_state);
935 status = cli_smb2_create_fnum_recv(
936 subreq, &state->fnum, NULL, NULL, NULL);
938 if (tevent_req_nterror(req, status)) {
942 subreq = cli_smb2_delete_on_close_send(
943 state, state->ev, state->cli, state->fnum, true);
944 if (tevent_req_nomem(subreq, req)) {
947 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
950 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq)
952 struct tevent_req *req = tevent_req_callback_data(
953 subreq, struct tevent_req);
954 struct cli_smb2_rmdir_state *state = tevent_req_data(
955 req, struct cli_smb2_rmdir_state);
957 state->status = cli_smb2_delete_on_close_recv(subreq);
961 * Close the fd even if the set_disp failed
964 subreq = cli_smb2_close_fnum_send(
965 state, state->ev, state->cli, state->fnum);
966 if (tevent_req_nomem(subreq, req)) {
969 tevent_req_set_callback(subreq, cli_smb2_rmdir_closed, req);
972 static void cli_smb2_rmdir_closed(struct tevent_req *subreq)
974 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
975 tevent_req_simple_finish_ntstatus(subreq, status);
978 NTSTATUS cli_smb2_rmdir_recv(struct tevent_req *req)
980 struct cli_smb2_rmdir_state *state = tevent_req_data(
981 req, struct cli_smb2_rmdir_state);
984 if (tevent_req_is_nterror(req, &status)) {
987 return state->status;
990 NTSTATUS cli_smb2_rmdir(
991 struct cli_state *cli,
993 const struct smb2_create_blobs *in_cblobs)
995 TALLOC_CTX *frame = talloc_stackframe();
996 struct tevent_context *ev;
997 struct tevent_req *req;
998 NTSTATUS status = NT_STATUS_NO_MEMORY;
1001 if (smbXcli_conn_has_async_calls(cli->conn)) {
1003 * Can't use sync call while an async call is in flight
1005 status = NT_STATUS_INVALID_PARAMETER;
1008 ev = samba_tevent_context_init(frame);
1012 req = cli_smb2_rmdir_send(frame, ev, cli, dname, in_cblobs);
1016 ok = tevent_req_poll_ntstatus(req, ev, &status);
1020 status = cli_smb2_rmdir_recv(req);
1022 cli->raw_status = status;
1027 /***************************************************************
1028 Small wrapper that allows SMB2 to unlink a pathname.
1030 ***************************************************************/
1032 struct cli_smb2_unlink_state {
1033 struct tevent_context *ev;
1034 struct cli_state *cli;
1036 const struct smb2_create_blobs *in_cblobs;
1039 static void cli_smb2_unlink_opened1(struct tevent_req *subreq);
1040 static void cli_smb2_unlink_opened2(struct tevent_req *subreq);
1041 static void cli_smb2_unlink_closed(struct tevent_req *subreq);
1043 struct tevent_req *cli_smb2_unlink_send(
1044 TALLOC_CTX *mem_ctx,
1045 struct tevent_context *ev,
1046 struct cli_state *cli,
1048 const struct smb2_create_blobs *in_cblobs)
1050 struct tevent_req *req = NULL, *subreq = NULL;
1051 struct cli_smb2_unlink_state *state = NULL;
1053 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_unlink_state);
1059 state->fname = fname;
1060 state->in_cblobs = in_cblobs;
1062 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1063 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1064 return tevent_req_post(req, ev);
1067 subreq = cli_smb2_create_fnum_send(
1068 state, /* mem_ctx */
1069 state->ev, /* tevent_context */
1070 state->cli, /* cli_struct */
1071 state->fname, /* filename */
1072 0, /* create_flags */
1073 SMB2_IMPERSONATION_IMPERSONATION,
1074 DELETE_ACCESS, /* desired_access */
1075 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1078 FILE_SHARE_DELETE, /* share_access */
1079 FILE_OPEN, /* create_disposition */
1080 FILE_DELETE_ON_CLOSE, /* create_options */
1081 state->in_cblobs); /* in_cblobs */
1082 if (tevent_req_nomem(subreq, req)) {
1083 return tevent_req_post(req, ev);
1085 tevent_req_set_callback(subreq, cli_smb2_unlink_opened1, req);
1089 static void cli_smb2_unlink_opened1(struct tevent_req *subreq)
1091 struct tevent_req *req = tevent_req_callback_data(
1092 subreq, struct tevent_req);
1093 struct cli_smb2_unlink_state *state = tevent_req_data(
1094 req, struct cli_smb2_unlink_state);
1098 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1099 TALLOC_FREE(subreq);
1101 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1103 * Naive option to match our SMB1 code. Assume the
1104 * symlink path that tripped us up was the last
1105 * component and try again. Eventually we will have to
1106 * deal with the returned path unprocessed component. JRA.
1108 subreq = cli_smb2_create_fnum_send(
1109 state, /* mem_ctx */
1110 state->ev, /* tevent_context */
1111 state->cli, /* cli_struct */
1112 state->fname, /* filename */
1113 0, /* create_flags */
1114 SMB2_IMPERSONATION_IMPERSONATION,
1115 DELETE_ACCESS, /* desired_access */
1116 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1119 FILE_SHARE_DELETE, /* share_access */
1120 FILE_OPEN, /* create_disposition */
1121 FILE_DELETE_ON_CLOSE|
1122 FILE_OPEN_REPARSE_POINT, /* create_options */
1123 state->in_cblobs); /* in_cblobs */
1124 if (tevent_req_nomem(subreq, req)) {
1127 tevent_req_set_callback(subreq, cli_smb2_unlink_opened2, req);
1131 if (tevent_req_nterror(req, status)) {
1135 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1136 if (tevent_req_nomem(subreq, req)) {
1139 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1142 static void cli_smb2_unlink_opened2(struct tevent_req *subreq)
1144 struct tevent_req *req = tevent_req_callback_data(
1145 subreq, struct tevent_req);
1146 struct cli_smb2_unlink_state *state = tevent_req_data(
1147 req, struct cli_smb2_unlink_state);
1151 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1152 TALLOC_FREE(subreq);
1153 if (tevent_req_nterror(req, status)) {
1157 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1158 if (tevent_req_nomem(subreq, req)) {
1161 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1164 static void cli_smb2_unlink_closed(struct tevent_req *subreq)
1166 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1167 tevent_req_simple_finish_ntstatus(subreq, status);
1170 NTSTATUS cli_smb2_unlink_recv(struct tevent_req *req)
1172 return tevent_req_simple_recv_ntstatus(req);
1175 NTSTATUS cli_smb2_unlink(
1176 struct cli_state *cli,
1178 const struct smb2_create_blobs *in_cblobs)
1180 TALLOC_CTX *frame = talloc_stackframe();
1181 struct tevent_context *ev;
1182 struct tevent_req *req;
1183 NTSTATUS status = NT_STATUS_NO_MEMORY;
1186 if (smbXcli_conn_has_async_calls(cli->conn)) {
1188 * Can't use sync call while an async call is in flight
1190 status = NT_STATUS_INVALID_PARAMETER;
1193 ev = samba_tevent_context_init(frame);
1197 req = cli_smb2_unlink_send(frame, ev, cli, fname, in_cblobs);
1201 ok = tevent_req_poll_ntstatus(req, ev, &status);
1205 status = cli_smb2_unlink_recv(req);
1207 cli->raw_status = status;
1212 /***************************************************************
1213 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1214 ***************************************************************/
1216 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
1217 uint32_t dir_data_length,
1218 struct file_info *finfo,
1219 uint32_t *next_offset)
1225 if (dir_data_length < 4) {
1226 return NT_STATUS_INFO_LENGTH_MISMATCH;
1229 *next_offset = IVAL(dir_data, 0);
1231 if (*next_offset > dir_data_length) {
1232 return NT_STATUS_INFO_LENGTH_MISMATCH;
1235 if (*next_offset != 0) {
1236 /* Ensure we only read what in this record. */
1237 dir_data_length = *next_offset;
1240 if (dir_data_length < 105) {
1241 return NT_STATUS_INFO_LENGTH_MISMATCH;
1244 finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
1245 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
1246 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
1247 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
1248 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
1249 finfo->allocated_size = IVAL2_TO_SMB_BIG_UINT(dir_data + 48, 0);
1250 finfo->mode = CVAL(dir_data + 56, 0);
1251 finfo->ino = IVAL2_TO_SMB_BIG_UINT(dir_data + 96, 0);
1252 namelen = IVAL(dir_data + 60,0);
1253 if (namelen > (dir_data_length - 104)) {
1254 return NT_STATUS_INFO_LENGTH_MISMATCH;
1256 slen = CVAL(dir_data + 68, 0);
1258 return NT_STATUS_INFO_LENGTH_MISMATCH;
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 ret = pull_string_talloc(finfo,
1274 FLAGS2_UNICODE_STRINGS,
1279 if (ret == (size_t)-1) {
1280 /* Bad conversion. */
1281 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1283 return NT_STATUS_OK;
1286 /*******************************************************************
1287 Given a filename - get its directory name
1288 ********************************************************************/
1290 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
1298 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
1301 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
1312 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
1315 (*parent)[len] = '\0';
1323 /***************************************************************
1324 Wrapper that allows SMB2 to list a directory.
1326 ***************************************************************/
1328 NTSTATUS cli_smb2_list(struct cli_state *cli,
1329 const char *pathname,
1331 NTSTATUS (*fn)(const char *,
1338 uint16_t fnum = 0xffff;
1339 char *parent_dir = NULL;
1340 const char *mask = NULL;
1341 struct smb2_hnd *ph = NULL;
1342 bool processed_file = false;
1343 TALLOC_CTX *frame = talloc_stackframe();
1344 TALLOC_CTX *subframe = NULL;
1347 uint32_t max_avail_len;
1350 if (smbXcli_conn_has_async_calls(cli->conn)) {
1352 * Can't use sync call while an async call is in flight
1354 status = NT_STATUS_INVALID_PARAMETER;
1358 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1359 status = NT_STATUS_INVALID_PARAMETER;
1363 /* Get the directory name. */
1364 if (!windows_parent_dirname(frame,
1368 status = NT_STATUS_NO_MEMORY;
1372 mask_has_wild = ms_has_wild(mask);
1374 status = cli_smb2_create_fnum(cli,
1376 0, /* create_flags */
1377 SMB2_IMPERSONATION_IMPERSONATION,
1378 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
1379 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1380 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
1381 FILE_OPEN, /* create_disposition */
1382 FILE_DIRECTORY_FILE, /* create_options */
1389 if (!NT_STATUS_IS_OK(status)) {
1393 status = map_fnum_to_smb2_handle(cli,
1396 if (!NT_STATUS_IS_OK(status)) {
1401 * ideally, use the max transaction size, but don't send a request
1402 * bigger than we have credits available for
1404 max_trans = smb2cli_conn_max_trans_size(cli->conn);
1405 ok = smb2cli_conn_req_possible(cli->conn, &max_avail_len);
1407 max_trans = MIN(max_trans, max_avail_len);
1411 uint8_t *dir_data = NULL;
1412 uint32_t dir_data_length = 0;
1413 uint32_t next_offset = 0;
1414 subframe = talloc_stackframe();
1416 status = smb2cli_query_directory(cli->conn,
1420 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
1431 if (!NT_STATUS_IS_OK(status)) {
1432 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1439 struct file_info *finfo = talloc_zero(subframe,
1442 if (finfo == NULL) {
1443 status = NT_STATUS_NO_MEMORY;
1447 status = parse_finfo_id_both_directory_info(dir_data,
1452 if (!NT_STATUS_IS_OK(status)) {
1456 if (dir_check_ftype((uint32_t)finfo->mode,
1457 (uint32_t)attribute)) {
1459 * Only process if attributes match.
1460 * On SMB1 server does this, so on
1461 * SMB2 we need to emulate in the
1464 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1466 processed_file = true;
1468 status = fn(cli->dfs_mountpoint,
1473 if (!NT_STATUS_IS_OK(status)) {
1480 /* Move to next entry. */
1482 dir_data += next_offset;
1483 dir_data_length -= next_offset;
1485 } while (next_offset != 0);
1487 TALLOC_FREE(subframe);
1489 if (!mask_has_wild) {
1491 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1492 * when handed a non-wildcard path. Do it
1493 * for the server (with a non-wildcard path
1494 * there should only ever be one file returned.
1496 status = STATUS_NO_MORE_FILES;
1500 } while (NT_STATUS_IS_OK(status));
1502 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1503 status = NT_STATUS_OK;
1506 if (NT_STATUS_IS_OK(status) && !processed_file) {
1508 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1509 * if no files match. Emulate this in the client.
1511 status = NT_STATUS_NO_SUCH_FILE;
1516 if (fnum != 0xffff) {
1517 cli_smb2_close_fnum(cli, fnum);
1520 cli->raw_status = status;
1522 TALLOC_FREE(subframe);
1527 /***************************************************************
1528 Wrapper that allows SMB2 to query a path info (basic level).
1530 ***************************************************************/
1532 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1534 SMB_STRUCT_STAT *sbuf,
1535 uint32_t *attributes)
1538 struct smb_create_returns cr;
1539 uint16_t fnum = 0xffff;
1540 size_t namelen = strlen(name);
1542 if (smbXcli_conn_has_async_calls(cli->conn)) {
1544 * Can't use sync call while an async call is in flight
1546 return NT_STATUS_INVALID_PARAMETER;
1549 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1550 return NT_STATUS_INVALID_PARAMETER;
1553 /* SMB2 is pickier about pathnames. Ensure it doesn't
1555 if (namelen > 0 && name[namelen-1] == '\\') {
1556 char *modname = talloc_strdup(talloc_tos(), name);
1557 modname[namelen-1] = '\0';
1561 /* This is commonly used as a 'cd'. Try qpathinfo on
1562 a directory handle first. */
1564 status = cli_smb2_create_fnum(cli,
1566 0, /* create_flags */
1567 SMB2_IMPERSONATION_IMPERSONATION,
1568 FILE_READ_ATTRIBUTES, /* desired_access */
1569 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1570 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1571 FILE_OPEN, /* create_disposition */
1572 FILE_DIRECTORY_FILE, /* create_options */
1579 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1580 /* Maybe a file ? */
1581 status = cli_smb2_create_fnum(cli,
1583 0, /* create_flags */
1584 SMB2_IMPERSONATION_IMPERSONATION,
1585 FILE_READ_ATTRIBUTES, /* desired_access */
1586 0, /* file attributes */
1587 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1588 FILE_OPEN, /* create_disposition */
1589 0, /* create_options */
1597 if (!NT_STATUS_IS_OK(status)) {
1601 status = cli_smb2_close_fnum(cli, fnum);
1605 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1606 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1607 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1608 sbuf->st_ex_size = cr.end_of_file;
1609 *attributes = cr.file_attributes;
1614 /***************************************************************
1615 Wrapper that allows SMB2 to check if a path is a directory.
1617 ***************************************************************/
1619 NTSTATUS cli_smb2_chkpath(struct cli_state *cli,
1623 uint16_t fnum = 0xffff;
1625 if (smbXcli_conn_has_async_calls(cli->conn)) {
1627 * Can't use sync call while an async call is in flight
1629 return NT_STATUS_INVALID_PARAMETER;
1632 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1633 return NT_STATUS_INVALID_PARAMETER;
1636 /* Ensure this is a directory. */
1637 status = cli_smb2_create_fnum(cli,
1639 0, /* create_flags */
1640 SMB2_IMPERSONATION_IMPERSONATION,
1641 FILE_READ_ATTRIBUTES, /* desired_access */
1642 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1643 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1644 FILE_OPEN, /* create_disposition */
1645 FILE_DIRECTORY_FILE, /* create_options */
1652 if (!NT_STATUS_IS_OK(status)) {
1656 return cli_smb2_close_fnum(cli, fnum);
1659 struct cli_smb2_query_info_fnum_state {
1663 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq);
1665 struct tevent_req *cli_smb2_query_info_fnum_send(
1666 TALLOC_CTX *mem_ctx,
1667 struct tevent_context *ev,
1668 struct cli_state *cli,
1670 uint8_t in_info_type,
1671 uint8_t in_info_class,
1672 uint32_t in_max_output_length,
1673 const DATA_BLOB *in_input_buffer,
1674 uint32_t in_additional_info,
1677 struct tevent_req *req = NULL, *subreq = NULL;
1678 struct cli_smb2_query_info_fnum_state *state = NULL;
1679 struct smb2_hnd *ph = NULL;
1682 req = tevent_req_create(
1683 mem_ctx, &state, struct cli_smb2_query_info_fnum_state);
1688 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1689 if (tevent_req_nterror(req, status)) {
1690 return tevent_req_post(req, ev);
1693 subreq = smb2cli_query_info_send(
1702 in_max_output_length,
1708 if (tevent_req_nomem(subreq, req)) {
1709 return tevent_req_post(req, ev);
1711 tevent_req_set_callback(subreq, cli_smb2_query_info_fnum_done, req);
1715 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq)
1717 struct tevent_req *req = tevent_req_callback_data(
1718 subreq, struct tevent_req);
1719 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1720 req, struct cli_smb2_query_info_fnum_state);
1724 status = smb2cli_query_info_recv(subreq, state, &outbuf);
1725 TALLOC_FREE(subreq);
1726 if (tevent_req_nterror(req, status)) {
1731 * We have to dup the memory here because outbuf.data is not
1732 * returned as a talloc object by smb2cli_query_info_recv.
1733 * It's a pointer into the received buffer.
1735 state->outbuf = data_blob_dup_talloc(state, outbuf);
1737 if ((outbuf.length != 0) &&
1738 tevent_req_nomem(state->outbuf.data, req)) {
1741 tevent_req_done(req);
1744 NTSTATUS cli_smb2_query_info_fnum_recv(
1745 struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *outbuf)
1747 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1748 req, struct cli_smb2_query_info_fnum_state);
1751 if (tevent_req_is_nterror(req, &status)) {
1754 *outbuf = (DATA_BLOB) {
1755 .data = talloc_move(mem_ctx, &state->outbuf.data),
1756 .length = state->outbuf.length,
1758 return NT_STATUS_OK;
1761 NTSTATUS cli_smb2_query_info_fnum(
1762 struct cli_state *cli,
1764 uint8_t in_info_type,
1765 uint8_t in_info_class,
1766 uint32_t in_max_output_length,
1767 const DATA_BLOB *in_input_buffer,
1768 uint32_t in_additional_info,
1770 TALLOC_CTX *mem_ctx,
1773 TALLOC_CTX *frame = talloc_stackframe();
1774 struct tevent_context *ev = NULL;
1775 struct tevent_req *req = NULL;
1776 NTSTATUS status = NT_STATUS_NO_MEMORY;
1779 if (smbXcli_conn_has_async_calls(cli->conn)) {
1781 * Can't use sync call while an async call is in flight
1783 status = NT_STATUS_INVALID_PARAMETER;
1786 ev = samba_tevent_context_init(frame);
1790 req = cli_smb2_query_info_fnum_send(
1797 in_max_output_length,
1804 ok = tevent_req_poll_ntstatus(req, ev, &status);
1808 status = cli_smb2_query_info_fnum_recv(req, mem_ctx, outbuf);
1814 /***************************************************************
1815 Helper function for pathname operations.
1816 ***************************************************************/
1818 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1820 uint32_t desired_access,
1824 size_t namelen = strlen(name);
1825 TALLOC_CTX *frame = talloc_stackframe();
1826 uint32_t create_options = 0;
1828 /* SMB2 is pickier about pathnames. Ensure it doesn't
1830 if (namelen > 0 && name[namelen-1] == '\\') {
1831 char *modname = talloc_strdup(frame, name);
1832 if (modname == NULL) {
1833 status = NT_STATUS_NO_MEMORY;
1836 modname[namelen-1] = '\0';
1840 /* Try to open a file handle first. */
1841 status = cli_smb2_create_fnum(cli,
1843 0, /* create_flags */
1844 SMB2_IMPERSONATION_IMPERSONATION,
1846 0, /* file attributes */
1847 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1848 FILE_OPEN, /* create_disposition */
1856 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1858 * Naive option to match our SMB1 code. Assume the
1859 * symlink path that tripped us up was the last
1860 * component and try again. Eventually we will have to
1861 * deal with the returned path unprocessed component. JRA.
1863 create_options |= FILE_OPEN_REPARSE_POINT;
1864 status = cli_smb2_create_fnum(cli,
1866 0, /* create_flags */
1867 SMB2_IMPERSONATION_IMPERSONATION,
1869 0, /* file attributes */
1870 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1871 FILE_OPEN, /* create_disposition */
1880 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1881 create_options |= FILE_DIRECTORY_FILE;
1882 status = cli_smb2_create_fnum(cli,
1884 0, /* create_flags */
1885 SMB2_IMPERSONATION_IMPERSONATION,
1887 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1888 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1889 FILE_OPEN, /* create_disposition */
1890 FILE_DIRECTORY_FILE, /* create_options */
1904 /***************************************************************
1905 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1907 ***************************************************************/
1909 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1914 DATA_BLOB outbuf = data_blob_null;
1915 uint16_t fnum = 0xffff;
1916 uint32_t altnamelen = 0;
1917 TALLOC_CTX *frame = talloc_stackframe();
1919 if (smbXcli_conn_has_async_calls(cli->conn)) {
1921 * Can't use sync call while an async call is in flight
1923 status = NT_STATUS_INVALID_PARAMETER;
1927 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1928 status = NT_STATUS_INVALID_PARAMETER;
1932 status = get_fnum_from_path(cli,
1934 FILE_READ_ATTRIBUTES,
1937 if (!NT_STATUS_IS_OK(status)) {
1941 status = cli_smb2_query_info_fnum(
1944 1, /* in_info_type */
1945 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1946 0xFFFF, /* in_max_output_length */
1947 NULL, /* in_input_buffer */
1948 0, /* in_additional_info */
1953 if (!NT_STATUS_IS_OK(status)) {
1957 /* Parse the reply. */
1958 if (outbuf.length < 4) {
1959 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1963 altnamelen = IVAL(outbuf.data, 0);
1964 if (altnamelen > outbuf.length - 4) {
1965 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1969 if (altnamelen > 0) {
1971 char *short_name = NULL;
1972 ret = pull_string_talloc(frame,
1974 FLAGS2_UNICODE_STRINGS,
1979 if (ret == (size_t)-1) {
1980 /* Bad conversion. */
1981 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1985 fstrcpy(alt_name, short_name);
1990 status = NT_STATUS_OK;
1994 if (fnum != 0xffff) {
1995 cli_smb2_close_fnum(cli, fnum);
1998 cli->raw_status = status;
2005 /***************************************************************
2006 Wrapper that allows SMB2 to query a fnum info (basic level).
2008 ***************************************************************/
2010 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
2014 struct timespec *create_time,
2015 struct timespec *access_time,
2016 struct timespec *write_time,
2017 struct timespec *change_time,
2021 DATA_BLOB outbuf = data_blob_null;
2022 TALLOC_CTX *frame = talloc_stackframe();
2024 if (smbXcli_conn_has_async_calls(cli->conn)) {
2026 * Can't use sync call while an async call is in flight
2028 status = NT_STATUS_INVALID_PARAMETER;
2032 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2033 status = NT_STATUS_INVALID_PARAMETER;
2037 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2038 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
2040 status = cli_smb2_query_info_fnum(
2043 1, /* in_info_type */
2044 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
2045 0xFFFF, /* in_max_output_length */
2046 NULL, /* in_input_buffer */
2047 0, /* in_additional_info */
2051 if (!NT_STATUS_IS_OK(status)) {
2055 /* Parse the reply. */
2056 if (outbuf.length < 0x60) {
2057 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2062 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
2065 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
2068 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
2071 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
2074 uint32_t attr = IVAL(outbuf.data, 0x20);
2075 *mode = (uint16_t)attr;
2078 uint64_t file_size = BVAL(outbuf.data, 0x30);
2079 *size = (off_t)file_size;
2082 uint64_t file_index = BVAL(outbuf.data, 0x40);
2083 *ino = (SMB_INO_T)file_index;
2088 cli->raw_status = status;
2094 /***************************************************************
2095 Wrapper that allows SMB2 to query an fnum.
2096 Implement on top of cli_smb2_qfileinfo_basic().
2098 ***************************************************************/
2100 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
2104 time_t *change_time,
2105 time_t *access_time,
2108 struct timespec access_time_ts;
2109 struct timespec write_time_ts;
2110 struct timespec change_time_ts;
2111 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
2121 cli->raw_status = status;
2123 if (!NT_STATUS_IS_OK(status)) {
2128 *change_time = change_time_ts.tv_sec;
2131 *access_time = access_time_ts.tv_sec;
2134 *write_time = write_time_ts.tv_sec;
2136 return NT_STATUS_OK;
2139 /***************************************************************
2140 Wrapper that allows SMB2 to get pathname attributes.
2142 ***************************************************************/
2144 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
2151 uint16_t fnum = 0xffff;
2152 struct smb2_hnd *ph = NULL;
2153 TALLOC_CTX *frame = talloc_stackframe();
2155 if (smbXcli_conn_has_async_calls(cli->conn)) {
2157 * Can't use sync call while an async call is in flight
2159 status = NT_STATUS_INVALID_PARAMETER;
2163 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2164 status = NT_STATUS_INVALID_PARAMETER;
2168 status = get_fnum_from_path(cli,
2170 FILE_READ_ATTRIBUTES,
2173 if (!NT_STATUS_IS_OK(status)) {
2177 status = map_fnum_to_smb2_handle(cli,
2180 if (!NT_STATUS_IS_OK(status)) {
2183 status = cli_smb2_getattrE(cli,
2190 if (!NT_STATUS_IS_OK(status)) {
2196 if (fnum != 0xffff) {
2197 cli_smb2_close_fnum(cli, fnum);
2200 cli->raw_status = status;
2206 /***************************************************************
2207 Wrapper that allows SMB2 to query a pathname info (basic level).
2208 Implement on top of cli_smb2_qfileinfo_basic().
2210 ***************************************************************/
2212 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
2214 struct timespec *create_time,
2215 struct timespec *access_time,
2216 struct timespec *write_time,
2217 struct timespec *change_time,
2223 struct smb2_hnd *ph = NULL;
2224 uint16_t fnum = 0xffff;
2225 TALLOC_CTX *frame = talloc_stackframe();
2227 if (smbXcli_conn_has_async_calls(cli->conn)) {
2229 * Can't use sync call while an async call is in flight
2231 status = NT_STATUS_INVALID_PARAMETER;
2235 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2236 status = NT_STATUS_INVALID_PARAMETER;
2240 status = get_fnum_from_path(cli,
2242 FILE_READ_ATTRIBUTES,
2245 if (!NT_STATUS_IS_OK(status)) {
2249 status = map_fnum_to_smb2_handle(cli,
2252 if (!NT_STATUS_IS_OK(status)) {
2256 status = cli_smb2_qfileinfo_basic(cli,
2268 if (fnum != 0xffff) {
2269 cli_smb2_close_fnum(cli, fnum);
2272 cli->raw_status = status;
2278 /***************************************************************
2279 Wrapper that allows SMB2 to query pathname streams.
2281 ***************************************************************/
2283 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
2285 TALLOC_CTX *mem_ctx,
2286 unsigned int *pnum_streams,
2287 struct stream_struct **pstreams)
2290 uint16_t fnum = 0xffff;
2291 DATA_BLOB outbuf = data_blob_null;
2292 TALLOC_CTX *frame = talloc_stackframe();
2294 if (smbXcli_conn_has_async_calls(cli->conn)) {
2296 * Can't use sync call while an async call is in flight
2298 status = NT_STATUS_INVALID_PARAMETER;
2302 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2303 status = NT_STATUS_INVALID_PARAMETER;
2307 status = get_fnum_from_path(cli,
2309 FILE_READ_ATTRIBUTES,
2312 if (!NT_STATUS_IS_OK(status)) {
2316 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2317 level 22 (SMB2_FILE_STREAM_INFORMATION). */
2319 status = cli_smb2_query_info_fnum(
2322 1, /* in_info_type */
2323 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
2324 0xFFFF, /* in_max_output_length */
2325 NULL, /* in_input_buffer */
2326 0, /* in_additional_info */
2331 if (!NT_STATUS_IS_OK(status)) {
2335 /* Parse the reply. */
2336 if (!parse_streams_blob(mem_ctx,
2341 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2347 if (fnum != 0xffff) {
2348 cli_smb2_close_fnum(cli, fnum);
2351 cli->raw_status = status;
2357 /***************************************************************
2358 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2361 ***************************************************************/
2363 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
2365 uint8_t in_info_type,
2366 uint8_t in_file_info_class,
2367 const DATA_BLOB *p_in_data)
2370 uint16_t fnum = 0xffff;
2371 struct smb2_hnd *ph = NULL;
2372 TALLOC_CTX *frame = talloc_stackframe();
2374 if (smbXcli_conn_has_async_calls(cli->conn)) {
2376 * Can't use sync call while an async call is in flight
2378 status = NT_STATUS_INVALID_PARAMETER;
2382 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2383 status = NT_STATUS_INVALID_PARAMETER;
2387 status = get_fnum_from_path(cli,
2389 FILE_WRITE_ATTRIBUTES,
2392 if (!NT_STATUS_IS_OK(status)) {
2396 status = map_fnum_to_smb2_handle(cli,
2399 if (!NT_STATUS_IS_OK(status)) {
2403 status = smb2cli_set_info(cli->conn,
2409 p_in_data, /* in_input_buffer */
2410 0, /* in_additional_info */
2415 if (fnum != 0xffff) {
2416 cli_smb2_close_fnum(cli, fnum);
2419 cli->raw_status = status;
2426 /***************************************************************
2427 Wrapper that allows SMB2 to set pathname attributes.
2429 ***************************************************************/
2431 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
2436 uint8_t inbuf_store[40];
2437 DATA_BLOB inbuf = data_blob_null;
2439 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2440 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2442 inbuf.data = inbuf_store;
2443 inbuf.length = sizeof(inbuf_store);
2444 data_blob_clear(&inbuf);
2447 * SMB1 uses attr == 0 to clear all attributes
2448 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2449 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2450 * request attribute change.
2452 * SMB2 uses exactly the reverse. Unfortunately as the
2453 * cli_setatr() ABI is exposed inside libsmbclient,
2454 * we must make the SMB2 cli_smb2_setatr() call
2455 * export the same ABI as the SMB1 cli_setatr()
2456 * which calls it. This means reversing the sense
2457 * of the requested attr argument if it's zero
2458 * or FILE_ATTRIBUTE_NORMAL.
2460 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2464 attr = FILE_ATTRIBUTE_NORMAL;
2465 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
2469 SSVAL(inbuf.data, 32, attr);
2471 put_long_date((char *)inbuf.data + 16,mtime);
2473 /* Set all the other times to -1. */
2474 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2475 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
2476 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
2478 return cli_smb2_setpathinfo(cli,
2480 1, /* in_info_type */
2481 /* in_file_info_class */
2482 SMB_FILE_BASIC_INFORMATION - 1000,
2487 /***************************************************************
2488 Wrapper that allows SMB2 to set file handle times.
2490 ***************************************************************/
2492 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
2499 struct smb2_hnd *ph = NULL;
2500 uint8_t inbuf_store[40];
2501 DATA_BLOB inbuf = data_blob_null;
2503 if (smbXcli_conn_has_async_calls(cli->conn)) {
2505 * Can't use sync call while an async call is in flight
2507 return NT_STATUS_INVALID_PARAMETER;
2510 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2511 return NT_STATUS_INVALID_PARAMETER;
2514 status = map_fnum_to_smb2_handle(cli,
2517 if (!NT_STATUS_IS_OK(status)) {
2521 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2522 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2524 inbuf.data = inbuf_store;
2525 inbuf.length = sizeof(inbuf_store);
2526 data_blob_clear(&inbuf);
2528 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2529 if (change_time != 0) {
2530 put_long_date((char *)inbuf.data + 24, change_time);
2532 if (access_time != 0) {
2533 put_long_date((char *)inbuf.data + 8, access_time);
2535 if (write_time != 0) {
2536 put_long_date((char *)inbuf.data + 16, write_time);
2539 cli->raw_status = smb2cli_set_info(cli->conn,
2543 1, /* in_info_type */
2544 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
2545 &inbuf, /* in_input_buffer */
2546 0, /* in_additional_info */
2550 return cli->raw_status;
2553 /***************************************************************
2554 Wrapper that allows SMB2 to query disk attributes (size).
2556 ***************************************************************/
2558 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2559 uint64_t *bsize, uint64_t *total, uint64_t *avail)
2562 uint16_t fnum = 0xffff;
2563 DATA_BLOB outbuf = data_blob_null;
2564 uint32_t sectors_per_unit = 0;
2565 uint32_t bytes_per_sector = 0;
2566 uint64_t total_size = 0;
2567 uint64_t size_free = 0;
2568 TALLOC_CTX *frame = talloc_stackframe();
2570 if (smbXcli_conn_has_async_calls(cli->conn)) {
2572 * Can't use sync call while an async call is in flight
2574 status = NT_STATUS_INVALID_PARAMETER;
2578 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2579 status = NT_STATUS_INVALID_PARAMETER;
2583 /* First open the top level directory. */
2584 status = cli_smb2_create_fnum(cli,
2586 0, /* create_flags */
2587 SMB2_IMPERSONATION_IMPERSONATION,
2588 FILE_READ_ATTRIBUTES, /* desired_access */
2589 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2590 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2591 FILE_OPEN, /* create_disposition */
2592 FILE_DIRECTORY_FILE, /* create_options */
2599 if (!NT_STATUS_IS_OK(status)) {
2603 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2604 level 3 (SMB_FS_SIZE_INFORMATION). */
2606 status = cli_smb2_query_info_fnum(
2609 2, /* in_info_type */
2610 3, /* in_file_info_class */
2611 0xFFFF, /* in_max_output_length */
2612 NULL, /* in_input_buffer */
2613 0, /* in_additional_info */
2617 if (!NT_STATUS_IS_OK(status)) {
2621 /* Parse the reply. */
2622 if (outbuf.length != 24) {
2623 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2627 total_size = BVAL(outbuf.data, 0);
2628 size_free = BVAL(outbuf.data, 8);
2629 sectors_per_unit = IVAL(outbuf.data, 16);
2630 bytes_per_sector = IVAL(outbuf.data, 20);
2633 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2636 *total = total_size;
2642 status = NT_STATUS_OK;
2646 if (fnum != 0xffff) {
2647 cli_smb2_close_fnum(cli, fnum);
2650 cli->raw_status = status;
2656 /***************************************************************
2657 Wrapper that allows SMB2 to query file system sizes.
2659 ***************************************************************/
2661 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2662 uint64_t *total_allocation_units,
2663 uint64_t *caller_allocation_units,
2664 uint64_t *actual_allocation_units,
2665 uint64_t *sectors_per_allocation_unit,
2666 uint64_t *bytes_per_sector)
2669 uint16_t fnum = 0xffff;
2670 DATA_BLOB outbuf = data_blob_null;
2671 TALLOC_CTX *frame = talloc_stackframe();
2673 if (smbXcli_conn_has_async_calls(cli->conn)) {
2675 * Can't use sync call while an async call is in flight
2677 status = NT_STATUS_INVALID_PARAMETER;
2681 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2682 status = NT_STATUS_INVALID_PARAMETER;
2686 /* First open the top level directory. */
2688 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2689 SMB2_IMPERSONATION_IMPERSONATION,
2690 FILE_READ_ATTRIBUTES, /* desired_access */
2691 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2692 FILE_SHARE_READ | FILE_SHARE_WRITE |
2693 FILE_SHARE_DELETE, /* share_access */
2694 FILE_OPEN, /* create_disposition */
2695 FILE_DIRECTORY_FILE, /* create_options */
2702 if (!NT_STATUS_IS_OK(status)) {
2706 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2707 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2709 status = cli_smb2_query_info_fnum(
2712 SMB2_GETINFO_FS, /* in_info_type */
2713 SMB_FS_FULL_SIZE_INFORMATION - 1000, /* in_file_info_class */
2714 0xFFFF, /* in_max_output_length */
2715 NULL, /* in_input_buffer */
2716 0, /* in_additional_info */
2720 if (!NT_STATUS_IS_OK(status)) {
2724 if (outbuf.length < 32) {
2725 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2729 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2730 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2731 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2732 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2733 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2737 if (fnum != 0xffff) {
2738 cli_smb2_close_fnum(cli, fnum);
2741 cli->raw_status = status;
2747 /***************************************************************
2748 Wrapper that allows SMB2 to query file system attributes.
2750 ***************************************************************/
2752 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2755 uint16_t fnum = 0xffff;
2756 DATA_BLOB outbuf = data_blob_null;
2757 TALLOC_CTX *frame = talloc_stackframe();
2759 if (smbXcli_conn_has_async_calls(cli->conn)) {
2761 * Can't use sync call while an async call is in flight
2763 status = NT_STATUS_INVALID_PARAMETER;
2767 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2768 status = NT_STATUS_INVALID_PARAMETER;
2772 /* First open the top level directory. */
2774 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2775 SMB2_IMPERSONATION_IMPERSONATION,
2776 FILE_READ_ATTRIBUTES, /* desired_access */
2777 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2778 FILE_SHARE_READ | FILE_SHARE_WRITE |
2779 FILE_SHARE_DELETE, /* share_access */
2780 FILE_OPEN, /* create_disposition */
2781 FILE_DIRECTORY_FILE, /* create_options */
2788 if (!NT_STATUS_IS_OK(status)) {
2792 status = cli_smb2_query_info_fnum(
2795 2, /* in_info_type */
2796 5, /* in_file_info_class */
2797 0xFFFF, /* in_max_output_length */
2798 NULL, /* in_input_buffer */
2799 0, /* in_additional_info */
2803 if (!NT_STATUS_IS_OK(status)) {
2807 if (outbuf.length < 12) {
2808 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2812 *fs_attr = IVAL(outbuf.data, 0);
2816 if (fnum != 0xffff) {
2817 cli_smb2_close_fnum(cli, fnum);
2820 cli->raw_status = status;
2826 /***************************************************************
2827 Wrapper that allows SMB2 to query file system volume info.
2829 ***************************************************************/
2831 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2832 TALLOC_CTX *mem_ctx,
2833 char **_volume_name,
2834 uint32_t *pserial_number,
2838 uint16_t fnum = 0xffff;
2839 DATA_BLOB outbuf = data_blob_null;
2841 char *volume_name = NULL;
2842 TALLOC_CTX *frame = talloc_stackframe();
2844 if (smbXcli_conn_has_async_calls(cli->conn)) {
2846 * Can't use sync call while an async call is in flight
2848 status = NT_STATUS_INVALID_PARAMETER;
2852 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2853 status = NT_STATUS_INVALID_PARAMETER;
2857 /* First open the top level directory. */
2859 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2860 SMB2_IMPERSONATION_IMPERSONATION,
2861 FILE_READ_ATTRIBUTES, /* desired_access */
2862 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2863 FILE_SHARE_READ | FILE_SHARE_WRITE |
2864 FILE_SHARE_DELETE, /* share_access */
2865 FILE_OPEN, /* create_disposition */
2866 FILE_DIRECTORY_FILE, /* create_options */
2873 if (!NT_STATUS_IS_OK(status)) {
2877 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2878 level 1 (SMB_FS_VOLUME_INFORMATION). */
2880 status = cli_smb2_query_info_fnum(
2883 SMB2_GETINFO_FS, /* in_info_type */
2884 /* in_file_info_class */
2885 SMB_FS_VOLUME_INFORMATION - 1000,
2886 0xFFFF, /* in_max_output_length */
2887 NULL, /* in_input_buffer */
2888 0, /* in_additional_info */
2892 if (!NT_STATUS_IS_OK(status)) {
2896 if (outbuf.length < 24) {
2897 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2903 ts = interpret_long_date((char *)outbuf.data);
2906 if (pserial_number) {
2907 *pserial_number = IVAL(outbuf.data,8);
2909 nlen = IVAL(outbuf.data,12);
2910 if (nlen + 18 < 18) {
2912 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2916 * The next check is safe as we know outbuf.length >= 24
2919 if (nlen > (outbuf.length - 18)) {
2920 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2924 clistr_pull_talloc(mem_ctx,
2925 (const char *)outbuf.data,
2931 if (volume_name == NULL) {
2932 status = map_nt_error_from_unix(errno);
2936 *_volume_name = volume_name;
2940 if (fnum != 0xffff) {
2941 cli_smb2_close_fnum(cli, fnum);
2944 cli->raw_status = status;
2951 /***************************************************************
2952 Wrapper that allows SMB2 to query a security descriptor.
2954 ***************************************************************/
2956 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2959 TALLOC_CTX *mem_ctx,
2960 struct security_descriptor **ppsd)
2963 DATA_BLOB outbuf = data_blob_null;
2964 struct security_descriptor *lsd = NULL;
2965 TALLOC_CTX *frame = talloc_stackframe();
2967 if (smbXcli_conn_has_async_calls(cli->conn)) {
2969 * Can't use sync call while an async call is in flight
2971 status = NT_STATUS_INVALID_PARAMETER;
2975 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2976 status = NT_STATUS_INVALID_PARAMETER;
2980 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2982 status = cli_smb2_query_info_fnum(
2985 3, /* in_info_type */
2986 0, /* in_file_info_class */
2987 0xFFFF, /* in_max_output_length */
2988 NULL, /* in_input_buffer */
2989 sec_info, /* in_additional_info */
2994 if (!NT_STATUS_IS_OK(status)) {
2998 /* Parse the reply. */
2999 status = unmarshall_sec_desc(mem_ctx,
3004 if (!NT_STATUS_IS_OK(status)) {
3016 cli->raw_status = status;
3022 /***************************************************************
3023 Wrapper that allows SMB2 to set a security descriptor.
3025 ***************************************************************/
3027 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
3030 const struct security_descriptor *sd)
3033 DATA_BLOB inbuf = data_blob_null;
3034 struct smb2_hnd *ph = NULL;
3035 TALLOC_CTX *frame = talloc_stackframe();
3037 if (smbXcli_conn_has_async_calls(cli->conn)) {
3039 * Can't use sync call while an async call is in flight
3041 status = NT_STATUS_INVALID_PARAMETER;
3045 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3046 status = NT_STATUS_INVALID_PARAMETER;
3050 status = map_fnum_to_smb2_handle(cli,
3053 if (!NT_STATUS_IS_OK(status)) {
3057 status = marshall_sec_desc(frame,
3062 if (!NT_STATUS_IS_OK(status)) {
3066 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
3068 status = smb2cli_set_info(cli->conn,
3072 3, /* in_info_type */
3073 0, /* in_file_info_class */
3074 &inbuf, /* in_input_buffer */
3075 sec_info, /* in_additional_info */
3081 cli->raw_status = status;
3087 /***************************************************************
3088 Wrapper that allows SMB2 to query a security descriptor.
3091 ***************************************************************/
3093 struct cli_smb2_mxac_state {
3094 struct tevent_context *ev;
3095 struct cli_state *cli;
3097 struct smb2_create_blobs in_cblobs;
3103 static void cli_smb2_mxac_opened(struct tevent_req *subreq);
3104 static void cli_smb2_mxac_closed(struct tevent_req *subreq);
3106 struct tevent_req *cli_smb2_query_mxac_send(TALLOC_CTX *mem_ctx,
3107 struct tevent_context *ev,
3108 struct cli_state *cli,
3111 struct tevent_req *req = NULL, *subreq = NULL;
3112 struct cli_smb2_mxac_state *state = NULL;
3115 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_mxac_state);
3119 *state = (struct cli_smb2_mxac_state) {
3122 state->fname = fname,
3125 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3126 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3127 return tevent_req_post(req, ev);
3130 status = smb2_create_blob_add(state,
3132 SMB2_CREATE_TAG_MXAC,
3133 data_blob(NULL, 0));
3134 if (tevent_req_nterror(req, status)) {
3135 return tevent_req_post(req, ev);
3138 subreq = cli_smb2_create_fnum_send(
3143 0, /* create_flags */
3144 SMB2_IMPERSONATION_IMPERSONATION,
3145 FILE_READ_ATTRIBUTES,
3146 0, /* file attributes */
3147 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
3149 0, /* create_options */
3151 if (tevent_req_nomem(subreq, req)) {
3152 return tevent_req_post(req, ev);
3154 tevent_req_set_callback(subreq, cli_smb2_mxac_opened, req);
3158 static void cli_smb2_mxac_opened(struct tevent_req *subreq)
3160 struct tevent_req *req = tevent_req_callback_data(
3161 subreq, struct tevent_req);
3162 struct cli_smb2_mxac_state *state = tevent_req_data(
3163 req, struct cli_smb2_mxac_state);
3164 struct smb2_create_blobs out_cblobs = {0};
3165 struct smb2_create_blob *mxac_blob = NULL;
3168 status = cli_smb2_create_fnum_recv(
3169 subreq, &state->fnum, NULL, state, &out_cblobs);
3170 TALLOC_FREE(subreq);
3172 if (tevent_req_nterror(req, status)) {
3176 mxac_blob = smb2_create_blob_find(&out_cblobs, SMB2_CREATE_TAG_MXAC);
3177 if (mxac_blob == NULL) {
3178 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3181 if (mxac_blob->data.length != 8) {
3182 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3186 state->status = NT_STATUS(IVAL(mxac_blob->data.data, 0));
3187 state->mxac = IVAL(mxac_blob->data.data, 4);
3190 subreq = cli_smb2_close_fnum_send(
3191 state, state->ev, state->cli, state->fnum);
3192 if (tevent_req_nomem(subreq, req)) {
3195 tevent_req_set_callback(subreq, cli_smb2_mxac_closed, req);
3200 static void cli_smb2_mxac_closed(struct tevent_req *subreq)
3202 struct tevent_req *req = tevent_req_callback_data(
3203 subreq, struct tevent_req);
3206 status = cli_smb2_close_fnum_recv(subreq);
3207 if (tevent_req_nterror(req, status)) {
3211 tevent_req_done(req);
3214 NTSTATUS cli_smb2_query_mxac_recv(struct tevent_req *req, uint32_t *mxac)
3216 struct cli_smb2_mxac_state *state = tevent_req_data(
3217 req, struct cli_smb2_mxac_state);
3220 if (tevent_req_is_nterror(req, &status)) {
3224 if (!NT_STATUS_IS_OK(state->status)) {
3225 return state->status;
3228 *mxac = state->mxac;
3229 return NT_STATUS_OK;
3232 NTSTATUS cli_smb2_query_mxac(struct cli_state *cli,
3236 TALLOC_CTX *frame = talloc_stackframe();
3237 struct tevent_context *ev = NULL;
3238 struct tevent_req *req = NULL;
3239 NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
3242 if (smbXcli_conn_has_async_calls(cli->conn)) {
3244 * Can't use sync call while an async call is in flight
3246 status = NT_STATUS_INVALID_PARAMETER;
3250 ev = samba_tevent_context_init(frame);
3254 req = cli_smb2_query_mxac_send(frame, ev, cli, fname);
3258 ok = tevent_req_poll_ntstatus(req, ev, &status);
3262 status = cli_smb2_query_mxac_recv(req, _mxac);
3265 cli->raw_status = status;
3270 /***************************************************************
3271 Wrapper that allows SMB2 to rename a file.
3273 ***************************************************************/
3275 NTSTATUS cli_smb2_rename(struct cli_state *cli,
3276 const char *fname_src,
3277 const char *fname_dst,
3281 DATA_BLOB inbuf = data_blob_null;
3282 uint16_t fnum = 0xffff;
3283 struct smb2_hnd *ph = NULL;
3284 smb_ucs2_t *converted_str = NULL;
3285 size_t converted_size_bytes = 0;
3287 TALLOC_CTX *frame = talloc_stackframe();
3289 if (smbXcli_conn_has_async_calls(cli->conn)) {
3291 * Can't use sync call while an async call is in flight
3293 status = NT_STATUS_INVALID_PARAMETER;
3297 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3298 status = NT_STATUS_INVALID_PARAMETER;
3302 status = get_fnum_from_path(cli,
3307 if (!NT_STATUS_IS_OK(status)) {
3311 status = map_fnum_to_smb2_handle(cli,
3314 if (!NT_STATUS_IS_OK(status)) {
3318 /* SMB2 is pickier about pathnames. Ensure it doesn't
3320 if (*fname_dst == '\\') {
3324 /* SMB2 is pickier about pathnames. Ensure it doesn't
3326 namelen = strlen(fname_dst);
3327 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
3328 char *modname = talloc_strdup(frame, fname_dst);
3329 modname[namelen-1] = '\0';
3330 fname_dst = modname;
3333 if (!push_ucs2_talloc(frame,
3336 &converted_size_bytes)) {
3337 status = NT_STATUS_INVALID_PARAMETER;
3341 /* W2K8 insists the dest name is not null
3342 terminated. Remove the last 2 zero bytes
3343 and reduce the name length. */
3345 if (converted_size_bytes < 2) {
3346 status = NT_STATUS_INVALID_PARAMETER;
3349 converted_size_bytes -= 2;
3351 inbuf = data_blob_talloc_zero(frame,
3352 20 + converted_size_bytes);
3353 if (inbuf.data == NULL) {
3354 status = NT_STATUS_NO_MEMORY;
3359 SCVAL(inbuf.data, 0, 1);
3362 SIVAL(inbuf.data, 16, converted_size_bytes);
3363 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
3365 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3366 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3368 status = smb2cli_set_info(cli->conn,
3372 1, /* in_info_type */
3373 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
3374 &inbuf, /* in_input_buffer */
3375 0, /* in_additional_info */
3381 if (fnum != 0xffff) {
3382 cli_smb2_close_fnum(cli, fnum);
3385 cli->raw_status = status;
3391 /***************************************************************
3392 Wrapper that allows SMB2 to set an EA on a fnum.
3394 ***************************************************************/
3396 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
3398 const char *ea_name,
3403 DATA_BLOB inbuf = data_blob_null;
3405 char *ea_name_ascii = NULL;
3407 struct smb2_hnd *ph = NULL;
3408 TALLOC_CTX *frame = talloc_stackframe();
3410 if (smbXcli_conn_has_async_calls(cli->conn)) {
3412 * Can't use sync call while an async call is in flight
3414 status = NT_STATUS_INVALID_PARAMETER;
3418 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3419 status = NT_STATUS_INVALID_PARAMETER;
3423 status = map_fnum_to_smb2_handle(cli,
3426 if (!NT_STATUS_IS_OK(status)) {
3430 /* Marshall the SMB2 EA data. */
3431 if (ea_len > 0xFFFF) {
3432 status = NT_STATUS_INVALID_PARAMETER;
3436 if (!push_ascii_talloc(frame,
3440 status = NT_STATUS_INVALID_PARAMETER;
3444 if (namelen < 2 || namelen > 0xFF) {
3445 status = NT_STATUS_INVALID_PARAMETER;
3449 bloblen = 8 + ea_len + namelen;
3450 /* Round up to a 4 byte boundary. */
3451 bloblen = ((bloblen + 3)&~3);
3453 inbuf = data_blob_talloc_zero(frame, bloblen);
3454 if (inbuf.data == NULL) {
3455 status = NT_STATUS_NO_MEMORY;
3458 /* namelen doesn't include the NULL byte. */
3459 SCVAL(inbuf.data, 5, namelen - 1);
3460 SSVAL(inbuf.data, 6, ea_len);
3461 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
3462 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
3464 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3465 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3467 status = smb2cli_set_info(cli->conn,
3471 1, /* in_info_type */
3472 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3473 &inbuf, /* in_input_buffer */
3474 0, /* in_additional_info */
3480 cli->raw_status = status;
3486 /***************************************************************
3487 Wrapper that allows SMB2 to set an EA on a pathname.
3489 ***************************************************************/
3491 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
3493 const char *ea_name,
3498 uint16_t fnum = 0xffff;
3500 if (smbXcli_conn_has_async_calls(cli->conn)) {
3502 * Can't use sync call while an async call is in flight
3504 status = NT_STATUS_INVALID_PARAMETER;
3508 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3509 status = NT_STATUS_INVALID_PARAMETER;
3513 status = get_fnum_from_path(cli,
3518 if (!NT_STATUS_IS_OK(status)) {
3522 status = cli_set_ea_fnum(cli,
3527 if (!NT_STATUS_IS_OK(status)) {
3533 if (fnum != 0xffff) {
3534 cli_smb2_close_fnum(cli, fnum);
3537 cli->raw_status = status;
3542 /***************************************************************
3543 Wrapper that allows SMB2 to get an EA list on a pathname.
3545 ***************************************************************/
3547 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
3551 struct ea_struct **pea_array)
3554 uint16_t fnum = 0xffff;
3555 DATA_BLOB outbuf = data_blob_null;
3556 struct ea_list *ea_list = NULL;
3557 struct ea_list *eal = NULL;
3558 size_t ea_count = 0;
3559 TALLOC_CTX *frame = talloc_stackframe();
3564 if (smbXcli_conn_has_async_calls(cli->conn)) {
3566 * Can't use sync call while an async call is in flight
3568 status = NT_STATUS_INVALID_PARAMETER;
3572 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3573 status = NT_STATUS_INVALID_PARAMETER;
3577 status = get_fnum_from_path(cli,
3582 if (!NT_STATUS_IS_OK(status)) {
3586 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3587 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3589 status = cli_smb2_query_info_fnum(
3592 1, /* in_info_type */
3593 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3594 0xFFFF, /* in_max_output_length */
3595 NULL, /* in_input_buffer */
3596 0, /* in_additional_info */
3601 if (!NT_STATUS_IS_OK(status)) {
3605 /* Parse the reply. */
3606 ea_list = read_nttrans_ea_list(ctx,
3607 (const char *)outbuf.data,
3609 if (ea_list == NULL) {
3610 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3614 /* Convert to an array. */
3615 for (eal = ea_list; eal; eal = eal->next) {
3620 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
3621 if (*pea_array == NULL) {
3622 status = NT_STATUS_NO_MEMORY;
3626 for (eal = ea_list; eal; eal = eal->next) {
3627 (*pea_array)[ea_count++] = eal->ea;
3629 *pnum_eas = ea_count;
3634 if (fnum != 0xffff) {
3635 cli_smb2_close_fnum(cli, fnum);
3638 cli->raw_status = status;
3644 /***************************************************************
3645 Wrapper that allows SMB2 to get user quota.
3647 ***************************************************************/
3649 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
3651 SMB_NTQUOTA_STRUCT *pqt)
3654 DATA_BLOB inbuf = data_blob_null;
3655 DATA_BLOB info_blob = data_blob_null;
3656 DATA_BLOB outbuf = data_blob_null;
3657 TALLOC_CTX *frame = talloc_stackframe();
3659 unsigned int offset;
3660 struct smb2_query_quota_info query = {0};
3661 struct file_get_quota_info info = {0};
3662 enum ndr_err_code err;
3663 struct ndr_push *ndr_push = NULL;
3665 if (smbXcli_conn_has_async_calls(cli->conn)) {
3667 * Can't use sync call while an async call is in flight
3669 status = NT_STATUS_INVALID_PARAMETER;
3673 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3674 status = NT_STATUS_INVALID_PARAMETER;
3678 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
3680 query.return_single = 1;
3682 info.next_entry_offset = 0;
3683 info.sid_length = sid_len;
3684 info.sid = pqt->sid;
3686 err = ndr_push_struct_blob(
3690 (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
3692 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3693 status = NT_STATUS_INTERNAL_ERROR;
3697 query.sid_list_length = info_blob.length;
3698 ndr_push = ndr_push_init_ctx(frame);
3700 status = NT_STATUS_NO_MEMORY;
3704 err = ndr_push_smb2_query_quota_info(ndr_push,
3705 NDR_SCALARS | NDR_BUFFERS,
3708 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3709 status = NT_STATUS_INTERNAL_ERROR;
3713 err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3716 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3717 status = NT_STATUS_INTERNAL_ERROR;
3720 inbuf.data = ndr_push->data;
3721 inbuf.length = ndr_push->offset;
3723 status = cli_smb2_query_info_fnum(
3726 4, /* in_info_type */
3727 0, /* in_file_info_class */
3728 0xFFFF, /* in_max_output_length */
3729 &inbuf, /* in_input_buffer */
3730 0, /* in_additional_info */
3735 if (!NT_STATUS_IS_OK(status)) {
3739 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3741 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3742 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3746 cli->raw_status = status;
3752 /***************************************************************
3753 Wrapper that allows SMB2 to list user quota.
3755 ***************************************************************/
3757 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3758 TALLOC_CTX *mem_ctx,
3760 SMB_NTQUOTA_LIST **pqt_list,
3764 DATA_BLOB inbuf = data_blob_null;
3765 DATA_BLOB outbuf = data_blob_null;
3766 TALLOC_CTX *frame = talloc_stackframe();
3767 struct smb2_query_quota_info info = {0};
3768 enum ndr_err_code err;
3770 if (smbXcli_conn_has_async_calls(cli->conn)) {
3772 * Can't use sync call while an async call is in flight
3774 status = NT_STATUS_INVALID_PARAMETER;
3778 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3779 status = NT_STATUS_INVALID_PARAMETER;
3783 info.restart_scan = first ? 1 : 0;
3785 err = ndr_push_struct_blob(
3789 (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3791 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3792 status = NT_STATUS_INTERNAL_ERROR;
3796 status = cli_smb2_query_info_fnum(
3799 4, /* in_info_type */
3800 0, /* in_file_info_class */
3801 0xFFFF, /* in_max_output_length */
3802 &inbuf, /* in_input_buffer */
3803 0, /* in_additional_info */
3809 * safeguard against panic from calling parse_user_quota_list with
3812 if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3813 status = NT_STATUS_NO_MORE_ENTRIES;
3816 if (!NT_STATUS_IS_OK(status)) {
3820 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3824 cli->raw_status = status;
3830 /***************************************************************
3831 Wrapper that allows SMB2 to get file system quota.
3833 ***************************************************************/
3835 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3837 SMB_NTQUOTA_STRUCT *pqt)
3840 DATA_BLOB outbuf = data_blob_null;
3841 TALLOC_CTX *frame = talloc_stackframe();
3843 if (smbXcli_conn_has_async_calls(cli->conn)) {
3845 * Can't use sync call while an async call is in flight
3847 status = NT_STATUS_INVALID_PARAMETER;
3851 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3852 status = NT_STATUS_INVALID_PARAMETER;
3856 status = cli_smb2_query_info_fnum(
3859 2, /* in_info_type */
3860 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3861 0xFFFF, /* in_max_output_length */
3862 NULL, /* in_input_buffer */
3863 0, /* in_additional_info */
3868 if (!NT_STATUS_IS_OK(status)) {
3872 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3875 cli->raw_status = status;
3881 /***************************************************************
3882 Wrapper that allows SMB2 to set user quota.
3884 ***************************************************************/
3886 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3888 SMB_NTQUOTA_LIST *qtl)
3891 DATA_BLOB inbuf = data_blob_null;
3892 struct smb2_hnd *ph = NULL;
3893 TALLOC_CTX *frame = talloc_stackframe();
3895 if (smbXcli_conn_has_async_calls(cli->conn)) {
3897 * Can't use sync call while an async call is in flight
3899 status = NT_STATUS_INVALID_PARAMETER;
3903 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3904 status = NT_STATUS_INVALID_PARAMETER;
3908 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3909 if (!NT_STATUS_IS_OK(status)) {
3913 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3914 if (!NT_STATUS_IS_OK(status)) {
3918 status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
3919 cli->smb2.tcon, 4, /* in_info_type */
3920 0, /* in_file_info_class */
3921 &inbuf, /* in_input_buffer */
3922 0, /* in_additional_info */
3923 ph->fid_persistent, ph->fid_volatile);
3926 cli->raw_status = status;
3933 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3935 SMB_NTQUOTA_STRUCT *pqt)
3938 DATA_BLOB inbuf = data_blob_null;
3939 struct smb2_hnd *ph = NULL;
3940 TALLOC_CTX *frame = talloc_stackframe();
3942 if (smbXcli_conn_has_async_calls(cli->conn)) {
3944 * Can't use sync call while an async call is in flight
3946 status = NT_STATUS_INVALID_PARAMETER;
3950 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3951 status = NT_STATUS_INVALID_PARAMETER;
3955 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3956 if (!NT_STATUS_IS_OK(status)) {
3960 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3961 if (!NT_STATUS_IS_OK(status)) {
3965 status = smb2cli_set_info(
3966 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3967 2, /* in_info_type */
3968 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3969 &inbuf, /* in_input_buffer */
3970 0, /* in_additional_info */
3971 ph->fid_persistent, ph->fid_volatile);
3973 cli->raw_status = status;
3979 struct cli_smb2_read_state {
3980 struct tevent_context *ev;
3981 struct cli_state *cli;
3982 struct smb2_hnd *ph;
3983 uint64_t start_offset;
3989 static void cli_smb2_read_done(struct tevent_req *subreq);
3991 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3992 struct tevent_context *ev,
3993 struct cli_state *cli,
3999 struct tevent_req *req, *subreq;
4000 struct cli_smb2_read_state *state;
4002 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
4008 state->start_offset = (uint64_t)offset;
4009 state->size = (uint32_t)size;
4010 state->received = 0;
4013 status = map_fnum_to_smb2_handle(cli,
4016 if (tevent_req_nterror(req, status)) {
4017 return tevent_req_post(req, ev);
4020 subreq = smb2cli_read_send(state,
4023 state->cli->timeout,
4024 state->cli->smb2.session,
4025 state->cli->smb2.tcon,
4027 state->start_offset,
4028 state->ph->fid_persistent,
4029 state->ph->fid_volatile,
4030 0, /* minimum_count */
4031 0); /* remaining_bytes */
4033 if (tevent_req_nomem(subreq, req)) {
4034 return tevent_req_post(req, ev);
4036 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
4040 static void cli_smb2_read_done(struct tevent_req *subreq)
4042 struct tevent_req *req = tevent_req_callback_data(
4043 subreq, struct tevent_req);
4044 struct cli_smb2_read_state *state = tevent_req_data(
4045 req, struct cli_smb2_read_state);
4048 status = smb2cli_read_recv(subreq, state,
4049 &state->buf, &state->received);
4050 if (tevent_req_nterror(req, status)) {
4054 if (state->received > state->size) {
4055 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4059 tevent_req_done(req);
4062 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
4067 struct cli_smb2_read_state *state = tevent_req_data(
4068 req, struct cli_smb2_read_state);
4070 if (tevent_req_is_nterror(req, &status)) {
4071 state->cli->raw_status = status;
4075 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
4076 * better make sure that you copy it away before you talloc_free(req).
4077 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
4079 *received = (ssize_t)state->received;
4080 *rcvbuf = state->buf;
4081 state->cli->raw_status = NT_STATUS_OK;
4082 return NT_STATUS_OK;
4085 struct cli_smb2_write_state {
4086 struct tevent_context *ev;
4087 struct cli_state *cli;
4088 struct smb2_hnd *ph;
4096 static void cli_smb2_write_written(struct tevent_req *req);
4098 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
4099 struct tevent_context *ev,
4100 struct cli_state *cli,
4108 struct tevent_req *req, *subreq = NULL;
4109 struct cli_smb2_write_state *state = NULL;
4111 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
4117 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4118 state->flags = (uint32_t)mode;
4120 state->offset = (uint64_t)offset;
4121 state->size = (uint32_t)size;
4124 status = map_fnum_to_smb2_handle(cli,
4127 if (tevent_req_nterror(req, status)) {
4128 return tevent_req_post(req, ev);
4131 subreq = smb2cli_write_send(state,
4134 state->cli->timeout,
4135 state->cli->smb2.session,
4136 state->cli->smb2.tcon,
4139 state->ph->fid_persistent,
4140 state->ph->fid_volatile,
4141 0, /* remaining_bytes */
4142 state->flags, /* flags */
4145 if (tevent_req_nomem(subreq, req)) {
4146 return tevent_req_post(req, ev);
4148 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
4152 static void cli_smb2_write_written(struct tevent_req *subreq)
4154 struct tevent_req *req = tevent_req_callback_data(
4155 subreq, struct tevent_req);
4156 struct cli_smb2_write_state *state = tevent_req_data(
4157 req, struct cli_smb2_write_state);
4161 status = smb2cli_write_recv(subreq, &written);
4162 TALLOC_FREE(subreq);
4163 if (tevent_req_nterror(req, status)) {
4167 state->written = written;
4169 tevent_req_done(req);
4172 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
4175 struct cli_smb2_write_state *state = tevent_req_data(
4176 req, struct cli_smb2_write_state);
4179 if (tevent_req_is_nterror(req, &status)) {
4180 state->cli->raw_status = status;
4181 tevent_req_received(req);
4185 if (pwritten != NULL) {
4186 *pwritten = (size_t)state->written;
4188 state->cli->raw_status = NT_STATUS_OK;
4189 tevent_req_received(req);
4190 return NT_STATUS_OK;
4193 /***************************************************************
4194 Wrapper that allows SMB2 async write using an fnum.
4195 This is mostly cut-and-paste from Volker's code inside
4196 source3/libsmb/clireadwrite.c, adapted for SMB2.
4198 Done this way so I can reuse all the logic inside cli_push()
4200 ***************************************************************/
4202 struct cli_smb2_writeall_state {
4203 struct tevent_context *ev;
4204 struct cli_state *cli;
4205 struct smb2_hnd *ph;
4213 static void cli_smb2_writeall_written(struct tevent_req *req);
4215 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
4216 struct tevent_context *ev,
4217 struct cli_state *cli,
4225 struct tevent_req *req, *subreq = NULL;
4226 struct cli_smb2_writeall_state *state = NULL;
4231 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
4237 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4238 state->flags = (uint32_t)mode;
4240 state->offset = (uint64_t)offset;
4241 state->size = (uint32_t)size;
4244 status = map_fnum_to_smb2_handle(cli,
4247 if (tevent_req_nterror(req, status)) {
4248 return tevent_req_post(req, ev);
4251 to_write = state->size;
4252 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4253 to_write = MIN(max_size, to_write);
4254 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4256 to_write = MIN(max_size, to_write);
4259 subreq = smb2cli_write_send(state,
4262 state->cli->timeout,
4263 state->cli->smb2.session,
4264 state->cli->smb2.tcon,
4267 state->ph->fid_persistent,
4268 state->ph->fid_volatile,
4269 0, /* remaining_bytes */
4270 state->flags, /* flags */
4271 state->buf + state->written);
4273 if (tevent_req_nomem(subreq, req)) {
4274 return tevent_req_post(req, ev);
4276 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4280 static void cli_smb2_writeall_written(struct tevent_req *subreq)
4282 struct tevent_req *req = tevent_req_callback_data(
4283 subreq, struct tevent_req);
4284 struct cli_smb2_writeall_state *state = tevent_req_data(
4285 req, struct cli_smb2_writeall_state);
4287 uint32_t written, to_write;
4291 status = smb2cli_write_recv(subreq, &written);
4292 TALLOC_FREE(subreq);
4293 if (tevent_req_nterror(req, status)) {
4297 state->written += written;
4299 if (state->written > state->size) {
4300 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4304 to_write = state->size - state->written;
4306 if (to_write == 0) {
4307 tevent_req_done(req);
4311 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4312 to_write = MIN(max_size, to_write);
4313 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4315 to_write = MIN(max_size, to_write);
4318 subreq = smb2cli_write_send(state,
4321 state->cli->timeout,
4322 state->cli->smb2.session,
4323 state->cli->smb2.tcon,
4325 state->offset + state->written,
4326 state->ph->fid_persistent,
4327 state->ph->fid_volatile,
4328 0, /* remaining_bytes */
4329 state->flags, /* flags */
4330 state->buf + state->written);
4332 if (tevent_req_nomem(subreq, req)) {
4335 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4338 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
4341 struct cli_smb2_writeall_state *state = tevent_req_data(
4342 req, struct cli_smb2_writeall_state);
4345 if (tevent_req_is_nterror(req, &status)) {
4346 state->cli->raw_status = status;
4349 if (pwritten != NULL) {
4350 *pwritten = (size_t)state->written;
4352 state->cli->raw_status = NT_STATUS_OK;
4353 return NT_STATUS_OK;
4356 struct cli_smb2_splice_state {
4357 struct tevent_context *ev;
4358 struct cli_state *cli;
4359 struct smb2_hnd *src_ph;
4360 struct smb2_hnd *dst_ph;
4361 int (*splice_cb)(off_t n, void *priv);
4368 struct req_resume_key_rsp resume_rsp;
4369 struct srv_copychunk_copy cc_copy;
4372 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4373 struct tevent_req *req);
4375 static void cli_splice_copychunk_done(struct tevent_req *subreq)
4377 struct tevent_req *req = tevent_req_callback_data(
4378 subreq, struct tevent_req);
4379 struct cli_smb2_splice_state *state =
4380 tevent_req_data(req,
4381 struct cli_smb2_splice_state);
4382 struct smbXcli_conn *conn = state->cli->conn;
4383 DATA_BLOB out_input_buffer = data_blob_null;
4384 DATA_BLOB out_output_buffer = data_blob_null;
4385 struct srv_copychunk_rsp cc_copy_rsp;
4386 enum ndr_err_code ndr_ret;
4389 status = smb2cli_ioctl_recv(subreq, state,
4391 &out_output_buffer);
4392 TALLOC_FREE(subreq);
4393 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
4394 state->resized) && tevent_req_nterror(req, status)) {
4398 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
4399 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
4400 if (ndr_ret != NDR_ERR_SUCCESS) {
4401 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4402 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4406 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
4407 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
4408 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
4409 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
4410 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
4411 tevent_req_nterror(req, status)) {
4415 state->resized = true;
4416 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
4417 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
4419 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4420 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4421 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
4422 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4425 state->src_offset += cc_copy_rsp.total_bytes_written;
4426 state->dst_offset += cc_copy_rsp.total_bytes_written;
4427 state->written += cc_copy_rsp.total_bytes_written;
4428 if (!state->splice_cb(state->written, state->priv)) {
4429 tevent_req_nterror(req, NT_STATUS_CANCELLED);
4434 cli_splice_copychunk_send(state, req);
4437 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4438 struct tevent_req *req)
4440 struct tevent_req *subreq;
4441 enum ndr_err_code ndr_ret;
4442 struct smbXcli_conn *conn = state->cli->conn;
4443 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
4444 off_t src_offset = state->src_offset;
4445 off_t dst_offset = state->dst_offset;
4446 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
4447 state->size - state->written);
4448 DATA_BLOB in_input_buffer = data_blob_null;
4449 DATA_BLOB in_output_buffer = data_blob_null;
4451 if (state->size - state->written == 0) {
4452 tevent_req_done(req);
4456 cc_copy->chunk_count = 0;
4458 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
4459 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
4460 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
4461 smb2cli_conn_cc_chunk_len(conn));
4462 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
4463 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4466 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
4467 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
4468 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
4469 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4472 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4473 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4474 cc_copy->chunk_count++;
4477 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
4478 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
4479 if (ndr_ret != NDR_ERR_SUCCESS) {
4480 DEBUG(0, ("failed to marshall copy chunk req\n"));
4481 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4485 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
4486 state->cli->timeout,
4487 state->cli->smb2.session,
4488 state->cli->smb2.tcon,
4489 state->dst_ph->fid_persistent, /* in_fid_persistent */
4490 state->dst_ph->fid_volatile, /* in_fid_volatile */
4491 FSCTL_SRV_COPYCHUNK_WRITE,
4492 0, /* in_max_input_length */
4494 12, /* in_max_output_length */
4496 SMB2_IOCTL_FLAG_IS_FSCTL);
4497 if (tevent_req_nomem(subreq, req)) {
4500 tevent_req_set_callback(subreq,
4501 cli_splice_copychunk_done,
4505 static void cli_splice_key_done(struct tevent_req *subreq)
4507 struct tevent_req *req = tevent_req_callback_data(
4508 subreq, struct tevent_req);
4509 struct cli_smb2_splice_state *state =
4510 tevent_req_data(req,
4511 struct cli_smb2_splice_state);
4512 enum ndr_err_code ndr_ret;
4515 DATA_BLOB out_input_buffer = data_blob_null;
4516 DATA_BLOB out_output_buffer = data_blob_null;
4518 status = smb2cli_ioctl_recv(subreq, state,
4520 &out_output_buffer);
4521 TALLOC_FREE(subreq);
4522 if (tevent_req_nterror(req, status)) {
4526 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
4527 state, &state->resume_rsp,
4528 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
4529 if (ndr_ret != NDR_ERR_SUCCESS) {
4530 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4531 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4535 memcpy(&state->cc_copy.source_key,
4536 &state->resume_rsp.resume_key,
4537 sizeof state->resume_rsp.resume_key);
4539 cli_splice_copychunk_send(state, req);
4542 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
4543 struct tevent_context *ev,
4544 struct cli_state *cli,
4545 uint16_t src_fnum, uint16_t dst_fnum,
4546 off_t size, off_t src_offset, off_t dst_offset,
4547 int (*splice_cb)(off_t n, void *priv),
4550 struct tevent_req *req;
4551 struct tevent_req *subreq;
4552 struct cli_smb2_splice_state *state;
4554 DATA_BLOB in_input_buffer = data_blob_null;
4555 DATA_BLOB in_output_buffer = data_blob_null;
4557 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
4563 state->splice_cb = splice_cb;
4567 state->src_offset = src_offset;
4568 state->dst_offset = dst_offset;
4569 state->cc_copy.chunks = talloc_array(state,
4570 struct srv_copychunk,
4571 smb2cli_conn_cc_max_chunks(cli->conn));
4572 if (state->cc_copy.chunks == NULL) {
4576 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
4577 if (tevent_req_nterror(req, status))
4578 return tevent_req_post(req, ev);
4580 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
4581 if (tevent_req_nterror(req, status))
4582 return tevent_req_post(req, ev);
4584 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
4588 state->src_ph->fid_persistent, /* in_fid_persistent */
4589 state->src_ph->fid_volatile, /* in_fid_volatile */
4590 FSCTL_SRV_REQUEST_RESUME_KEY,
4591 0, /* in_max_input_length */
4593 32, /* in_max_output_length */
4595 SMB2_IOCTL_FLAG_IS_FSCTL);
4596 if (tevent_req_nomem(subreq, req)) {
4599 tevent_req_set_callback(subreq,
4600 cli_splice_key_done,
4606 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
4608 struct cli_smb2_splice_state *state = tevent_req_data(
4609 req, struct cli_smb2_splice_state);
4612 if (tevent_req_is_nterror(req, &status)) {
4613 state->cli->raw_status = status;
4614 tevent_req_received(req);
4617 if (written != NULL) {
4618 *written = state->written;
4620 state->cli->raw_status = NT_STATUS_OK;
4621 tevent_req_received(req);
4622 return NT_STATUS_OK;
4625 /***************************************************************
4626 SMB2 enum shadow copy data.
4627 ***************************************************************/
4629 struct cli_smb2_shadow_copy_data_fnum_state {
4630 struct cli_state *cli;
4632 struct smb2_hnd *ph;
4633 DATA_BLOB out_input_buffer;
4634 DATA_BLOB out_output_buffer;
4637 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
4639 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
4640 TALLOC_CTX *mem_ctx,
4641 struct tevent_context *ev,
4642 struct cli_state *cli,
4646 struct tevent_req *req, *subreq;
4647 struct cli_smb2_shadow_copy_data_fnum_state *state;
4650 req = tevent_req_create(mem_ctx, &state,
4651 struct cli_smb2_shadow_copy_data_fnum_state);
4656 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4657 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4658 return tevent_req_post(req, ev);
4664 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4665 if (tevent_req_nterror(req, status)) {
4666 return tevent_req_post(req, ev);
4670 * TODO. Under SMB2 we should send a zero max_output_length
4671 * ioctl to get the required size, then send another ioctl
4672 * to get the data, but the current SMB1 implementation just
4673 * does one roundtrip with a 64K buffer size. Do the same
4677 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4678 state->cli->timeout,
4679 state->cli->smb2.session,
4680 state->cli->smb2.tcon,
4681 state->ph->fid_persistent, /* in_fid_persistent */
4682 state->ph->fid_volatile, /* in_fid_volatile */
4683 FSCTL_GET_SHADOW_COPY_DATA,
4684 0, /* in_max_input_length */
4685 NULL, /* in_input_buffer */
4687 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
4688 NULL, /* in_output_buffer */
4689 SMB2_IOCTL_FLAG_IS_FSCTL);
4691 if (tevent_req_nomem(subreq, req)) {
4692 return tevent_req_post(req, ev);
4694 tevent_req_set_callback(subreq,
4695 cli_smb2_shadow_copy_data_fnum_done,
4701 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4703 struct tevent_req *req = tevent_req_callback_data(
4704 subreq, struct tevent_req);
4705 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4706 req, struct cli_smb2_shadow_copy_data_fnum_state);
4709 status = smb2cli_ioctl_recv(subreq, state,
4710 &state->out_input_buffer,
4711 &state->out_output_buffer);
4712 tevent_req_simple_finish_ntstatus(subreq, status);
4715 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4716 TALLOC_CTX *mem_ctx,
4721 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4722 req, struct cli_smb2_shadow_copy_data_fnum_state);
4723 char **names = NULL;
4724 uint32_t num_names = 0;
4725 uint32_t num_names_returned = 0;
4726 uint32_t dlength = 0;
4728 uint8_t *endp = NULL;
4731 if (tevent_req_is_nterror(req, &status)) {
4735 if (state->out_output_buffer.length < 16) {
4736 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4739 num_names = IVAL(state->out_output_buffer.data, 0);
4740 num_names_returned = IVAL(state->out_output_buffer.data, 4);
4741 dlength = IVAL(state->out_output_buffer.data, 8);
4743 if (num_names > 0x7FFFFFFF) {
4744 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4747 if (get_names == false) {
4748 *pnum_names = (int)num_names;
4749 return NT_STATUS_OK;
4751 if (num_names != num_names_returned) {
4752 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4754 if (dlength + 12 < 12) {
4755 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4758 * NB. The below is an allowable return if there are
4759 * more snapshots than the buffer size we told the
4760 * server we can receive. We currently don't support
4763 if (dlength + 12 > state->out_output_buffer.length) {
4764 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4766 if (state->out_output_buffer.length +
4767 (2 * sizeof(SHADOW_COPY_LABEL)) <
4768 state->out_output_buffer.length) {
4769 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4772 names = talloc_array(mem_ctx, char *, num_names_returned);
4773 if (names == NULL) {
4774 return NT_STATUS_NO_MEMORY;
4777 endp = state->out_output_buffer.data +
4778 state->out_output_buffer.length;
4780 for (i=0; i<num_names_returned; i++) {
4783 size_t converted_size;
4785 src = state->out_output_buffer.data + 12 +
4786 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4788 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4789 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4791 ret = convert_string_talloc(
4792 names, CH_UTF16LE, CH_UNIX,
4793 src, 2 * sizeof(SHADOW_COPY_LABEL),
4794 &names[i], &converted_size);
4797 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4800 *pnum_names = num_names;
4802 return NT_STATUS_OK;
4805 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4806 struct cli_state *cli,
4812 TALLOC_CTX *frame = talloc_stackframe();
4813 struct tevent_context *ev;
4814 struct tevent_req *req;
4815 NTSTATUS status = NT_STATUS_NO_MEMORY;
4817 if (smbXcli_conn_has_async_calls(cli->conn)) {
4819 * Can't use sync call while an async call is in flight
4821 status = NT_STATUS_INVALID_PARAMETER;
4824 ev = samba_tevent_context_init(frame);
4828 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4836 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4839 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4845 cli->raw_status = status;
4851 /***************************************************************
4852 Wrapper that allows SMB2 to truncate a file.
4854 ***************************************************************/
4856 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4861 DATA_BLOB inbuf = data_blob_null;
4862 struct smb2_hnd *ph = NULL;
4863 TALLOC_CTX *frame = talloc_stackframe();
4865 if (smbXcli_conn_has_async_calls(cli->conn)) {
4867 * Can't use sync call while an async call is in flight
4869 status = NT_STATUS_INVALID_PARAMETER;
4873 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4874 status = NT_STATUS_INVALID_PARAMETER;
4878 status = map_fnum_to_smb2_handle(cli,
4881 if (!NT_STATUS_IS_OK(status)) {
4885 inbuf = data_blob_talloc_zero(frame, 8);
4886 if (inbuf.data == NULL) {
4887 status = NT_STATUS_NO_MEMORY;
4891 SBVAL(inbuf.data, 0, newsize);
4893 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4894 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4896 status = smb2cli_set_info(cli->conn,
4900 1, /* in_info_type */
4901 /* in_file_info_class */
4902 SMB_FILE_END_OF_FILE_INFORMATION - 1000,
4903 &inbuf, /* in_input_buffer */
4904 0, /* in_additional_info */
4910 cli->raw_status = status;
4916 struct cli_smb2_notify_state {
4917 struct tevent_req *subreq;
4918 struct notify_change *changes;
4922 static void cli_smb2_notify_done(struct tevent_req *subreq);
4923 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4925 struct tevent_req *cli_smb2_notify_send(
4926 TALLOC_CTX *mem_ctx,
4927 struct tevent_context *ev,
4928 struct cli_state *cli,
4930 uint32_t buffer_size,
4931 uint32_t completion_filter,
4934 struct tevent_req *req = NULL;
4935 struct cli_smb2_notify_state *state = NULL;
4936 struct smb2_hnd *ph = NULL;
4939 req = tevent_req_create(mem_ctx, &state,
4940 struct cli_smb2_notify_state);
4945 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4946 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4947 return tevent_req_post(req, ev);
4950 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4951 if (tevent_req_nterror(req, status)) {
4952 return tevent_req_post(req, ev);
4955 state->subreq = smb2cli_notify_send(
4967 if (tevent_req_nomem(state->subreq, req)) {
4968 return tevent_req_post(req, ev);
4970 tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4971 tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4975 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4977 struct cli_smb2_notify_state *state = tevent_req_data(
4978 req, struct cli_smb2_notify_state);
4981 ok = tevent_req_cancel(state->subreq);
4985 static void cli_smb2_notify_done(struct tevent_req *subreq)
4987 struct tevent_req *req = tevent_req_callback_data(
4988 subreq, struct tevent_req);
4989 struct cli_smb2_notify_state *state = tevent_req_data(
4990 req, struct cli_smb2_notify_state);
4996 status = smb2cli_notify_recv(subreq, state, &base, &len);
4997 TALLOC_FREE(subreq);
4999 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
5000 tevent_req_done(req);
5003 if (tevent_req_nterror(req, status)) {
5009 while (len - ofs >= 12) {
5010 struct notify_change *tmp;
5011 struct notify_change *c;
5012 uint32_t next_ofs = IVAL(base, ofs);
5013 uint32_t file_name_length = IVAL(base, ofs+8);
5017 tmp = talloc_realloc(
5020 struct notify_change,
5021 state->num_changes + 1);
5022 if (tevent_req_nomem(tmp, req)) {
5025 state->changes = tmp;
5026 c = &state->changes[state->num_changes];
5027 state->num_changes += 1;
5029 if (smb_buffer_oob(len, ofs, next_ofs) ||
5030 smb_buffer_oob(len, ofs+12, file_name_length)) {
5032 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
5036 c->action = IVAL(base, ofs+4);
5038 ok = convert_string_talloc(
5048 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
5052 if (next_ofs == 0) {
5058 tevent_req_done(req);
5061 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
5062 TALLOC_CTX *mem_ctx,
5063 struct notify_change **pchanges,
5064 uint32_t *pnum_changes)
5066 struct cli_smb2_notify_state *state = tevent_req_data(
5067 req, struct cli_smb2_notify_state);
5070 if (tevent_req_is_nterror(req, &status)) {
5073 *pchanges = talloc_move(mem_ctx, &state->changes);
5074 *pnum_changes = state->num_changes;
5075 return NT_STATUS_OK;
5078 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
5079 uint32_t buffer_size, uint32_t completion_filter,
5080 bool recursive, TALLOC_CTX *mem_ctx,
5081 struct notify_change **pchanges,
5082 uint32_t *pnum_changes)
5084 TALLOC_CTX *frame = talloc_stackframe();
5085 struct tevent_context *ev;
5086 struct tevent_req *req;
5087 NTSTATUS status = NT_STATUS_NO_MEMORY;
5089 if (smbXcli_conn_has_async_calls(cli->conn)) {
5091 * Can't use sync call while an async call is in flight
5093 status = NT_STATUS_INVALID_PARAMETER;
5096 ev = samba_tevent_context_init(frame);
5100 req = cli_smb2_notify_send(
5111 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5114 status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
5120 struct cli_smb2_set_reparse_point_fnum_state {
5121 struct cli_state *cli;
5123 struct smb2_hnd *ph;
5124 DATA_BLOB input_buffer;
5127 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
5129 struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
5130 TALLOC_CTX *mem_ctx,
5131 struct tevent_context *ev,
5132 struct cli_state *cli,
5136 struct tevent_req *req, *subreq;
5137 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
5140 req = tevent_req_create(mem_ctx, &state,
5141 struct cli_smb2_set_reparse_point_fnum_state);
5146 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5147 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
5148 return tevent_req_post(req, ev);
5154 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
5155 if (tevent_req_nterror(req, status)) {
5156 return tevent_req_post(req, ev);
5159 state->input_buffer = data_blob_talloc(state,
5162 if (state->input_buffer.data == NULL) {
5163 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
5164 return tevent_req_post(req, ev);
5167 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
5168 state->cli->timeout,
5169 state->cli->smb2.session,
5170 state->cli->smb2.tcon,
5171 state->ph->fid_persistent, /* in_fid_persistent */
5172 state->ph->fid_volatile, /* in_fid_volatile */
5173 FSCTL_SET_REPARSE_POINT,
5174 0, /* in_max_input_length */
5175 &state->input_buffer ,
5178 SMB2_IOCTL_FLAG_IS_FSCTL);
5180 if (tevent_req_nomem(subreq, req)) {
5181 return tevent_req_post(req, ev);
5183 tevent_req_set_callback(subreq,
5184 cli_smb2_set_reparse_point_fnum_done,
5190 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
5192 struct tevent_req *req = tevent_req_callback_data(
5193 subreq, struct tevent_req);
5194 struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
5195 req, struct cli_smb2_set_reparse_point_fnum_state);
5198 status = smb2cli_ioctl_recv(subreq, state,
5201 TALLOC_FREE(subreq);
5202 if (tevent_req_nterror(req, status)) {
5205 tevent_req_done(req);
5208 NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
5210 return tevent_req_simple_recv_ntstatus(req);
5213 struct cli_smb2_get_reparse_point_fnum_state {
5214 struct cli_state *cli;
5216 struct smb2_hnd *ph;
5217 DATA_BLOB output_buffer;
5220 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
5222 struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
5223 TALLOC_CTX *mem_ctx,
5224 struct tevent_context *ev,
5225 struct cli_state *cli,
5228 struct tevent_req *req, *subreq;
5229 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
5232 req = tevent_req_create(mem_ctx, &state,
5233 struct cli_smb2_get_reparse_point_fnum_state);
5238 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5239 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
5240 return tevent_req_post(req, ev);
5246 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
5247 if (tevent_req_nterror(req, status)) {
5248 return tevent_req_post(req, ev);
5251 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
5252 state->cli->timeout,
5253 state->cli->smb2.session,
5254 state->cli->smb2.tcon,
5255 state->ph->fid_persistent, /* in_fid_persistent */
5256 state->ph->fid_volatile, /* in_fid_volatile */
5257 FSCTL_GET_REPARSE_POINT,
5258 0, /* in_max_input_length */
5262 SMB2_IOCTL_FLAG_IS_FSCTL);
5264 if (tevent_req_nomem(subreq, req)) {
5265 return tevent_req_post(req, ev);
5267 tevent_req_set_callback(subreq,
5268 cli_smb2_get_reparse_point_fnum_done,
5274 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
5276 struct tevent_req *req = tevent_req_callback_data(
5277 subreq, struct tevent_req);
5278 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
5279 req, struct cli_smb2_get_reparse_point_fnum_state);
5282 status = smb2cli_ioctl_recv(subreq, state,
5284 &state->output_buffer);
5285 TALLOC_FREE(subreq);
5286 if (tevent_req_nterror(req, status)) {
5287 state->cli->raw_status = status;
5290 tevent_req_done(req);
5293 NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
5294 TALLOC_CTX *mem_ctx,
5297 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
5298 req, struct cli_smb2_get_reparse_point_fnum_state);
5300 if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
5301 tevent_req_received(req);
5302 return state->cli->raw_status;
5304 *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
5305 if (output->data == NULL) {
5306 tevent_req_received(req);
5307 return NT_STATUS_NO_MEMORY;
5309 tevent_req_received(req);
5310 return NT_STATUS_OK;