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;
714 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq);
715 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq);
716 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq);
717 static void cli_smb2_rmdir_closed(struct tevent_req *subreq);
719 struct tevent_req *cli_smb2_rmdir_send(TALLOC_CTX *mem_ctx,
720 struct tevent_context *ev,
721 struct cli_state *cli,
724 struct tevent_req *req = NULL, *subreq = NULL;
725 struct cli_smb2_rmdir_state *state = NULL;
727 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_rmdir_state);
733 state->dname = dname;
735 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
736 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
737 return tevent_req_post(req, ev);
740 subreq = cli_smb2_create_fnum_send(
745 0, /* create_flags */
746 SMB2_IMPERSONATION_IMPERSONATION,
747 DELETE_ACCESS, /* desired_access */
748 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
749 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
750 FILE_OPEN, /* create_disposition */
751 FILE_DIRECTORY_FILE, /* create_options */
752 NULL); /* in_cblobs */
753 if (tevent_req_nomem(subreq, req)) {
754 return tevent_req_post(req, ev);
756 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened1, req);
760 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq)
762 struct tevent_req *req = tevent_req_callback_data(
763 subreq, struct tevent_req);
764 struct cli_smb2_rmdir_state *state = tevent_req_data(
765 req, struct cli_smb2_rmdir_state);
768 status = cli_smb2_create_fnum_recv(
769 subreq, &state->fnum, NULL, NULL, NULL);
772 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
774 * Naive option to match our SMB1 code. Assume the
775 * symlink path that tripped us up was the last
776 * component and try again. Eventually we will have to
777 * deal with the returned path unprocessed component. JRA.
779 subreq = cli_smb2_create_fnum_send(
784 0, /* create_flags */
785 SMB2_IMPERSONATION_IMPERSONATION,
786 DELETE_ACCESS, /* desired_access */
787 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
788 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
789 FILE_OPEN, /* create_disposition */
791 FILE_DELETE_ON_CLOSE|
792 FILE_OPEN_REPARSE_POINT, /* create_options */
793 NULL); /* in_cblobs */
794 if (tevent_req_nomem(subreq, req)) {
797 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened2, req);
801 if (tevent_req_nterror(req, status)) {
805 subreq = cli_smb2_delete_on_close_send(
806 state, state->ev, state->cli, state->fnum, true);
807 if (tevent_req_nomem(subreq, req)) {
810 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
813 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq)
815 struct tevent_req *req = tevent_req_callback_data(
816 subreq, struct tevent_req);
817 struct cli_smb2_rmdir_state *state = tevent_req_data(
818 req, struct cli_smb2_rmdir_state);
821 status = cli_smb2_create_fnum_recv(
822 subreq, &state->fnum, NULL, NULL, NULL);
824 if (tevent_req_nterror(req, status)) {
828 subreq = cli_smb2_delete_on_close_send(
829 state, state->ev, state->cli, state->fnum, true);
830 if (tevent_req_nomem(subreq, req)) {
833 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
836 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq)
838 struct tevent_req *req = tevent_req_callback_data(
839 subreq, struct tevent_req);
840 struct cli_smb2_rmdir_state *state = tevent_req_data(
841 req, struct cli_smb2_rmdir_state);
843 state->status = cli_smb2_delete_on_close_recv(subreq);
847 * Close the fd even if the set_disp failed
850 subreq = cli_smb2_close_fnum_send(
851 state, state->ev, state->cli, state->fnum);
852 if (tevent_req_nomem(subreq, req)) {
855 tevent_req_set_callback(subreq, cli_smb2_rmdir_closed, req);
858 static void cli_smb2_rmdir_closed(struct tevent_req *subreq)
860 struct tevent_req *req = tevent_req_callback_data(
861 subreq, struct tevent_req);
864 status = cli_smb2_close_fnum_recv(subreq);
865 if (tevent_req_nterror(req, status)) {
868 tevent_req_done(req);
871 NTSTATUS cli_smb2_rmdir_recv(struct tevent_req *req)
873 struct cli_smb2_rmdir_state *state = tevent_req_data(
874 req, struct cli_smb2_rmdir_state);
877 if (tevent_req_is_nterror(req, &status)) {
880 return state->status;
883 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
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);
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 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
927 if (smbXcli_conn_has_async_calls(cli->conn)) {
929 * Can't use sync call while an async call is in flight
931 return NT_STATUS_INVALID_PARAMETER;
934 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
935 return NT_STATUS_INVALID_PARAMETER;
938 status = cli_smb2_create_fnum(cli,
940 0, /* create_flags */
941 SMB2_IMPERSONATION_IMPERSONATION,
942 DELETE_ACCESS, /* desired_access */
943 FILE_ATTRIBUTE_NORMAL, /* file attributes */
944 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
945 FILE_OPEN, /* create_disposition */
946 FILE_DELETE_ON_CLOSE, /* create_options */
953 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
955 * Naive option to match our SMB1 code. Assume the
956 * symlink path that tripped us up was the last
957 * component and try again. Eventually we will have to
958 * deal with the returned path unprocessed component. JRA.
960 status = cli_smb2_create_fnum(cli,
962 0, /* create_flags */
963 SMB2_IMPERSONATION_IMPERSONATION,
964 DELETE_ACCESS, /* desired_access */
965 FILE_ATTRIBUTE_NORMAL, /* file attributes */
966 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
967 FILE_OPEN, /* create_disposition */
968 FILE_DELETE_ON_CLOSE|
969 FILE_OPEN_REPARSE_POINT, /* create_options */
977 if (!NT_STATUS_IS_OK(status)) {
980 return cli_smb2_close_fnum(cli, fnum);
983 /***************************************************************
984 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
985 ***************************************************************/
987 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
988 uint32_t dir_data_length,
989 struct file_info *finfo,
990 uint32_t *next_offset)
996 if (dir_data_length < 4) {
997 return NT_STATUS_INFO_LENGTH_MISMATCH;
1000 *next_offset = IVAL(dir_data, 0);
1002 if (*next_offset > dir_data_length) {
1003 return NT_STATUS_INFO_LENGTH_MISMATCH;
1006 if (*next_offset != 0) {
1007 /* Ensure we only read what in this record. */
1008 dir_data_length = *next_offset;
1011 if (dir_data_length < 105) {
1012 return NT_STATUS_INFO_LENGTH_MISMATCH;
1015 finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
1016 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
1017 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
1018 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
1019 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
1020 finfo->allocated_size = IVAL2_TO_SMB_BIG_UINT(dir_data + 48, 0);
1021 finfo->mode = CVAL(dir_data + 56, 0);
1022 finfo->ino = IVAL2_TO_SMB_BIG_UINT(dir_data + 96, 0);
1023 namelen = IVAL(dir_data + 60,0);
1024 if (namelen > (dir_data_length - 104)) {
1025 return NT_STATUS_INFO_LENGTH_MISMATCH;
1027 slen = CVAL(dir_data + 68, 0);
1029 return NT_STATUS_INFO_LENGTH_MISMATCH;
1031 ret = pull_string_talloc(finfo,
1033 FLAGS2_UNICODE_STRINGS,
1038 if (ret == (size_t)-1) {
1039 /* Bad conversion. */
1040 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1043 ret = pull_string_talloc(finfo,
1045 FLAGS2_UNICODE_STRINGS,
1050 if (ret == (size_t)-1) {
1051 /* Bad conversion. */
1052 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1054 return NT_STATUS_OK;
1057 /*******************************************************************
1058 Given a filename - get its directory name
1059 ********************************************************************/
1061 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
1069 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
1072 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
1083 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
1086 (*parent)[len] = '\0';
1094 /***************************************************************
1095 Wrapper that allows SMB2 to list a directory.
1097 ***************************************************************/
1099 NTSTATUS cli_smb2_list(struct cli_state *cli,
1100 const char *pathname,
1102 NTSTATUS (*fn)(const char *,
1109 uint16_t fnum = 0xffff;
1110 char *parent_dir = NULL;
1111 const char *mask = NULL;
1112 struct smb2_hnd *ph = NULL;
1113 bool processed_file = false;
1114 TALLOC_CTX *frame = talloc_stackframe();
1115 TALLOC_CTX *subframe = NULL;
1118 uint32_t max_avail_len;
1121 if (smbXcli_conn_has_async_calls(cli->conn)) {
1123 * Can't use sync call while an async call is in flight
1125 status = NT_STATUS_INVALID_PARAMETER;
1129 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1130 status = NT_STATUS_INVALID_PARAMETER;
1134 /* Get the directory name. */
1135 if (!windows_parent_dirname(frame,
1139 status = NT_STATUS_NO_MEMORY;
1143 mask_has_wild = ms_has_wild(mask);
1145 status = cli_smb2_create_fnum(cli,
1147 0, /* create_flags */
1148 SMB2_IMPERSONATION_IMPERSONATION,
1149 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
1150 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1151 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
1152 FILE_OPEN, /* create_disposition */
1153 FILE_DIRECTORY_FILE, /* create_options */
1160 if (!NT_STATUS_IS_OK(status)) {
1164 status = map_fnum_to_smb2_handle(cli,
1167 if (!NT_STATUS_IS_OK(status)) {
1172 * ideally, use the max transaction size, but don't send a request
1173 * bigger than we have credits available for
1175 max_trans = smb2cli_conn_max_trans_size(cli->conn);
1176 ok = smb2cli_conn_req_possible(cli->conn, &max_avail_len);
1178 max_trans = MIN(max_trans, max_avail_len);
1182 uint8_t *dir_data = NULL;
1183 uint32_t dir_data_length = 0;
1184 uint32_t next_offset = 0;
1185 subframe = talloc_stackframe();
1187 status = smb2cli_query_directory(cli->conn,
1191 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
1202 if (!NT_STATUS_IS_OK(status)) {
1203 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1210 struct file_info *finfo = talloc_zero(subframe,
1213 if (finfo == NULL) {
1214 status = NT_STATUS_NO_MEMORY;
1218 status = parse_finfo_id_both_directory_info(dir_data,
1223 if (!NT_STATUS_IS_OK(status)) {
1227 if (dir_check_ftype((uint32_t)finfo->mode,
1228 (uint32_t)attribute)) {
1230 * Only process if attributes match.
1231 * On SMB1 server does this, so on
1232 * SMB2 we need to emulate in the
1235 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1237 processed_file = true;
1239 status = fn(cli->dfs_mountpoint,
1244 if (!NT_STATUS_IS_OK(status)) {
1251 /* Move to next entry. */
1253 dir_data += next_offset;
1254 dir_data_length -= next_offset;
1256 } while (next_offset != 0);
1258 TALLOC_FREE(subframe);
1260 if (!mask_has_wild) {
1262 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1263 * when handed a non-wildcard path. Do it
1264 * for the server (with a non-wildcard path
1265 * there should only ever be one file returned.
1267 status = STATUS_NO_MORE_FILES;
1271 } while (NT_STATUS_IS_OK(status));
1273 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1274 status = NT_STATUS_OK;
1277 if (NT_STATUS_IS_OK(status) && !processed_file) {
1279 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1280 * if no files match. Emulate this in the client.
1282 status = NT_STATUS_NO_SUCH_FILE;
1287 if (fnum != 0xffff) {
1288 cli_smb2_close_fnum(cli, fnum);
1291 cli->raw_status = status;
1293 TALLOC_FREE(subframe);
1298 /***************************************************************
1299 Wrapper that allows SMB2 to query a path info (basic level).
1301 ***************************************************************/
1303 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1305 SMB_STRUCT_STAT *sbuf,
1306 uint32_t *attributes)
1309 struct smb_create_returns cr;
1310 uint16_t fnum = 0xffff;
1311 size_t namelen = strlen(name);
1313 if (smbXcli_conn_has_async_calls(cli->conn)) {
1315 * Can't use sync call while an async call is in flight
1317 return NT_STATUS_INVALID_PARAMETER;
1320 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1321 return NT_STATUS_INVALID_PARAMETER;
1324 /* SMB2 is pickier about pathnames. Ensure it doesn't
1326 if (namelen > 0 && name[namelen-1] == '\\') {
1327 char *modname = talloc_strdup(talloc_tos(), name);
1328 modname[namelen-1] = '\0';
1332 /* This is commonly used as a 'cd'. Try qpathinfo on
1333 a directory handle first. */
1335 status = cli_smb2_create_fnum(cli,
1337 0, /* create_flags */
1338 SMB2_IMPERSONATION_IMPERSONATION,
1339 FILE_READ_ATTRIBUTES, /* desired_access */
1340 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1341 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1342 FILE_OPEN, /* create_disposition */
1343 FILE_DIRECTORY_FILE, /* create_options */
1350 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1351 /* Maybe a file ? */
1352 status = cli_smb2_create_fnum(cli,
1354 0, /* create_flags */
1355 SMB2_IMPERSONATION_IMPERSONATION,
1356 FILE_READ_ATTRIBUTES, /* desired_access */
1357 0, /* file attributes */
1358 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1359 FILE_OPEN, /* create_disposition */
1360 0, /* create_options */
1368 if (!NT_STATUS_IS_OK(status)) {
1372 status = cli_smb2_close_fnum(cli, fnum);
1376 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1377 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1378 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1379 sbuf->st_ex_size = cr.end_of_file;
1380 *attributes = cr.file_attributes;
1385 /***************************************************************
1386 Wrapper that allows SMB2 to check if a path is a directory.
1388 ***************************************************************/
1390 NTSTATUS cli_smb2_chkpath(struct cli_state *cli,
1394 uint16_t fnum = 0xffff;
1396 if (smbXcli_conn_has_async_calls(cli->conn)) {
1398 * Can't use sync call while an async call is in flight
1400 return NT_STATUS_INVALID_PARAMETER;
1403 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1404 return NT_STATUS_INVALID_PARAMETER;
1407 /* Ensure this is a directory. */
1408 status = cli_smb2_create_fnum(cli,
1410 0, /* create_flags */
1411 SMB2_IMPERSONATION_IMPERSONATION,
1412 FILE_READ_ATTRIBUTES, /* desired_access */
1413 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1414 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1415 FILE_OPEN, /* create_disposition */
1416 FILE_DIRECTORY_FILE, /* create_options */
1423 if (!NT_STATUS_IS_OK(status)) {
1427 return cli_smb2_close_fnum(cli, fnum);
1430 /***************************************************************
1431 Helper function for pathname operations.
1432 ***************************************************************/
1434 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1436 uint32_t desired_access,
1440 size_t namelen = strlen(name);
1441 TALLOC_CTX *frame = talloc_stackframe();
1442 uint32_t create_options = 0;
1444 /* SMB2 is pickier about pathnames. Ensure it doesn't
1446 if (namelen > 0 && name[namelen-1] == '\\') {
1447 char *modname = talloc_strdup(frame, name);
1448 if (modname == NULL) {
1449 status = NT_STATUS_NO_MEMORY;
1452 modname[namelen-1] = '\0';
1456 /* Try to open a file handle first. */
1457 status = cli_smb2_create_fnum(cli,
1459 0, /* create_flags */
1460 SMB2_IMPERSONATION_IMPERSONATION,
1462 0, /* file attributes */
1463 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1464 FILE_OPEN, /* create_disposition */
1472 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1474 * Naive option to match our SMB1 code. Assume the
1475 * symlink path that tripped us up was the last
1476 * component and try again. Eventually we will have to
1477 * deal with the returned path unprocessed component. JRA.
1479 create_options |= FILE_OPEN_REPARSE_POINT;
1480 status = cli_smb2_create_fnum(cli,
1482 0, /* create_flags */
1483 SMB2_IMPERSONATION_IMPERSONATION,
1485 0, /* file attributes */
1486 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1487 FILE_OPEN, /* create_disposition */
1496 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1497 create_options |= FILE_DIRECTORY_FILE;
1498 status = cli_smb2_create_fnum(cli,
1500 0, /* create_flags */
1501 SMB2_IMPERSONATION_IMPERSONATION,
1503 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1504 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1505 FILE_OPEN, /* create_disposition */
1506 FILE_DIRECTORY_FILE, /* create_options */
1520 /***************************************************************
1521 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1523 ***************************************************************/
1525 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1530 DATA_BLOB outbuf = data_blob_null;
1531 uint16_t fnum = 0xffff;
1532 struct smb2_hnd *ph = NULL;
1533 uint32_t altnamelen = 0;
1534 TALLOC_CTX *frame = talloc_stackframe();
1536 if (smbXcli_conn_has_async_calls(cli->conn)) {
1538 * Can't use sync call while an async call is in flight
1540 status = NT_STATUS_INVALID_PARAMETER;
1544 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1545 status = NT_STATUS_INVALID_PARAMETER;
1549 status = get_fnum_from_path(cli,
1551 FILE_READ_ATTRIBUTES,
1554 if (!NT_STATUS_IS_OK(status)) {
1558 status = map_fnum_to_smb2_handle(cli,
1561 if (!NT_STATUS_IS_OK(status)) {
1565 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1566 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1568 status = smb2cli_query_info(cli->conn,
1572 1, /* in_info_type */
1573 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1574 0xFFFF, /* in_max_output_length */
1575 NULL, /* in_input_buffer */
1576 0, /* in_additional_info */
1583 if (!NT_STATUS_IS_OK(status)) {
1587 /* Parse the reply. */
1588 if (outbuf.length < 4) {
1589 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1593 altnamelen = IVAL(outbuf.data, 0);
1594 if (altnamelen > outbuf.length - 4) {
1595 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1599 if (altnamelen > 0) {
1601 char *short_name = NULL;
1602 ret = pull_string_talloc(frame,
1604 FLAGS2_UNICODE_STRINGS,
1609 if (ret == (size_t)-1) {
1610 /* Bad conversion. */
1611 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1615 fstrcpy(alt_name, short_name);
1620 status = NT_STATUS_OK;
1624 if (fnum != 0xffff) {
1625 cli_smb2_close_fnum(cli, fnum);
1628 cli->raw_status = status;
1635 /***************************************************************
1636 Wrapper that allows SMB2 to query a fnum info (basic level).
1638 ***************************************************************/
1640 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1644 struct timespec *create_time,
1645 struct timespec *access_time,
1646 struct timespec *write_time,
1647 struct timespec *change_time,
1651 DATA_BLOB outbuf = data_blob_null;
1652 struct smb2_hnd *ph = NULL;
1653 TALLOC_CTX *frame = talloc_stackframe();
1655 if (smbXcli_conn_has_async_calls(cli->conn)) {
1657 * Can't use sync call while an async call is in flight
1659 status = NT_STATUS_INVALID_PARAMETER;
1663 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1664 status = NT_STATUS_INVALID_PARAMETER;
1668 status = map_fnum_to_smb2_handle(cli,
1671 if (!NT_STATUS_IS_OK(status)) {
1675 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1676 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1678 status = smb2cli_query_info(cli->conn,
1682 1, /* in_info_type */
1683 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1684 0xFFFF, /* in_max_output_length */
1685 NULL, /* in_input_buffer */
1686 0, /* in_additional_info */
1692 if (!NT_STATUS_IS_OK(status)) {
1696 /* Parse the reply. */
1697 if (outbuf.length < 0x60) {
1698 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1703 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1706 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1709 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1712 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1715 uint32_t attr = IVAL(outbuf.data, 0x20);
1716 *mode = (uint16_t)attr;
1719 uint64_t file_size = BVAL(outbuf.data, 0x30);
1720 *size = (off_t)file_size;
1723 uint64_t file_index = BVAL(outbuf.data, 0x40);
1724 *ino = (SMB_INO_T)file_index;
1729 cli->raw_status = status;
1735 /***************************************************************
1736 Wrapper that allows SMB2 to query an fnum.
1737 Implement on top of cli_smb2_qfileinfo_basic().
1739 ***************************************************************/
1741 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1745 time_t *change_time,
1746 time_t *access_time,
1749 struct timespec access_time_ts;
1750 struct timespec write_time_ts;
1751 struct timespec change_time_ts;
1752 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1762 cli->raw_status = status;
1764 if (!NT_STATUS_IS_OK(status)) {
1769 *change_time = change_time_ts.tv_sec;
1772 *access_time = access_time_ts.tv_sec;
1775 *write_time = write_time_ts.tv_sec;
1777 return NT_STATUS_OK;
1780 /***************************************************************
1781 Wrapper that allows SMB2 to get pathname attributes.
1783 ***************************************************************/
1785 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1792 uint16_t fnum = 0xffff;
1793 struct smb2_hnd *ph = NULL;
1794 TALLOC_CTX *frame = talloc_stackframe();
1796 if (smbXcli_conn_has_async_calls(cli->conn)) {
1798 * Can't use sync call while an async call is in flight
1800 status = NT_STATUS_INVALID_PARAMETER;
1804 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1805 status = NT_STATUS_INVALID_PARAMETER;
1809 status = get_fnum_from_path(cli,
1811 FILE_READ_ATTRIBUTES,
1814 if (!NT_STATUS_IS_OK(status)) {
1818 status = map_fnum_to_smb2_handle(cli,
1821 if (!NT_STATUS_IS_OK(status)) {
1824 status = cli_smb2_getattrE(cli,
1831 if (!NT_STATUS_IS_OK(status)) {
1837 if (fnum != 0xffff) {
1838 cli_smb2_close_fnum(cli, fnum);
1841 cli->raw_status = status;
1847 /***************************************************************
1848 Wrapper that allows SMB2 to query a pathname info (basic level).
1849 Implement on top of cli_smb2_qfileinfo_basic().
1851 ***************************************************************/
1853 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1855 struct timespec *create_time,
1856 struct timespec *access_time,
1857 struct timespec *write_time,
1858 struct timespec *change_time,
1864 struct smb2_hnd *ph = NULL;
1865 uint16_t fnum = 0xffff;
1866 TALLOC_CTX *frame = talloc_stackframe();
1868 if (smbXcli_conn_has_async_calls(cli->conn)) {
1870 * Can't use sync call while an async call is in flight
1872 status = NT_STATUS_INVALID_PARAMETER;
1876 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1877 status = NT_STATUS_INVALID_PARAMETER;
1881 status = get_fnum_from_path(cli,
1883 FILE_READ_ATTRIBUTES,
1886 if (!NT_STATUS_IS_OK(status)) {
1890 status = map_fnum_to_smb2_handle(cli,
1893 if (!NT_STATUS_IS_OK(status)) {
1897 status = cli_smb2_qfileinfo_basic(cli,
1909 if (fnum != 0xffff) {
1910 cli_smb2_close_fnum(cli, fnum);
1913 cli->raw_status = status;
1919 /***************************************************************
1920 Wrapper that allows SMB2 to query pathname streams.
1922 ***************************************************************/
1924 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1926 TALLOC_CTX *mem_ctx,
1927 unsigned int *pnum_streams,
1928 struct stream_struct **pstreams)
1931 struct smb2_hnd *ph = NULL;
1932 uint16_t fnum = 0xffff;
1933 DATA_BLOB outbuf = data_blob_null;
1934 TALLOC_CTX *frame = talloc_stackframe();
1936 if (smbXcli_conn_has_async_calls(cli->conn)) {
1938 * Can't use sync call while an async call is in flight
1940 status = NT_STATUS_INVALID_PARAMETER;
1944 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1945 status = NT_STATUS_INVALID_PARAMETER;
1949 status = get_fnum_from_path(cli,
1951 FILE_READ_ATTRIBUTES,
1954 if (!NT_STATUS_IS_OK(status)) {
1958 status = map_fnum_to_smb2_handle(cli,
1961 if (!NT_STATUS_IS_OK(status)) {
1965 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1966 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1968 status = smb2cli_query_info(cli->conn,
1972 1, /* in_info_type */
1973 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1974 0xFFFF, /* in_max_output_length */
1975 NULL, /* in_input_buffer */
1976 0, /* in_additional_info */
1983 if (!NT_STATUS_IS_OK(status)) {
1987 /* Parse the reply. */
1988 if (!parse_streams_blob(mem_ctx,
1993 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1999 if (fnum != 0xffff) {
2000 cli_smb2_close_fnum(cli, fnum);
2003 cli->raw_status = status;
2009 /***************************************************************
2010 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2013 ***************************************************************/
2015 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
2017 uint8_t in_info_type,
2018 uint8_t in_file_info_class,
2019 const DATA_BLOB *p_in_data)
2022 uint16_t fnum = 0xffff;
2023 struct smb2_hnd *ph = NULL;
2024 TALLOC_CTX *frame = talloc_stackframe();
2026 if (smbXcli_conn_has_async_calls(cli->conn)) {
2028 * Can't use sync call while an async call is in flight
2030 status = NT_STATUS_INVALID_PARAMETER;
2034 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2035 status = NT_STATUS_INVALID_PARAMETER;
2039 status = get_fnum_from_path(cli,
2041 FILE_WRITE_ATTRIBUTES,
2044 if (!NT_STATUS_IS_OK(status)) {
2048 status = map_fnum_to_smb2_handle(cli,
2051 if (!NT_STATUS_IS_OK(status)) {
2055 status = smb2cli_set_info(cli->conn,
2061 p_in_data, /* in_input_buffer */
2062 0, /* in_additional_info */
2067 if (fnum != 0xffff) {
2068 cli_smb2_close_fnum(cli, fnum);
2071 cli->raw_status = status;
2078 /***************************************************************
2079 Wrapper that allows SMB2 to set pathname attributes.
2081 ***************************************************************/
2083 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
2088 uint8_t inbuf_store[40];
2089 DATA_BLOB inbuf = data_blob_null;
2091 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2092 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2094 inbuf.data = inbuf_store;
2095 inbuf.length = sizeof(inbuf_store);
2096 data_blob_clear(&inbuf);
2099 * SMB1 uses attr == 0 to clear all attributes
2100 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2101 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2102 * request attribute change.
2104 * SMB2 uses exactly the reverse. Unfortunately as the
2105 * cli_setatr() ABI is exposed inside libsmbclient,
2106 * we must make the SMB2 cli_smb2_setatr() call
2107 * export the same ABI as the SMB1 cli_setatr()
2108 * which calls it. This means reversing the sense
2109 * of the requested attr argument if it's zero
2110 * or FILE_ATTRIBUTE_NORMAL.
2112 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2116 attr = FILE_ATTRIBUTE_NORMAL;
2117 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
2121 SSVAL(inbuf.data, 32, attr);
2123 put_long_date((char *)inbuf.data + 16,mtime);
2125 /* Set all the other times to -1. */
2126 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2127 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
2128 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
2130 return cli_smb2_setpathinfo(cli,
2132 1, /* in_info_type */
2133 /* in_file_info_class */
2134 SMB_FILE_BASIC_INFORMATION - 1000,
2139 /***************************************************************
2140 Wrapper that allows SMB2 to set file handle times.
2142 ***************************************************************/
2144 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
2151 struct smb2_hnd *ph = NULL;
2152 uint8_t inbuf_store[40];
2153 DATA_BLOB inbuf = data_blob_null;
2155 if (smbXcli_conn_has_async_calls(cli->conn)) {
2157 * Can't use sync call while an async call is in flight
2159 return NT_STATUS_INVALID_PARAMETER;
2162 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2163 return NT_STATUS_INVALID_PARAMETER;
2166 status = map_fnum_to_smb2_handle(cli,
2169 if (!NT_STATUS_IS_OK(status)) {
2173 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2174 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2176 inbuf.data = inbuf_store;
2177 inbuf.length = sizeof(inbuf_store);
2178 data_blob_clear(&inbuf);
2180 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2181 if (change_time != 0) {
2182 put_long_date((char *)inbuf.data + 24, change_time);
2184 if (access_time != 0) {
2185 put_long_date((char *)inbuf.data + 8, access_time);
2187 if (write_time != 0) {
2188 put_long_date((char *)inbuf.data + 16, write_time);
2191 cli->raw_status = smb2cli_set_info(cli->conn,
2195 1, /* in_info_type */
2196 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
2197 &inbuf, /* in_input_buffer */
2198 0, /* in_additional_info */
2202 return cli->raw_status;
2205 /***************************************************************
2206 Wrapper that allows SMB2 to query disk attributes (size).
2208 ***************************************************************/
2210 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2211 uint64_t *bsize, uint64_t *total, uint64_t *avail)
2214 uint16_t fnum = 0xffff;
2215 DATA_BLOB outbuf = data_blob_null;
2216 struct smb2_hnd *ph = NULL;
2217 uint32_t sectors_per_unit = 0;
2218 uint32_t bytes_per_sector = 0;
2219 uint64_t total_size = 0;
2220 uint64_t size_free = 0;
2221 TALLOC_CTX *frame = talloc_stackframe();
2223 if (smbXcli_conn_has_async_calls(cli->conn)) {
2225 * Can't use sync call while an async call is in flight
2227 status = NT_STATUS_INVALID_PARAMETER;
2231 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2232 status = NT_STATUS_INVALID_PARAMETER;
2236 /* First open the top level directory. */
2237 status = cli_smb2_create_fnum(cli,
2239 0, /* create_flags */
2240 SMB2_IMPERSONATION_IMPERSONATION,
2241 FILE_READ_ATTRIBUTES, /* desired_access */
2242 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2243 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2244 FILE_OPEN, /* create_disposition */
2245 FILE_DIRECTORY_FILE, /* create_options */
2252 if (!NT_STATUS_IS_OK(status)) {
2256 status = map_fnum_to_smb2_handle(cli,
2259 if (!NT_STATUS_IS_OK(status)) {
2263 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2264 level 3 (SMB_FS_SIZE_INFORMATION). */
2266 status = smb2cli_query_info(cli->conn,
2270 2, /* in_info_type */
2271 3, /* in_file_info_class */
2272 0xFFFF, /* in_max_output_length */
2273 NULL, /* in_input_buffer */
2274 0, /* in_additional_info */
2280 if (!NT_STATUS_IS_OK(status)) {
2284 /* Parse the reply. */
2285 if (outbuf.length != 24) {
2286 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2290 total_size = BVAL(outbuf.data, 0);
2291 size_free = BVAL(outbuf.data, 8);
2292 sectors_per_unit = IVAL(outbuf.data, 16);
2293 bytes_per_sector = IVAL(outbuf.data, 20);
2296 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2299 *total = total_size;
2305 status = NT_STATUS_OK;
2309 if (fnum != 0xffff) {
2310 cli_smb2_close_fnum(cli, fnum);
2313 cli->raw_status = status;
2319 /***************************************************************
2320 Wrapper that allows SMB2 to query file system sizes.
2322 ***************************************************************/
2324 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2325 uint64_t *total_allocation_units,
2326 uint64_t *caller_allocation_units,
2327 uint64_t *actual_allocation_units,
2328 uint64_t *sectors_per_allocation_unit,
2329 uint64_t *bytes_per_sector)
2332 uint16_t fnum = 0xffff;
2333 DATA_BLOB outbuf = data_blob_null;
2334 struct smb2_hnd *ph = NULL;
2335 TALLOC_CTX *frame = talloc_stackframe();
2337 if (smbXcli_conn_has_async_calls(cli->conn)) {
2339 * Can't use sync call while an async call is in flight
2341 status = NT_STATUS_INVALID_PARAMETER;
2345 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2346 status = NT_STATUS_INVALID_PARAMETER;
2350 /* First open the top level directory. */
2352 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2353 SMB2_IMPERSONATION_IMPERSONATION,
2354 FILE_READ_ATTRIBUTES, /* desired_access */
2355 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2356 FILE_SHARE_READ | FILE_SHARE_WRITE |
2357 FILE_SHARE_DELETE, /* share_access */
2358 FILE_OPEN, /* create_disposition */
2359 FILE_DIRECTORY_FILE, /* create_options */
2366 if (!NT_STATUS_IS_OK(status)) {
2370 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2371 if (!NT_STATUS_IS_OK(status)) {
2375 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2376 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2378 status = smb2cli_query_info(cli->conn,
2382 SMB2_GETINFO_FS, /* in_info_type */
2383 /* in_file_info_class */
2384 SMB_FS_FULL_SIZE_INFORMATION - 1000,
2385 0xFFFF, /* in_max_output_length */
2386 NULL, /* in_input_buffer */
2387 0, /* in_additional_info */
2393 if (!NT_STATUS_IS_OK(status)) {
2397 if (outbuf.length < 32) {
2398 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2402 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2403 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2404 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2405 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2406 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2410 if (fnum != 0xffff) {
2411 cli_smb2_close_fnum(cli, fnum);
2414 cli->raw_status = status;
2420 /***************************************************************
2421 Wrapper that allows SMB2 to query file system attributes.
2423 ***************************************************************/
2425 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2428 uint16_t fnum = 0xffff;
2429 DATA_BLOB outbuf = data_blob_null;
2430 struct smb2_hnd *ph = NULL;
2431 TALLOC_CTX *frame = talloc_stackframe();
2433 if (smbXcli_conn_has_async_calls(cli->conn)) {
2435 * Can't use sync call while an async call is in flight
2437 status = NT_STATUS_INVALID_PARAMETER;
2441 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2442 status = NT_STATUS_INVALID_PARAMETER;
2446 /* First open the top level directory. */
2448 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2449 SMB2_IMPERSONATION_IMPERSONATION,
2450 FILE_READ_ATTRIBUTES, /* desired_access */
2451 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2452 FILE_SHARE_READ | FILE_SHARE_WRITE |
2453 FILE_SHARE_DELETE, /* share_access */
2454 FILE_OPEN, /* create_disposition */
2455 FILE_DIRECTORY_FILE, /* create_options */
2462 if (!NT_STATUS_IS_OK(status)) {
2466 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2467 if (!NT_STATUS_IS_OK(status)) {
2471 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2472 cli->smb2.tcon, 2, /* in_info_type */
2473 5, /* in_file_info_class */
2474 0xFFFF, /* in_max_output_length */
2475 NULL, /* in_input_buffer */
2476 0, /* in_additional_info */
2478 ph->fid_persistent, ph->fid_volatile, frame,
2480 if (!NT_STATUS_IS_OK(status)) {
2484 if (outbuf.length < 12) {
2485 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2489 *fs_attr = IVAL(outbuf.data, 0);
2493 if (fnum != 0xffff) {
2494 cli_smb2_close_fnum(cli, fnum);
2497 cli->raw_status = status;
2503 /***************************************************************
2504 Wrapper that allows SMB2 to query file system volume info.
2506 ***************************************************************/
2508 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2509 TALLOC_CTX *mem_ctx,
2510 char **_volume_name,
2511 uint32_t *pserial_number,
2515 uint16_t fnum = 0xffff;
2516 DATA_BLOB outbuf = data_blob_null;
2517 struct smb2_hnd *ph = NULL;
2519 char *volume_name = NULL;
2520 TALLOC_CTX *frame = talloc_stackframe();
2522 if (smbXcli_conn_has_async_calls(cli->conn)) {
2524 * Can't use sync call while an async call is in flight
2526 status = NT_STATUS_INVALID_PARAMETER;
2530 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2531 status = NT_STATUS_INVALID_PARAMETER;
2535 /* First open the top level directory. */
2537 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2538 SMB2_IMPERSONATION_IMPERSONATION,
2539 FILE_READ_ATTRIBUTES, /* desired_access */
2540 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2541 FILE_SHARE_READ | FILE_SHARE_WRITE |
2542 FILE_SHARE_DELETE, /* share_access */
2543 FILE_OPEN, /* create_disposition */
2544 FILE_DIRECTORY_FILE, /* create_options */
2551 if (!NT_STATUS_IS_OK(status)) {
2555 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2556 if (!NT_STATUS_IS_OK(status)) {
2560 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2561 level 1 (SMB_FS_VOLUME_INFORMATION). */
2563 status = smb2cli_query_info(cli->conn,
2567 SMB2_GETINFO_FS, /* in_info_type */
2568 /* in_file_info_class */
2569 SMB_FS_VOLUME_INFORMATION - 1000,
2570 0xFFFF, /* in_max_output_length */
2571 NULL, /* in_input_buffer */
2572 0, /* in_additional_info */
2578 if (!NT_STATUS_IS_OK(status)) {
2582 if (outbuf.length < 24) {
2583 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2589 ts = interpret_long_date((char *)outbuf.data);
2592 if (pserial_number) {
2593 *pserial_number = IVAL(outbuf.data,8);
2595 nlen = IVAL(outbuf.data,12);
2596 if (nlen + 18 < 18) {
2598 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2602 * The next check is safe as we know outbuf.length >= 24
2605 if (nlen > (outbuf.length - 18)) {
2606 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2610 clistr_pull_talloc(mem_ctx,
2611 (const char *)outbuf.data,
2617 if (volume_name == NULL) {
2618 status = map_nt_error_from_unix(errno);
2622 *_volume_name = volume_name;
2626 if (fnum != 0xffff) {
2627 cli_smb2_close_fnum(cli, fnum);
2630 cli->raw_status = status;
2637 /***************************************************************
2638 Wrapper that allows SMB2 to query a security descriptor.
2640 ***************************************************************/
2642 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2645 TALLOC_CTX *mem_ctx,
2646 struct security_descriptor **ppsd)
2649 DATA_BLOB outbuf = data_blob_null;
2650 struct smb2_hnd *ph = NULL;
2651 struct security_descriptor *lsd = NULL;
2652 TALLOC_CTX *frame = talloc_stackframe();
2654 if (smbXcli_conn_has_async_calls(cli->conn)) {
2656 * Can't use sync call while an async call is in flight
2658 status = NT_STATUS_INVALID_PARAMETER;
2662 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2663 status = NT_STATUS_INVALID_PARAMETER;
2667 status = map_fnum_to_smb2_handle(cli,
2670 if (!NT_STATUS_IS_OK(status)) {
2674 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2676 status = smb2cli_query_info(cli->conn,
2680 3, /* in_info_type */
2681 0, /* in_file_info_class */
2682 0xFFFF, /* in_max_output_length */
2683 NULL, /* in_input_buffer */
2684 sec_info, /* in_additional_info */
2691 if (!NT_STATUS_IS_OK(status)) {
2695 /* Parse the reply. */
2696 status = unmarshall_sec_desc(mem_ctx,
2701 if (!NT_STATUS_IS_OK(status)) {
2713 cli->raw_status = status;
2719 /***************************************************************
2720 Wrapper that allows SMB2 to set a security descriptor.
2722 ***************************************************************/
2724 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
2727 const struct security_descriptor *sd)
2730 DATA_BLOB inbuf = data_blob_null;
2731 struct smb2_hnd *ph = NULL;
2732 TALLOC_CTX *frame = talloc_stackframe();
2734 if (smbXcli_conn_has_async_calls(cli->conn)) {
2736 * Can't use sync call while an async call is in flight
2738 status = NT_STATUS_INVALID_PARAMETER;
2742 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2743 status = NT_STATUS_INVALID_PARAMETER;
2747 status = map_fnum_to_smb2_handle(cli,
2750 if (!NT_STATUS_IS_OK(status)) {
2754 status = marshall_sec_desc(frame,
2759 if (!NT_STATUS_IS_OK(status)) {
2763 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2765 status = smb2cli_set_info(cli->conn,
2769 3, /* in_info_type */
2770 0, /* in_file_info_class */
2771 &inbuf, /* in_input_buffer */
2772 sec_info, /* in_additional_info */
2778 cli->raw_status = status;
2784 /***************************************************************
2785 Wrapper that allows SMB2 to rename a file.
2787 ***************************************************************/
2789 NTSTATUS cli_smb2_rename(struct cli_state *cli,
2790 const char *fname_src,
2791 const char *fname_dst,
2795 DATA_BLOB inbuf = data_blob_null;
2796 uint16_t fnum = 0xffff;
2797 struct smb2_hnd *ph = NULL;
2798 smb_ucs2_t *converted_str = NULL;
2799 size_t converted_size_bytes = 0;
2801 TALLOC_CTX *frame = talloc_stackframe();
2803 if (smbXcli_conn_has_async_calls(cli->conn)) {
2805 * Can't use sync call while an async call is in flight
2807 status = NT_STATUS_INVALID_PARAMETER;
2811 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2812 status = NT_STATUS_INVALID_PARAMETER;
2816 status = get_fnum_from_path(cli,
2821 if (!NT_STATUS_IS_OK(status)) {
2825 status = map_fnum_to_smb2_handle(cli,
2828 if (!NT_STATUS_IS_OK(status)) {
2832 /* SMB2 is pickier about pathnames. Ensure it doesn't
2834 if (*fname_dst == '\\') {
2838 /* SMB2 is pickier about pathnames. Ensure it doesn't
2840 namelen = strlen(fname_dst);
2841 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2842 char *modname = talloc_strdup(frame, fname_dst);
2843 modname[namelen-1] = '\0';
2844 fname_dst = modname;
2847 if (!push_ucs2_talloc(frame,
2850 &converted_size_bytes)) {
2851 status = NT_STATUS_INVALID_PARAMETER;
2855 /* W2K8 insists the dest name is not null
2856 terminated. Remove the last 2 zero bytes
2857 and reduce the name length. */
2859 if (converted_size_bytes < 2) {
2860 status = NT_STATUS_INVALID_PARAMETER;
2863 converted_size_bytes -= 2;
2865 inbuf = data_blob_talloc_zero(frame,
2866 20 + converted_size_bytes);
2867 if (inbuf.data == NULL) {
2868 status = NT_STATUS_NO_MEMORY;
2873 SCVAL(inbuf.data, 0, 1);
2876 SIVAL(inbuf.data, 16, converted_size_bytes);
2877 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2879 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2880 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2882 status = smb2cli_set_info(cli->conn,
2886 1, /* in_info_type */
2887 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2888 &inbuf, /* in_input_buffer */
2889 0, /* in_additional_info */
2895 if (fnum != 0xffff) {
2896 cli_smb2_close_fnum(cli, fnum);
2899 cli->raw_status = status;
2905 /***************************************************************
2906 Wrapper that allows SMB2 to set an EA on a fnum.
2908 ***************************************************************/
2910 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2912 const char *ea_name,
2917 DATA_BLOB inbuf = data_blob_null;
2919 char *ea_name_ascii = NULL;
2921 struct smb2_hnd *ph = NULL;
2922 TALLOC_CTX *frame = talloc_stackframe();
2924 if (smbXcli_conn_has_async_calls(cli->conn)) {
2926 * Can't use sync call while an async call is in flight
2928 status = NT_STATUS_INVALID_PARAMETER;
2932 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2933 status = NT_STATUS_INVALID_PARAMETER;
2937 status = map_fnum_to_smb2_handle(cli,
2940 if (!NT_STATUS_IS_OK(status)) {
2944 /* Marshall the SMB2 EA data. */
2945 if (ea_len > 0xFFFF) {
2946 status = NT_STATUS_INVALID_PARAMETER;
2950 if (!push_ascii_talloc(frame,
2954 status = NT_STATUS_INVALID_PARAMETER;
2958 if (namelen < 2 || namelen > 0xFF) {
2959 status = NT_STATUS_INVALID_PARAMETER;
2963 bloblen = 8 + ea_len + namelen;
2964 /* Round up to a 4 byte boundary. */
2965 bloblen = ((bloblen + 3)&~3);
2967 inbuf = data_blob_talloc_zero(frame, bloblen);
2968 if (inbuf.data == NULL) {
2969 status = NT_STATUS_NO_MEMORY;
2972 /* namelen doesn't include the NULL byte. */
2973 SCVAL(inbuf.data, 5, namelen - 1);
2974 SSVAL(inbuf.data, 6, ea_len);
2975 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2976 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2978 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2979 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2981 status = smb2cli_set_info(cli->conn,
2985 1, /* in_info_type */
2986 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2987 &inbuf, /* in_input_buffer */
2988 0, /* in_additional_info */
2994 cli->raw_status = status;
3000 /***************************************************************
3001 Wrapper that allows SMB2 to set an EA on a pathname.
3003 ***************************************************************/
3005 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
3007 const char *ea_name,
3012 uint16_t fnum = 0xffff;
3014 if (smbXcli_conn_has_async_calls(cli->conn)) {
3016 * Can't use sync call while an async call is in flight
3018 status = NT_STATUS_INVALID_PARAMETER;
3022 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3023 status = NT_STATUS_INVALID_PARAMETER;
3027 status = get_fnum_from_path(cli,
3032 if (!NT_STATUS_IS_OK(status)) {
3036 status = cli_set_ea_fnum(cli,
3041 if (!NT_STATUS_IS_OK(status)) {
3047 if (fnum != 0xffff) {
3048 cli_smb2_close_fnum(cli, fnum);
3051 cli->raw_status = status;
3056 /***************************************************************
3057 Wrapper that allows SMB2 to get an EA list on a pathname.
3059 ***************************************************************/
3061 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
3065 struct ea_struct **pea_array)
3068 uint16_t fnum = 0xffff;
3069 DATA_BLOB outbuf = data_blob_null;
3070 struct smb2_hnd *ph = NULL;
3071 struct ea_list *ea_list = NULL;
3072 struct ea_list *eal = NULL;
3073 size_t ea_count = 0;
3074 TALLOC_CTX *frame = talloc_stackframe();
3079 if (smbXcli_conn_has_async_calls(cli->conn)) {
3081 * Can't use sync call while an async call is in flight
3083 status = NT_STATUS_INVALID_PARAMETER;
3087 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3088 status = NT_STATUS_INVALID_PARAMETER;
3092 status = get_fnum_from_path(cli,
3097 if (!NT_STATUS_IS_OK(status)) {
3101 status = map_fnum_to_smb2_handle(cli,
3104 if (!NT_STATUS_IS_OK(status)) {
3108 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3109 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3111 status = smb2cli_query_info(cli->conn,
3115 1, /* in_info_type */
3116 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3117 0xFFFF, /* in_max_output_length */
3118 NULL, /* in_input_buffer */
3119 0, /* in_additional_info */
3126 if (!NT_STATUS_IS_OK(status)) {
3130 /* Parse the reply. */
3131 ea_list = read_nttrans_ea_list(ctx,
3132 (const char *)outbuf.data,
3134 if (ea_list == NULL) {
3135 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3139 /* Convert to an array. */
3140 for (eal = ea_list; eal; eal = eal->next) {
3145 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
3146 if (*pea_array == NULL) {
3147 status = NT_STATUS_NO_MEMORY;
3151 for (eal = ea_list; eal; eal = eal->next) {
3152 (*pea_array)[ea_count++] = eal->ea;
3154 *pnum_eas = ea_count;
3159 if (fnum != 0xffff) {
3160 cli_smb2_close_fnum(cli, fnum);
3163 cli->raw_status = status;
3169 /***************************************************************
3170 Wrapper that allows SMB2 to get user quota.
3172 ***************************************************************/
3174 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
3176 SMB_NTQUOTA_STRUCT *pqt)
3179 DATA_BLOB inbuf = data_blob_null;
3180 DATA_BLOB info_blob = data_blob_null;
3181 DATA_BLOB outbuf = data_blob_null;
3182 struct smb2_hnd *ph = NULL;
3183 TALLOC_CTX *frame = talloc_stackframe();
3185 unsigned int offset;
3186 struct smb2_query_quota_info query = {0};
3187 struct file_get_quota_info info = {0};
3188 enum ndr_err_code err;
3189 struct ndr_push *ndr_push = NULL;
3191 if (smbXcli_conn_has_async_calls(cli->conn)) {
3193 * Can't use sync call while an async call is in flight
3195 status = NT_STATUS_INVALID_PARAMETER;
3199 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3200 status = NT_STATUS_INVALID_PARAMETER;
3204 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3205 if (!NT_STATUS_IS_OK(status)) {
3209 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
3211 query.return_single = 1;
3213 info.next_entry_offset = 0;
3214 info.sid_length = sid_len;
3215 info.sid = pqt->sid;
3217 err = ndr_push_struct_blob(
3221 (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
3223 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3224 status = NT_STATUS_INTERNAL_ERROR;
3228 query.sid_list_length = info_blob.length;
3229 ndr_push = ndr_push_init_ctx(frame);
3231 status = NT_STATUS_NO_MEMORY;
3235 err = ndr_push_smb2_query_quota_info(ndr_push,
3236 NDR_SCALARS | NDR_BUFFERS,
3239 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3240 status = NT_STATUS_INTERNAL_ERROR;
3244 err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3247 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3248 status = NT_STATUS_INTERNAL_ERROR;
3251 inbuf.data = ndr_push->data;
3252 inbuf.length = ndr_push->offset;
3254 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
3255 cli->smb2.tcon, 4, /* in_info_type */
3256 0, /* in_file_info_class */
3257 0xFFFF, /* in_max_output_length */
3258 &inbuf, /* in_input_buffer */
3259 0, /* in_additional_info */
3261 ph->fid_persistent, ph->fid_volatile, frame,
3264 if (!NT_STATUS_IS_OK(status)) {
3268 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3270 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3271 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3275 cli->raw_status = status;
3281 /***************************************************************
3282 Wrapper that allows SMB2 to list user quota.
3284 ***************************************************************/
3286 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3287 TALLOC_CTX *mem_ctx,
3289 SMB_NTQUOTA_LIST **pqt_list,
3293 DATA_BLOB inbuf = data_blob_null;
3294 DATA_BLOB outbuf = data_blob_null;
3295 struct smb2_hnd *ph = NULL;
3296 TALLOC_CTX *frame = talloc_stackframe();
3297 struct smb2_query_quota_info info = {0};
3298 enum ndr_err_code err;
3300 if (smbXcli_conn_has_async_calls(cli->conn)) {
3302 * Can't use sync call while an async call is in flight
3304 status = NT_STATUS_INVALID_PARAMETER;
3308 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3309 status = NT_STATUS_INVALID_PARAMETER;
3313 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3314 if (!NT_STATUS_IS_OK(status)) {
3319 info.restart_scan = first ? 1 : 0;
3321 err = ndr_push_struct_blob(
3325 (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3327 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3328 status = NT_STATUS_INTERNAL_ERROR;
3332 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
3333 cli->smb2.tcon, 4, /* in_info_type */
3334 0, /* in_file_info_class */
3335 0xFFFF, /* in_max_output_length */
3336 &inbuf, /* in_input_buffer */
3337 0, /* in_additional_info */
3339 ph->fid_persistent, ph->fid_volatile, frame,
3343 * safeguard against panic from calling parse_user_quota_list with
3346 if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3347 status = NT_STATUS_NO_MORE_ENTRIES;
3350 if (!NT_STATUS_IS_OK(status)) {
3354 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3358 cli->raw_status = status;
3364 /***************************************************************
3365 Wrapper that allows SMB2 to get file system quota.
3367 ***************************************************************/
3369 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3371 SMB_NTQUOTA_STRUCT *pqt)
3374 DATA_BLOB outbuf = data_blob_null;
3375 struct smb2_hnd *ph = NULL;
3376 TALLOC_CTX *frame = talloc_stackframe();
3378 if (smbXcli_conn_has_async_calls(cli->conn)) {
3380 * Can't use sync call while an async call is in flight
3382 status = NT_STATUS_INVALID_PARAMETER;
3386 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3387 status = NT_STATUS_INVALID_PARAMETER;
3391 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3392 if (!NT_STATUS_IS_OK(status)) {
3396 status = smb2cli_query_info(
3397 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3398 2, /* in_info_type */
3399 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3400 0xFFFF, /* in_max_output_length */
3401 NULL, /* in_input_buffer */
3402 0, /* in_additional_info */
3404 ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
3406 if (!NT_STATUS_IS_OK(status)) {
3410 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3413 cli->raw_status = status;
3419 /***************************************************************
3420 Wrapper that allows SMB2 to set user quota.
3422 ***************************************************************/
3424 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3426 SMB_NTQUOTA_LIST *qtl)
3429 DATA_BLOB inbuf = data_blob_null;
3430 struct smb2_hnd *ph = NULL;
3431 TALLOC_CTX *frame = talloc_stackframe();
3433 if (smbXcli_conn_has_async_calls(cli->conn)) {
3435 * Can't use sync call while an async call is in flight
3437 status = NT_STATUS_INVALID_PARAMETER;
3441 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3442 status = NT_STATUS_INVALID_PARAMETER;
3446 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3447 if (!NT_STATUS_IS_OK(status)) {
3451 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3452 if (!NT_STATUS_IS_OK(status)) {
3456 status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
3457 cli->smb2.tcon, 4, /* in_info_type */
3458 0, /* in_file_info_class */
3459 &inbuf, /* in_input_buffer */
3460 0, /* in_additional_info */
3461 ph->fid_persistent, ph->fid_volatile);
3464 cli->raw_status = status;
3471 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3473 SMB_NTQUOTA_STRUCT *pqt)
3476 DATA_BLOB inbuf = data_blob_null;
3477 struct smb2_hnd *ph = NULL;
3478 TALLOC_CTX *frame = talloc_stackframe();
3480 if (smbXcli_conn_has_async_calls(cli->conn)) {
3482 * Can't use sync call while an async call is in flight
3484 status = NT_STATUS_INVALID_PARAMETER;
3488 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3489 status = NT_STATUS_INVALID_PARAMETER;
3493 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3494 if (!NT_STATUS_IS_OK(status)) {
3498 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3499 if (!NT_STATUS_IS_OK(status)) {
3503 status = smb2cli_set_info(
3504 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3505 2, /* in_info_type */
3506 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3507 &inbuf, /* in_input_buffer */
3508 0, /* in_additional_info */
3509 ph->fid_persistent, ph->fid_volatile);
3511 cli->raw_status = status;
3517 struct cli_smb2_read_state {
3518 struct tevent_context *ev;
3519 struct cli_state *cli;
3520 struct smb2_hnd *ph;
3521 uint64_t start_offset;
3527 static void cli_smb2_read_done(struct tevent_req *subreq);
3529 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3530 struct tevent_context *ev,
3531 struct cli_state *cli,
3537 struct tevent_req *req, *subreq;
3538 struct cli_smb2_read_state *state;
3540 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3546 state->start_offset = (uint64_t)offset;
3547 state->size = (uint32_t)size;
3548 state->received = 0;
3551 status = map_fnum_to_smb2_handle(cli,
3554 if (tevent_req_nterror(req, status)) {
3555 return tevent_req_post(req, ev);
3558 subreq = smb2cli_read_send(state,
3561 state->cli->timeout,
3562 state->cli->smb2.session,
3563 state->cli->smb2.tcon,
3565 state->start_offset,
3566 state->ph->fid_persistent,
3567 state->ph->fid_volatile,
3568 0, /* minimum_count */
3569 0); /* remaining_bytes */
3571 if (tevent_req_nomem(subreq, req)) {
3572 return tevent_req_post(req, ev);
3574 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3578 static void cli_smb2_read_done(struct tevent_req *subreq)
3580 struct tevent_req *req = tevent_req_callback_data(
3581 subreq, struct tevent_req);
3582 struct cli_smb2_read_state *state = tevent_req_data(
3583 req, struct cli_smb2_read_state);
3586 status = smb2cli_read_recv(subreq, state,
3587 &state->buf, &state->received);
3588 if (tevent_req_nterror(req, status)) {
3592 if (state->received > state->size) {
3593 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3597 tevent_req_done(req);
3600 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
3605 struct cli_smb2_read_state *state = tevent_req_data(
3606 req, struct cli_smb2_read_state);
3608 if (tevent_req_is_nterror(req, &status)) {
3609 state->cli->raw_status = status;
3613 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3614 * better make sure that you copy it away before you talloc_free(req).
3615 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3617 *received = (ssize_t)state->received;
3618 *rcvbuf = state->buf;
3619 state->cli->raw_status = NT_STATUS_OK;
3620 return NT_STATUS_OK;
3623 struct cli_smb2_write_state {
3624 struct tevent_context *ev;
3625 struct cli_state *cli;
3626 struct smb2_hnd *ph;
3634 static void cli_smb2_write_written(struct tevent_req *req);
3636 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
3637 struct tevent_context *ev,
3638 struct cli_state *cli,
3646 struct tevent_req *req, *subreq = NULL;
3647 struct cli_smb2_write_state *state = NULL;
3649 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
3655 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3656 state->flags = (uint32_t)mode;
3658 state->offset = (uint64_t)offset;
3659 state->size = (uint32_t)size;
3662 status = map_fnum_to_smb2_handle(cli,
3665 if (tevent_req_nterror(req, status)) {
3666 return tevent_req_post(req, ev);
3669 subreq = smb2cli_write_send(state,
3672 state->cli->timeout,
3673 state->cli->smb2.session,
3674 state->cli->smb2.tcon,
3677 state->ph->fid_persistent,
3678 state->ph->fid_volatile,
3679 0, /* remaining_bytes */
3680 state->flags, /* flags */
3683 if (tevent_req_nomem(subreq, req)) {
3684 return tevent_req_post(req, ev);
3686 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
3690 static void cli_smb2_write_written(struct tevent_req *subreq)
3692 struct tevent_req *req = tevent_req_callback_data(
3693 subreq, struct tevent_req);
3694 struct cli_smb2_write_state *state = tevent_req_data(
3695 req, struct cli_smb2_write_state);
3699 status = smb2cli_write_recv(subreq, &written);
3700 TALLOC_FREE(subreq);
3701 if (tevent_req_nterror(req, status)) {
3705 state->written = written;
3707 tevent_req_done(req);
3710 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
3713 struct cli_smb2_write_state *state = tevent_req_data(
3714 req, struct cli_smb2_write_state);
3717 if (tevent_req_is_nterror(req, &status)) {
3718 state->cli->raw_status = status;
3719 tevent_req_received(req);
3723 if (pwritten != NULL) {
3724 *pwritten = (size_t)state->written;
3726 state->cli->raw_status = NT_STATUS_OK;
3727 tevent_req_received(req);
3728 return NT_STATUS_OK;
3731 /***************************************************************
3732 Wrapper that allows SMB2 async write using an fnum.
3733 This is mostly cut-and-paste from Volker's code inside
3734 source3/libsmb/clireadwrite.c, adapted for SMB2.
3736 Done this way so I can reuse all the logic inside cli_push()
3738 ***************************************************************/
3740 struct cli_smb2_writeall_state {
3741 struct tevent_context *ev;
3742 struct cli_state *cli;
3743 struct smb2_hnd *ph;
3751 static void cli_smb2_writeall_written(struct tevent_req *req);
3753 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
3754 struct tevent_context *ev,
3755 struct cli_state *cli,
3763 struct tevent_req *req, *subreq = NULL;
3764 struct cli_smb2_writeall_state *state = NULL;
3769 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
3775 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3776 state->flags = (uint32_t)mode;
3778 state->offset = (uint64_t)offset;
3779 state->size = (uint32_t)size;
3782 status = map_fnum_to_smb2_handle(cli,
3785 if (tevent_req_nterror(req, status)) {
3786 return tevent_req_post(req, ev);
3789 to_write = state->size;
3790 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3791 to_write = MIN(max_size, to_write);
3792 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3794 to_write = MIN(max_size, to_write);
3797 subreq = smb2cli_write_send(state,
3800 state->cli->timeout,
3801 state->cli->smb2.session,
3802 state->cli->smb2.tcon,
3805 state->ph->fid_persistent,
3806 state->ph->fid_volatile,
3807 0, /* remaining_bytes */
3808 state->flags, /* flags */
3809 state->buf + state->written);
3811 if (tevent_req_nomem(subreq, req)) {
3812 return tevent_req_post(req, ev);
3814 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3818 static void cli_smb2_writeall_written(struct tevent_req *subreq)
3820 struct tevent_req *req = tevent_req_callback_data(
3821 subreq, struct tevent_req);
3822 struct cli_smb2_writeall_state *state = tevent_req_data(
3823 req, struct cli_smb2_writeall_state);
3825 uint32_t written, to_write;
3829 status = smb2cli_write_recv(subreq, &written);
3830 TALLOC_FREE(subreq);
3831 if (tevent_req_nterror(req, status)) {
3835 state->written += written;
3837 if (state->written > state->size) {
3838 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3842 to_write = state->size - state->written;
3844 if (to_write == 0) {
3845 tevent_req_done(req);
3849 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3850 to_write = MIN(max_size, to_write);
3851 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3853 to_write = MIN(max_size, to_write);
3856 subreq = smb2cli_write_send(state,
3859 state->cli->timeout,
3860 state->cli->smb2.session,
3861 state->cli->smb2.tcon,
3863 state->offset + state->written,
3864 state->ph->fid_persistent,
3865 state->ph->fid_volatile,
3866 0, /* remaining_bytes */
3867 state->flags, /* flags */
3868 state->buf + state->written);
3870 if (tevent_req_nomem(subreq, req)) {
3873 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3876 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
3879 struct cli_smb2_writeall_state *state = tevent_req_data(
3880 req, struct cli_smb2_writeall_state);
3883 if (tevent_req_is_nterror(req, &status)) {
3884 state->cli->raw_status = status;
3887 if (pwritten != NULL) {
3888 *pwritten = (size_t)state->written;
3890 state->cli->raw_status = NT_STATUS_OK;
3891 return NT_STATUS_OK;
3894 struct cli_smb2_splice_state {
3895 struct tevent_context *ev;
3896 struct cli_state *cli;
3897 struct smb2_hnd *src_ph;
3898 struct smb2_hnd *dst_ph;
3899 int (*splice_cb)(off_t n, void *priv);
3906 struct req_resume_key_rsp resume_rsp;
3907 struct srv_copychunk_copy cc_copy;
3910 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3911 struct tevent_req *req);
3913 static void cli_splice_copychunk_done(struct tevent_req *subreq)
3915 struct tevent_req *req = tevent_req_callback_data(
3916 subreq, struct tevent_req);
3917 struct cli_smb2_splice_state *state =
3918 tevent_req_data(req,
3919 struct cli_smb2_splice_state);
3920 struct smbXcli_conn *conn = state->cli->conn;
3921 DATA_BLOB out_input_buffer = data_blob_null;
3922 DATA_BLOB out_output_buffer = data_blob_null;
3923 struct srv_copychunk_rsp cc_copy_rsp;
3924 enum ndr_err_code ndr_ret;
3927 status = smb2cli_ioctl_recv(subreq, state,
3929 &out_output_buffer);
3930 TALLOC_FREE(subreq);
3931 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
3932 state->resized) && tevent_req_nterror(req, status)) {
3936 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
3937 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
3938 if (ndr_ret != NDR_ERR_SUCCESS) {
3939 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3940 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3944 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
3945 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
3946 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
3947 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
3948 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
3949 tevent_req_nterror(req, status)) {
3953 state->resized = true;
3954 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
3955 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
3957 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3958 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3959 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
3960 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3963 state->src_offset += cc_copy_rsp.total_bytes_written;
3964 state->dst_offset += cc_copy_rsp.total_bytes_written;
3965 state->written += cc_copy_rsp.total_bytes_written;
3966 if (!state->splice_cb(state->written, state->priv)) {
3967 tevent_req_nterror(req, NT_STATUS_CANCELLED);
3972 cli_splice_copychunk_send(state, req);
3975 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3976 struct tevent_req *req)
3978 struct tevent_req *subreq;
3979 enum ndr_err_code ndr_ret;
3980 struct smbXcli_conn *conn = state->cli->conn;
3981 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
3982 off_t src_offset = state->src_offset;
3983 off_t dst_offset = state->dst_offset;
3984 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
3985 state->size - state->written);
3986 DATA_BLOB in_input_buffer = data_blob_null;
3987 DATA_BLOB in_output_buffer = data_blob_null;
3989 if (state->size - state->written == 0) {
3990 tevent_req_done(req);
3994 cc_copy->chunk_count = 0;
3996 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
3997 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
3998 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
3999 smb2cli_conn_cc_chunk_len(conn));
4000 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
4001 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4004 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
4005 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
4006 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
4007 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4010 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4011 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4012 cc_copy->chunk_count++;
4015 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
4016 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
4017 if (ndr_ret != NDR_ERR_SUCCESS) {
4018 DEBUG(0, ("failed to marshall copy chunk req\n"));
4019 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4023 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
4024 state->cli->timeout,
4025 state->cli->smb2.session,
4026 state->cli->smb2.tcon,
4027 state->dst_ph->fid_persistent, /* in_fid_persistent */
4028 state->dst_ph->fid_volatile, /* in_fid_volatile */
4029 FSCTL_SRV_COPYCHUNK_WRITE,
4030 0, /* in_max_input_length */
4032 12, /* in_max_output_length */
4034 SMB2_IOCTL_FLAG_IS_FSCTL);
4035 if (tevent_req_nomem(subreq, req)) {
4038 tevent_req_set_callback(subreq,
4039 cli_splice_copychunk_done,
4043 static void cli_splice_key_done(struct tevent_req *subreq)
4045 struct tevent_req *req = tevent_req_callback_data(
4046 subreq, struct tevent_req);
4047 struct cli_smb2_splice_state *state =
4048 tevent_req_data(req,
4049 struct cli_smb2_splice_state);
4050 enum ndr_err_code ndr_ret;
4053 DATA_BLOB out_input_buffer = data_blob_null;
4054 DATA_BLOB out_output_buffer = data_blob_null;
4056 status = smb2cli_ioctl_recv(subreq, state,
4058 &out_output_buffer);
4059 TALLOC_FREE(subreq);
4060 if (tevent_req_nterror(req, status)) {
4064 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
4065 state, &state->resume_rsp,
4066 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
4067 if (ndr_ret != NDR_ERR_SUCCESS) {
4068 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4069 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4073 memcpy(&state->cc_copy.source_key,
4074 &state->resume_rsp.resume_key,
4075 sizeof state->resume_rsp.resume_key);
4077 cli_splice_copychunk_send(state, req);
4080 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
4081 struct tevent_context *ev,
4082 struct cli_state *cli,
4083 uint16_t src_fnum, uint16_t dst_fnum,
4084 off_t size, off_t src_offset, off_t dst_offset,
4085 int (*splice_cb)(off_t n, void *priv),
4088 struct tevent_req *req;
4089 struct tevent_req *subreq;
4090 struct cli_smb2_splice_state *state;
4092 DATA_BLOB in_input_buffer = data_blob_null;
4093 DATA_BLOB in_output_buffer = data_blob_null;
4095 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
4101 state->splice_cb = splice_cb;
4105 state->src_offset = src_offset;
4106 state->dst_offset = dst_offset;
4107 state->cc_copy.chunks = talloc_array(state,
4108 struct srv_copychunk,
4109 smb2cli_conn_cc_max_chunks(cli->conn));
4110 if (state->cc_copy.chunks == NULL) {
4114 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
4115 if (tevent_req_nterror(req, status))
4116 return tevent_req_post(req, ev);
4118 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
4119 if (tevent_req_nterror(req, status))
4120 return tevent_req_post(req, ev);
4122 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
4126 state->src_ph->fid_persistent, /* in_fid_persistent */
4127 state->src_ph->fid_volatile, /* in_fid_volatile */
4128 FSCTL_SRV_REQUEST_RESUME_KEY,
4129 0, /* in_max_input_length */
4131 32, /* in_max_output_length */
4133 SMB2_IOCTL_FLAG_IS_FSCTL);
4134 if (tevent_req_nomem(subreq, req)) {
4137 tevent_req_set_callback(subreq,
4138 cli_splice_key_done,
4144 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
4146 struct cli_smb2_splice_state *state = tevent_req_data(
4147 req, struct cli_smb2_splice_state);
4150 if (tevent_req_is_nterror(req, &status)) {
4151 state->cli->raw_status = status;
4152 tevent_req_received(req);
4155 if (written != NULL) {
4156 *written = state->written;
4158 state->cli->raw_status = NT_STATUS_OK;
4159 tevent_req_received(req);
4160 return NT_STATUS_OK;
4163 /***************************************************************
4164 SMB2 enum shadow copy data.
4165 ***************************************************************/
4167 struct cli_smb2_shadow_copy_data_fnum_state {
4168 struct cli_state *cli;
4170 struct smb2_hnd *ph;
4171 DATA_BLOB out_input_buffer;
4172 DATA_BLOB out_output_buffer;
4175 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
4177 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
4178 TALLOC_CTX *mem_ctx,
4179 struct tevent_context *ev,
4180 struct cli_state *cli,
4184 struct tevent_req *req, *subreq;
4185 struct cli_smb2_shadow_copy_data_fnum_state *state;
4188 req = tevent_req_create(mem_ctx, &state,
4189 struct cli_smb2_shadow_copy_data_fnum_state);
4194 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4195 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4196 return tevent_req_post(req, ev);
4202 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4203 if (tevent_req_nterror(req, status)) {
4204 return tevent_req_post(req, ev);
4208 * TODO. Under SMB2 we should send a zero max_output_length
4209 * ioctl to get the required size, then send another ioctl
4210 * to get the data, but the current SMB1 implementation just
4211 * does one roundtrip with a 64K buffer size. Do the same
4215 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4216 state->cli->timeout,
4217 state->cli->smb2.session,
4218 state->cli->smb2.tcon,
4219 state->ph->fid_persistent, /* in_fid_persistent */
4220 state->ph->fid_volatile, /* in_fid_volatile */
4221 FSCTL_GET_SHADOW_COPY_DATA,
4222 0, /* in_max_input_length */
4223 NULL, /* in_input_buffer */
4225 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
4226 NULL, /* in_output_buffer */
4227 SMB2_IOCTL_FLAG_IS_FSCTL);
4229 if (tevent_req_nomem(subreq, req)) {
4230 return tevent_req_post(req, ev);
4232 tevent_req_set_callback(subreq,
4233 cli_smb2_shadow_copy_data_fnum_done,
4239 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4241 struct tevent_req *req = tevent_req_callback_data(
4242 subreq, struct tevent_req);
4243 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4244 req, struct cli_smb2_shadow_copy_data_fnum_state);
4247 status = smb2cli_ioctl_recv(subreq, state,
4248 &state->out_input_buffer,
4249 &state->out_output_buffer);
4250 TALLOC_FREE(subreq);
4251 if (tevent_req_nterror(req, status)) {
4254 tevent_req_done(req);
4257 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4258 TALLOC_CTX *mem_ctx,
4263 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4264 req, struct cli_smb2_shadow_copy_data_fnum_state);
4265 char **names = NULL;
4266 uint32_t num_names = 0;
4267 uint32_t num_names_returned = 0;
4268 uint32_t dlength = 0;
4270 uint8_t *endp = NULL;
4273 if (tevent_req_is_nterror(req, &status)) {
4277 if (state->out_output_buffer.length < 16) {
4278 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4281 num_names = IVAL(state->out_output_buffer.data, 0);
4282 num_names_returned = IVAL(state->out_output_buffer.data, 4);
4283 dlength = IVAL(state->out_output_buffer.data, 8);
4285 if (num_names > 0x7FFFFFFF) {
4286 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4289 if (get_names == false) {
4290 *pnum_names = (int)num_names;
4291 return NT_STATUS_OK;
4293 if (num_names != num_names_returned) {
4294 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4296 if (dlength + 12 < 12) {
4297 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4300 * NB. The below is an allowable return if there are
4301 * more snapshots than the buffer size we told the
4302 * server we can receive. We currently don't support
4305 if (dlength + 12 > state->out_output_buffer.length) {
4306 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4308 if (state->out_output_buffer.length +
4309 (2 * sizeof(SHADOW_COPY_LABEL)) <
4310 state->out_output_buffer.length) {
4311 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4314 names = talloc_array(mem_ctx, char *, num_names_returned);
4315 if (names == NULL) {
4316 return NT_STATUS_NO_MEMORY;
4319 endp = state->out_output_buffer.data +
4320 state->out_output_buffer.length;
4322 for (i=0; i<num_names_returned; i++) {
4325 size_t converted_size;
4327 src = state->out_output_buffer.data + 12 +
4328 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4330 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4331 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4333 ret = convert_string_talloc(
4334 names, CH_UTF16LE, CH_UNIX,
4335 src, 2 * sizeof(SHADOW_COPY_LABEL),
4336 &names[i], &converted_size);
4339 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4342 *pnum_names = num_names;
4344 return NT_STATUS_OK;
4347 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4348 struct cli_state *cli,
4354 TALLOC_CTX *frame = talloc_stackframe();
4355 struct tevent_context *ev;
4356 struct tevent_req *req;
4357 NTSTATUS status = NT_STATUS_NO_MEMORY;
4359 if (smbXcli_conn_has_async_calls(cli->conn)) {
4361 * Can't use sync call while an async call is in flight
4363 status = NT_STATUS_INVALID_PARAMETER;
4366 ev = samba_tevent_context_init(frame);
4370 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4378 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4381 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4387 cli->raw_status = status;
4393 /***************************************************************
4394 Wrapper that allows SMB2 to truncate a file.
4396 ***************************************************************/
4398 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4403 DATA_BLOB inbuf = data_blob_null;
4404 struct smb2_hnd *ph = NULL;
4405 TALLOC_CTX *frame = talloc_stackframe();
4407 if (smbXcli_conn_has_async_calls(cli->conn)) {
4409 * Can't use sync call while an async call is in flight
4411 status = NT_STATUS_INVALID_PARAMETER;
4415 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4416 status = NT_STATUS_INVALID_PARAMETER;
4420 status = map_fnum_to_smb2_handle(cli,
4423 if (!NT_STATUS_IS_OK(status)) {
4427 inbuf = data_blob_talloc_zero(frame, 8);
4428 if (inbuf.data == NULL) {
4429 status = NT_STATUS_NO_MEMORY;
4433 SBVAL(inbuf.data, 0, newsize);
4435 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4436 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4438 status = smb2cli_set_info(cli->conn,
4442 1, /* in_info_type */
4443 /* in_file_info_class */
4444 SMB_FILE_END_OF_FILE_INFORMATION - 1000,
4445 &inbuf, /* in_input_buffer */
4446 0, /* in_additional_info */
4452 cli->raw_status = status;
4458 struct cli_smb2_notify_state {
4459 struct tevent_req *subreq;
4460 struct notify_change *changes;
4464 static void cli_smb2_notify_done(struct tevent_req *subreq);
4465 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4467 struct tevent_req *cli_smb2_notify_send(
4468 TALLOC_CTX *mem_ctx,
4469 struct tevent_context *ev,
4470 struct cli_state *cli,
4472 uint32_t buffer_size,
4473 uint32_t completion_filter,
4476 struct tevent_req *req = NULL;
4477 struct cli_smb2_notify_state *state = NULL;
4478 struct smb2_hnd *ph = NULL;
4481 req = tevent_req_create(mem_ctx, &state,
4482 struct cli_smb2_notify_state);
4487 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4488 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4489 return tevent_req_post(req, ev);
4492 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4493 if (tevent_req_nterror(req, status)) {
4494 return tevent_req_post(req, ev);
4497 state->subreq = smb2cli_notify_send(
4509 if (tevent_req_nomem(state->subreq, req)) {
4510 return tevent_req_post(req, ev);
4512 tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4513 tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4517 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4519 struct cli_smb2_notify_state *state = tevent_req_data(
4520 req, struct cli_smb2_notify_state);
4523 ok = tevent_req_cancel(state->subreq);
4527 static void cli_smb2_notify_done(struct tevent_req *subreq)
4529 struct tevent_req *req = tevent_req_callback_data(
4530 subreq, struct tevent_req);
4531 struct cli_smb2_notify_state *state = tevent_req_data(
4532 req, struct cli_smb2_notify_state);
4538 status = smb2cli_notify_recv(subreq, state, &base, &len);
4539 TALLOC_FREE(subreq);
4541 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4542 tevent_req_done(req);
4545 if (tevent_req_nterror(req, status)) {
4551 while (len - ofs >= 12) {
4552 struct notify_change *tmp;
4553 struct notify_change *c;
4554 uint32_t next_ofs = IVAL(base, ofs);
4555 uint32_t file_name_length = IVAL(base, ofs+8);
4559 tmp = talloc_realloc(
4562 struct notify_change,
4563 state->num_changes + 1);
4564 if (tevent_req_nomem(tmp, req)) {
4567 state->changes = tmp;
4568 c = &state->changes[state->num_changes];
4569 state->num_changes += 1;
4571 if (smb_buffer_oob(len, ofs, next_ofs) ||
4572 smb_buffer_oob(len, ofs+12, file_name_length)) {
4574 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4578 c->action = IVAL(base, ofs+4);
4580 ok = convert_string_talloc(
4590 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4594 if (next_ofs == 0) {
4600 tevent_req_done(req);
4603 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
4604 TALLOC_CTX *mem_ctx,
4605 struct notify_change **pchanges,
4606 uint32_t *pnum_changes)
4608 struct cli_smb2_notify_state *state = tevent_req_data(
4609 req, struct cli_smb2_notify_state);
4612 if (tevent_req_is_nterror(req, &status)) {
4615 *pchanges = talloc_move(mem_ctx, &state->changes);
4616 *pnum_changes = state->num_changes;
4617 return NT_STATUS_OK;
4620 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
4621 uint32_t buffer_size, uint32_t completion_filter,
4622 bool recursive, TALLOC_CTX *mem_ctx,
4623 struct notify_change **pchanges,
4624 uint32_t *pnum_changes)
4626 TALLOC_CTX *frame = talloc_stackframe();
4627 struct tevent_context *ev;
4628 struct tevent_req *req;
4629 NTSTATUS status = NT_STATUS_NO_MEMORY;
4631 if (smbXcli_conn_has_async_calls(cli->conn)) {
4633 * Can't use sync call while an async call is in flight
4635 status = NT_STATUS_INVALID_PARAMETER;
4638 ev = samba_tevent_context_init(frame);
4642 req = cli_smb2_notify_send(
4653 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4656 status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
4662 struct cli_smb2_set_reparse_point_fnum_state {
4663 struct cli_state *cli;
4665 struct smb2_hnd *ph;
4666 DATA_BLOB input_buffer;
4669 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
4671 struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
4672 TALLOC_CTX *mem_ctx,
4673 struct tevent_context *ev,
4674 struct cli_state *cli,
4678 struct tevent_req *req, *subreq;
4679 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
4682 req = tevent_req_create(mem_ctx, &state,
4683 struct cli_smb2_set_reparse_point_fnum_state);
4688 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4689 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4690 return tevent_req_post(req, ev);
4696 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4697 if (tevent_req_nterror(req, status)) {
4698 return tevent_req_post(req, ev);
4701 state->input_buffer = data_blob_talloc(state,
4704 if (state->input_buffer.data == NULL) {
4705 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4706 return tevent_req_post(req, ev);
4709 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4710 state->cli->timeout,
4711 state->cli->smb2.session,
4712 state->cli->smb2.tcon,
4713 state->ph->fid_persistent, /* in_fid_persistent */
4714 state->ph->fid_volatile, /* in_fid_volatile */
4715 FSCTL_SET_REPARSE_POINT,
4716 0, /* in_max_input_length */
4717 &state->input_buffer ,
4720 SMB2_IOCTL_FLAG_IS_FSCTL);
4722 if (tevent_req_nomem(subreq, req)) {
4723 return tevent_req_post(req, ev);
4725 tevent_req_set_callback(subreq,
4726 cli_smb2_set_reparse_point_fnum_done,
4732 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
4734 struct tevent_req *req = tevent_req_callback_data(
4735 subreq, struct tevent_req);
4736 struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
4737 req, struct cli_smb2_set_reparse_point_fnum_state);
4740 status = smb2cli_ioctl_recv(subreq, state,
4743 TALLOC_FREE(subreq);
4744 if (tevent_req_nterror(req, status)) {
4747 tevent_req_done(req);
4750 NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
4752 return tevent_req_simple_recv_ntstatus(req);
4755 struct cli_smb2_get_reparse_point_fnum_state {
4756 struct cli_state *cli;
4758 struct smb2_hnd *ph;
4759 DATA_BLOB output_buffer;
4762 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
4764 struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
4765 TALLOC_CTX *mem_ctx,
4766 struct tevent_context *ev,
4767 struct cli_state *cli,
4770 struct tevent_req *req, *subreq;
4771 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
4774 req = tevent_req_create(mem_ctx, &state,
4775 struct cli_smb2_get_reparse_point_fnum_state);
4780 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4781 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4782 return tevent_req_post(req, ev);
4788 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4789 if (tevent_req_nterror(req, status)) {
4790 return tevent_req_post(req, ev);
4793 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4794 state->cli->timeout,
4795 state->cli->smb2.session,
4796 state->cli->smb2.tcon,
4797 state->ph->fid_persistent, /* in_fid_persistent */
4798 state->ph->fid_volatile, /* in_fid_volatile */
4799 FSCTL_GET_REPARSE_POINT,
4800 0, /* in_max_input_length */
4804 SMB2_IOCTL_FLAG_IS_FSCTL);
4806 if (tevent_req_nomem(subreq, req)) {
4807 return tevent_req_post(req, ev);
4809 tevent_req_set_callback(subreq,
4810 cli_smb2_get_reparse_point_fnum_done,
4816 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
4818 struct tevent_req *req = tevent_req_callback_data(
4819 subreq, struct tevent_req);
4820 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
4821 req, struct cli_smb2_get_reparse_point_fnum_state);
4824 status = smb2cli_ioctl_recv(subreq, state,
4826 &state->output_buffer);
4827 TALLOC_FREE(subreq);
4828 if (tevent_req_nterror(req, status)) {
4829 state->cli->raw_status = status;
4832 tevent_req_done(req);
4835 NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
4836 TALLOC_CTX *mem_ctx,
4839 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
4840 req, struct cli_smb2_get_reparse_point_fnum_state);
4842 if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
4843 tevent_req_received(req);
4844 return state->cli->raw_status;
4846 *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
4847 if (output->data == NULL) {
4848 tevent_req_received(req);
4849 return NT_STATUS_NO_MEMORY;
4851 tevent_req_received(req);
4852 return NT_STATUS_OK;