2 Unix SMB/CIFS implementation.
4 Copyright (C) Jeremy Allison 2013
5 Copyright (C) Volker Lendecke 2013
6 Copyright (C) Stefan Metzmacher 2013
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This code is a thin wrapper around the existing
24 cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c,
25 but allows the handles to be mapped to uint16_t fnums,
26 which are easier for smbclient to use.
31 #include "async_smb.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "cli_smb2_fnum.h"
36 #include "../libcli/smb/smb2_create_blob.h"
37 #include "libsmb/proto.h"
38 #include "lib/util/tevent_ntstatus.h"
39 #include "../libcli/security/security.h"
40 #include "../librpc/gen_ndr/ndr_security.h"
41 #include "lib/util_ea.h"
42 #include "librpc/gen_ndr/ndr_ioctl.h"
44 #include "librpc/gen_ndr/ndr_quota.h"
47 uint64_t fid_persistent;
48 uint64_t fid_volatile;
52 * Handle mapping code.
55 /***************************************************************
56 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
57 Ensures handle is owned by cli struct.
58 ***************************************************************/
60 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
61 const struct smb2_hnd *ph, /* In */
62 uint16_t *pfnum) /* Out */
65 struct idr_context *idp = cli->smb2.open_handles;
66 struct smb2_hnd *owned_h = talloc_memdup(cli,
68 sizeof(struct smb2_hnd));
70 if (owned_h == NULL) {
71 return NT_STATUS_NO_MEMORY;
76 cli->smb2.open_handles = idr_init(cli);
77 if (cli->smb2.open_handles == NULL) {
79 return NT_STATUS_NO_MEMORY;
81 idp = cli->smb2.open_handles;
84 ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
87 return NT_STATUS_NO_MEMORY;
90 *pfnum = (uint16_t)ret;
94 /***************************************************************
95 Return the smb2_hnd pointer associated with the given fnum.
96 ***************************************************************/
98 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
99 uint16_t fnum, /* In */
100 struct smb2_hnd **pph) /* Out */
102 struct idr_context *idp = cli->smb2.open_handles;
105 return NT_STATUS_INVALID_PARAMETER;
107 *pph = (struct smb2_hnd *)idr_find(idp, fnum);
109 return NT_STATUS_INVALID_HANDLE;
114 /***************************************************************
115 Delete the fnum to smb2_hnd mapping. Zeros out handle on
117 ***************************************************************/
119 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
120 struct smb2_hnd **pph, /* In */
121 uint16_t fnum) /* In */
123 struct idr_context *idp = cli->smb2.open_handles;
127 return NT_STATUS_INVALID_PARAMETER;
130 ph = (struct smb2_hnd *)idr_find(idp, fnum);
132 return NT_STATUS_INVALID_PARAMETER;
134 idr_remove(idp, fnum);
139 /***************************************************************
141 ***************************************************************/
143 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
145 if (create_flags & REQUEST_BATCH_OPLOCK) {
146 return SMB2_OPLOCK_LEVEL_BATCH;
147 } else if (create_flags & REQUEST_OPLOCK) {
148 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
151 /* create_flags doesn't do a level2 request. */
152 return SMB2_OPLOCK_LEVEL_NONE;
155 /***************************************************************
156 Small wrapper that allows SMB2 create to return a uint16_t fnum.
157 ***************************************************************/
159 struct cli_smb2_create_fnum_state {
160 struct cli_state *cli;
161 struct smb2_create_blobs in_cblobs;
162 struct smb2_create_blobs out_cblobs;
163 struct smb_create_returns cr;
165 struct tevent_req *subreq;
168 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
169 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
171 struct tevent_req *cli_smb2_create_fnum_send(
173 struct tevent_context *ev,
174 struct cli_state *cli,
176 uint32_t create_flags,
177 uint32_t impersonation_level,
178 uint32_t desired_access,
179 uint32_t file_attributes,
180 uint32_t share_access,
181 uint32_t create_disposition,
182 uint32_t create_options,
183 const struct smb2_create_blobs *in_cblobs)
185 struct tevent_req *req, *subreq;
186 struct cli_smb2_create_fnum_state *state;
187 size_t fname_len = 0;
188 const char *startp = NULL;
189 const char *endp = NULL;
190 time_t tstamp = (time_t)0;
193 req = tevent_req_create(mem_ctx, &state,
194 struct cli_smb2_create_fnum_state);
200 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
201 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
202 return tevent_req_post(req, ev);
205 if (cli->backup_intent) {
206 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
209 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
210 fname_len = strlen(fname);
211 if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
212 size_t len_before_gmt = startp - fname;
213 size_t len_after_gmt = fname + fname_len - endp;
217 char *new_fname = talloc_array(state, char,
218 len_before_gmt + len_after_gmt + 1);
220 if (tevent_req_nomem(new_fname, req)) {
221 return tevent_req_post(req, ev);
224 memcpy(new_fname, fname, len_before_gmt);
225 memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
227 fname_len = len_before_gmt + len_after_gmt;
229 unix_to_nt_time(&ntt, tstamp);
230 twrp_blob = data_blob_const((const void *)&ntt, 8);
232 status = smb2_create_blob_add(
235 SMB2_CREATE_TAG_TWRP,
237 if (!NT_STATUS_IS_OK(status)) {
238 tevent_req_nterror(req, status);
239 return tevent_req_post(req, ev);
243 if (in_cblobs != NULL) {
245 for (i=0; i<in_cblobs->num_blobs; i++) {
246 struct smb2_create_blob *b = &in_cblobs->blobs[i];
247 status = smb2_create_blob_add(
248 state, &state->in_cblobs, b->tag, b->data);
249 if (!NT_STATUS_IS_OK(status)) {
250 tevent_req_nterror(req, status);
251 return tevent_req_post(req, ev);
256 /* SMB2 is pickier about pathnames. Ensure it doesn't
258 if (*fname == '\\') {
263 /* Or end in a '\' */
264 if (fname_len > 0 && fname[fname_len-1] == '\\') {
265 char *new_fname = talloc_strdup(state, fname);
266 if (tevent_req_nomem(new_fname, req)) {
267 return tevent_req_post(req, ev);
269 new_fname[fname_len-1] = '\0';
273 subreq = smb2cli_create_send(state, ev,
279 flags_to_smb2_oplock(create_flags),
287 if (tevent_req_nomem(subreq, req)) {
288 return tevent_req_post(req, ev);
290 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
292 state->subreq = subreq;
293 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
298 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
300 struct tevent_req *req = tevent_req_callback_data(
301 subreq, struct tevent_req);
302 struct cli_smb2_create_fnum_state *state = tevent_req_data(
303 req, struct cli_smb2_create_fnum_state);
307 status = smb2cli_create_recv(
310 &h.fid_volatile, &state->cr,
314 if (tevent_req_nterror(req, status)) {
318 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
319 if (tevent_req_nterror(req, status)) {
322 tevent_req_done(req);
325 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
327 struct cli_smb2_create_fnum_state *state = tevent_req_data(
328 req, struct cli_smb2_create_fnum_state);
329 return tevent_req_cancel(state->subreq);
332 NTSTATUS cli_smb2_create_fnum_recv(
333 struct tevent_req *req,
335 struct smb_create_returns *cr,
337 struct smb2_create_blobs *out_cblobs)
339 struct cli_smb2_create_fnum_state *state = tevent_req_data(
340 req, struct cli_smb2_create_fnum_state);
343 if (tevent_req_is_nterror(req, &status)) {
344 state->cli->raw_status = status;
348 *pfnum = state->fnum;
353 if (out_cblobs != NULL) {
354 *out_cblobs = (struct smb2_create_blobs) {
355 .num_blobs = state->out_cblobs.num_blobs,
356 .blobs = talloc_move(
357 mem_ctx, &state->out_cblobs.blobs),
360 state->cli->raw_status = NT_STATUS_OK;
364 NTSTATUS cli_smb2_create_fnum(
365 struct cli_state *cli,
367 uint32_t create_flags,
368 uint32_t impersonation_level,
369 uint32_t desired_access,
370 uint32_t file_attributes,
371 uint32_t share_access,
372 uint32_t create_disposition,
373 uint32_t create_options,
374 const struct smb2_create_blobs *in_cblobs,
376 struct smb_create_returns *cr,
378 struct smb2_create_blobs *out_cblobs)
380 TALLOC_CTX *frame = talloc_stackframe();
381 struct tevent_context *ev;
382 struct tevent_req *req;
383 NTSTATUS status = NT_STATUS_NO_MEMORY;
385 if (smbXcli_conn_has_async_calls(cli->conn)) {
387 * Can't use sync call while an async call is in flight
389 status = NT_STATUS_INVALID_PARAMETER;
392 ev = samba_tevent_context_init(frame);
396 req = cli_smb2_create_fnum_send(
412 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
415 status = cli_smb2_create_fnum_recv(req, pfid, cr, mem_ctx, out_cblobs);
421 /***************************************************************
422 Small wrapper that allows SMB2 close to use a uint16_t fnum.
423 ***************************************************************/
425 struct cli_smb2_close_fnum_state {
426 struct cli_state *cli;
431 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
433 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
434 struct tevent_context *ev,
435 struct cli_state *cli,
438 struct tevent_req *req, *subreq;
439 struct cli_smb2_close_fnum_state *state;
442 req = tevent_req_create(mem_ctx, &state,
443 struct cli_smb2_close_fnum_state);
450 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
451 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
452 return tevent_req_post(req, ev);
455 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
456 if (tevent_req_nterror(req, status)) {
457 return tevent_req_post(req, ev);
460 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
461 cli->smb2.session, cli->smb2.tcon,
462 0, state->ph->fid_persistent,
463 state->ph->fid_volatile);
464 if (tevent_req_nomem(subreq, req)) {
465 return tevent_req_post(req, ev);
467 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
471 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
473 struct tevent_req *req = tevent_req_callback_data(
474 subreq, struct tevent_req);
475 struct cli_smb2_close_fnum_state *state = tevent_req_data(
476 req, struct cli_smb2_close_fnum_state);
479 status = smb2cli_close_recv(subreq);
480 if (tevent_req_nterror(req, status)) {
484 /* Delete the fnum -> handle mapping. */
485 status = delete_smb2_handle_mapping(state->cli, &state->ph,
487 if (tevent_req_nterror(req, status)) {
490 tevent_req_done(req);
493 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
495 struct cli_smb2_close_fnum_state *state = tevent_req_data(
496 req, struct cli_smb2_close_fnum_state);
497 NTSTATUS status = NT_STATUS_OK;
499 if (tevent_req_is_nterror(req, &status)) {
500 state->cli->raw_status = status;
502 tevent_req_received(req);
506 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
508 TALLOC_CTX *frame = talloc_stackframe();
509 struct tevent_context *ev;
510 struct tevent_req *req;
511 NTSTATUS status = NT_STATUS_NO_MEMORY;
513 if (smbXcli_conn_has_async_calls(cli->conn)) {
515 * Can't use sync call while an async call is in flight
517 status = NT_STATUS_INVALID_PARAMETER;
520 ev = samba_tevent_context_init(frame);
524 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
528 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
531 status = cli_smb2_close_fnum_recv(req);
537 struct cli_smb2_set_info_fnum_state {
541 static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq);
543 struct tevent_req *cli_smb2_set_info_fnum_send(
545 struct tevent_context *ev,
546 struct cli_state *cli,
548 uint8_t in_info_type,
549 uint8_t in_info_class,
550 const DATA_BLOB *in_input_buffer,
551 uint32_t in_additional_info)
553 struct tevent_req *req = NULL, *subreq = NULL;
554 struct cli_smb2_set_info_fnum_state *state = NULL;
555 struct smb2_hnd *ph = NULL;
558 req = tevent_req_create(
559 mem_ctx, &state, struct cli_smb2_set_info_fnum_state);
564 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
565 if (tevent_req_nterror(req, status)) {
566 return tevent_req_post(req, ev);
569 subreq = smb2cli_set_info_send(
582 if (tevent_req_nomem(subreq, req)) {
583 return tevent_req_post(req, ev);
585 tevent_req_set_callback(subreq, cli_smb2_set_info_fnum_done, req);
589 static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq)
591 NTSTATUS status = smb2cli_set_info_recv(subreq);
592 tevent_req_simple_finish_ntstatus(subreq, status);
595 NTSTATUS cli_smb2_set_info_fnum_recv(struct tevent_req *req)
597 return tevent_req_simple_recv_ntstatus(req);
600 NTSTATUS cli_smb2_set_info_fnum(
601 struct cli_state *cli,
603 uint8_t in_info_type,
604 uint8_t in_info_class,
605 const DATA_BLOB *in_input_buffer,
606 uint32_t in_additional_info)
608 TALLOC_CTX *frame = talloc_stackframe();
609 struct tevent_context *ev = NULL;
610 struct tevent_req *req = NULL;
611 NTSTATUS status = NT_STATUS_NO_MEMORY;
614 if (smbXcli_conn_has_async_calls(cli->conn)) {
616 * Can't use sync call while an async call is in flight
618 status = NT_STATUS_INVALID_PARAMETER;
621 ev = samba_tevent_context_init(frame);
625 req = cli_smb2_set_info_fnum_send(
637 ok = tevent_req_poll_ntstatus(req, ev, &status);
641 status = cli_smb2_set_info_fnum_recv(req);
647 struct cli_smb2_delete_on_close_state {
648 struct cli_state *cli;
653 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
655 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
656 struct tevent_context *ev,
657 struct cli_state *cli,
661 struct tevent_req *req = NULL;
662 struct cli_smb2_delete_on_close_state *state = NULL;
663 struct tevent_req *subreq = NULL;
664 uint8_t in_info_type;
665 uint8_t in_file_info_class;
667 req = tevent_req_create(mem_ctx, &state,
668 struct cli_smb2_delete_on_close_state);
674 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
675 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
676 return tevent_req_post(req, ev);
680 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
681 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
684 in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
685 /* Setup data array. */
686 SCVAL(&state->data[0], 0, flag ? 1 : 0);
687 state->inbuf.data = &state->data[0];
688 state->inbuf.length = 1;
690 subreq = cli_smb2_set_info_fnum_send(
699 if (tevent_req_nomem(subreq, req)) {
700 return tevent_req_post(req, ev);
702 tevent_req_set_callback(subreq,
703 cli_smb2_delete_on_close_done,
708 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
710 NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
711 tevent_req_simple_finish_ntstatus(subreq, status);
714 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
716 struct cli_smb2_delete_on_close_state *state =
718 struct cli_smb2_delete_on_close_state);
721 if (tevent_req_is_nterror(req, &status)) {
722 state->cli->raw_status = status;
723 tevent_req_received(req);
727 state->cli->raw_status = NT_STATUS_OK;
728 tevent_req_received(req);
732 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
734 TALLOC_CTX *frame = talloc_stackframe();
735 struct tevent_context *ev;
736 struct tevent_req *req;
737 NTSTATUS status = NT_STATUS_NO_MEMORY;
739 if (smbXcli_conn_has_async_calls(cli->conn)) {
741 * Can't use sync call while an async call is in flight
743 status = NT_STATUS_INVALID_PARAMETER;
746 ev = samba_tevent_context_init(frame);
750 req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
754 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
757 status = cli_smb2_delete_on_close_recv(req);
763 struct cli_smb2_mkdir_state {
764 struct tevent_context *ev;
765 struct cli_state *cli;
768 static void cli_smb2_mkdir_opened(struct tevent_req *subreq);
769 static void cli_smb2_mkdir_closed(struct tevent_req *subreq);
771 struct tevent_req *cli_smb2_mkdir_send(
773 struct tevent_context *ev,
774 struct cli_state *cli,
777 struct tevent_req *req = NULL, *subreq = NULL;
778 struct cli_smb2_mkdir_state *state = NULL;
780 req = tevent_req_create(
781 mem_ctx, &state, struct cli_smb2_mkdir_state);
788 /* Ensure this is a directory. */
789 subreq = cli_smb2_create_fnum_send(
794 0, /* create_flags */
795 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level */
796 FILE_READ_ATTRIBUTES, /* desired_access */
797 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
799 FILE_SHARE_WRITE, /* share_access */
800 FILE_CREATE, /* create_disposition */
801 FILE_DIRECTORY_FILE, /* create_options */
802 NULL); /* in_cblobs */
803 if (tevent_req_nomem(subreq, req)) {
804 return tevent_req_post(req, ev);
806 tevent_req_set_callback(subreq, cli_smb2_mkdir_opened, req);
810 static void cli_smb2_mkdir_opened(struct tevent_req *subreq)
812 struct tevent_req *req = tevent_req_callback_data(
813 subreq, struct tevent_req);
814 struct cli_smb2_mkdir_state *state = tevent_req_data(
815 req, struct cli_smb2_mkdir_state);
819 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
821 if (tevent_req_nterror(req, status)) {
825 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
826 if (tevent_req_nomem(subreq, req)) {
829 tevent_req_set_callback(subreq, cli_smb2_mkdir_closed, req);
832 static void cli_smb2_mkdir_closed(struct tevent_req *subreq)
834 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
835 tevent_req_simple_finish_ntstatus(subreq, status);
838 NTSTATUS cli_smb2_mkdir_recv(struct tevent_req *req)
840 return tevent_req_simple_recv_ntstatus(req);
843 struct cli_smb2_rmdir_state {
844 struct tevent_context *ev;
845 struct cli_state *cli;
847 const struct smb2_create_blobs *in_cblobs;
852 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq);
853 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq);
854 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq);
855 static void cli_smb2_rmdir_closed(struct tevent_req *subreq);
857 struct tevent_req *cli_smb2_rmdir_send(
859 struct tevent_context *ev,
860 struct cli_state *cli,
862 const struct smb2_create_blobs *in_cblobs)
864 struct tevent_req *req = NULL, *subreq = NULL;
865 struct cli_smb2_rmdir_state *state = NULL;
867 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_rmdir_state);
873 state->dname = dname;
874 state->in_cblobs = in_cblobs;
876 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
877 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
878 return tevent_req_post(req, ev);
881 subreq = cli_smb2_create_fnum_send(
886 0, /* create_flags */
887 SMB2_IMPERSONATION_IMPERSONATION,
888 DELETE_ACCESS, /* desired_access */
889 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
890 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
891 FILE_OPEN, /* create_disposition */
892 FILE_DIRECTORY_FILE, /* create_options */
893 state->in_cblobs); /* in_cblobs */
894 if (tevent_req_nomem(subreq, req)) {
895 return tevent_req_post(req, ev);
897 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened1, req);
901 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq)
903 struct tevent_req *req = tevent_req_callback_data(
904 subreq, struct tevent_req);
905 struct cli_smb2_rmdir_state *state = tevent_req_data(
906 req, struct cli_smb2_rmdir_state);
909 status = cli_smb2_create_fnum_recv(
910 subreq, &state->fnum, NULL, NULL, NULL);
913 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
915 * Naive option to match our SMB1 code. Assume the
916 * symlink path that tripped us up was the last
917 * component and try again. Eventually we will have to
918 * deal with the returned path unprocessed component. JRA.
920 subreq = cli_smb2_create_fnum_send(
925 0, /* create_flags */
926 SMB2_IMPERSONATION_IMPERSONATION,
927 DELETE_ACCESS, /* desired_access */
928 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
929 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
930 FILE_OPEN, /* create_disposition */
932 FILE_DELETE_ON_CLOSE|
933 FILE_OPEN_REPARSE_POINT, /* create_options */
934 state->in_cblobs); /* in_cblobs */
935 if (tevent_req_nomem(subreq, req)) {
938 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened2, req);
942 if (tevent_req_nterror(req, status)) {
946 subreq = cli_smb2_delete_on_close_send(
947 state, state->ev, state->cli, state->fnum, true);
948 if (tevent_req_nomem(subreq, req)) {
951 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
954 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq)
956 struct tevent_req *req = tevent_req_callback_data(
957 subreq, struct tevent_req);
958 struct cli_smb2_rmdir_state *state = tevent_req_data(
959 req, struct cli_smb2_rmdir_state);
962 status = cli_smb2_create_fnum_recv(
963 subreq, &state->fnum, NULL, NULL, NULL);
965 if (tevent_req_nterror(req, status)) {
969 subreq = cli_smb2_delete_on_close_send(
970 state, state->ev, state->cli, state->fnum, true);
971 if (tevent_req_nomem(subreq, req)) {
974 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
977 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq)
979 struct tevent_req *req = tevent_req_callback_data(
980 subreq, struct tevent_req);
981 struct cli_smb2_rmdir_state *state = tevent_req_data(
982 req, struct cli_smb2_rmdir_state);
984 state->status = cli_smb2_delete_on_close_recv(subreq);
988 * Close the fd even if the set_disp failed
991 subreq = cli_smb2_close_fnum_send(
992 state, state->ev, state->cli, state->fnum);
993 if (tevent_req_nomem(subreq, req)) {
996 tevent_req_set_callback(subreq, cli_smb2_rmdir_closed, req);
999 static void cli_smb2_rmdir_closed(struct tevent_req *subreq)
1001 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1002 tevent_req_simple_finish_ntstatus(subreq, status);
1005 NTSTATUS cli_smb2_rmdir_recv(struct tevent_req *req)
1007 struct cli_smb2_rmdir_state *state = tevent_req_data(
1008 req, struct cli_smb2_rmdir_state);
1011 if (tevent_req_is_nterror(req, &status)) {
1014 return state->status;
1017 /***************************************************************
1018 Small wrapper that allows SMB2 to unlink a pathname.
1019 ***************************************************************/
1021 struct cli_smb2_unlink_state {
1022 struct tevent_context *ev;
1023 struct cli_state *cli;
1025 const struct smb2_create_blobs *in_cblobs;
1028 static void cli_smb2_unlink_opened1(struct tevent_req *subreq);
1029 static void cli_smb2_unlink_opened2(struct tevent_req *subreq);
1030 static void cli_smb2_unlink_closed(struct tevent_req *subreq);
1032 struct tevent_req *cli_smb2_unlink_send(
1033 TALLOC_CTX *mem_ctx,
1034 struct tevent_context *ev,
1035 struct cli_state *cli,
1037 const struct smb2_create_blobs *in_cblobs)
1039 struct tevent_req *req = NULL, *subreq = NULL;
1040 struct cli_smb2_unlink_state *state = NULL;
1042 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_unlink_state);
1048 state->fname = fname;
1049 state->in_cblobs = in_cblobs;
1051 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1052 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1053 return tevent_req_post(req, ev);
1056 subreq = cli_smb2_create_fnum_send(
1057 state, /* mem_ctx */
1058 state->ev, /* tevent_context */
1059 state->cli, /* cli_struct */
1060 state->fname, /* filename */
1061 0, /* create_flags */
1062 SMB2_IMPERSONATION_IMPERSONATION,
1063 DELETE_ACCESS, /* desired_access */
1064 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1067 FILE_SHARE_DELETE, /* share_access */
1068 FILE_OPEN, /* create_disposition */
1069 FILE_DELETE_ON_CLOSE, /* create_options */
1070 state->in_cblobs); /* in_cblobs */
1071 if (tevent_req_nomem(subreq, req)) {
1072 return tevent_req_post(req, ev);
1074 tevent_req_set_callback(subreq, cli_smb2_unlink_opened1, req);
1078 static void cli_smb2_unlink_opened1(struct tevent_req *subreq)
1080 struct tevent_req *req = tevent_req_callback_data(
1081 subreq, struct tevent_req);
1082 struct cli_smb2_unlink_state *state = tevent_req_data(
1083 req, struct cli_smb2_unlink_state);
1087 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1088 TALLOC_FREE(subreq);
1090 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1092 * Naive option to match our SMB1 code. Assume the
1093 * symlink path that tripped us up was the last
1094 * component and try again. Eventually we will have to
1095 * deal with the returned path unprocessed component. JRA.
1097 subreq = cli_smb2_create_fnum_send(
1098 state, /* mem_ctx */
1099 state->ev, /* tevent_context */
1100 state->cli, /* cli_struct */
1101 state->fname, /* filename */
1102 0, /* create_flags */
1103 SMB2_IMPERSONATION_IMPERSONATION,
1104 DELETE_ACCESS, /* desired_access */
1105 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1108 FILE_SHARE_DELETE, /* share_access */
1109 FILE_OPEN, /* create_disposition */
1110 FILE_DELETE_ON_CLOSE|
1111 FILE_OPEN_REPARSE_POINT, /* create_options */
1112 state->in_cblobs); /* in_cblobs */
1113 if (tevent_req_nomem(subreq, req)) {
1116 tevent_req_set_callback(subreq, cli_smb2_unlink_opened2, req);
1120 if (tevent_req_nterror(req, status)) {
1124 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1125 if (tevent_req_nomem(subreq, req)) {
1128 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1131 static void cli_smb2_unlink_opened2(struct tevent_req *subreq)
1133 struct tevent_req *req = tevent_req_callback_data(
1134 subreq, struct tevent_req);
1135 struct cli_smb2_unlink_state *state = tevent_req_data(
1136 req, struct cli_smb2_unlink_state);
1140 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1141 TALLOC_FREE(subreq);
1142 if (tevent_req_nterror(req, status)) {
1146 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1147 if (tevent_req_nomem(subreq, req)) {
1150 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1153 static void cli_smb2_unlink_closed(struct tevent_req *subreq)
1155 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1156 tevent_req_simple_finish_ntstatus(subreq, status);
1159 NTSTATUS cli_smb2_unlink_recv(struct tevent_req *req)
1161 return tevent_req_simple_recv_ntstatus(req);
1164 /***************************************************************
1165 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1166 ***************************************************************/
1168 static NTSTATUS parse_finfo_id_both_directory_info(const uint8_t *dir_data,
1169 uint32_t dir_data_length,
1170 struct file_info *finfo,
1171 uint32_t *next_offset)
1177 if (dir_data_length < 4) {
1178 return NT_STATUS_INFO_LENGTH_MISMATCH;
1181 *next_offset = IVAL(dir_data, 0);
1183 if (*next_offset > dir_data_length) {
1184 return NT_STATUS_INFO_LENGTH_MISMATCH;
1187 if (*next_offset != 0) {
1188 /* Ensure we only read what in this record. */
1189 dir_data_length = *next_offset;
1192 if (dir_data_length < 105) {
1193 return NT_STATUS_INFO_LENGTH_MISMATCH;
1196 finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
1197 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
1198 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
1199 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
1200 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
1201 finfo->allocated_size = IVAL2_TO_SMB_BIG_UINT(dir_data + 48, 0);
1202 /* NB. We need to enlarge finfo->mode to be 32-bits. */
1203 finfo->mode = (uint16_t)IVAL(dir_data + 56, 0);
1204 finfo->ino = IVAL2_TO_SMB_BIG_UINT(dir_data + 96, 0);
1205 namelen = IVAL(dir_data + 60,0);
1206 if (namelen > (dir_data_length - 104)) {
1207 return NT_STATUS_INFO_LENGTH_MISMATCH;
1209 slen = CVAL(dir_data + 68, 0);
1211 return NT_STATUS_INFO_LENGTH_MISMATCH;
1213 ret = pull_string_talloc(finfo,
1215 FLAGS2_UNICODE_STRINGS,
1220 if (ret == (size_t)-1) {
1221 /* Bad conversion. */
1222 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1225 ret = pull_string_talloc(finfo,
1227 FLAGS2_UNICODE_STRINGS,
1232 if (ret == (size_t)-1) {
1233 /* Bad conversion. */
1234 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1237 if (finfo->name == NULL) {
1238 /* Bad conversion. */
1239 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1242 return NT_STATUS_OK;
1245 /*******************************************************************
1246 Given a filename - get its directory name
1247 ********************************************************************/
1249 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
1257 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
1260 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
1271 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
1274 (*parent)[len] = '\0';
1282 /***************************************************************
1283 Wrapper that allows SMB2 to list a directory.
1285 ***************************************************************/
1287 NTSTATUS cli_smb2_list(struct cli_state *cli,
1288 const char *pathname,
1290 NTSTATUS (*fn)(const char *,
1297 uint16_t fnum = 0xffff;
1298 char *parent_dir = NULL;
1299 const char *mask = NULL;
1300 struct smb2_hnd *ph = NULL;
1301 bool processed_file = false;
1302 TALLOC_CTX *frame = talloc_stackframe();
1303 TALLOC_CTX *subframe = NULL;
1306 uint32_t max_avail_len;
1309 if (smbXcli_conn_has_async_calls(cli->conn)) {
1311 * Can't use sync call while an async call is in flight
1313 status = NT_STATUS_INVALID_PARAMETER;
1317 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1318 status = NT_STATUS_INVALID_PARAMETER;
1322 /* Get the directory name. */
1323 if (!windows_parent_dirname(frame,
1327 status = NT_STATUS_NO_MEMORY;
1331 mask_has_wild = ms_has_wild(mask);
1333 status = cli_smb2_create_fnum(cli,
1335 0, /* create_flags */
1336 SMB2_IMPERSONATION_IMPERSONATION,
1337 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
1338 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1339 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
1340 FILE_OPEN, /* create_disposition */
1341 FILE_DIRECTORY_FILE, /* create_options */
1348 if (!NT_STATUS_IS_OK(status)) {
1352 status = map_fnum_to_smb2_handle(cli,
1355 if (!NT_STATUS_IS_OK(status)) {
1360 * ideally, use the max transaction size, but don't send a request
1361 * bigger than we have credits available for
1363 max_trans = smb2cli_conn_max_trans_size(cli->conn);
1364 ok = smb2cli_conn_req_possible(cli->conn, &max_avail_len);
1366 max_trans = MIN(max_trans, max_avail_len);
1370 uint8_t *dir_data = NULL;
1371 uint32_t dir_data_length = 0;
1372 uint32_t next_offset = 0;
1373 subframe = talloc_stackframe();
1375 status = smb2cli_query_directory(cli->conn,
1379 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
1390 if (!NT_STATUS_IS_OK(status)) {
1391 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1398 struct file_info *finfo = talloc_zero(subframe,
1401 if (finfo == NULL) {
1402 status = NT_STATUS_NO_MEMORY;
1406 status = parse_finfo_id_both_directory_info(dir_data,
1411 if (!NT_STATUS_IS_OK(status)) {
1415 /* Protect against server attack. */
1416 status = is_bad_finfo_name(cli, finfo);
1417 if (!NT_STATUS_IS_OK(status)) {
1418 smbXcli_conn_disconnect(cli->conn, status);
1422 if (dir_check_ftype((uint32_t)finfo->mode,
1423 (uint32_t)attribute)) {
1425 * Only process if attributes match.
1426 * On SMB1 server does this, so on
1427 * SMB2 we need to emulate in the
1430 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1432 processed_file = true;
1434 status = fn(cli->dfs_mountpoint,
1439 if (!NT_STATUS_IS_OK(status)) {
1446 /* Move to next entry. */
1448 dir_data += next_offset;
1449 dir_data_length -= next_offset;
1451 } while (next_offset != 0);
1453 TALLOC_FREE(subframe);
1455 if (!mask_has_wild) {
1457 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1458 * when handed a non-wildcard path. Do it
1459 * for the server (with a non-wildcard path
1460 * there should only ever be one file returned.
1462 status = STATUS_NO_MORE_FILES;
1466 } while (NT_STATUS_IS_OK(status));
1468 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1469 status = NT_STATUS_OK;
1472 if (NT_STATUS_IS_OK(status) && !processed_file) {
1474 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1475 * if no files match. Emulate this in the client.
1477 status = NT_STATUS_NO_SUCH_FILE;
1482 if (fnum != 0xffff) {
1483 cli_smb2_close_fnum(cli, fnum);
1486 cli->raw_status = status;
1488 TALLOC_FREE(subframe);
1493 /***************************************************************
1494 Wrapper that allows SMB2 to query a path info (basic level).
1496 ***************************************************************/
1498 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1500 SMB_STRUCT_STAT *sbuf,
1501 uint32_t *attributes)
1504 struct smb_create_returns cr;
1505 uint16_t fnum = 0xffff;
1506 size_t namelen = strlen(name);
1508 if (smbXcli_conn_has_async_calls(cli->conn)) {
1510 * Can't use sync call while an async call is in flight
1512 return NT_STATUS_INVALID_PARAMETER;
1515 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1516 return NT_STATUS_INVALID_PARAMETER;
1519 /* SMB2 is pickier about pathnames. Ensure it doesn't
1521 if (namelen > 0 && name[namelen-1] == '\\') {
1522 char *modname = talloc_strndup(talloc_tos(), name, namelen-1);
1523 if (modname == NULL) {
1524 return NT_STATUS_NO_MEMORY;
1529 /* This is commonly used as a 'cd'. Try qpathinfo on
1530 a directory handle first. */
1532 status = cli_smb2_create_fnum(cli,
1534 0, /* create_flags */
1535 SMB2_IMPERSONATION_IMPERSONATION,
1536 FILE_READ_ATTRIBUTES, /* desired_access */
1537 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1538 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1539 FILE_OPEN, /* create_disposition */
1540 FILE_DIRECTORY_FILE, /* create_options */
1547 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1548 /* Maybe a file ? */
1549 status = cli_smb2_create_fnum(cli,
1551 0, /* create_flags */
1552 SMB2_IMPERSONATION_IMPERSONATION,
1553 FILE_READ_ATTRIBUTES, /* desired_access */
1554 0, /* file attributes */
1555 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1556 FILE_OPEN, /* create_disposition */
1557 0, /* create_options */
1565 if (!NT_STATUS_IS_OK(status)) {
1569 status = cli_smb2_close_fnum(cli, fnum);
1573 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1574 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1575 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1576 sbuf->st_ex_size = cr.end_of_file;
1577 *attributes = cr.file_attributes;
1582 struct cli_smb2_chkpath_state {
1583 struct tevent_context *ev;
1584 struct cli_state *cli;
1587 static void cli_smb2_chkpath_opened(struct tevent_req *subreq);
1588 static void cli_smb2_chkpath_closed(struct tevent_req *subreq);
1590 struct tevent_req *cli_smb2_chkpath_send(
1591 TALLOC_CTX *mem_ctx,
1592 struct tevent_context *ev,
1593 struct cli_state *cli,
1596 struct tevent_req *req = NULL, *subreq = NULL;
1597 struct cli_smb2_chkpath_state *state = NULL;
1599 req = tevent_req_create(
1600 mem_ctx, &state, struct cli_smb2_chkpath_state);
1607 /* Ensure this is a directory. */
1608 subreq = cli_smb2_create_fnum_send(
1609 state, /* mem_ctx */
1613 0, /* create_flags */
1614 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level */
1615 FILE_READ_ATTRIBUTES, /* desired_access */
1616 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
1619 FILE_SHARE_DELETE, /* share_access */
1620 FILE_OPEN, /* create_disposition */
1621 FILE_DIRECTORY_FILE, /* create_options */
1622 NULL); /* in_cblobs */
1623 if (tevent_req_nomem(subreq, req)) {
1624 return tevent_req_post(req, ev);
1626 tevent_req_set_callback(subreq, cli_smb2_chkpath_opened, req);
1630 static void cli_smb2_chkpath_opened(struct tevent_req *subreq)
1632 struct tevent_req *req = tevent_req_callback_data(
1633 subreq, struct tevent_req);
1634 struct cli_smb2_chkpath_state *state = tevent_req_data(
1635 req, struct cli_smb2_chkpath_state);
1639 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1640 TALLOC_FREE(subreq);
1641 if (tevent_req_nterror(req, status)) {
1645 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1646 if (tevent_req_nomem(subreq, req)) {
1649 tevent_req_set_callback(subreq, cli_smb2_chkpath_closed, req);
1652 static void cli_smb2_chkpath_closed(struct tevent_req *subreq)
1654 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1655 tevent_req_simple_finish_ntstatus(subreq, status);
1658 NTSTATUS cli_smb2_chkpath_recv(struct tevent_req *req)
1660 return tevent_req_simple_recv_ntstatus(req);
1663 struct cli_smb2_query_info_fnum_state {
1667 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq);
1669 struct tevent_req *cli_smb2_query_info_fnum_send(
1670 TALLOC_CTX *mem_ctx,
1671 struct tevent_context *ev,
1672 struct cli_state *cli,
1674 uint8_t in_info_type,
1675 uint8_t in_info_class,
1676 uint32_t in_max_output_length,
1677 const DATA_BLOB *in_input_buffer,
1678 uint32_t in_additional_info,
1681 struct tevent_req *req = NULL, *subreq = NULL;
1682 struct cli_smb2_query_info_fnum_state *state = NULL;
1683 struct smb2_hnd *ph = NULL;
1686 req = tevent_req_create(
1687 mem_ctx, &state, struct cli_smb2_query_info_fnum_state);
1692 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1693 if (tevent_req_nterror(req, status)) {
1694 return tevent_req_post(req, ev);
1697 subreq = smb2cli_query_info_send(
1706 in_max_output_length,
1712 if (tevent_req_nomem(subreq, req)) {
1713 return tevent_req_post(req, ev);
1715 tevent_req_set_callback(subreq, cli_smb2_query_info_fnum_done, req);
1719 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq)
1721 struct tevent_req *req = tevent_req_callback_data(
1722 subreq, struct tevent_req);
1723 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1724 req, struct cli_smb2_query_info_fnum_state);
1728 status = smb2cli_query_info_recv(subreq, state, &outbuf);
1729 TALLOC_FREE(subreq);
1730 if (tevent_req_nterror(req, status)) {
1735 * We have to dup the memory here because outbuf.data is not
1736 * returned as a talloc object by smb2cli_query_info_recv.
1737 * It's a pointer into the received buffer.
1739 state->outbuf = data_blob_dup_talloc(state, outbuf);
1741 if ((outbuf.length != 0) &&
1742 tevent_req_nomem(state->outbuf.data, req)) {
1745 tevent_req_done(req);
1748 NTSTATUS cli_smb2_query_info_fnum_recv(
1749 struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *outbuf)
1751 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1752 req, struct cli_smb2_query_info_fnum_state);
1755 if (tevent_req_is_nterror(req, &status)) {
1758 *outbuf = (DATA_BLOB) {
1759 .data = talloc_move(mem_ctx, &state->outbuf.data),
1760 .length = state->outbuf.length,
1762 return NT_STATUS_OK;
1765 NTSTATUS cli_smb2_query_info_fnum(
1766 struct cli_state *cli,
1768 uint8_t in_info_type,
1769 uint8_t in_info_class,
1770 uint32_t in_max_output_length,
1771 const DATA_BLOB *in_input_buffer,
1772 uint32_t in_additional_info,
1774 TALLOC_CTX *mem_ctx,
1777 TALLOC_CTX *frame = talloc_stackframe();
1778 struct tevent_context *ev = NULL;
1779 struct tevent_req *req = NULL;
1780 NTSTATUS status = NT_STATUS_NO_MEMORY;
1783 if (smbXcli_conn_has_async_calls(cli->conn)) {
1785 * Can't use sync call while an async call is in flight
1787 status = NT_STATUS_INVALID_PARAMETER;
1790 ev = samba_tevent_context_init(frame);
1794 req = cli_smb2_query_info_fnum_send(
1801 in_max_output_length,
1808 ok = tevent_req_poll_ntstatus(req, ev, &status);
1812 status = cli_smb2_query_info_fnum_recv(req, mem_ctx, outbuf);
1818 /***************************************************************
1819 Helper function for pathname operations.
1820 ***************************************************************/
1822 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1824 uint32_t desired_access,
1828 size_t namelen = strlen(name);
1829 TALLOC_CTX *frame = talloc_stackframe();
1830 uint32_t create_options = 0;
1832 /* SMB2 is pickier about pathnames. Ensure it doesn't
1834 if (namelen > 0 && name[namelen-1] == '\\') {
1835 char *modname = talloc_strdup(frame, name);
1836 if (modname == NULL) {
1837 status = NT_STATUS_NO_MEMORY;
1840 modname[namelen-1] = '\0';
1844 /* Try to open a file handle first. */
1845 status = cli_smb2_create_fnum(cli,
1847 0, /* create_flags */
1848 SMB2_IMPERSONATION_IMPERSONATION,
1850 0, /* file attributes */
1851 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1852 FILE_OPEN, /* create_disposition */
1860 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1862 * Naive option to match our SMB1 code. Assume the
1863 * symlink path that tripped us up was the last
1864 * component and try again. Eventually we will have to
1865 * deal with the returned path unprocessed component. JRA.
1867 create_options |= FILE_OPEN_REPARSE_POINT;
1868 status = cli_smb2_create_fnum(cli,
1870 0, /* create_flags */
1871 SMB2_IMPERSONATION_IMPERSONATION,
1873 0, /* file attributes */
1874 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1875 FILE_OPEN, /* create_disposition */
1884 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1885 create_options |= FILE_DIRECTORY_FILE;
1886 status = cli_smb2_create_fnum(cli,
1888 0, /* create_flags */
1889 SMB2_IMPERSONATION_IMPERSONATION,
1891 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1892 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1893 FILE_OPEN, /* create_disposition */
1894 create_options, /* create_options */
1908 /***************************************************************
1909 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1911 ***************************************************************/
1913 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1918 DATA_BLOB outbuf = data_blob_null;
1919 uint16_t fnum = 0xffff;
1920 uint32_t altnamelen = 0;
1921 TALLOC_CTX *frame = talloc_stackframe();
1923 if (smbXcli_conn_has_async_calls(cli->conn)) {
1925 * Can't use sync call while an async call is in flight
1927 status = NT_STATUS_INVALID_PARAMETER;
1931 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1932 status = NT_STATUS_INVALID_PARAMETER;
1936 status = get_fnum_from_path(cli,
1938 FILE_READ_ATTRIBUTES,
1941 if (!NT_STATUS_IS_OK(status)) {
1945 status = cli_smb2_query_info_fnum(
1948 1, /* in_info_type */
1949 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1950 0xFFFF, /* in_max_output_length */
1951 NULL, /* in_input_buffer */
1952 0, /* in_additional_info */
1957 if (!NT_STATUS_IS_OK(status)) {
1961 /* Parse the reply. */
1962 if (outbuf.length < 4) {
1963 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1967 altnamelen = IVAL(outbuf.data, 0);
1968 if (altnamelen > outbuf.length - 4) {
1969 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1973 if (altnamelen > 0) {
1975 char *short_name = NULL;
1976 ret = pull_string_talloc(frame,
1978 FLAGS2_UNICODE_STRINGS,
1983 if (ret == (size_t)-1) {
1984 /* Bad conversion. */
1985 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1989 fstrcpy(alt_name, short_name);
1994 status = NT_STATUS_OK;
1998 if (fnum != 0xffff) {
1999 cli_smb2_close_fnum(cli, fnum);
2002 cli->raw_status = status;
2009 /***************************************************************
2010 Wrapper that allows SMB2 to query a fnum info (basic level).
2012 ***************************************************************/
2014 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
2018 struct timespec *create_time,
2019 struct timespec *access_time,
2020 struct timespec *write_time,
2021 struct timespec *change_time,
2025 DATA_BLOB outbuf = data_blob_null;
2026 TALLOC_CTX *frame = talloc_stackframe();
2028 if (smbXcli_conn_has_async_calls(cli->conn)) {
2030 * Can't use sync call while an async call is in flight
2032 status = NT_STATUS_INVALID_PARAMETER;
2036 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2037 status = NT_STATUS_INVALID_PARAMETER;
2041 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2042 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
2044 status = cli_smb2_query_info_fnum(
2047 1, /* in_info_type */
2048 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
2049 0xFFFF, /* in_max_output_length */
2050 NULL, /* in_input_buffer */
2051 0, /* in_additional_info */
2055 if (!NT_STATUS_IS_OK(status)) {
2059 /* Parse the reply. */
2060 if (outbuf.length < 0x60) {
2061 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2066 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
2069 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
2072 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
2075 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
2078 uint32_t attr = IVAL(outbuf.data, 0x20);
2079 *mode = (uint16_t)attr;
2082 uint64_t file_size = BVAL(outbuf.data, 0x30);
2083 *size = (off_t)file_size;
2086 uint64_t file_index = BVAL(outbuf.data, 0x40);
2087 *ino = (SMB_INO_T)file_index;
2092 cli->raw_status = status;
2098 /***************************************************************
2099 Wrapper that allows SMB2 to query an fnum.
2100 Implement on top of cli_smb2_qfileinfo_basic().
2102 ***************************************************************/
2104 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
2108 time_t *change_time,
2109 time_t *access_time,
2112 struct timespec access_time_ts;
2113 struct timespec write_time_ts;
2114 struct timespec change_time_ts;
2115 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
2125 cli->raw_status = status;
2127 if (!NT_STATUS_IS_OK(status)) {
2132 *change_time = change_time_ts.tv_sec;
2135 *access_time = access_time_ts.tv_sec;
2138 *write_time = write_time_ts.tv_sec;
2140 return NT_STATUS_OK;
2143 /***************************************************************
2144 Wrapper that allows SMB2 to get pathname attributes.
2146 ***************************************************************/
2148 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
2155 uint16_t fnum = 0xffff;
2156 struct smb2_hnd *ph = NULL;
2157 TALLOC_CTX *frame = talloc_stackframe();
2159 if (smbXcli_conn_has_async_calls(cli->conn)) {
2161 * Can't use sync call while an async call is in flight
2163 status = NT_STATUS_INVALID_PARAMETER;
2167 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2168 status = NT_STATUS_INVALID_PARAMETER;
2172 status = get_fnum_from_path(cli,
2174 FILE_READ_ATTRIBUTES,
2177 if (!NT_STATUS_IS_OK(status)) {
2181 status = map_fnum_to_smb2_handle(cli,
2184 if (!NT_STATUS_IS_OK(status)) {
2187 status = cli_smb2_getattrE(cli,
2194 if (!NT_STATUS_IS_OK(status)) {
2200 if (fnum != 0xffff) {
2201 cli_smb2_close_fnum(cli, fnum);
2204 cli->raw_status = status;
2210 /***************************************************************
2211 Wrapper that allows SMB2 to query a pathname info (basic level).
2212 Implement on top of cli_smb2_qfileinfo_basic().
2214 ***************************************************************/
2216 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
2218 struct timespec *create_time,
2219 struct timespec *access_time,
2220 struct timespec *write_time,
2221 struct timespec *change_time,
2227 struct smb2_hnd *ph = NULL;
2228 uint16_t fnum = 0xffff;
2229 TALLOC_CTX *frame = talloc_stackframe();
2231 if (smbXcli_conn_has_async_calls(cli->conn)) {
2233 * Can't use sync call while an async call is in flight
2235 status = NT_STATUS_INVALID_PARAMETER;
2239 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2240 status = NT_STATUS_INVALID_PARAMETER;
2244 status = get_fnum_from_path(cli,
2246 FILE_READ_ATTRIBUTES,
2249 if (!NT_STATUS_IS_OK(status)) {
2253 status = map_fnum_to_smb2_handle(cli,
2256 if (!NT_STATUS_IS_OK(status)) {
2260 status = cli_smb2_qfileinfo_basic(cli,
2272 if (fnum != 0xffff) {
2273 cli_smb2_close_fnum(cli, fnum);
2276 cli->raw_status = status;
2282 /***************************************************************
2283 Wrapper that allows SMB2 to query pathname streams.
2285 ***************************************************************/
2287 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
2289 TALLOC_CTX *mem_ctx,
2290 unsigned int *pnum_streams,
2291 struct stream_struct **pstreams)
2294 uint16_t fnum = 0xffff;
2295 DATA_BLOB outbuf = data_blob_null;
2296 TALLOC_CTX *frame = talloc_stackframe();
2298 if (smbXcli_conn_has_async_calls(cli->conn)) {
2300 * Can't use sync call while an async call is in flight
2302 status = NT_STATUS_INVALID_PARAMETER;
2306 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2307 status = NT_STATUS_INVALID_PARAMETER;
2311 status = get_fnum_from_path(cli,
2313 FILE_READ_ATTRIBUTES,
2316 if (!NT_STATUS_IS_OK(status)) {
2320 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2321 level 22 (SMB2_FILE_STREAM_INFORMATION). */
2323 status = cli_smb2_query_info_fnum(
2326 1, /* in_info_type */
2327 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
2328 0xFFFF, /* in_max_output_length */
2329 NULL, /* in_input_buffer */
2330 0, /* in_additional_info */
2335 if (!NT_STATUS_IS_OK(status)) {
2339 /* Parse the reply. */
2340 if (!parse_streams_blob(mem_ctx,
2345 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2351 if (fnum != 0xffff) {
2352 cli_smb2_close_fnum(cli, fnum);
2355 cli->raw_status = status;
2361 /***************************************************************
2362 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2365 ***************************************************************/
2367 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
2369 uint8_t in_info_type,
2370 uint8_t in_file_info_class,
2371 const DATA_BLOB *p_in_data)
2374 uint16_t fnum = 0xffff;
2375 TALLOC_CTX *frame = talloc_stackframe();
2377 if (smbXcli_conn_has_async_calls(cli->conn)) {
2379 * Can't use sync call while an async call is in flight
2381 status = NT_STATUS_INVALID_PARAMETER;
2385 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2386 status = NT_STATUS_INVALID_PARAMETER;
2390 status = get_fnum_from_path(cli,
2392 FILE_WRITE_ATTRIBUTES,
2395 if (!NT_STATUS_IS_OK(status)) {
2399 status = cli_smb2_set_info_fnum(
2404 p_in_data, /* in_input_buffer */
2405 0); /* in_additional_info */
2408 if (fnum != 0xffff) {
2409 cli_smb2_close_fnum(cli, fnum);
2412 cli->raw_status = status;
2419 /***************************************************************
2420 Wrapper that allows SMB2 to set pathname attributes.
2422 ***************************************************************/
2424 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
2429 uint8_t inbuf_store[40];
2430 DATA_BLOB inbuf = data_blob_null;
2432 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2433 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2435 inbuf.data = inbuf_store;
2436 inbuf.length = sizeof(inbuf_store);
2437 data_blob_clear(&inbuf);
2440 * SMB1 uses attr == 0 to clear all attributes
2441 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2442 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2443 * request attribute change.
2445 * SMB2 uses exactly the reverse. Unfortunately as the
2446 * cli_setatr() ABI is exposed inside libsmbclient,
2447 * we must make the SMB2 cli_smb2_setatr() call
2448 * export the same ABI as the SMB1 cli_setatr()
2449 * which calls it. This means reversing the sense
2450 * of the requested attr argument if it's zero
2451 * or FILE_ATTRIBUTE_NORMAL.
2453 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2457 attr = FILE_ATTRIBUTE_NORMAL;
2458 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
2462 SSVAL(inbuf.data, 32, attr);
2464 put_long_date((char *)inbuf.data + 16,mtime);
2466 /* Set all the other times to -1. */
2467 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2468 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
2469 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
2471 return cli_smb2_setpathinfo(cli,
2473 1, /* in_info_type */
2474 /* in_file_info_class */
2475 SMB_FILE_BASIC_INFORMATION - 1000,
2480 /***************************************************************
2481 Wrapper that allows SMB2 to set file handle times.
2483 ***************************************************************/
2485 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
2491 uint8_t inbuf_store[40];
2492 DATA_BLOB inbuf = data_blob_null;
2494 if (smbXcli_conn_has_async_calls(cli->conn)) {
2496 * Can't use sync call while an async call is in flight
2498 return NT_STATUS_INVALID_PARAMETER;
2501 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2502 return NT_STATUS_INVALID_PARAMETER;
2505 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2506 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2508 inbuf.data = inbuf_store;
2509 inbuf.length = sizeof(inbuf_store);
2510 data_blob_clear(&inbuf);
2512 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2513 if (change_time != 0) {
2514 put_long_date((char *)inbuf.data + 24, change_time);
2516 if (access_time != 0) {
2517 put_long_date((char *)inbuf.data + 8, access_time);
2519 if (write_time != 0) {
2520 put_long_date((char *)inbuf.data + 16, write_time);
2523 cli->raw_status = cli_smb2_set_info_fnum(
2526 1, /* in_info_type */
2527 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
2528 &inbuf, /* in_input_buffer */
2529 0); /* in_additional_info */
2531 return cli->raw_status;
2534 /***************************************************************
2535 Wrapper that allows SMB2 to query disk attributes (size).
2537 ***************************************************************/
2539 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2540 uint64_t *bsize, uint64_t *total, uint64_t *avail)
2543 uint16_t fnum = 0xffff;
2544 DATA_BLOB outbuf = data_blob_null;
2545 uint32_t sectors_per_unit = 0;
2546 uint32_t bytes_per_sector = 0;
2547 uint64_t total_size = 0;
2548 uint64_t size_free = 0;
2549 TALLOC_CTX *frame = talloc_stackframe();
2551 if (smbXcli_conn_has_async_calls(cli->conn)) {
2553 * Can't use sync call while an async call is in flight
2555 status = NT_STATUS_INVALID_PARAMETER;
2559 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2560 status = NT_STATUS_INVALID_PARAMETER;
2564 /* First open the top level directory. */
2565 status = cli_smb2_create_fnum(cli,
2567 0, /* create_flags */
2568 SMB2_IMPERSONATION_IMPERSONATION,
2569 FILE_READ_ATTRIBUTES, /* desired_access */
2570 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2571 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2572 FILE_OPEN, /* create_disposition */
2573 FILE_DIRECTORY_FILE, /* create_options */
2580 if (!NT_STATUS_IS_OK(status)) {
2584 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2585 level 3 (SMB_FS_SIZE_INFORMATION). */
2587 status = cli_smb2_query_info_fnum(
2590 2, /* in_info_type */
2591 3, /* in_file_info_class */
2592 0xFFFF, /* in_max_output_length */
2593 NULL, /* in_input_buffer */
2594 0, /* in_additional_info */
2598 if (!NT_STATUS_IS_OK(status)) {
2602 /* Parse the reply. */
2603 if (outbuf.length != 24) {
2604 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2608 total_size = BVAL(outbuf.data, 0);
2609 size_free = BVAL(outbuf.data, 8);
2610 sectors_per_unit = IVAL(outbuf.data, 16);
2611 bytes_per_sector = IVAL(outbuf.data, 20);
2614 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2617 *total = total_size;
2623 status = NT_STATUS_OK;
2627 if (fnum != 0xffff) {
2628 cli_smb2_close_fnum(cli, fnum);
2631 cli->raw_status = status;
2637 /***************************************************************
2638 Wrapper that allows SMB2 to query file system sizes.
2640 ***************************************************************/
2642 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2643 uint64_t *total_allocation_units,
2644 uint64_t *caller_allocation_units,
2645 uint64_t *actual_allocation_units,
2646 uint64_t *sectors_per_allocation_unit,
2647 uint64_t *bytes_per_sector)
2650 uint16_t fnum = 0xffff;
2651 DATA_BLOB outbuf = data_blob_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 /* First open the top level directory. */
2669 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2670 SMB2_IMPERSONATION_IMPERSONATION,
2671 FILE_READ_ATTRIBUTES, /* desired_access */
2672 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2673 FILE_SHARE_READ | FILE_SHARE_WRITE |
2674 FILE_SHARE_DELETE, /* share_access */
2675 FILE_OPEN, /* create_disposition */
2676 FILE_DIRECTORY_FILE, /* create_options */
2683 if (!NT_STATUS_IS_OK(status)) {
2687 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2688 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2690 status = cli_smb2_query_info_fnum(
2693 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2694 SMB_FS_FULL_SIZE_INFORMATION - 1000, /* in_file_info_class */
2695 0xFFFF, /* in_max_output_length */
2696 NULL, /* in_input_buffer */
2697 0, /* in_additional_info */
2701 if (!NT_STATUS_IS_OK(status)) {
2705 if (outbuf.length < 32) {
2706 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2710 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2711 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2712 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2713 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2714 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2718 if (fnum != 0xffff) {
2719 cli_smb2_close_fnum(cli, fnum);
2722 cli->raw_status = status;
2728 /***************************************************************
2729 Wrapper that allows SMB2 to query file system attributes.
2731 ***************************************************************/
2733 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2736 uint16_t fnum = 0xffff;
2737 DATA_BLOB outbuf = data_blob_null;
2738 TALLOC_CTX *frame = talloc_stackframe();
2740 if (smbXcli_conn_has_async_calls(cli->conn)) {
2742 * Can't use sync call while an async call is in flight
2744 status = NT_STATUS_INVALID_PARAMETER;
2748 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2749 status = NT_STATUS_INVALID_PARAMETER;
2753 /* First open the top level directory. */
2755 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2756 SMB2_IMPERSONATION_IMPERSONATION,
2757 FILE_READ_ATTRIBUTES, /* desired_access */
2758 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2759 FILE_SHARE_READ | FILE_SHARE_WRITE |
2760 FILE_SHARE_DELETE, /* share_access */
2761 FILE_OPEN, /* create_disposition */
2762 FILE_DIRECTORY_FILE, /* create_options */
2769 if (!NT_STATUS_IS_OK(status)) {
2773 status = cli_smb2_query_info_fnum(
2776 2, /* in_info_type */
2777 5, /* in_file_info_class */
2778 0xFFFF, /* in_max_output_length */
2779 NULL, /* in_input_buffer */
2780 0, /* in_additional_info */
2784 if (!NT_STATUS_IS_OK(status)) {
2788 if (outbuf.length < 12) {
2789 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2793 *fs_attr = IVAL(outbuf.data, 0);
2797 if (fnum != 0xffff) {
2798 cli_smb2_close_fnum(cli, fnum);
2801 cli->raw_status = status;
2807 /***************************************************************
2808 Wrapper that allows SMB2 to query file system volume info.
2810 ***************************************************************/
2812 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2813 TALLOC_CTX *mem_ctx,
2814 char **_volume_name,
2815 uint32_t *pserial_number,
2819 uint16_t fnum = 0xffff;
2820 DATA_BLOB outbuf = data_blob_null;
2822 char *volume_name = NULL;
2823 TALLOC_CTX *frame = talloc_stackframe();
2825 if (smbXcli_conn_has_async_calls(cli->conn)) {
2827 * Can't use sync call while an async call is in flight
2829 status = NT_STATUS_INVALID_PARAMETER;
2833 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2834 status = NT_STATUS_INVALID_PARAMETER;
2838 /* First open the top level directory. */
2840 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2841 SMB2_IMPERSONATION_IMPERSONATION,
2842 FILE_READ_ATTRIBUTES, /* desired_access */
2843 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2844 FILE_SHARE_READ | FILE_SHARE_WRITE |
2845 FILE_SHARE_DELETE, /* share_access */
2846 FILE_OPEN, /* create_disposition */
2847 FILE_DIRECTORY_FILE, /* create_options */
2854 if (!NT_STATUS_IS_OK(status)) {
2858 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2859 level 1 (SMB_FS_VOLUME_INFORMATION). */
2861 status = cli_smb2_query_info_fnum(
2864 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2865 /* in_file_info_class */
2866 SMB_FS_VOLUME_INFORMATION - 1000,
2867 0xFFFF, /* in_max_output_length */
2868 NULL, /* in_input_buffer */
2869 0, /* in_additional_info */
2873 if (!NT_STATUS_IS_OK(status)) {
2877 if (outbuf.length < 24) {
2878 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2884 ts = interpret_long_date((char *)outbuf.data);
2887 if (pserial_number) {
2888 *pserial_number = IVAL(outbuf.data,8);
2890 nlen = IVAL(outbuf.data,12);
2891 if (nlen + 18 < 18) {
2893 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2897 * The next check is safe as we know outbuf.length >= 24
2900 if (nlen > (outbuf.length - 18)) {
2901 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2905 pull_string_talloc(mem_ctx,
2906 (const char *)outbuf.data,
2912 if (volume_name == NULL) {
2913 status = map_nt_error_from_unix(errno);
2917 *_volume_name = volume_name;
2921 if (fnum != 0xffff) {
2922 cli_smb2_close_fnum(cli, fnum);
2925 cli->raw_status = status;
2932 /***************************************************************
2933 Wrapper that allows SMB2 to query a security descriptor.
2935 ***************************************************************/
2937 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2940 TALLOC_CTX *mem_ctx,
2941 struct security_descriptor **ppsd)
2944 DATA_BLOB outbuf = data_blob_null;
2945 struct security_descriptor *lsd = NULL;
2946 TALLOC_CTX *frame = talloc_stackframe();
2948 if (smbXcli_conn_has_async_calls(cli->conn)) {
2950 * Can't use sync call while an async call is in flight
2952 status = NT_STATUS_INVALID_PARAMETER;
2956 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2957 status = NT_STATUS_INVALID_PARAMETER;
2961 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2963 status = cli_smb2_query_info_fnum(
2966 3, /* in_info_type */
2967 0, /* in_file_info_class */
2968 0xFFFF, /* in_max_output_length */
2969 NULL, /* in_input_buffer */
2970 sec_info, /* in_additional_info */
2975 if (!NT_STATUS_IS_OK(status)) {
2979 /* Parse the reply. */
2980 status = unmarshall_sec_desc(mem_ctx,
2985 if (!NT_STATUS_IS_OK(status)) {
2997 cli->raw_status = status;
3003 /***************************************************************
3004 Wrapper that allows SMB2 to set a security descriptor.
3006 ***************************************************************/
3008 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
3011 const struct security_descriptor *sd)
3014 DATA_BLOB inbuf = data_blob_null;
3015 TALLOC_CTX *frame = talloc_stackframe();
3017 if (smbXcli_conn_has_async_calls(cli->conn)) {
3019 * Can't use sync call while an async call is in flight
3021 status = NT_STATUS_INVALID_PARAMETER;
3025 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3026 status = NT_STATUS_INVALID_PARAMETER;
3030 status = marshall_sec_desc(frame,
3035 if (!NT_STATUS_IS_OK(status)) {
3039 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
3041 status = cli_smb2_set_info_fnum(
3044 3, /* in_info_type */
3045 0, /* in_file_info_class */
3046 &inbuf, /* in_input_buffer */
3047 sec_info); /* in_additional_info */
3051 cli->raw_status = status;
3057 /***************************************************************
3058 Wrapper that allows SMB2 to query a security descriptor.
3061 ***************************************************************/
3063 struct cli_smb2_mxac_state {
3064 struct tevent_context *ev;
3065 struct cli_state *cli;
3067 struct smb2_create_blobs in_cblobs;
3073 static void cli_smb2_mxac_opened(struct tevent_req *subreq);
3074 static void cli_smb2_mxac_closed(struct tevent_req *subreq);
3076 struct tevent_req *cli_smb2_query_mxac_send(TALLOC_CTX *mem_ctx,
3077 struct tevent_context *ev,
3078 struct cli_state *cli,
3081 struct tevent_req *req = NULL, *subreq = NULL;
3082 struct cli_smb2_mxac_state *state = NULL;
3085 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_mxac_state);
3089 *state = (struct cli_smb2_mxac_state) {
3095 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3096 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3097 return tevent_req_post(req, ev);
3100 status = smb2_create_blob_add(state,
3102 SMB2_CREATE_TAG_MXAC,
3103 data_blob(NULL, 0));
3104 if (tevent_req_nterror(req, status)) {
3105 return tevent_req_post(req, ev);
3108 subreq = cli_smb2_create_fnum_send(
3113 0, /* create_flags */
3114 SMB2_IMPERSONATION_IMPERSONATION,
3115 FILE_READ_ATTRIBUTES,
3116 0, /* file attributes */
3117 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
3119 0, /* create_options */
3121 if (tevent_req_nomem(subreq, req)) {
3122 return tevent_req_post(req, ev);
3124 tevent_req_set_callback(subreq, cli_smb2_mxac_opened, req);
3128 static void cli_smb2_mxac_opened(struct tevent_req *subreq)
3130 struct tevent_req *req = tevent_req_callback_data(
3131 subreq, struct tevent_req);
3132 struct cli_smb2_mxac_state *state = tevent_req_data(
3133 req, struct cli_smb2_mxac_state);
3134 struct smb2_create_blobs out_cblobs = {0};
3135 struct smb2_create_blob *mxac_blob = NULL;
3138 status = cli_smb2_create_fnum_recv(
3139 subreq, &state->fnum, NULL, state, &out_cblobs);
3140 TALLOC_FREE(subreq);
3142 if (tevent_req_nterror(req, status)) {
3146 mxac_blob = smb2_create_blob_find(&out_cblobs, SMB2_CREATE_TAG_MXAC);
3147 if (mxac_blob == NULL) {
3148 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3151 if (mxac_blob->data.length != 8) {
3152 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3156 state->status = NT_STATUS(IVAL(mxac_blob->data.data, 0));
3157 state->mxac = IVAL(mxac_blob->data.data, 4);
3160 subreq = cli_smb2_close_fnum_send(
3161 state, state->ev, state->cli, state->fnum);
3162 if (tevent_req_nomem(subreq, req)) {
3165 tevent_req_set_callback(subreq, cli_smb2_mxac_closed, req);
3170 static void cli_smb2_mxac_closed(struct tevent_req *subreq)
3172 struct tevent_req *req = tevent_req_callback_data(
3173 subreq, struct tevent_req);
3176 status = cli_smb2_close_fnum_recv(subreq);
3177 if (tevent_req_nterror(req, status)) {
3181 tevent_req_done(req);
3184 NTSTATUS cli_smb2_query_mxac_recv(struct tevent_req *req, uint32_t *mxac)
3186 struct cli_smb2_mxac_state *state = tevent_req_data(
3187 req, struct cli_smb2_mxac_state);
3190 if (tevent_req_is_nterror(req, &status)) {
3194 if (!NT_STATUS_IS_OK(state->status)) {
3195 return state->status;
3198 *mxac = state->mxac;
3199 return NT_STATUS_OK;
3202 NTSTATUS cli_smb2_query_mxac(struct cli_state *cli,
3206 TALLOC_CTX *frame = talloc_stackframe();
3207 struct tevent_context *ev = NULL;
3208 struct tevent_req *req = NULL;
3209 NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
3212 if (smbXcli_conn_has_async_calls(cli->conn)) {
3214 * Can't use sync call while an async call is in flight
3216 status = NT_STATUS_INVALID_PARAMETER;
3220 ev = samba_tevent_context_init(frame);
3224 req = cli_smb2_query_mxac_send(frame, ev, cli, fname);
3228 ok = tevent_req_poll_ntstatus(req, ev, &status);
3232 status = cli_smb2_query_mxac_recv(req, _mxac);
3235 cli->raw_status = status;
3240 /***************************************************************
3241 Wrapper that allows SMB2 to rename a file.
3243 ***************************************************************/
3245 NTSTATUS cli_smb2_rename(struct cli_state *cli,
3246 const char *fname_src,
3247 const char *fname_dst,
3251 DATA_BLOB inbuf = data_blob_null;
3252 uint16_t fnum = 0xffff;
3253 smb_ucs2_t *converted_str = NULL;
3254 size_t converted_size_bytes = 0;
3256 TALLOC_CTX *frame = talloc_stackframe();
3258 if (smbXcli_conn_has_async_calls(cli->conn)) {
3260 * Can't use sync call while an async call is in flight
3262 status = NT_STATUS_INVALID_PARAMETER;
3266 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3267 status = NT_STATUS_INVALID_PARAMETER;
3271 status = get_fnum_from_path(cli,
3276 if (!NT_STATUS_IS_OK(status)) {
3280 /* SMB2 is pickier about pathnames. Ensure it doesn't
3282 if (*fname_dst == '\\') {
3286 /* SMB2 is pickier about pathnames. Ensure it doesn't
3288 namelen = strlen(fname_dst);
3289 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
3290 char *modname = talloc_strdup(frame, fname_dst);
3291 modname[namelen-1] = '\0';
3292 fname_dst = modname;
3295 if (!push_ucs2_talloc(frame,
3298 &converted_size_bytes)) {
3299 status = NT_STATUS_INVALID_PARAMETER;
3303 /* W2K8 insists the dest name is not null
3304 terminated. Remove the last 2 zero bytes
3305 and reduce the name length. */
3307 if (converted_size_bytes < 2) {
3308 status = NT_STATUS_INVALID_PARAMETER;
3311 converted_size_bytes -= 2;
3313 inbuf = data_blob_talloc_zero(frame,
3314 20 + converted_size_bytes);
3315 if (inbuf.data == NULL) {
3316 status = NT_STATUS_NO_MEMORY;
3321 SCVAL(inbuf.data, 0, 1);
3324 SIVAL(inbuf.data, 16, converted_size_bytes);
3325 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
3327 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3328 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3330 status = cli_smb2_set_info_fnum(
3333 1, /* in_info_type */
3334 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
3335 &inbuf, /* in_input_buffer */
3336 0); /* in_additional_info */
3340 if (fnum != 0xffff) {
3341 cli_smb2_close_fnum(cli, fnum);
3344 cli->raw_status = status;
3350 /***************************************************************
3351 Wrapper that allows SMB2 to set an EA on a fnum.
3353 ***************************************************************/
3355 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
3357 const char *ea_name,
3362 DATA_BLOB inbuf = data_blob_null;
3364 char *ea_name_ascii = NULL;
3366 TALLOC_CTX *frame = talloc_stackframe();
3368 if (smbXcli_conn_has_async_calls(cli->conn)) {
3370 * Can't use sync call while an async call is in flight
3372 status = NT_STATUS_INVALID_PARAMETER;
3376 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3377 status = NT_STATUS_INVALID_PARAMETER;
3381 /* Marshall the SMB2 EA data. */
3382 if (ea_len > 0xFFFF) {
3383 status = NT_STATUS_INVALID_PARAMETER;
3387 if (!push_ascii_talloc(frame,
3391 status = NT_STATUS_INVALID_PARAMETER;
3395 if (namelen < 2 || namelen > 0xFF) {
3396 status = NT_STATUS_INVALID_PARAMETER;
3400 bloblen = 8 + ea_len + namelen;
3401 /* Round up to a 4 byte boundary. */
3402 bloblen = ((bloblen + 3)&~3);
3404 inbuf = data_blob_talloc_zero(frame, bloblen);
3405 if (inbuf.data == NULL) {
3406 status = NT_STATUS_NO_MEMORY;
3409 /* namelen doesn't include the NULL byte. */
3410 SCVAL(inbuf.data, 5, namelen - 1);
3411 SSVAL(inbuf.data, 6, ea_len);
3412 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
3413 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
3415 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3416 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3418 status = cli_smb2_set_info_fnum(
3421 1, /* in_info_type */
3422 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3423 &inbuf, /* in_input_buffer */
3424 0); /* in_additional_info */
3428 cli->raw_status = status;
3434 /***************************************************************
3435 Wrapper that allows SMB2 to set an EA on a pathname.
3437 ***************************************************************/
3439 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
3441 const char *ea_name,
3446 uint16_t fnum = 0xffff;
3448 if (smbXcli_conn_has_async_calls(cli->conn)) {
3450 * Can't use sync call while an async call is in flight
3452 status = NT_STATUS_INVALID_PARAMETER;
3456 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3457 status = NT_STATUS_INVALID_PARAMETER;
3461 status = get_fnum_from_path(cli,
3466 if (!NT_STATUS_IS_OK(status)) {
3470 status = cli_set_ea_fnum(cli,
3475 if (!NT_STATUS_IS_OK(status)) {