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_delete_on_close_state {
538 struct cli_state *cli;
545 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
547 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
548 struct tevent_context *ev,
549 struct cli_state *cli,
553 struct tevent_req *req = NULL;
554 struct cli_smb2_delete_on_close_state *state = NULL;
555 struct tevent_req *subreq = NULL;
556 uint8_t in_info_type;
557 uint8_t in_file_info_class;
560 req = tevent_req_create(mem_ctx, &state,
561 struct cli_smb2_delete_on_close_state);
568 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
569 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
570 return tevent_req_post(req, ev);
573 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
574 if (tevent_req_nterror(req, status)) {
575 return tevent_req_post(req, ev);
579 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
580 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
583 in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
584 /* Setup data array. */
585 SCVAL(&state->data[0], 0, flag ? 1 : 0);
586 state->inbuf.data = &state->data[0];
587 state->inbuf.length = 1;
589 subreq = smb2cli_set_info_send(state, ev,
596 &state->inbuf, /* in_input_buffer */
597 0, /* in_additional_info */
598 state->ph->fid_persistent,
599 state->ph->fid_volatile);
600 if (tevent_req_nomem(subreq, req)) {
601 return tevent_req_post(req, ev);
603 tevent_req_set_callback(subreq,
604 cli_smb2_delete_on_close_done,
609 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
611 NTSTATUS status = smb2cli_set_info_recv(subreq);
612 tevent_req_simple_finish_ntstatus(subreq, status);
615 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
617 struct cli_smb2_delete_on_close_state *state =
619 struct cli_smb2_delete_on_close_state);
622 if (tevent_req_is_nterror(req, &status)) {
623 state->cli->raw_status = status;
624 tevent_req_received(req);
628 state->cli->raw_status = NT_STATUS_OK;
629 tevent_req_received(req);
633 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
635 TALLOC_CTX *frame = talloc_stackframe();
636 struct tevent_context *ev;
637 struct tevent_req *req;
638 NTSTATUS status = NT_STATUS_NO_MEMORY;
640 if (smbXcli_conn_has_async_calls(cli->conn)) {
642 * Can't use sync call while an async call is in flight
644 status = NT_STATUS_INVALID_PARAMETER;
647 ev = samba_tevent_context_init(frame);
651 req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
655 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
658 status = cli_smb2_delete_on_close_recv(req);
664 /***************************************************************
665 Small wrapper that allows SMB2 to create a directory
667 ***************************************************************/
669 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
674 if (smbXcli_conn_has_async_calls(cli->conn)) {
676 * Can't use sync call while an async call is in flight
678 return NT_STATUS_INVALID_PARAMETER;
681 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
682 return NT_STATUS_INVALID_PARAMETER;
685 status = cli_smb2_create_fnum(cli,
687 0, /* create_flags */
688 SMB2_IMPERSONATION_IMPERSONATION,
689 FILE_READ_ATTRIBUTES, /* desired_access */
690 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
691 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
692 FILE_CREATE, /* create_disposition */
693 FILE_DIRECTORY_FILE, /* create_options */
700 if (!NT_STATUS_IS_OK(status)) {
703 return cli_smb2_close_fnum(cli, fnum);
706 struct cli_smb2_rmdir_state {
707 struct tevent_context *ev;
708 struct cli_state *cli;
710 const struct smb2_create_blobs *in_cblobs;
715 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq);
716 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq);
717 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq);
718 static void cli_smb2_rmdir_closed(struct tevent_req *subreq);
720 struct tevent_req *cli_smb2_rmdir_send(
722 struct tevent_context *ev,
723 struct cli_state *cli,
725 const struct smb2_create_blobs *in_cblobs)
727 struct tevent_req *req = NULL, *subreq = NULL;
728 struct cli_smb2_rmdir_state *state = NULL;
730 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_rmdir_state);
736 state->dname = dname;
737 state->in_cblobs = in_cblobs;
739 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
740 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
741 return tevent_req_post(req, ev);
744 subreq = cli_smb2_create_fnum_send(
749 0, /* create_flags */
750 SMB2_IMPERSONATION_IMPERSONATION,
751 DELETE_ACCESS, /* desired_access */
752 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
753 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
754 FILE_OPEN, /* create_disposition */
755 FILE_DIRECTORY_FILE, /* create_options */
756 state->in_cblobs); /* in_cblobs */
757 if (tevent_req_nomem(subreq, req)) {
758 return tevent_req_post(req, ev);
760 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened1, req);
764 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq)
766 struct tevent_req *req = tevent_req_callback_data(
767 subreq, struct tevent_req);
768 struct cli_smb2_rmdir_state *state = tevent_req_data(
769 req, struct cli_smb2_rmdir_state);
772 status = cli_smb2_create_fnum_recv(
773 subreq, &state->fnum, NULL, NULL, NULL);
776 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
778 * Naive option to match our SMB1 code. Assume the
779 * symlink path that tripped us up was the last
780 * component and try again. Eventually we will have to
781 * deal with the returned path unprocessed component. JRA.
783 subreq = cli_smb2_create_fnum_send(
788 0, /* create_flags */
789 SMB2_IMPERSONATION_IMPERSONATION,
790 DELETE_ACCESS, /* desired_access */
791 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
792 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
793 FILE_OPEN, /* create_disposition */
795 FILE_DELETE_ON_CLOSE|
796 FILE_OPEN_REPARSE_POINT, /* create_options */
797 state->in_cblobs); /* in_cblobs */
798 if (tevent_req_nomem(subreq, req)) {
801 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened2, req);
805 if (tevent_req_nterror(req, status)) {
809 subreq = cli_smb2_delete_on_close_send(
810 state, state->ev, state->cli, state->fnum, true);
811 if (tevent_req_nomem(subreq, req)) {
814 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
817 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq)
819 struct tevent_req *req = tevent_req_callback_data(
820 subreq, struct tevent_req);
821 struct cli_smb2_rmdir_state *state = tevent_req_data(
822 req, struct cli_smb2_rmdir_state);
825 status = cli_smb2_create_fnum_recv(
826 subreq, &state->fnum, NULL, NULL, NULL);
828 if (tevent_req_nterror(req, status)) {
832 subreq = cli_smb2_delete_on_close_send(
833 state, state->ev, state->cli, state->fnum, true);
834 if (tevent_req_nomem(subreq, req)) {
837 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
840 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq)
842 struct tevent_req *req = tevent_req_callback_data(
843 subreq, struct tevent_req);
844 struct cli_smb2_rmdir_state *state = tevent_req_data(
845 req, struct cli_smb2_rmdir_state);
847 state->status = cli_smb2_delete_on_close_recv(subreq);
851 * Close the fd even if the set_disp failed
854 subreq = cli_smb2_close_fnum_send(
855 state, state->ev, state->cli, state->fnum);
856 if (tevent_req_nomem(subreq, req)) {
859 tevent_req_set_callback(subreq, cli_smb2_rmdir_closed, req);
862 static void cli_smb2_rmdir_closed(struct tevent_req *subreq)
864 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
865 tevent_req_simple_finish_ntstatus(subreq, status);
868 NTSTATUS cli_smb2_rmdir_recv(struct tevent_req *req)
870 struct cli_smb2_rmdir_state *state = tevent_req_data(
871 req, struct cli_smb2_rmdir_state);
874 if (tevent_req_is_nterror(req, &status)) {
877 return state->status;
880 NTSTATUS cli_smb2_rmdir(
881 struct cli_state *cli,
883 const struct smb2_create_blobs *in_cblobs)
885 TALLOC_CTX *frame = talloc_stackframe();
886 struct tevent_context *ev;
887 struct tevent_req *req;
888 NTSTATUS status = NT_STATUS_NO_MEMORY;
891 if (smbXcli_conn_has_async_calls(cli->conn)) {
893 * Can't use sync call while an async call is in flight
895 status = NT_STATUS_INVALID_PARAMETER;
898 ev = samba_tevent_context_init(frame);
902 req = cli_smb2_rmdir_send(frame, ev, cli, dname, in_cblobs);
906 ok = tevent_req_poll_ntstatus(req, ev, &status);
910 status = cli_smb2_rmdir_recv(req);
912 cli->raw_status = status;
917 /***************************************************************
918 Small wrapper that allows SMB2 to unlink a pathname.
920 ***************************************************************/
922 struct cli_smb2_unlink_state {
923 struct tevent_context *ev;
924 struct cli_state *cli;
926 const struct smb2_create_blobs *in_cblobs;
929 static void cli_smb2_unlink_opened1(struct tevent_req *subreq);
930 static void cli_smb2_unlink_opened2(struct tevent_req *subreq);
931 static void cli_smb2_unlink_closed(struct tevent_req *subreq);
933 struct tevent_req *cli_smb2_unlink_send(
935 struct tevent_context *ev,
936 struct cli_state *cli,
938 const struct smb2_create_blobs *in_cblobs)
940 struct tevent_req *req = NULL, *subreq = NULL;
941 struct cli_smb2_unlink_state *state = NULL;
943 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_unlink_state);
949 state->fname = fname;
950 state->in_cblobs = in_cblobs;
952 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
953 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
954 return tevent_req_post(req, ev);
957 subreq = cli_smb2_create_fnum_send(
959 state->ev, /* tevent_context */
960 state->cli, /* cli_struct */
961 state->fname, /* filename */
962 0, /* create_flags */
963 SMB2_IMPERSONATION_IMPERSONATION,
964 DELETE_ACCESS, /* desired_access */
965 FILE_ATTRIBUTE_NORMAL, /* file attributes */
968 FILE_SHARE_DELETE, /* share_access */
969 FILE_OPEN, /* create_disposition */
970 FILE_DELETE_ON_CLOSE, /* create_options */
971 state->in_cblobs); /* in_cblobs */
972 if (tevent_req_nomem(subreq, req)) {
973 return tevent_req_post(req, ev);
975 tevent_req_set_callback(subreq, cli_smb2_unlink_opened1, req);
979 static void cli_smb2_unlink_opened1(struct tevent_req *subreq)
981 struct tevent_req *req = tevent_req_callback_data(
982 subreq, struct tevent_req);
983 struct cli_smb2_unlink_state *state = tevent_req_data(
984 req, struct cli_smb2_unlink_state);
988 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
991 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
993 * Naive option to match our SMB1 code. Assume the
994 * symlink path that tripped us up was the last
995 * component and try again. Eventually we will have to
996 * deal with the returned path unprocessed component. JRA.
998 subreq = cli_smb2_create_fnum_send(
1000 state->ev, /* tevent_context */
1001 state->cli, /* cli_struct */
1002 state->fname, /* filename */
1003 0, /* create_flags */
1004 SMB2_IMPERSONATION_IMPERSONATION,
1005 DELETE_ACCESS, /* desired_access */
1006 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1009 FILE_SHARE_DELETE, /* share_access */
1010 FILE_OPEN, /* create_disposition */
1011 FILE_DELETE_ON_CLOSE|
1012 FILE_OPEN_REPARSE_POINT, /* create_options */
1013 state->in_cblobs); /* in_cblobs */
1014 if (tevent_req_nomem(subreq, req)) {
1017 tevent_req_set_callback(subreq, cli_smb2_unlink_opened2, req);
1021 if (tevent_req_nterror(req, status)) {
1025 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1026 if (tevent_req_nomem(subreq, req)) {
1029 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1032 static void cli_smb2_unlink_opened2(struct tevent_req *subreq)
1034 struct tevent_req *req = tevent_req_callback_data(
1035 subreq, struct tevent_req);
1036 struct cli_smb2_unlink_state *state = tevent_req_data(
1037 req, struct cli_smb2_unlink_state);
1041 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1042 TALLOC_FREE(subreq);
1043 if (tevent_req_nterror(req, status)) {
1047 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1048 if (tevent_req_nomem(subreq, req)) {
1051 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1054 static void cli_smb2_unlink_closed(struct tevent_req *subreq)
1056 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1057 tevent_req_simple_finish_ntstatus(subreq, status);
1060 NTSTATUS cli_smb2_unlink_recv(struct tevent_req *req)
1062 return tevent_req_simple_recv_ntstatus(req);
1065 NTSTATUS cli_smb2_unlink(
1066 struct cli_state *cli,
1068 const struct smb2_create_blobs *in_cblobs)
1070 TALLOC_CTX *frame = talloc_stackframe();
1071 struct tevent_context *ev;
1072 struct tevent_req *req;
1073 NTSTATUS status = NT_STATUS_NO_MEMORY;
1076 if (smbXcli_conn_has_async_calls(cli->conn)) {
1078 * Can't use sync call while an async call is in flight
1080 status = NT_STATUS_INVALID_PARAMETER;
1083 ev = samba_tevent_context_init(frame);
1087 req = cli_smb2_unlink_send(frame, ev, cli, fname, in_cblobs);
1091 ok = tevent_req_poll_ntstatus(req, ev, &status);
1095 status = cli_smb2_unlink_recv(req);
1097 cli->raw_status = status;
1102 /***************************************************************
1103 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1104 ***************************************************************/
1106 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
1107 uint32_t dir_data_length,
1108 struct file_info *finfo,
1109 uint32_t *next_offset)
1115 if (dir_data_length < 4) {
1116 return NT_STATUS_INFO_LENGTH_MISMATCH;
1119 *next_offset = IVAL(dir_data, 0);
1121 if (*next_offset > dir_data_length) {
1122 return NT_STATUS_INFO_LENGTH_MISMATCH;
1125 if (*next_offset != 0) {
1126 /* Ensure we only read what in this record. */
1127 dir_data_length = *next_offset;
1130 if (dir_data_length < 105) {
1131 return NT_STATUS_INFO_LENGTH_MISMATCH;
1134 finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
1135 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
1136 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
1137 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
1138 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
1139 finfo->allocated_size = IVAL2_TO_SMB_BIG_UINT(dir_data + 48, 0);
1140 finfo->mode = CVAL(dir_data + 56, 0);
1141 finfo->ino = IVAL2_TO_SMB_BIG_UINT(dir_data + 96, 0);
1142 namelen = IVAL(dir_data + 60,0);
1143 if (namelen > (dir_data_length - 104)) {
1144 return NT_STATUS_INFO_LENGTH_MISMATCH;
1146 slen = CVAL(dir_data + 68, 0);
1148 return NT_STATUS_INFO_LENGTH_MISMATCH;
1150 ret = pull_string_talloc(finfo,
1152 FLAGS2_UNICODE_STRINGS,
1157 if (ret == (size_t)-1) {
1158 /* Bad conversion. */
1159 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1162 ret = pull_string_talloc(finfo,
1164 FLAGS2_UNICODE_STRINGS,
1169 if (ret == (size_t)-1) {
1170 /* Bad conversion. */
1171 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1173 return NT_STATUS_OK;
1176 /*******************************************************************
1177 Given a filename - get its directory name
1178 ********************************************************************/
1180 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
1188 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
1191 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
1202 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
1205 (*parent)[len] = '\0';
1213 /***************************************************************
1214 Wrapper that allows SMB2 to list a directory.
1216 ***************************************************************/
1218 NTSTATUS cli_smb2_list(struct cli_state *cli,
1219 const char *pathname,
1221 NTSTATUS (*fn)(const char *,
1228 uint16_t fnum = 0xffff;
1229 char *parent_dir = NULL;
1230 const char *mask = NULL;
1231 struct smb2_hnd *ph = NULL;
1232 bool processed_file = false;
1233 TALLOC_CTX *frame = talloc_stackframe();
1234 TALLOC_CTX *subframe = NULL;
1237 uint32_t max_avail_len;
1240 if (smbXcli_conn_has_async_calls(cli->conn)) {
1242 * Can't use sync call while an async call is in flight
1244 status = NT_STATUS_INVALID_PARAMETER;
1248 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1249 status = NT_STATUS_INVALID_PARAMETER;
1253 /* Get the directory name. */
1254 if (!windows_parent_dirname(frame,
1258 status = NT_STATUS_NO_MEMORY;
1262 mask_has_wild = ms_has_wild(mask);
1264 status = cli_smb2_create_fnum(cli,
1266 0, /* create_flags */
1267 SMB2_IMPERSONATION_IMPERSONATION,
1268 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
1269 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1270 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
1271 FILE_OPEN, /* create_disposition */
1272 FILE_DIRECTORY_FILE, /* create_options */
1279 if (!NT_STATUS_IS_OK(status)) {
1283 status = map_fnum_to_smb2_handle(cli,
1286 if (!NT_STATUS_IS_OK(status)) {
1291 * ideally, use the max transaction size, but don't send a request
1292 * bigger than we have credits available for
1294 max_trans = smb2cli_conn_max_trans_size(cli->conn);
1295 ok = smb2cli_conn_req_possible(cli->conn, &max_avail_len);
1297 max_trans = MIN(max_trans, max_avail_len);
1301 uint8_t *dir_data = NULL;
1302 uint32_t dir_data_length = 0;
1303 uint32_t next_offset = 0;
1304 subframe = talloc_stackframe();
1306 status = smb2cli_query_directory(cli->conn,
1310 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
1321 if (!NT_STATUS_IS_OK(status)) {
1322 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1329 struct file_info *finfo = talloc_zero(subframe,
1332 if (finfo == NULL) {
1333 status = NT_STATUS_NO_MEMORY;
1337 status = parse_finfo_id_both_directory_info(dir_data,
1342 if (!NT_STATUS_IS_OK(status)) {
1346 if (dir_check_ftype((uint32_t)finfo->mode,
1347 (uint32_t)attribute)) {
1349 * Only process if attributes match.
1350 * On SMB1 server does this, so on
1351 * SMB2 we need to emulate in the
1354 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1356 processed_file = true;
1358 status = fn(cli->dfs_mountpoint,
1363 if (!NT_STATUS_IS_OK(status)) {
1370 /* Move to next entry. */
1372 dir_data += next_offset;
1373 dir_data_length -= next_offset;
1375 } while (next_offset != 0);
1377 TALLOC_FREE(subframe);
1379 if (!mask_has_wild) {
1381 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1382 * when handed a non-wildcard path. Do it
1383 * for the server (with a non-wildcard path
1384 * there should only ever be one file returned.
1386 status = STATUS_NO_MORE_FILES;
1390 } while (NT_STATUS_IS_OK(status));
1392 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1393 status = NT_STATUS_OK;
1396 if (NT_STATUS_IS_OK(status) && !processed_file) {
1398 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1399 * if no files match. Emulate this in the client.
1401 status = NT_STATUS_NO_SUCH_FILE;
1406 if (fnum != 0xffff) {
1407 cli_smb2_close_fnum(cli, fnum);
1410 cli->raw_status = status;
1412 TALLOC_FREE(subframe);
1417 /***************************************************************
1418 Wrapper that allows SMB2 to query a path info (basic level).
1420 ***************************************************************/
1422 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1424 SMB_STRUCT_STAT *sbuf,
1425 uint32_t *attributes)
1428 struct smb_create_returns cr;
1429 uint16_t fnum = 0xffff;
1430 size_t namelen = strlen(name);
1432 if (smbXcli_conn_has_async_calls(cli->conn)) {
1434 * Can't use sync call while an async call is in flight
1436 return NT_STATUS_INVALID_PARAMETER;
1439 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1440 return NT_STATUS_INVALID_PARAMETER;
1443 /* SMB2 is pickier about pathnames. Ensure it doesn't
1445 if (namelen > 0 && name[namelen-1] == '\\') {
1446 char *modname = talloc_strdup(talloc_tos(), name);
1447 modname[namelen-1] = '\0';
1451 /* This is commonly used as a 'cd'. Try qpathinfo on
1452 a directory handle first. */
1454 status = cli_smb2_create_fnum(cli,
1456 0, /* create_flags */
1457 SMB2_IMPERSONATION_IMPERSONATION,
1458 FILE_READ_ATTRIBUTES, /* desired_access */
1459 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1460 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1461 FILE_OPEN, /* create_disposition */
1462 FILE_DIRECTORY_FILE, /* create_options */
1469 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1470 /* Maybe a file ? */
1471 status = cli_smb2_create_fnum(cli,
1473 0, /* create_flags */
1474 SMB2_IMPERSONATION_IMPERSONATION,
1475 FILE_READ_ATTRIBUTES, /* desired_access */
1476 0, /* file attributes */
1477 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1478 FILE_OPEN, /* create_disposition */
1479 0, /* create_options */
1487 if (!NT_STATUS_IS_OK(status)) {
1491 status = cli_smb2_close_fnum(cli, fnum);
1495 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1496 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1497 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1498 sbuf->st_ex_size = cr.end_of_file;
1499 *attributes = cr.file_attributes;
1504 /***************************************************************
1505 Wrapper that allows SMB2 to check if a path is a directory.
1507 ***************************************************************/
1509 NTSTATUS cli_smb2_chkpath(struct cli_state *cli,
1513 uint16_t fnum = 0xffff;
1515 if (smbXcli_conn_has_async_calls(cli->conn)) {
1517 * Can't use sync call while an async call is in flight
1519 return NT_STATUS_INVALID_PARAMETER;
1522 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1523 return NT_STATUS_INVALID_PARAMETER;
1526 /* Ensure this is a directory. */
1527 status = cli_smb2_create_fnum(cli,
1529 0, /* create_flags */
1530 SMB2_IMPERSONATION_IMPERSONATION,
1531 FILE_READ_ATTRIBUTES, /* desired_access */
1532 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1533 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1534 FILE_OPEN, /* create_disposition */
1535 FILE_DIRECTORY_FILE, /* create_options */
1542 if (!NT_STATUS_IS_OK(status)) {
1546 return cli_smb2_close_fnum(cli, fnum);
1549 struct cli_smb2_query_info_fnum_state {
1553 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq);
1555 struct tevent_req *cli_smb2_query_info_fnum_send(
1556 TALLOC_CTX *mem_ctx,
1557 struct tevent_context *ev,
1558 struct cli_state *cli,
1560 uint8_t in_info_type,
1561 uint8_t in_info_class,
1562 uint32_t in_max_output_length,
1563 const DATA_BLOB *in_input_buffer,
1564 uint32_t in_additional_info,
1567 struct tevent_req *req = NULL, *subreq = NULL;
1568 struct cli_smb2_query_info_fnum_state *state = NULL;
1569 struct smb2_hnd *ph = NULL;
1572 req = tevent_req_create(
1573 mem_ctx, &state, struct cli_smb2_query_info_fnum_state);
1578 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1579 if (tevent_req_nterror(req, status)) {
1580 return tevent_req_post(req, ev);
1583 subreq = smb2cli_query_info_send(
1592 in_max_output_length,
1598 if (tevent_req_nomem(subreq, req)) {
1599 return tevent_req_post(req, ev);
1601 tevent_req_set_callback(subreq, cli_smb2_query_info_fnum_done, req);
1605 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq)
1607 struct tevent_req *req = tevent_req_callback_data(
1608 subreq, struct tevent_req);
1609 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1610 req, struct cli_smb2_query_info_fnum_state);
1614 status = smb2cli_query_info_recv(subreq, state, &outbuf);
1615 TALLOC_FREE(subreq);
1616 if (tevent_req_nterror(req, status)) {
1621 * We have to dup the memory here because outbuf.data is not
1622 * returned as a talloc object by smb2cli_query_info_recv.
1623 * It's a pointer into the received buffer.
1625 state->outbuf = data_blob_dup_talloc(state, outbuf);
1627 if ((outbuf.length != 0) &&
1628 tevent_req_nomem(state->outbuf.data, req)) {
1631 tevent_req_done(req);
1634 NTSTATUS cli_smb2_query_info_fnum_recv(
1635 struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *outbuf)
1637 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1638 req, struct cli_smb2_query_info_fnum_state);
1641 if (tevent_req_is_nterror(req, &status)) {
1644 *outbuf = (DATA_BLOB) {
1645 .data = talloc_move(mem_ctx, &state->outbuf.data),
1646 .length = state->outbuf.length,
1648 return NT_STATUS_OK;
1651 NTSTATUS cli_smb2_query_info_fnum(
1652 struct cli_state *cli,
1654 uint8_t in_info_type,
1655 uint8_t in_info_class,
1656 uint32_t in_max_output_length,
1657 const DATA_BLOB *in_input_buffer,
1658 uint32_t in_additional_info,
1660 TALLOC_CTX *mem_ctx,
1663 TALLOC_CTX *frame = talloc_stackframe();
1664 struct tevent_context *ev = NULL;
1665 struct tevent_req *req = NULL;
1666 NTSTATUS status = NT_STATUS_NO_MEMORY;
1669 if (smbXcli_conn_has_async_calls(cli->conn)) {
1671 * Can't use sync call while an async call is in flight
1673 status = NT_STATUS_INVALID_PARAMETER;
1676 ev = samba_tevent_context_init(frame);
1680 req = cli_smb2_query_info_fnum_send(
1687 in_max_output_length,
1694 ok = tevent_req_poll_ntstatus(req, ev, &status);
1698 status = cli_smb2_query_info_fnum_recv(req, mem_ctx, outbuf);
1704 /***************************************************************
1705 Helper function for pathname operations.
1706 ***************************************************************/
1708 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1710 uint32_t desired_access,
1714 size_t namelen = strlen(name);
1715 TALLOC_CTX *frame = talloc_stackframe();
1716 uint32_t create_options = 0;
1718 /* SMB2 is pickier about pathnames. Ensure it doesn't
1720 if (namelen > 0 && name[namelen-1] == '\\') {
1721 char *modname = talloc_strdup(frame, name);
1722 if (modname == NULL) {
1723 status = NT_STATUS_NO_MEMORY;
1726 modname[namelen-1] = '\0';
1730 /* Try to open a file handle first. */
1731 status = cli_smb2_create_fnum(cli,
1733 0, /* create_flags */
1734 SMB2_IMPERSONATION_IMPERSONATION,
1736 0, /* file attributes */
1737 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1738 FILE_OPEN, /* create_disposition */
1746 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1748 * Naive option to match our SMB1 code. Assume the
1749 * symlink path that tripped us up was the last
1750 * component and try again. Eventually we will have to
1751 * deal with the returned path unprocessed component. JRA.
1753 create_options |= FILE_OPEN_REPARSE_POINT;
1754 status = cli_smb2_create_fnum(cli,
1756 0, /* create_flags */
1757 SMB2_IMPERSONATION_IMPERSONATION,
1759 0, /* file attributes */
1760 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1761 FILE_OPEN, /* create_disposition */
1770 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1771 create_options |= FILE_DIRECTORY_FILE;
1772 status = cli_smb2_create_fnum(cli,
1774 0, /* create_flags */
1775 SMB2_IMPERSONATION_IMPERSONATION,
1777 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1778 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1779 FILE_OPEN, /* create_disposition */
1780 FILE_DIRECTORY_FILE, /* create_options */
1794 /***************************************************************
1795 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1797 ***************************************************************/
1799 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1804 DATA_BLOB outbuf = data_blob_null;
1805 uint16_t fnum = 0xffff;
1806 struct smb2_hnd *ph = NULL;
1807 uint32_t altnamelen = 0;
1808 TALLOC_CTX *frame = talloc_stackframe();
1810 if (smbXcli_conn_has_async_calls(cli->conn)) {
1812 * Can't use sync call while an async call is in flight
1814 status = NT_STATUS_INVALID_PARAMETER;
1818 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1819 status = NT_STATUS_INVALID_PARAMETER;
1823 status = get_fnum_from_path(cli,
1825 FILE_READ_ATTRIBUTES,
1828 if (!NT_STATUS_IS_OK(status)) {
1832 status = map_fnum_to_smb2_handle(cli,
1835 if (!NT_STATUS_IS_OK(status)) {
1839 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1840 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1842 status = smb2cli_query_info(cli->conn,
1846 1, /* in_info_type */
1847 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1848 0xFFFF, /* in_max_output_length */
1849 NULL, /* in_input_buffer */
1850 0, /* in_additional_info */
1857 if (!NT_STATUS_IS_OK(status)) {
1861 /* Parse the reply. */
1862 if (outbuf.length < 4) {
1863 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1867 altnamelen = IVAL(outbuf.data, 0);
1868 if (altnamelen > outbuf.length - 4) {
1869 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1873 if (altnamelen > 0) {
1875 char *short_name = NULL;
1876 ret = pull_string_talloc(frame,
1878 FLAGS2_UNICODE_STRINGS,
1883 if (ret == (size_t)-1) {
1884 /* Bad conversion. */
1885 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1889 fstrcpy(alt_name, short_name);
1894 status = NT_STATUS_OK;
1898 if (fnum != 0xffff) {
1899 cli_smb2_close_fnum(cli, fnum);
1902 cli->raw_status = status;
1909 /***************************************************************
1910 Wrapper that allows SMB2 to query a fnum info (basic level).
1912 ***************************************************************/
1914 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1918 struct timespec *create_time,
1919 struct timespec *access_time,
1920 struct timespec *write_time,
1921 struct timespec *change_time,
1925 DATA_BLOB outbuf = data_blob_null;
1926 struct smb2_hnd *ph = NULL;
1927 TALLOC_CTX *frame = talloc_stackframe();
1929 if (smbXcli_conn_has_async_calls(cli->conn)) {
1931 * Can't use sync call while an async call is in flight
1933 status = NT_STATUS_INVALID_PARAMETER;
1937 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1938 status = NT_STATUS_INVALID_PARAMETER;
1942 status = map_fnum_to_smb2_handle(cli,
1945 if (!NT_STATUS_IS_OK(status)) {
1949 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1950 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1952 status = smb2cli_query_info(cli->conn,
1956 1, /* in_info_type */
1957 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1958 0xFFFF, /* in_max_output_length */
1959 NULL, /* in_input_buffer */
1960 0, /* in_additional_info */
1966 if (!NT_STATUS_IS_OK(status)) {
1970 /* Parse the reply. */
1971 if (outbuf.length < 0x60) {
1972 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1977 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1980 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1983 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1986 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1989 uint32_t attr = IVAL(outbuf.data, 0x20);
1990 *mode = (uint16_t)attr;
1993 uint64_t file_size = BVAL(outbuf.data, 0x30);
1994 *size = (off_t)file_size;
1997 uint64_t file_index = BVAL(outbuf.data, 0x40);
1998 *ino = (SMB_INO_T)file_index;
2003 cli->raw_status = status;
2009 /***************************************************************
2010 Wrapper that allows SMB2 to query an fnum.
2011 Implement on top of cli_smb2_qfileinfo_basic().
2013 ***************************************************************/
2015 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
2019 time_t *change_time,
2020 time_t *access_time,
2023 struct timespec access_time_ts;
2024 struct timespec write_time_ts;
2025 struct timespec change_time_ts;
2026 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
2036 cli->raw_status = status;
2038 if (!NT_STATUS_IS_OK(status)) {
2043 *change_time = change_time_ts.tv_sec;
2046 *access_time = access_time_ts.tv_sec;
2049 *write_time = write_time_ts.tv_sec;
2051 return NT_STATUS_OK;
2054 /***************************************************************
2055 Wrapper that allows SMB2 to get pathname attributes.
2057 ***************************************************************/
2059 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
2066 uint16_t fnum = 0xffff;
2067 struct smb2_hnd *ph = NULL;
2068 TALLOC_CTX *frame = talloc_stackframe();
2070 if (smbXcli_conn_has_async_calls(cli->conn)) {
2072 * Can't use sync call while an async call is in flight
2074 status = NT_STATUS_INVALID_PARAMETER;
2078 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2079 status = NT_STATUS_INVALID_PARAMETER;
2083 status = get_fnum_from_path(cli,
2085 FILE_READ_ATTRIBUTES,
2088 if (!NT_STATUS_IS_OK(status)) {
2092 status = map_fnum_to_smb2_handle(cli,
2095 if (!NT_STATUS_IS_OK(status)) {
2098 status = cli_smb2_getattrE(cli,
2105 if (!NT_STATUS_IS_OK(status)) {
2111 if (fnum != 0xffff) {
2112 cli_smb2_close_fnum(cli, fnum);
2115 cli->raw_status = status;
2121 /***************************************************************
2122 Wrapper that allows SMB2 to query a pathname info (basic level).
2123 Implement on top of cli_smb2_qfileinfo_basic().
2125 ***************************************************************/
2127 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
2129 struct timespec *create_time,
2130 struct timespec *access_time,
2131 struct timespec *write_time,
2132 struct timespec *change_time,
2138 struct smb2_hnd *ph = NULL;
2139 uint16_t fnum = 0xffff;
2140 TALLOC_CTX *frame = talloc_stackframe();
2142 if (smbXcli_conn_has_async_calls(cli->conn)) {
2144 * Can't use sync call while an async call is in flight
2146 status = NT_STATUS_INVALID_PARAMETER;
2150 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2151 status = NT_STATUS_INVALID_PARAMETER;
2155 status = get_fnum_from_path(cli,
2157 FILE_READ_ATTRIBUTES,
2160 if (!NT_STATUS_IS_OK(status)) {
2164 status = map_fnum_to_smb2_handle(cli,
2167 if (!NT_STATUS_IS_OK(status)) {
2171 status = cli_smb2_qfileinfo_basic(cli,
2183 if (fnum != 0xffff) {
2184 cli_smb2_close_fnum(cli, fnum);
2187 cli->raw_status = status;
2193 /***************************************************************
2194 Wrapper that allows SMB2 to query pathname streams.
2196 ***************************************************************/
2198 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
2200 TALLOC_CTX *mem_ctx,
2201 unsigned int *pnum_streams,
2202 struct stream_struct **pstreams)
2205 struct smb2_hnd *ph = NULL;
2206 uint16_t fnum = 0xffff;
2207 DATA_BLOB outbuf = data_blob_null;
2208 TALLOC_CTX *frame = talloc_stackframe();
2210 if (smbXcli_conn_has_async_calls(cli->conn)) {
2212 * Can't use sync call while an async call is in flight
2214 status = NT_STATUS_INVALID_PARAMETER;
2218 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2219 status = NT_STATUS_INVALID_PARAMETER;
2223 status = get_fnum_from_path(cli,
2225 FILE_READ_ATTRIBUTES,
2228 if (!NT_STATUS_IS_OK(status)) {
2232 status = map_fnum_to_smb2_handle(cli,
2235 if (!NT_STATUS_IS_OK(status)) {
2239 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2240 level 22 (SMB2_FILE_STREAM_INFORMATION). */
2242 status = smb2cli_query_info(cli->conn,
2246 1, /* in_info_type */
2247 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
2248 0xFFFF, /* in_max_output_length */
2249 NULL, /* in_input_buffer */
2250 0, /* in_additional_info */
2257 if (!NT_STATUS_IS_OK(status)) {
2261 /* Parse the reply. */
2262 if (!parse_streams_blob(mem_ctx,
2267 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2273 if (fnum != 0xffff) {
2274 cli_smb2_close_fnum(cli, fnum);
2277 cli->raw_status = status;
2283 /***************************************************************
2284 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2287 ***************************************************************/
2289 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
2291 uint8_t in_info_type,
2292 uint8_t in_file_info_class,
2293 const DATA_BLOB *p_in_data)
2296 uint16_t fnum = 0xffff;
2297 struct smb2_hnd *ph = NULL;
2298 TALLOC_CTX *frame = talloc_stackframe();
2300 if (smbXcli_conn_has_async_calls(cli->conn)) {
2302 * Can't use sync call while an async call is in flight
2304 status = NT_STATUS_INVALID_PARAMETER;
2308 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2309 status = NT_STATUS_INVALID_PARAMETER;
2313 status = get_fnum_from_path(cli,
2315 FILE_WRITE_ATTRIBUTES,
2318 if (!NT_STATUS_IS_OK(status)) {
2322 status = map_fnum_to_smb2_handle(cli,
2325 if (!NT_STATUS_IS_OK(status)) {
2329 status = smb2cli_set_info(cli->conn,
2335 p_in_data, /* in_input_buffer */
2336 0, /* in_additional_info */
2341 if (fnum != 0xffff) {
2342 cli_smb2_close_fnum(cli, fnum);
2345 cli->raw_status = status;
2352 /***************************************************************
2353 Wrapper that allows SMB2 to set pathname attributes.
2355 ***************************************************************/
2357 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
2362 uint8_t inbuf_store[40];
2363 DATA_BLOB inbuf = data_blob_null;
2365 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2366 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2368 inbuf.data = inbuf_store;
2369 inbuf.length = sizeof(inbuf_store);
2370 data_blob_clear(&inbuf);
2373 * SMB1 uses attr == 0 to clear all attributes
2374 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2375 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2376 * request attribute change.
2378 * SMB2 uses exactly the reverse. Unfortunately as the
2379 * cli_setatr() ABI is exposed inside libsmbclient,
2380 * we must make the SMB2 cli_smb2_setatr() call
2381 * export the same ABI as the SMB1 cli_setatr()
2382 * which calls it. This means reversing the sense
2383 * of the requested attr argument if it's zero
2384 * or FILE_ATTRIBUTE_NORMAL.
2386 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2390 attr = FILE_ATTRIBUTE_NORMAL;
2391 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
2395 SSVAL(inbuf.data, 32, attr);
2397 put_long_date((char *)inbuf.data + 16,mtime);
2399 /* Set all the other times to -1. */
2400 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2401 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
2402 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
2404 return cli_smb2_setpathinfo(cli,
2406 1, /* in_info_type */
2407 /* in_file_info_class */
2408 SMB_FILE_BASIC_INFORMATION - 1000,
2413 /***************************************************************
2414 Wrapper that allows SMB2 to set file handle times.
2416 ***************************************************************/
2418 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
2425 struct smb2_hnd *ph = NULL;
2426 uint8_t inbuf_store[40];
2427 DATA_BLOB inbuf = data_blob_null;
2429 if (smbXcli_conn_has_async_calls(cli->conn)) {
2431 * Can't use sync call while an async call is in flight
2433 return NT_STATUS_INVALID_PARAMETER;
2436 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2437 return NT_STATUS_INVALID_PARAMETER;
2440 status = map_fnum_to_smb2_handle(cli,
2443 if (!NT_STATUS_IS_OK(status)) {
2447 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2448 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2450 inbuf.data = inbuf_store;
2451 inbuf.length = sizeof(inbuf_store);
2452 data_blob_clear(&inbuf);
2454 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2455 if (change_time != 0) {
2456 put_long_date((char *)inbuf.data + 24, change_time);
2458 if (access_time != 0) {
2459 put_long_date((char *)inbuf.data + 8, access_time);
2461 if (write_time != 0) {
2462 put_long_date((char *)inbuf.data + 16, write_time);
2465 cli->raw_status = smb2cli_set_info(cli->conn,
2469 1, /* in_info_type */
2470 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
2471 &inbuf, /* in_input_buffer */
2472 0, /* in_additional_info */
2476 return cli->raw_status;
2479 /***************************************************************
2480 Wrapper that allows SMB2 to query disk attributes (size).
2482 ***************************************************************/
2484 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2485 uint64_t *bsize, uint64_t *total, uint64_t *avail)
2488 uint16_t fnum = 0xffff;
2489 DATA_BLOB outbuf = data_blob_null;
2490 struct smb2_hnd *ph = NULL;
2491 uint32_t sectors_per_unit = 0;
2492 uint32_t bytes_per_sector = 0;
2493 uint64_t total_size = 0;
2494 uint64_t size_free = 0;
2495 TALLOC_CTX *frame = talloc_stackframe();
2497 if (smbXcli_conn_has_async_calls(cli->conn)) {
2499 * Can't use sync call while an async call is in flight
2501 status = NT_STATUS_INVALID_PARAMETER;
2505 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2506 status = NT_STATUS_INVALID_PARAMETER;
2510 /* First open the top level directory. */
2511 status = cli_smb2_create_fnum(cli,
2513 0, /* create_flags */
2514 SMB2_IMPERSONATION_IMPERSONATION,
2515 FILE_READ_ATTRIBUTES, /* desired_access */
2516 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2517 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2518 FILE_OPEN, /* create_disposition */
2519 FILE_DIRECTORY_FILE, /* create_options */
2526 if (!NT_STATUS_IS_OK(status)) {
2530 status = map_fnum_to_smb2_handle(cli,
2533 if (!NT_STATUS_IS_OK(status)) {
2537 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2538 level 3 (SMB_FS_SIZE_INFORMATION). */
2540 status = smb2cli_query_info(cli->conn,
2544 2, /* in_info_type */
2545 3, /* in_file_info_class */
2546 0xFFFF, /* in_max_output_length */
2547 NULL, /* in_input_buffer */
2548 0, /* in_additional_info */
2554 if (!NT_STATUS_IS_OK(status)) {
2558 /* Parse the reply. */
2559 if (outbuf.length != 24) {
2560 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2564 total_size = BVAL(outbuf.data, 0);
2565 size_free = BVAL(outbuf.data, 8);
2566 sectors_per_unit = IVAL(outbuf.data, 16);
2567 bytes_per_sector = IVAL(outbuf.data, 20);
2570 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2573 *total = total_size;
2579 status = NT_STATUS_OK;
2583 if (fnum != 0xffff) {
2584 cli_smb2_close_fnum(cli, fnum);
2587 cli->raw_status = status;
2593 /***************************************************************
2594 Wrapper that allows SMB2 to query file system sizes.
2596 ***************************************************************/
2598 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2599 uint64_t *total_allocation_units,
2600 uint64_t *caller_allocation_units,
2601 uint64_t *actual_allocation_units,
2602 uint64_t *sectors_per_allocation_unit,
2603 uint64_t *bytes_per_sector)
2606 uint16_t fnum = 0xffff;
2607 DATA_BLOB outbuf = data_blob_null;
2608 struct smb2_hnd *ph = NULL;
2609 TALLOC_CTX *frame = talloc_stackframe();
2611 if (smbXcli_conn_has_async_calls(cli->conn)) {
2613 * Can't use sync call while an async call is in flight
2615 status = NT_STATUS_INVALID_PARAMETER;
2619 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2620 status = NT_STATUS_INVALID_PARAMETER;
2624 /* First open the top level directory. */
2626 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2627 SMB2_IMPERSONATION_IMPERSONATION,
2628 FILE_READ_ATTRIBUTES, /* desired_access */
2629 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2630 FILE_SHARE_READ | FILE_SHARE_WRITE |
2631 FILE_SHARE_DELETE, /* share_access */
2632 FILE_OPEN, /* create_disposition */
2633 FILE_DIRECTORY_FILE, /* create_options */
2640 if (!NT_STATUS_IS_OK(status)) {
2644 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2645 if (!NT_STATUS_IS_OK(status)) {
2649 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2650 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2652 status = smb2cli_query_info(cli->conn,
2656 SMB2_GETINFO_FS, /* in_info_type */
2657 /* in_file_info_class */
2658 SMB_FS_FULL_SIZE_INFORMATION - 1000,
2659 0xFFFF, /* in_max_output_length */
2660 NULL, /* in_input_buffer */
2661 0, /* in_additional_info */
2667 if (!NT_STATUS_IS_OK(status)) {
2671 if (outbuf.length < 32) {
2672 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2676 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2677 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2678 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2679 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2680 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2684 if (fnum != 0xffff) {
2685 cli_smb2_close_fnum(cli, fnum);
2688 cli->raw_status = status;
2694 /***************************************************************
2695 Wrapper that allows SMB2 to query file system attributes.
2697 ***************************************************************/
2699 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2702 uint16_t fnum = 0xffff;
2703 DATA_BLOB outbuf = data_blob_null;
2704 struct smb2_hnd *ph = NULL;
2705 TALLOC_CTX *frame = talloc_stackframe();
2707 if (smbXcli_conn_has_async_calls(cli->conn)) {
2709 * Can't use sync call while an async call is in flight
2711 status = NT_STATUS_INVALID_PARAMETER;
2715 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2716 status = NT_STATUS_INVALID_PARAMETER;
2720 /* First open the top level directory. */
2722 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2723 SMB2_IMPERSONATION_IMPERSONATION,
2724 FILE_READ_ATTRIBUTES, /* desired_access */
2725 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2726 FILE_SHARE_READ | FILE_SHARE_WRITE |
2727 FILE_SHARE_DELETE, /* share_access */
2728 FILE_OPEN, /* create_disposition */
2729 FILE_DIRECTORY_FILE, /* create_options */
2736 if (!NT_STATUS_IS_OK(status)) {
2740 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2741 if (!NT_STATUS_IS_OK(status)) {
2745 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2746 cli->smb2.tcon, 2, /* in_info_type */
2747 5, /* in_file_info_class */
2748 0xFFFF, /* in_max_output_length */
2749 NULL, /* in_input_buffer */
2750 0, /* in_additional_info */
2752 ph->fid_persistent, ph->fid_volatile, frame,
2754 if (!NT_STATUS_IS_OK(status)) {
2758 if (outbuf.length < 12) {
2759 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2763 *fs_attr = IVAL(outbuf.data, 0);
2767 if (fnum != 0xffff) {
2768 cli_smb2_close_fnum(cli, fnum);
2771 cli->raw_status = status;
2777 /***************************************************************
2778 Wrapper that allows SMB2 to query file system volume info.
2780 ***************************************************************/
2782 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2783 TALLOC_CTX *mem_ctx,
2784 char **_volume_name,
2785 uint32_t *pserial_number,
2789 uint16_t fnum = 0xffff;
2790 DATA_BLOB outbuf = data_blob_null;
2791 struct smb2_hnd *ph = NULL;
2793 char *volume_name = NULL;
2794 TALLOC_CTX *frame = talloc_stackframe();
2796 if (smbXcli_conn_has_async_calls(cli->conn)) {
2798 * Can't use sync call while an async call is in flight
2800 status = NT_STATUS_INVALID_PARAMETER;
2804 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2805 status = NT_STATUS_INVALID_PARAMETER;
2809 /* First open the top level directory. */
2811 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2812 SMB2_IMPERSONATION_IMPERSONATION,
2813 FILE_READ_ATTRIBUTES, /* desired_access */
2814 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2815 FILE_SHARE_READ | FILE_SHARE_WRITE |
2816 FILE_SHARE_DELETE, /* share_access */
2817 FILE_OPEN, /* create_disposition */
2818 FILE_DIRECTORY_FILE, /* create_options */
2825 if (!NT_STATUS_IS_OK(status)) {
2829 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2830 if (!NT_STATUS_IS_OK(status)) {
2834 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2835 level 1 (SMB_FS_VOLUME_INFORMATION). */
2837 status = smb2cli_query_info(cli->conn,
2841 SMB2_GETINFO_FS, /* in_info_type */
2842 /* in_file_info_class */
2843 SMB_FS_VOLUME_INFORMATION - 1000,
2844 0xFFFF, /* in_max_output_length */
2845 NULL, /* in_input_buffer */
2846 0, /* in_additional_info */
2852 if (!NT_STATUS_IS_OK(status)) {
2856 if (outbuf.length < 24) {
2857 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2863 ts = interpret_long_date((char *)outbuf.data);
2866 if (pserial_number) {
2867 *pserial_number = IVAL(outbuf.data,8);
2869 nlen = IVAL(outbuf.data,12);
2870 if (nlen + 18 < 18) {
2872 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2876 * The next check is safe as we know outbuf.length >= 24
2879 if (nlen > (outbuf.length - 18)) {
2880 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2884 clistr_pull_talloc(mem_ctx,
2885 (const char *)outbuf.data,
2891 if (volume_name == NULL) {
2892 status = map_nt_error_from_unix(errno);
2896 *_volume_name = volume_name;
2900 if (fnum != 0xffff) {
2901 cli_smb2_close_fnum(cli, fnum);
2904 cli->raw_status = status;
2911 /***************************************************************
2912 Wrapper that allows SMB2 to query a security descriptor.
2914 ***************************************************************/
2916 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2919 TALLOC_CTX *mem_ctx,
2920 struct security_descriptor **ppsd)
2923 DATA_BLOB outbuf = data_blob_null;
2924 struct smb2_hnd *ph = NULL;
2925 struct security_descriptor *lsd = NULL;
2926 TALLOC_CTX *frame = talloc_stackframe();
2928 if (smbXcli_conn_has_async_calls(cli->conn)) {
2930 * Can't use sync call while an async call is in flight
2932 status = NT_STATUS_INVALID_PARAMETER;
2936 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2937 status = NT_STATUS_INVALID_PARAMETER;
2941 status = map_fnum_to_smb2_handle(cli,
2944 if (!NT_STATUS_IS_OK(status)) {
2948 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2950 status = smb2cli_query_info(cli->conn,
2954 3, /* in_info_type */
2955 0, /* in_file_info_class */
2956 0xFFFF, /* in_max_output_length */
2957 NULL, /* in_input_buffer */
2958 sec_info, /* in_additional_info */
2965 if (!NT_STATUS_IS_OK(status)) {
2969 /* Parse the reply. */
2970 status = unmarshall_sec_desc(mem_ctx,
2975 if (!NT_STATUS_IS_OK(status)) {
2987 cli->raw_status = status;
2993 /***************************************************************
2994 Wrapper that allows SMB2 to set a security descriptor.
2996 ***************************************************************/
2998 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
3001 const struct security_descriptor *sd)
3004 DATA_BLOB inbuf = data_blob_null;
3005 struct smb2_hnd *ph = NULL;
3006 TALLOC_CTX *frame = talloc_stackframe();
3008 if (smbXcli_conn_has_async_calls(cli->conn)) {
3010 * Can't use sync call while an async call is in flight
3012 status = NT_STATUS_INVALID_PARAMETER;
3016 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3017 status = NT_STATUS_INVALID_PARAMETER;
3021 status = map_fnum_to_smb2_handle(cli,
3024 if (!NT_STATUS_IS_OK(status)) {
3028 status = marshall_sec_desc(frame,
3033 if (!NT_STATUS_IS_OK(status)) {
3037 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
3039 status = smb2cli_set_info(cli->conn,
3043 3, /* in_info_type */
3044 0, /* in_file_info_class */
3045 &inbuf, /* in_input_buffer */
3046 sec_info, /* in_additional_info */
3052 cli->raw_status = status;
3058 /***************************************************************
3059 Wrapper that allows SMB2 to query a security descriptor.
3062 ***************************************************************/
3064 struct cli_smb2_mxac_state {
3065 struct tevent_context *ev;
3066 struct cli_state *cli;
3068 struct smb2_create_blobs in_cblobs;
3074 static void cli_smb2_mxac_opened(struct tevent_req *subreq);
3075 static void cli_smb2_mxac_closed(struct tevent_req *subreq);
3077 struct tevent_req *cli_smb2_query_mxac_send(TALLOC_CTX *mem_ctx,
3078 struct tevent_context *ev,
3079 struct cli_state *cli,
3082 struct tevent_req *req = NULL, *subreq = NULL;
3083 struct cli_smb2_mxac_state *state = NULL;
3086 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_mxac_state);
3090 *state = (struct cli_smb2_mxac_state) {
3093 state->fname = fname,
3096 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3097 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3098 return tevent_req_post(req, ev);
3101 status = smb2_create_blob_add(state,
3103 SMB2_CREATE_TAG_MXAC,
3104 data_blob(NULL, 0));
3105 if (tevent_req_nterror(req, status)) {
3106 return tevent_req_post(req, ev);
3109 subreq = cli_smb2_create_fnum_send(
3114 0, /* create_flags */
3115 SMB2_IMPERSONATION_IMPERSONATION,
3116 FILE_READ_ATTRIBUTES,
3117 0, /* file attributes */
3118 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
3120 0, /* create_options */
3122 if (tevent_req_nomem(subreq, req)) {
3123 return tevent_req_post(req, ev);
3125 tevent_req_set_callback(subreq, cli_smb2_mxac_opened, req);
3129 static void cli_smb2_mxac_opened(struct tevent_req *subreq)
3131 struct tevent_req *req = tevent_req_callback_data(
3132 subreq, struct tevent_req);
3133 struct cli_smb2_mxac_state *state = tevent_req_data(
3134 req, struct cli_smb2_mxac_state);
3135 struct smb2_create_blobs out_cblobs = {0};
3136 struct smb2_create_blob *mxac_blob = NULL;
3139 status = cli_smb2_create_fnum_recv(
3140 subreq, &state->fnum, NULL, state, &out_cblobs);
3141 TALLOC_FREE(subreq);
3143 if (tevent_req_nterror(req, status)) {
3147 mxac_blob = smb2_create_blob_find(&out_cblobs, SMB2_CREATE_TAG_MXAC);
3148 if (mxac_blob == NULL) {
3149 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3152 if (mxac_blob->data.length != 8) {
3153 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3157 state->status = NT_STATUS(IVAL(mxac_blob->data.data, 0));
3158 state->mxac = IVAL(mxac_blob->data.data, 4);
3161 subreq = cli_smb2_close_fnum_send(
3162 state, state->ev, state->cli, state->fnum);
3163 if (tevent_req_nomem(subreq, req)) {
3166 tevent_req_set_callback(subreq, cli_smb2_mxac_closed, req);
3171 static void cli_smb2_mxac_closed(struct tevent_req *subreq)
3173 struct tevent_req *req = tevent_req_callback_data(
3174 subreq, struct tevent_req);
3177 status = cli_smb2_close_fnum_recv(subreq);
3178 if (tevent_req_nterror(req, status)) {
3182 tevent_req_done(req);
3185 NTSTATUS cli_smb2_query_mxac_recv(struct tevent_req *req, uint32_t *mxac)
3187 struct cli_smb2_mxac_state *state = tevent_req_data(
3188 req, struct cli_smb2_mxac_state);
3191 if (tevent_req_is_nterror(req, &status)) {
3195 if (!NT_STATUS_IS_OK(state->status)) {
3196 return state->status;
3199 *mxac = state->mxac;
3200 return NT_STATUS_OK;
3203 NTSTATUS cli_smb2_query_mxac(struct cli_state *cli,
3207 TALLOC_CTX *frame = talloc_stackframe();
3208 struct tevent_context *ev = NULL;
3209 struct tevent_req *req = NULL;
3210 NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
3213 if (smbXcli_conn_has_async_calls(cli->conn)) {
3215 * Can't use sync call while an async call is in flight
3217 status = NT_STATUS_INVALID_PARAMETER;
3221 ev = samba_tevent_context_init(frame);
3225 req = cli_smb2_query_mxac_send(frame, ev, cli, fname);
3229 ok = tevent_req_poll_ntstatus(req, ev, &status);
3233 status = cli_smb2_query_mxac_recv(req, _mxac);
3236 cli->raw_status = status;
3241 /***************************************************************
3242 Wrapper that allows SMB2 to rename a file.
3244 ***************************************************************/
3246 NTSTATUS cli_smb2_rename(struct cli_state *cli,
3247 const char *fname_src,
3248 const char *fname_dst,
3252 DATA_BLOB inbuf = data_blob_null;
3253 uint16_t fnum = 0xffff;
3254 struct smb2_hnd *ph = NULL;
3255 smb_ucs2_t *converted_str = NULL;
3256 size_t converted_size_bytes = 0;
3258 TALLOC_CTX *frame = talloc_stackframe();
3260 if (smbXcli_conn_has_async_calls(cli->conn)) {
3262 * Can't use sync call while an async call is in flight
3264 status = NT_STATUS_INVALID_PARAMETER;
3268 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3269 status = NT_STATUS_INVALID_PARAMETER;
3273 status = get_fnum_from_path(cli,
3278 if (!NT_STATUS_IS_OK(status)) {
3282 status = map_fnum_to_smb2_handle(cli,
3285 if (!NT_STATUS_IS_OK(status)) {
3289 /* SMB2 is pickier about pathnames. Ensure it doesn't
3291 if (*fname_dst == '\\') {
3295 /* SMB2 is pickier about pathnames. Ensure it doesn't
3297 namelen = strlen(fname_dst);
3298 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
3299 char *modname = talloc_strdup(frame, fname_dst);
3300 modname[namelen-1] = '\0';
3301 fname_dst = modname;
3304 if (!push_ucs2_talloc(frame,
3307 &converted_size_bytes)) {
3308 status = NT_STATUS_INVALID_PARAMETER;
3312 /* W2K8 insists the dest name is not null
3313 terminated. Remove the last 2 zero bytes
3314 and reduce the name length. */
3316 if (converted_size_bytes < 2) {
3317 status = NT_STATUS_INVALID_PARAMETER;
3320 converted_size_bytes -= 2;
3322 inbuf = data_blob_talloc_zero(frame,
3323 20 + converted_size_bytes);
3324 if (inbuf.data == NULL) {
3325 status = NT_STATUS_NO_MEMORY;
3330 SCVAL(inbuf.data, 0, 1);
3333 SIVAL(inbuf.data, 16, converted_size_bytes);
3334 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
3336 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3337 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3339 status = smb2cli_set_info(cli->conn,
3343 1, /* in_info_type */
3344 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
3345 &inbuf, /* in_input_buffer */
3346 0, /* in_additional_info */
3352 if (fnum != 0xffff) {
3353 cli_smb2_close_fnum(cli, fnum);
3356 cli->raw_status = status;
3362 /***************************************************************
3363 Wrapper that allows SMB2 to set an EA on a fnum.
3365 ***************************************************************/
3367 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
3369 const char *ea_name,
3374 DATA_BLOB inbuf = data_blob_null;
3376 char *ea_name_ascii = NULL;
3378 struct smb2_hnd *ph = NULL;
3379 TALLOC_CTX *frame = talloc_stackframe();
3381 if (smbXcli_conn_has_async_calls(cli->conn)) {
3383 * Can't use sync call while an async call is in flight
3385 status = NT_STATUS_INVALID_PARAMETER;
3389 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3390 status = NT_STATUS_INVALID_PARAMETER;
3394 status = map_fnum_to_smb2_handle(cli,
3397 if (!NT_STATUS_IS_OK(status)) {
3401 /* Marshall the SMB2 EA data. */
3402 if (ea_len > 0xFFFF) {
3403 status = NT_STATUS_INVALID_PARAMETER;
3407 if (!push_ascii_talloc(frame,
3411 status = NT_STATUS_INVALID_PARAMETER;
3415 if (namelen < 2 || namelen > 0xFF) {
3416 status = NT_STATUS_INVALID_PARAMETER;
3420 bloblen = 8 + ea_len + namelen;
3421 /* Round up to a 4 byte boundary. */
3422 bloblen = ((bloblen + 3)&~3);
3424 inbuf = data_blob_talloc_zero(frame, bloblen);
3425 if (inbuf.data == NULL) {
3426 status = NT_STATUS_NO_MEMORY;
3429 /* namelen doesn't include the NULL byte. */
3430 SCVAL(inbuf.data, 5, namelen - 1);
3431 SSVAL(inbuf.data, 6, ea_len);
3432 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
3433 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
3435 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3436 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3438 status = smb2cli_set_info(cli->conn,
3442 1, /* in_info_type */
3443 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3444 &inbuf, /* in_input_buffer */
3445 0, /* in_additional_info */
3451 cli->raw_status = status;
3457 /***************************************************************
3458 Wrapper that allows SMB2 to set an EA on a pathname.
3460 ***************************************************************/
3462 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
3464 const char *ea_name,
3469 uint16_t fnum = 0xffff;
3471 if (smbXcli_conn_has_async_calls(cli->conn)) {
3473 * Can't use sync call while an async call is in flight
3475 status = NT_STATUS_INVALID_PARAMETER;
3479 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3480 status = NT_STATUS_INVALID_PARAMETER;
3484 status = get_fnum_from_path(cli,
3489 if (!NT_STATUS_IS_OK(status)) {
3493 status = cli_set_ea_fnum(cli,
3498 if (!NT_STATUS_IS_OK(status)) {
3504 if (fnum != 0xffff) {
3505 cli_smb2_close_fnum(cli, fnum);
3508 cli->raw_status = status;
3513 /***************************************************************
3514 Wrapper that allows SMB2 to get an EA list on a pathname.
3516 ***************************************************************/
3518 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
3522 struct ea_struct **pea_array)
3525 uint16_t fnum = 0xffff;
3526 DATA_BLOB outbuf = data_blob_null;
3527 struct smb2_hnd *ph = NULL;
3528 struct ea_list *ea_list = NULL;
3529 struct ea_list *eal = NULL;
3530 size_t ea_count = 0;
3531 TALLOC_CTX *frame = talloc_stackframe();
3536 if (smbXcli_conn_has_async_calls(cli->conn)) {
3538 * Can't use sync call while an async call is in flight
3540 status = NT_STATUS_INVALID_PARAMETER;
3544 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3545 status = NT_STATUS_INVALID_PARAMETER;
3549 status = get_fnum_from_path(cli,
3554 if (!NT_STATUS_IS_OK(status)) {
3558 status = map_fnum_to_smb2_handle(cli,
3561 if (!NT_STATUS_IS_OK(status)) {
3565 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3566 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3568 status = smb2cli_query_info(cli->conn,
3572 1, /* in_info_type */
3573 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3574 0xFFFF, /* in_max_output_length */
3575 NULL, /* in_input_buffer */
3576 0, /* in_additional_info */
3583 if (!NT_STATUS_IS_OK(status)) {
3587 /* Parse the reply. */
3588 ea_list = read_nttrans_ea_list(ctx,
3589 (const char *)outbuf.data,
3591 if (ea_list == NULL) {
3592 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3596 /* Convert to an array. */
3597 for (eal = ea_list; eal; eal = eal->next) {
3602 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
3603 if (*pea_array == NULL) {
3604 status = NT_STATUS_NO_MEMORY;
3608 for (eal = ea_list; eal; eal = eal->next) {
3609 (*pea_array)[ea_count++] = eal->ea;
3611 *pnum_eas = ea_count;
3616 if (fnum != 0xffff) {
3617 cli_smb2_close_fnum(cli, fnum);
3620 cli->raw_status = status;
3626 /***************************************************************
3627 Wrapper that allows SMB2 to get user quota.
3629 ***************************************************************/
3631 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
3633 SMB_NTQUOTA_STRUCT *pqt)
3636 DATA_BLOB inbuf = data_blob_null;
3637 DATA_BLOB info_blob = data_blob_null;
3638 DATA_BLOB outbuf = data_blob_null;
3639 struct smb2_hnd *ph = NULL;
3640 TALLOC_CTX *frame = talloc_stackframe();
3642 unsigned int offset;
3643 struct smb2_query_quota_info query = {0};
3644 struct file_get_quota_info info = {0};
3645 enum ndr_err_code err;
3646 struct ndr_push *ndr_push = NULL;
3648 if (smbXcli_conn_has_async_calls(cli->conn)) {
3650 * Can't use sync call while an async call is in flight
3652 status = NT_STATUS_INVALID_PARAMETER;
3656 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3657 status = NT_STATUS_INVALID_PARAMETER;
3661 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3662 if (!NT_STATUS_IS_OK(status)) {
3666 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
3668 query.return_single = 1;
3670 info.next_entry_offset = 0;
3671 info.sid_length = sid_len;
3672 info.sid = pqt->sid;
3674 err = ndr_push_struct_blob(
3678 (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
3680 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3681 status = NT_STATUS_INTERNAL_ERROR;
3685 query.sid_list_length = info_blob.length;
3686 ndr_push = ndr_push_init_ctx(frame);
3688 status = NT_STATUS_NO_MEMORY;
3692 err = ndr_push_smb2_query_quota_info(ndr_push,
3693 NDR_SCALARS | NDR_BUFFERS,
3696 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3697 status = NT_STATUS_INTERNAL_ERROR;
3701 err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3704 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3705 status = NT_STATUS_INTERNAL_ERROR;
3708 inbuf.data = ndr_push->data;
3709 inbuf.length = ndr_push->offset;
3711 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
3712 cli->smb2.tcon, 4, /* in_info_type */
3713 0, /* in_file_info_class */
3714 0xFFFF, /* in_max_output_length */
3715 &inbuf, /* in_input_buffer */
3716 0, /* in_additional_info */
3718 ph->fid_persistent, ph->fid_volatile, frame,
3721 if (!NT_STATUS_IS_OK(status)) {
3725 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3727 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3728 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3732 cli->raw_status = status;
3738 /***************************************************************
3739 Wrapper that allows SMB2 to list user quota.
3741 ***************************************************************/
3743 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3744 TALLOC_CTX *mem_ctx,
3746 SMB_NTQUOTA_LIST **pqt_list,
3750 DATA_BLOB inbuf = data_blob_null;
3751 DATA_BLOB outbuf = data_blob_null;
3752 struct smb2_hnd *ph = NULL;
3753 TALLOC_CTX *frame = talloc_stackframe();
3754 struct smb2_query_quota_info info = {0};
3755 enum ndr_err_code err;
3757 if (smbXcli_conn_has_async_calls(cli->conn)) {
3759 * Can't use sync call while an async call is in flight
3761 status = NT_STATUS_INVALID_PARAMETER;
3765 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3766 status = NT_STATUS_INVALID_PARAMETER;
3770 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3771 if (!NT_STATUS_IS_OK(status)) {
3776 info.restart_scan = first ? 1 : 0;
3778 err = ndr_push_struct_blob(
3782 (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3784 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3785 status = NT_STATUS_INTERNAL_ERROR;
3789 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
3790 cli->smb2.tcon, 4, /* in_info_type */
3791 0, /* in_file_info_class */
3792 0xFFFF, /* in_max_output_length */
3793 &inbuf, /* in_input_buffer */
3794 0, /* in_additional_info */
3796 ph->fid_persistent, ph->fid_volatile, frame,
3800 * safeguard against panic from calling parse_user_quota_list with
3803 if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3804 status = NT_STATUS_NO_MORE_ENTRIES;
3807 if (!NT_STATUS_IS_OK(status)) {
3811 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3815 cli->raw_status = status;
3821 /***************************************************************
3822 Wrapper that allows SMB2 to get file system quota.
3824 ***************************************************************/
3826 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3828 SMB_NTQUOTA_STRUCT *pqt)
3831 DATA_BLOB outbuf = data_blob_null;
3832 struct smb2_hnd *ph = NULL;
3833 TALLOC_CTX *frame = talloc_stackframe();
3835 if (smbXcli_conn_has_async_calls(cli->conn)) {
3837 * Can't use sync call while an async call is in flight
3839 status = NT_STATUS_INVALID_PARAMETER;
3843 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3844 status = NT_STATUS_INVALID_PARAMETER;
3848 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3849 if (!NT_STATUS_IS_OK(status)) {
3853 status = smb2cli_query_info(
3854 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3855 2, /* in_info_type */
3856 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3857 0xFFFF, /* in_max_output_length */
3858 NULL, /* in_input_buffer */
3859 0, /* in_additional_info */
3861 ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
3863 if (!NT_STATUS_IS_OK(status)) {
3867 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3870 cli->raw_status = status;
3876 /***************************************************************
3877 Wrapper that allows SMB2 to set user quota.
3879 ***************************************************************/
3881 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3883 SMB_NTQUOTA_LIST *qtl)
3886 DATA_BLOB inbuf = data_blob_null;
3887 struct smb2_hnd *ph = NULL;
3888 TALLOC_CTX *frame = talloc_stackframe();
3890 if (smbXcli_conn_has_async_calls(cli->conn)) {
3892 * Can't use sync call while an async call is in flight
3894 status = NT_STATUS_INVALID_PARAMETER;
3898 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3899 status = NT_STATUS_INVALID_PARAMETER;
3903 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3904 if (!NT_STATUS_IS_OK(status)) {
3908 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3909 if (!NT_STATUS_IS_OK(status)) {
3913 status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
3914 cli->smb2.tcon, 4, /* in_info_type */
3915 0, /* in_file_info_class */
3916 &inbuf, /* in_input_buffer */
3917 0, /* in_additional_info */
3918 ph->fid_persistent, ph->fid_volatile);
3921 cli->raw_status = status;
3928 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3930 SMB_NTQUOTA_STRUCT *pqt)
3933 DATA_BLOB inbuf = data_blob_null;
3934 struct smb2_hnd *ph = NULL;
3935 TALLOC_CTX *frame = talloc_stackframe();
3937 if (smbXcli_conn_has_async_calls(cli->conn)) {
3939 * Can't use sync call while an async call is in flight
3941 status = NT_STATUS_INVALID_PARAMETER;
3945 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3946 status = NT_STATUS_INVALID_PARAMETER;
3950 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3951 if (!NT_STATUS_IS_OK(status)) {
3955 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3956 if (!NT_STATUS_IS_OK(status)) {
3960 status = smb2cli_set_info(
3961 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3962 2, /* in_info_type */
3963 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3964 &inbuf, /* in_input_buffer */
3965 0, /* in_additional_info */
3966 ph->fid_persistent, ph->fid_volatile);
3968 cli->raw_status = status;
3974 struct cli_smb2_read_state {
3975 struct tevent_context *ev;
3976 struct cli_state *cli;
3977 struct smb2_hnd *ph;
3978 uint64_t start_offset;
3984 static void cli_smb2_read_done(struct tevent_req *subreq);
3986 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3987 struct tevent_context *ev,
3988 struct cli_state *cli,
3994 struct tevent_req *req, *subreq;
3995 struct cli_smb2_read_state *state;
3997 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
4003 state->start_offset = (uint64_t)offset;
4004 state->size = (uint32_t)size;
4005 state->received = 0;
4008 status = map_fnum_to_smb2_handle(cli,
4011 if (tevent_req_nterror(req, status)) {
4012 return tevent_req_post(req, ev);
4015 subreq = smb2cli_read_send(state,
4018 state->cli->timeout,
4019 state->cli->smb2.session,
4020 state->cli->smb2.tcon,
4022 state->start_offset,
4023 state->ph->fid_persistent,
4024 state->ph->fid_volatile,
4025 0, /* minimum_count */
4026 0); /* remaining_bytes */
4028 if (tevent_req_nomem(subreq, req)) {
4029 return tevent_req_post(req, ev);
4031 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
4035 static void cli_smb2_read_done(struct tevent_req *subreq)
4037 struct tevent_req *req = tevent_req_callback_data(
4038 subreq, struct tevent_req);
4039 struct cli_smb2_read_state *state = tevent_req_data(
4040 req, struct cli_smb2_read_state);
4043 status = smb2cli_read_recv(subreq, state,
4044 &state->buf, &state->received);
4045 if (tevent_req_nterror(req, status)) {
4049 if (state->received > state->size) {
4050 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4054 tevent_req_done(req);
4057 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
4062 struct cli_smb2_read_state *state = tevent_req_data(
4063 req, struct cli_smb2_read_state);
4065 if (tevent_req_is_nterror(req, &status)) {
4066 state->cli->raw_status = status;
4070 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
4071 * better make sure that you copy it away before you talloc_free(req).
4072 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
4074 *received = (ssize_t)state->received;
4075 *rcvbuf = state->buf;
4076 state->cli->raw_status = NT_STATUS_OK;
4077 return NT_STATUS_OK;
4080 struct cli_smb2_write_state {
4081 struct tevent_context *ev;
4082 struct cli_state *cli;
4083 struct smb2_hnd *ph;
4091 static void cli_smb2_write_written(struct tevent_req *req);
4093 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
4094 struct tevent_context *ev,
4095 struct cli_state *cli,
4103 struct tevent_req *req, *subreq = NULL;
4104 struct cli_smb2_write_state *state = NULL;
4106 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
4112 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4113 state->flags = (uint32_t)mode;
4115 state->offset = (uint64_t)offset;
4116 state->size = (uint32_t)size;
4119 status = map_fnum_to_smb2_handle(cli,
4122 if (tevent_req_nterror(req, status)) {
4123 return tevent_req_post(req, ev);
4126 subreq = smb2cli_write_send(state,
4129 state->cli->timeout,
4130 state->cli->smb2.session,
4131 state->cli->smb2.tcon,
4134 state->ph->fid_persistent,
4135 state->ph->fid_volatile,
4136 0, /* remaining_bytes */
4137 state->flags, /* flags */
4140 if (tevent_req_nomem(subreq, req)) {
4141 return tevent_req_post(req, ev);
4143 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
4147 static void cli_smb2_write_written(struct tevent_req *subreq)
4149 struct tevent_req *req = tevent_req_callback_data(
4150 subreq, struct tevent_req);
4151 struct cli_smb2_write_state *state = tevent_req_data(
4152 req, struct cli_smb2_write_state);
4156 status = smb2cli_write_recv(subreq, &written);
4157 TALLOC_FREE(subreq);
4158 if (tevent_req_nterror(req, status)) {
4162 state->written = written;
4164 tevent_req_done(req);
4167 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
4170 struct cli_smb2_write_state *state = tevent_req_data(
4171 req, struct cli_smb2_write_state);
4174 if (tevent_req_is_nterror(req, &status)) {
4175 state->cli->raw_status = status;
4176 tevent_req_received(req);
4180 if (pwritten != NULL) {
4181 *pwritten = (size_t)state->written;
4183 state->cli->raw_status = NT_STATUS_OK;
4184 tevent_req_received(req);
4185 return NT_STATUS_OK;
4188 /***************************************************************
4189 Wrapper that allows SMB2 async write using an fnum.
4190 This is mostly cut-and-paste from Volker's code inside
4191 source3/libsmb/clireadwrite.c, adapted for SMB2.
4193 Done this way so I can reuse all the logic inside cli_push()
4195 ***************************************************************/
4197 struct cli_smb2_writeall_state {
4198 struct tevent_context *ev;
4199 struct cli_state *cli;
4200 struct smb2_hnd *ph;
4208 static void cli_smb2_writeall_written(struct tevent_req *req);
4210 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
4211 struct tevent_context *ev,
4212 struct cli_state *cli,
4220 struct tevent_req *req, *subreq = NULL;
4221 struct cli_smb2_writeall_state *state = NULL;
4226 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
4232 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4233 state->flags = (uint32_t)mode;
4235 state->offset = (uint64_t)offset;
4236 state->size = (uint32_t)size;
4239 status = map_fnum_to_smb2_handle(cli,
4242 if (tevent_req_nterror(req, status)) {
4243 return tevent_req_post(req, ev);
4246 to_write = state->size;
4247 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4248 to_write = MIN(max_size, to_write);
4249 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4251 to_write = MIN(max_size, to_write);
4254 subreq = smb2cli_write_send(state,
4257 state->cli->timeout,
4258 state->cli->smb2.session,
4259 state->cli->smb2.tcon,
4262 state->ph->fid_persistent,
4263 state->ph->fid_volatile,
4264 0, /* remaining_bytes */
4265 state->flags, /* flags */
4266 state->buf + state->written);
4268 if (tevent_req_nomem(subreq, req)) {
4269 return tevent_req_post(req, ev);
4271 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4275 static void cli_smb2_writeall_written(struct tevent_req *subreq)
4277 struct tevent_req *req = tevent_req_callback_data(
4278 subreq, struct tevent_req);
4279 struct cli_smb2_writeall_state *state = tevent_req_data(
4280 req, struct cli_smb2_writeall_state);
4282 uint32_t written, to_write;
4286 status = smb2cli_write_recv(subreq, &written);
4287 TALLOC_FREE(subreq);
4288 if (tevent_req_nterror(req, status)) {
4292 state->written += written;
4294 if (state->written > state->size) {
4295 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4299 to_write = state->size - state->written;
4301 if (to_write == 0) {
4302 tevent_req_done(req);
4306 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4307 to_write = MIN(max_size, to_write);
4308 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4310 to_write = MIN(max_size, to_write);
4313 subreq = smb2cli_write_send(state,
4316 state->cli->timeout,
4317 state->cli->smb2.session,
4318 state->cli->smb2.tcon,
4320 state->offset + state->written,
4321 state->ph->fid_persistent,
4322 state->ph->fid_volatile,
4323 0, /* remaining_bytes */
4324 state->flags, /* flags */
4325 state->buf + state->written);
4327 if (tevent_req_nomem(subreq, req)) {
4330 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4333 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
4336 struct cli_smb2_writeall_state *state = tevent_req_data(
4337 req, struct cli_smb2_writeall_state);
4340 if (tevent_req_is_nterror(req, &status)) {
4341 state->cli->raw_status = status;
4344 if (pwritten != NULL) {
4345 *pwritten = (size_t)state->written;
4347 state->cli->raw_status = NT_STATUS_OK;
4348 return NT_STATUS_OK;
4351 struct cli_smb2_splice_state {
4352 struct tevent_context *ev;
4353 struct cli_state *cli;
4354 struct smb2_hnd *src_ph;
4355 struct smb2_hnd *dst_ph;
4356 int (*splice_cb)(off_t n, void *priv);
4363 struct req_resume_key_rsp resume_rsp;
4364 struct srv_copychunk_copy cc_copy;
4367 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4368 struct tevent_req *req);
4370 static void cli_splice_copychunk_done(struct tevent_req *subreq)
4372 struct tevent_req *req = tevent_req_callback_data(
4373 subreq, struct tevent_req);
4374 struct cli_smb2_splice_state *state =
4375 tevent_req_data(req,
4376 struct cli_smb2_splice_state);
4377 struct smbXcli_conn *conn = state->cli->conn;
4378 DATA_BLOB out_input_buffer = data_blob_null;
4379 DATA_BLOB out_output_buffer = data_blob_null;
4380 struct srv_copychunk_rsp cc_copy_rsp;
4381 enum ndr_err_code ndr_ret;
4384 status = smb2cli_ioctl_recv(subreq, state,
4386 &out_output_buffer);
4387 TALLOC_FREE(subreq);
4388 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
4389 state->resized) && tevent_req_nterror(req, status)) {
4393 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
4394 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
4395 if (ndr_ret != NDR_ERR_SUCCESS) {
4396 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4397 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4401 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
4402 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
4403 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
4404 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
4405 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
4406 tevent_req_nterror(req, status)) {
4410 state->resized = true;
4411 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
4412 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
4414 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4415 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4416 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
4417 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4420 state->src_offset += cc_copy_rsp.total_bytes_written;
4421 state->dst_offset += cc_copy_rsp.total_bytes_written;
4422 state->written += cc_copy_rsp.total_bytes_written;
4423 if (!state->splice_cb(state->written, state->priv)) {
4424 tevent_req_nterror(req, NT_STATUS_CANCELLED);
4429 cli_splice_copychunk_send(state, req);
4432 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4433 struct tevent_req *req)
4435 struct tevent_req *subreq;
4436 enum ndr_err_code ndr_ret;
4437 struct smbXcli_conn *conn = state->cli->conn;
4438 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
4439 off_t src_offset = state->src_offset;
4440 off_t dst_offset = state->dst_offset;
4441 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
4442 state->size - state->written);
4443 DATA_BLOB in_input_buffer = data_blob_null;
4444 DATA_BLOB in_output_buffer = data_blob_null;
4446 if (state->size - state->written == 0) {
4447 tevent_req_done(req);
4451 cc_copy->chunk_count = 0;
4453 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
4454 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
4455 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
4456 smb2cli_conn_cc_chunk_len(conn));
4457 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
4458 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4461 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
4462 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
4463 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
4464 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4467 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4468 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4469 cc_copy->chunk_count++;
4472 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
4473 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
4474 if (ndr_ret != NDR_ERR_SUCCESS) {
4475 DEBUG(0, ("failed to marshall copy chunk req\n"));
4476 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4480 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
4481 state->cli->timeout,
4482 state->cli->smb2.session,
4483 state->cli->smb2.tcon,
4484 state->dst_ph->fid_persistent, /* in_fid_persistent */
4485 state->dst_ph->fid_volatile, /* in_fid_volatile */
4486 FSCTL_SRV_COPYCHUNK_WRITE,
4487 0, /* in_max_input_length */
4489 12, /* in_max_output_length */
4491 SMB2_IOCTL_FLAG_IS_FSCTL);
4492 if (tevent_req_nomem(subreq, req)) {
4495 tevent_req_set_callback(subreq,
4496 cli_splice_copychunk_done,
4500 static void cli_splice_key_done(struct tevent_req *subreq)
4502 struct tevent_req *req = tevent_req_callback_data(
4503 subreq, struct tevent_req);
4504 struct cli_smb2_splice_state *state =
4505 tevent_req_data(req,
4506 struct cli_smb2_splice_state);
4507 enum ndr_err_code ndr_ret;
4510 DATA_BLOB out_input_buffer = data_blob_null;
4511 DATA_BLOB out_output_buffer = data_blob_null;
4513 status = smb2cli_ioctl_recv(subreq, state,
4515 &out_output_buffer);
4516 TALLOC_FREE(subreq);
4517 if (tevent_req_nterror(req, status)) {
4521 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
4522 state, &state->resume_rsp,
4523 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
4524 if (ndr_ret != NDR_ERR_SUCCESS) {
4525 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4526 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4530 memcpy(&state->cc_copy.source_key,
4531 &state->resume_rsp.resume_key,
4532 sizeof state->resume_rsp.resume_key);
4534 cli_splice_copychunk_send(state, req);
4537 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
4538 struct tevent_context *ev,
4539 struct cli_state *cli,
4540 uint16_t src_fnum, uint16_t dst_fnum,
4541 off_t size, off_t src_offset, off_t dst_offset,
4542 int (*splice_cb)(off_t n, void *priv),
4545 struct tevent_req *req;
4546 struct tevent_req *subreq;
4547 struct cli_smb2_splice_state *state;
4549 DATA_BLOB in_input_buffer = data_blob_null;
4550 DATA_BLOB in_output_buffer = data_blob_null;
4552 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
4558 state->splice_cb = splice_cb;
4562 state->src_offset = src_offset;
4563 state->dst_offset = dst_offset;
4564 state->cc_copy.chunks = talloc_array(state,
4565 struct srv_copychunk,
4566 smb2cli_conn_cc_max_chunks(cli->conn));
4567 if (state->cc_copy.chunks == NULL) {
4571 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
4572 if (tevent_req_nterror(req, status))
4573 return tevent_req_post(req, ev);
4575 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
4576 if (tevent_req_nterror(req, status))
4577 return tevent_req_post(req, ev);
4579 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
4583 state->src_ph->fid_persistent, /* in_fid_persistent */
4584 state->src_ph->fid_volatile, /* in_fid_volatile */
4585 FSCTL_SRV_REQUEST_RESUME_KEY,
4586 0, /* in_max_input_length */
4588 32, /* in_max_output_length */
4590 SMB2_IOCTL_FLAG_IS_FSCTL);
4591 if (tevent_req_nomem(subreq, req)) {
4594 tevent_req_set_callback(subreq,
4595 cli_splice_key_done,
4601 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
4603 struct cli_smb2_splice_state *state = tevent_req_data(
4604 req, struct cli_smb2_splice_state);
4607 if (tevent_req_is_nterror(req, &status)) {
4608 state->cli->raw_status = status;
4609 tevent_req_received(req);
4612 if (written != NULL) {
4613 *written = state->written;
4615 state->cli->raw_status = NT_STATUS_OK;
4616 tevent_req_received(req);
4617 return NT_STATUS_OK;
4620 /***************************************************************
4621 SMB2 enum shadow copy data.
4622 ***************************************************************/
4624 struct cli_smb2_shadow_copy_data_fnum_state {
4625 struct cli_state *cli;
4627 struct smb2_hnd *ph;
4628 DATA_BLOB out_input_buffer;
4629 DATA_BLOB out_output_buffer;
4632 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
4634 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
4635 TALLOC_CTX *mem_ctx,
4636 struct tevent_context *ev,
4637 struct cli_state *cli,
4641 struct tevent_req *req, *subreq;
4642 struct cli_smb2_shadow_copy_data_fnum_state *state;
4645 req = tevent_req_create(mem_ctx, &state,
4646 struct cli_smb2_shadow_copy_data_fnum_state);
4651 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4652 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4653 return tevent_req_post(req, ev);
4659 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4660 if (tevent_req_nterror(req, status)) {
4661 return tevent_req_post(req, ev);
4665 * TODO. Under SMB2 we should send a zero max_output_length
4666 * ioctl to get the required size, then send another ioctl
4667 * to get the data, but the current SMB1 implementation just
4668 * does one roundtrip with a 64K buffer size. Do the same
4672 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4673 state->cli->timeout,
4674 state->cli->smb2.session,
4675 state->cli->smb2.tcon,
4676 state->ph->fid_persistent, /* in_fid_persistent */
4677 state->ph->fid_volatile, /* in_fid_volatile */
4678 FSCTL_GET_SHADOW_COPY_DATA,
4679 0, /* in_max_input_length */
4680 NULL, /* in_input_buffer */
4682 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
4683 NULL, /* in_output_buffer */
4684 SMB2_IOCTL_FLAG_IS_FSCTL);
4686 if (tevent_req_nomem(subreq, req)) {
4687 return tevent_req_post(req, ev);
4689 tevent_req_set_callback(subreq,
4690 cli_smb2_shadow_copy_data_fnum_done,
4696 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4698 struct tevent_req *req = tevent_req_callback_data(
4699 subreq, struct tevent_req);
4700 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4701 req, struct cli_smb2_shadow_copy_data_fnum_state);
4704 status = smb2cli_ioctl_recv(subreq, state,
4705 &state->out_input_buffer,
4706 &state->out_output_buffer);
4707 tevent_req_simple_finish_ntstatus(subreq, status);
4710 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4711 TALLOC_CTX *mem_ctx,
4716 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4717 req, struct cli_smb2_shadow_copy_data_fnum_state);
4718 char **names = NULL;
4719 uint32_t num_names = 0;
4720 uint32_t num_names_returned = 0;
4721 uint32_t dlength = 0;
4723 uint8_t *endp = NULL;
4726 if (tevent_req_is_nterror(req, &status)) {
4730 if (state->out_output_buffer.length < 16) {
4731 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4734 num_names = IVAL(state->out_output_buffer.data, 0);
4735 num_names_returned = IVAL(state->out_output_buffer.data, 4);
4736 dlength = IVAL(state->out_output_buffer.data, 8);
4738 if (num_names > 0x7FFFFFFF) {
4739 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4742 if (get_names == false) {
4743 *pnum_names = (int)num_names;
4744 return NT_STATUS_OK;
4746 if (num_names != num_names_returned) {
4747 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4749 if (dlength + 12 < 12) {
4750 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4753 * NB. The below is an allowable return if there are
4754 * more snapshots than the buffer size we told the
4755 * server we can receive. We currently don't support
4758 if (dlength + 12 > state->out_output_buffer.length) {
4759 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4761 if (state->out_output_buffer.length +
4762 (2 * sizeof(SHADOW_COPY_LABEL)) <
4763 state->out_output_buffer.length) {
4764 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4767 names = talloc_array(mem_ctx, char *, num_names_returned);
4768 if (names == NULL) {
4769 return NT_STATUS_NO_MEMORY;
4772 endp = state->out_output_buffer.data +
4773 state->out_output_buffer.length;
4775 for (i=0; i<num_names_returned; i++) {
4778 size_t converted_size;
4780 src = state->out_output_buffer.data + 12 +
4781 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4783 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4784 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4786 ret = convert_string_talloc(
4787 names, CH_UTF16LE, CH_UNIX,
4788 src, 2 * sizeof(SHADOW_COPY_LABEL),
4789 &names[i], &converted_size);
4792 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4795 *pnum_names = num_names;
4797 return NT_STATUS_OK;
4800 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4801 struct cli_state *cli,
4807 TALLOC_CTX *frame = talloc_stackframe();
4808 struct tevent_context *ev;
4809 struct tevent_req *req;
4810 NTSTATUS status = NT_STATUS_NO_MEMORY;
4812 if (smbXcli_conn_has_async_calls(cli->conn)) {
4814 * Can't use sync call while an async call is in flight
4816 status = NT_STATUS_INVALID_PARAMETER;
4819 ev = samba_tevent_context_init(frame);
4823 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4831 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4834 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4840 cli->raw_status = status;
4846 /***************************************************************
4847 Wrapper that allows SMB2 to truncate a file.
4849 ***************************************************************/
4851 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4856 DATA_BLOB inbuf = data_blob_null;
4857 struct smb2_hnd *ph = NULL;
4858 TALLOC_CTX *frame = talloc_stackframe();
4860 if (smbXcli_conn_has_async_calls(cli->conn)) {
4862 * Can't use sync call while an async call is in flight
4864 status = NT_STATUS_INVALID_PARAMETER;
4868 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4869 status = NT_STATUS_INVALID_PARAMETER;
4873 status = map_fnum_to_smb2_handle(cli,
4876 if (!NT_STATUS_IS_OK(status)) {
4880 inbuf = data_blob_talloc_zero(frame, 8);
4881 if (inbuf.data == NULL) {
4882 status = NT_STATUS_NO_MEMORY;
4886 SBVAL(inbuf.data, 0, newsize);
4888 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4889 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4891 status = smb2cli_set_info(cli->conn,
4895 1, /* in_info_type */
4896 /* in_file_info_class */
4897 SMB_FILE_END_OF_FILE_INFORMATION - 1000,
4898 &inbuf, /* in_input_buffer */
4899 0, /* in_additional_info */
4905 cli->raw_status = status;
4911 struct cli_smb2_notify_state {
4912 struct tevent_req *subreq;
4913 struct notify_change *changes;
4917 static void cli_smb2_notify_done(struct tevent_req *subreq);
4918 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4920 struct tevent_req *cli_smb2_notify_send(
4921 TALLOC_CTX *mem_ctx,
4922 struct tevent_context *ev,
4923 struct cli_state *cli,
4925 uint32_t buffer_size,
4926 uint32_t completion_filter,
4929 struct tevent_req *req = NULL;
4930 struct cli_smb2_notify_state *state = NULL;
4931 struct smb2_hnd *ph = NULL;
4934 req = tevent_req_create(mem_ctx, &state,
4935 struct cli_smb2_notify_state);
4940 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4941 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4942 return tevent_req_post(req, ev);
4945 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4946 if (tevent_req_nterror(req, status)) {
4947 return tevent_req_post(req, ev);
4950 state->subreq = smb2cli_notify_send(
4962 if (tevent_req_nomem(state->subreq, req)) {
4963 return tevent_req_post(req, ev);
4965 tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4966 tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4970 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4972 struct cli_smb2_notify_state *state = tevent_req_data(
4973 req, struct cli_smb2_notify_state);
4976 ok = tevent_req_cancel(state->subreq);
4980 static void cli_smb2_notify_done(struct tevent_req *subreq)
4982 struct tevent_req *req = tevent_req_callback_data(
4983 subreq, struct tevent_req);
4984 struct cli_smb2_notify_state *state = tevent_req_data(
4985 req, struct cli_smb2_notify_state);
4991 status = smb2cli_notify_recv(subreq, state, &base, &len);
4992 TALLOC_FREE(subreq);
4994 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4995 tevent_req_done(req);
4998 if (tevent_req_nterror(req, status)) {
5004 while (len - ofs >= 12) {
5005 struct notify_change *tmp;
5006 struct notify_change *c;
5007 uint32_t next_ofs = IVAL(base, ofs);
5008 uint32_t file_name_length = IVAL(base, ofs+8);
5012 tmp = talloc_realloc(
5015 struct notify_change,
5016 state->num_changes + 1);
5017 if (tevent_req_nomem(tmp, req)) {
5020 state->changes = tmp;
5021 c = &state->changes[state->num_changes];
5022 state->num_changes += 1;
5024 if (smb_buffer_oob(len, ofs, next_ofs) ||
5025 smb_buffer_oob(len, ofs+12, file_name_length)) {
5027 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
5031 c->action = IVAL(base, ofs+4);
5033 ok = convert_string_talloc(
5043 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
5047 if (next_ofs == 0) {
5053 tevent_req_done(req);
5056 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
5057 TALLOC_CTX *mem_ctx,
5058 struct notify_change **pchanges,
5059 uint32_t *pnum_changes)
5061 struct cli_smb2_notify_state *state = tevent_req_data(
5062 req, struct cli_smb2_notify_state);
5065 if (tevent_req_is_nterror(req, &status)) {
5068 *pchanges = talloc_move(mem_ctx, &state->changes);
5069 *pnum_changes = state->num_changes;
5070 return NT_STATUS_OK;
5073 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
5074 uint32_t buffer_size, uint32_t completion_filter,
5075 bool recursive, TALLOC_CTX *mem_ctx,
5076 struct notify_change **pchanges,
5077 uint32_t *pnum_changes)
5079 TALLOC_CTX *frame = talloc_stackframe();
5080 struct tevent_context *ev;
5081 struct tevent_req *req;
5082 NTSTATUS status = NT_STATUS_NO_MEMORY;
5084 if (smbXcli_conn_has_async_calls(cli->conn)) {
5086 * Can't use sync call while an async call is in flight
5088 status = NT_STATUS_INVALID_PARAMETER;
5091 ev = samba_tevent_context_init(frame);
5095 req = cli_smb2_notify_send(
5106 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5109 status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
5115 struct cli_smb2_set_reparse_point_fnum_state {
5116 struct cli_state *cli;
5118 struct smb2_hnd *ph;
5119 DATA_BLOB input_buffer;
5122 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
5124 struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
5125 TALLOC_CTX *mem_ctx,
5126 struct tevent_context *ev,
5127 struct cli_state *cli,
5131 struct tevent_req *req, *subreq;
5132 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
5135 req = tevent_req_create(mem_ctx, &state,
5136 struct cli_smb2_set_reparse_point_fnum_state);
5141 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5142 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
5143 return tevent_req_post(req, ev);
5149 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
5150 if (tevent_req_nterror(req, status)) {
5151 return tevent_req_post(req, ev);
5154 state->input_buffer = data_blob_talloc(state,
5157 if (state->input_buffer.data == NULL) {
5158 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
5159 return tevent_req_post(req, ev);
5162 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
5163 state->cli->timeout,
5164 state->cli->smb2.session,
5165 state->cli->smb2.tcon,
5166 state->ph->fid_persistent, /* in_fid_persistent */
5167 state->ph->fid_volatile, /* in_fid_volatile */
5168 FSCTL_SET_REPARSE_POINT,
5169 0, /* in_max_input_length */
5170 &state->input_buffer ,
5173 SMB2_IOCTL_FLAG_IS_FSCTL);
5175 if (tevent_req_nomem(subreq, req)) {
5176 return tevent_req_post(req, ev);
5178 tevent_req_set_callback(subreq,
5179 cli_smb2_set_reparse_point_fnum_done,
5185 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
5187 struct tevent_req *req = tevent_req_callback_data(
5188 subreq, struct tevent_req);
5189 struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
5190 req, struct cli_smb2_set_reparse_point_fnum_state);
5193 status = smb2cli_ioctl_recv(subreq, state,
5196 TALLOC_FREE(subreq);
5197 if (tevent_req_nterror(req, status)) {
5200 tevent_req_done(req);
5203 NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
5205 return tevent_req_simple_recv_ntstatus(req);
5208 struct cli_smb2_get_reparse_point_fnum_state {
5209 struct cli_state *cli;
5211 struct smb2_hnd *ph;
5212 DATA_BLOB output_buffer;
5215 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
5217 struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
5218 TALLOC_CTX *mem_ctx,
5219 struct tevent_context *ev,
5220 struct cli_state *cli,
5223 struct tevent_req *req, *subreq;
5224 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
5227 req = tevent_req_create(mem_ctx, &state,
5228 struct cli_smb2_get_reparse_point_fnum_state);
5233 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5234 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
5235 return tevent_req_post(req, ev);
5241 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
5242 if (tevent_req_nterror(req, status)) {
5243 return tevent_req_post(req, ev);
5246 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
5247 state->cli->timeout,
5248 state->cli->smb2.session,
5249 state->cli->smb2.tcon,
5250 state->ph->fid_persistent, /* in_fid_persistent */
5251 state->ph->fid_volatile, /* in_fid_volatile */
5252 FSCTL_GET_REPARSE_POINT,
5253 0, /* in_max_input_length */
5257 SMB2_IOCTL_FLAG_IS_FSCTL);
5259 if (tevent_req_nomem(subreq, req)) {
5260 return tevent_req_post(req, ev);
5262 tevent_req_set_callback(subreq,
5263 cli_smb2_get_reparse_point_fnum_done,
5269 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
5271 struct tevent_req *req = tevent_req_callback_data(
5272 subreq, struct tevent_req);
5273 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
5274 req, struct cli_smb2_get_reparse_point_fnum_state);
5277 status = smb2cli_ioctl_recv(subreq, state,
5279 &state->output_buffer);
5280 TALLOC_FREE(subreq);
5281 if (tevent_req_nterror(req, status)) {
5282 state->cli->raw_status = status;
5285 tevent_req_done(req);
5288 NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
5289 TALLOC_CTX *mem_ctx,
5292 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
5293 req, struct cli_smb2_get_reparse_point_fnum_state);
5295 if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
5296 tevent_req_received(req);
5297 return state->cli->raw_status;
5299 *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
5300 if (output->data == NULL) {
5301 tevent_req_received(req);
5302 return NT_STATUS_NO_MEMORY;
5304 tevent_req_received(req);
5305 return NT_STATUS_OK;