libsmb: Add cli_smb2_query_info_fnum
[Samba.git] / source3 / libsmb / cli_smb2_fnum.c
blob771b6fe8c5034906cf2a5fa675bb5d8a06922922
1 /*
2 Unix SMB/CIFS implementation.
3 smb2 lib
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.
29 #include "includes.h"
30 #include "client.h"
31 #include "async_smb.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "cli_smb2_fnum.h"
34 #include "trans2.h"
35 #include "clirap.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"
43 #include "ntioctl.h"
44 #include "librpc/gen_ndr/ndr_quota.h"
46 struct smb2_hnd {
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 */
64 int ret;
65 struct idr_context *idp = cli->smb2.open_handles;
66 struct smb2_hnd *owned_h = talloc_memdup(cli,
67 ph,
68 sizeof(struct smb2_hnd));
70 if (owned_h == NULL) {
71 return NT_STATUS_NO_MEMORY;
74 if (idp == NULL) {
75 /* Lazy init */
76 cli->smb2.open_handles = idr_init(cli);
77 if (cli->smb2.open_handles == NULL) {
78 TALLOC_FREE(owned_h);
79 return NT_STATUS_NO_MEMORY;
81 idp = cli->smb2.open_handles;
84 ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
85 if (ret == -1) {
86 TALLOC_FREE(owned_h);
87 return NT_STATUS_NO_MEMORY;
90 *pfnum = (uint16_t)ret;
91 return NT_STATUS_OK;
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;
104 if (idp == NULL) {
105 return NT_STATUS_INVALID_PARAMETER;
107 *pph = (struct smb2_hnd *)idr_find(idp, fnum);
108 if (*pph == NULL) {
109 return NT_STATUS_INVALID_HANDLE;
111 return NT_STATUS_OK;
114 /***************************************************************
115 Delete the fnum to smb2_hnd mapping. Zeros out handle on
116 successful return.
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;
124 struct smb2_hnd *ph;
126 if (idp == NULL) {
127 return NT_STATUS_INVALID_PARAMETER;
130 ph = (struct smb2_hnd *)idr_find(idp, fnum);
131 if (ph != *pph) {
132 return NT_STATUS_INVALID_PARAMETER;
134 idr_remove(idp, fnum);
135 TALLOC_FREE(*pph);
136 return NT_STATUS_OK;
139 /***************************************************************
140 Oplock mapping code.
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;
164 uint16_t fnum;
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(
172 TALLOC_CTX *mem_ctx,
173 struct tevent_context *ev,
174 struct cli_state *cli,
175 const char *fname,
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;
191 NTSTATUS status;
193 req = tevent_req_create(mem_ctx, &state,
194 struct cli_smb2_create_fnum_state);
195 if (req == NULL) {
196 return NULL;
198 state->cli = cli;
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;
214 DATA_BLOB twrp_blob;
215 NTTIME ntt;
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);
226 fname = new_fname;
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(
233 state,
234 &state->in_cblobs,
235 SMB2_CREATE_TAG_TWRP,
236 twrp_blob);
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) {
244 uint32_t i;
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
257 start in a '\' */
258 if (*fname == '\\') {
259 fname++;
260 fname_len--;
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';
270 fname = new_fname;
273 subreq = smb2cli_create_send(state, ev,
274 cli->conn,
275 cli->timeout,
276 cli->smb2.session,
277 cli->smb2.tcon,
278 fname,
279 flags_to_smb2_oplock(create_flags),
280 impersonation_level,
281 desired_access,
282 file_attributes,
283 share_access,
284 create_disposition,
285 create_options,
286 &state->in_cblobs);
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);
295 return req;
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);
304 struct smb2_hnd h;
305 NTSTATUS status;
307 status = smb2cli_create_recv(
308 subreq,
309 &h.fid_persistent,
310 &h.fid_volatile, &state->cr,
311 state,
312 &state->out_cblobs);
313 TALLOC_FREE(subreq);
314 if (tevent_req_nterror(req, status)) {
315 return;
318 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
319 if (tevent_req_nterror(req, status)) {
320 return;
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,
334 uint16_t *pfnum,
335 struct smb_create_returns *cr,
336 TALLOC_CTX *mem_ctx,
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);
341 NTSTATUS status;
343 if (tevent_req_is_nterror(req, &status)) {
344 state->cli->raw_status = status;
345 return status;
347 if (pfnum != NULL) {
348 *pfnum = state->fnum;
350 if (cr != NULL) {
351 *cr = state->cr;
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;
361 return NT_STATUS_OK;
364 NTSTATUS cli_smb2_create_fnum(
365 struct cli_state *cli,
366 const char *fname,
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,
375 uint16_t *pfid,
376 struct smb_create_returns *cr,
377 TALLOC_CTX *mem_ctx,
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;
390 goto fail;
392 ev = samba_tevent_context_init(frame);
393 if (ev == NULL) {
394 goto fail;
396 req = cli_smb2_create_fnum_send(
397 frame,
399 cli,
400 fname,
401 create_flags,
402 impersonation_level,
403 desired_access,
404 file_attributes,
405 share_access,
406 create_disposition,
407 create_options,
408 in_cblobs);
409 if (req == NULL) {
410 goto fail;
412 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
413 goto fail;
415 status = cli_smb2_create_fnum_recv(req, pfid, cr, mem_ctx, out_cblobs);
416 fail:
417 TALLOC_FREE(frame);
418 return status;
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;
427 uint16_t fnum;
428 struct smb2_hnd *ph;
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,
436 uint16_t fnum)
438 struct tevent_req *req, *subreq;
439 struct cli_smb2_close_fnum_state *state;
440 NTSTATUS status;
442 req = tevent_req_create(mem_ctx, &state,
443 struct cli_smb2_close_fnum_state);
444 if (req == NULL) {
445 return NULL;
447 state->cli = cli;
448 state->fnum = fnum;
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);
468 return 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);
477 NTSTATUS status;
479 status = smb2cli_close_recv(subreq);
480 if (tevent_req_nterror(req, status)) {
481 return;
484 /* Delete the fnum -> handle mapping. */
485 status = delete_smb2_handle_mapping(state->cli, &state->ph,
486 state->fnum);
487 if (tevent_req_nterror(req, status)) {
488 return;
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);
503 return status;
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;
518 goto fail;
520 ev = samba_tevent_context_init(frame);
521 if (ev == NULL) {
522 goto fail;
524 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
525 if (req == NULL) {
526 goto fail;
528 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
529 goto fail;
531 status = cli_smb2_close_fnum_recv(req);
532 fail:
533 TALLOC_FREE(frame);
534 return status;
537 struct cli_smb2_delete_on_close_state {
538 struct cli_state *cli;
539 uint16_t fnum;
540 struct smb2_hnd *ph;
541 uint8_t data[1];
542 DATA_BLOB inbuf;
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,
550 uint16_t fnum,
551 bool flag)
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;
558 NTSTATUS status;
560 req = tevent_req_create(mem_ctx, &state,
561 struct cli_smb2_delete_on_close_state);
562 if (req == NULL) {
563 return NULL;
565 state->cli = cli;
566 state->fnum = fnum;
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).
582 in_info_type = 1;
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,
590 cli->conn,
591 cli->timeout,
592 cli->smb2.session,
593 cli->smb2.tcon,
594 in_info_type,
595 in_file_info_class,
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,
605 req);
606 return req;
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 =
618 tevent_req_data(req,
619 struct cli_smb2_delete_on_close_state);
620 NTSTATUS status;
622 if (tevent_req_is_nterror(req, &status)) {
623 state->cli->raw_status = status;
624 tevent_req_received(req);
625 return status;
628 state->cli->raw_status = NT_STATUS_OK;
629 tevent_req_received(req);
630 return NT_STATUS_OK;
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;
645 goto fail;
647 ev = samba_tevent_context_init(frame);
648 if (ev == NULL) {
649 goto fail;
651 req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
652 if (req == NULL) {
653 goto fail;
655 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
656 goto fail;
658 status = cli_smb2_delete_on_close_recv(req);
659 fail:
660 TALLOC_FREE(frame);
661 return status;
664 /***************************************************************
665 Small wrapper that allows SMB2 to create a directory
666 Synchronous only.
667 ***************************************************************/
669 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
671 NTSTATUS status;
672 uint16_t fnum;
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,
686 dname,
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 */
694 NULL,
695 &fnum,
696 NULL,
697 NULL,
698 NULL);
700 if (!NT_STATUS_IS_OK(status)) {
701 return 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;
709 const char *dname;
710 const struct smb2_create_blobs *in_cblobs;
711 uint16_t fnum;
712 NTSTATUS status;
715 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq);
716 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq);
717 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq);
718 static void cli_smb2_rmdir_closed(struct tevent_req *subreq);
720 struct tevent_req *cli_smb2_rmdir_send(
721 TALLOC_CTX *mem_ctx,
722 struct tevent_context *ev,
723 struct cli_state *cli,
724 const char *dname,
725 const struct smb2_create_blobs *in_cblobs)
727 struct tevent_req *req = NULL, *subreq = NULL;
728 struct cli_smb2_rmdir_state *state = NULL;
730 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_rmdir_state);
731 if (req == NULL) {
732 return NULL;
734 state->ev = ev;
735 state->cli = cli;
736 state->dname = dname;
737 state->in_cblobs = in_cblobs;
739 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
740 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
741 return tevent_req_post(req, ev);
744 subreq = cli_smb2_create_fnum_send(
745 state,
746 state->ev,
747 state->cli,
748 state->dname,
749 0, /* create_flags */
750 SMB2_IMPERSONATION_IMPERSONATION,
751 DELETE_ACCESS, /* desired_access */
752 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
753 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
754 FILE_OPEN, /* create_disposition */
755 FILE_DIRECTORY_FILE, /* create_options */
756 state->in_cblobs); /* in_cblobs */
757 if (tevent_req_nomem(subreq, req)) {
758 return tevent_req_post(req, ev);
760 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened1, req);
761 return req;
764 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq)
766 struct tevent_req *req = tevent_req_callback_data(
767 subreq, struct tevent_req);
768 struct cli_smb2_rmdir_state *state = tevent_req_data(
769 req, struct cli_smb2_rmdir_state);
770 NTSTATUS status;
772 status = cli_smb2_create_fnum_recv(
773 subreq, &state->fnum, NULL, NULL, NULL);
774 TALLOC_FREE(subreq);
776 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
778 * Naive option to match our SMB1 code. Assume the
779 * symlink path that tripped us up was the last
780 * component and try again. Eventually we will have to
781 * deal with the returned path unprocessed component. JRA.
783 subreq = cli_smb2_create_fnum_send(
784 state,
785 state->ev,
786 state->cli,
787 state->dname,
788 0, /* create_flags */
789 SMB2_IMPERSONATION_IMPERSONATION,
790 DELETE_ACCESS, /* desired_access */
791 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
792 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
793 FILE_OPEN, /* create_disposition */
794 FILE_DIRECTORY_FILE|
795 FILE_DELETE_ON_CLOSE|
796 FILE_OPEN_REPARSE_POINT, /* create_options */
797 state->in_cblobs); /* in_cblobs */
798 if (tevent_req_nomem(subreq, req)) {
799 return;
801 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened2, req);
802 return;
805 if (tevent_req_nterror(req, status)) {
806 return;
809 subreq = cli_smb2_delete_on_close_send(
810 state, state->ev, state->cli, state->fnum, true);
811 if (tevent_req_nomem(subreq, req)) {
812 return;
814 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
817 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq)
819 struct tevent_req *req = tevent_req_callback_data(
820 subreq, struct tevent_req);
821 struct cli_smb2_rmdir_state *state = tevent_req_data(
822 req, struct cli_smb2_rmdir_state);
823 NTSTATUS status;
825 status = cli_smb2_create_fnum_recv(
826 subreq, &state->fnum, NULL, NULL, NULL);
827 TALLOC_FREE(subreq);
828 if (tevent_req_nterror(req, status)) {
829 return;
832 subreq = cli_smb2_delete_on_close_send(
833 state, state->ev, state->cli, state->fnum, true);
834 if (tevent_req_nomem(subreq, req)) {
835 return;
837 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
840 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq)
842 struct tevent_req *req = tevent_req_callback_data(
843 subreq, struct tevent_req);
844 struct cli_smb2_rmdir_state *state = tevent_req_data(
845 req, struct cli_smb2_rmdir_state);
847 state->status = cli_smb2_delete_on_close_recv(subreq);
848 TALLOC_FREE(subreq);
851 * Close the fd even if the set_disp failed
854 subreq = cli_smb2_close_fnum_send(
855 state, state->ev, state->cli, state->fnum);
856 if (tevent_req_nomem(subreq, req)) {
857 return;
859 tevent_req_set_callback(subreq, cli_smb2_rmdir_closed, req);
862 static void cli_smb2_rmdir_closed(struct tevent_req *subreq)
864 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
865 tevent_req_simple_finish_ntstatus(subreq, status);
868 NTSTATUS cli_smb2_rmdir_recv(struct tevent_req *req)
870 struct cli_smb2_rmdir_state *state = tevent_req_data(
871 req, struct cli_smb2_rmdir_state);
872 NTSTATUS status;
874 if (tevent_req_is_nterror(req, &status)) {
875 return status;
877 return state->status;
880 NTSTATUS cli_smb2_rmdir(
881 struct cli_state *cli,
882 const char *dname,
883 const struct smb2_create_blobs *in_cblobs)
885 TALLOC_CTX *frame = talloc_stackframe();
886 struct tevent_context *ev;
887 struct tevent_req *req;
888 NTSTATUS status = NT_STATUS_NO_MEMORY;
889 bool ok;
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;
896 goto fail;
898 ev = samba_tevent_context_init(frame);
899 if (ev == NULL) {
900 goto fail;
902 req = cli_smb2_rmdir_send(frame, ev, cli, dname, in_cblobs);
903 if (req == NULL) {
904 goto fail;
906 ok = tevent_req_poll_ntstatus(req, ev, &status);
907 if (!ok) {
908 goto fail;
910 status = cli_smb2_rmdir_recv(req);
911 fail:
912 cli->raw_status = status;
913 TALLOC_FREE(frame);
914 return status;
917 /***************************************************************
918 Small wrapper that allows SMB2 to unlink a pathname.
919 Synchronous only.
920 ***************************************************************/
922 struct cli_smb2_unlink_state {
923 struct tevent_context *ev;
924 struct cli_state *cli;
925 const char *fname;
926 const struct smb2_create_blobs *in_cblobs;
929 static void cli_smb2_unlink_opened1(struct tevent_req *subreq);
930 static void cli_smb2_unlink_opened2(struct tevent_req *subreq);
931 static void cli_smb2_unlink_closed(struct tevent_req *subreq);
933 struct tevent_req *cli_smb2_unlink_send(
934 TALLOC_CTX *mem_ctx,
935 struct tevent_context *ev,
936 struct cli_state *cli,
937 const char *fname,
938 const struct smb2_create_blobs *in_cblobs)
940 struct tevent_req *req = NULL, *subreq = NULL;
941 struct cli_smb2_unlink_state *state = NULL;
943 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_unlink_state);
944 if (req == NULL) {
945 return NULL;
947 state->ev = ev;
948 state->cli = cli;
949 state->fname = fname;
950 state->in_cblobs = in_cblobs;
952 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
953 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
954 return tevent_req_post(req, ev);
957 subreq = cli_smb2_create_fnum_send(
958 state, /* mem_ctx */
959 state->ev, /* tevent_context */
960 state->cli, /* cli_struct */
961 state->fname, /* filename */
962 0, /* create_flags */
963 SMB2_IMPERSONATION_IMPERSONATION,
964 DELETE_ACCESS, /* desired_access */
965 FILE_ATTRIBUTE_NORMAL, /* file attributes */
966 FILE_SHARE_READ|
967 FILE_SHARE_WRITE|
968 FILE_SHARE_DELETE, /* share_access */
969 FILE_OPEN, /* create_disposition */
970 FILE_DELETE_ON_CLOSE, /* create_options */
971 state->in_cblobs); /* in_cblobs */
972 if (tevent_req_nomem(subreq, req)) {
973 return tevent_req_post(req, ev);
975 tevent_req_set_callback(subreq, cli_smb2_unlink_opened1, req);
976 return req;
979 static void cli_smb2_unlink_opened1(struct tevent_req *subreq)
981 struct tevent_req *req = tevent_req_callback_data(
982 subreq, struct tevent_req);
983 struct cli_smb2_unlink_state *state = tevent_req_data(
984 req, struct cli_smb2_unlink_state);
985 uint16_t fnum;
986 NTSTATUS status;
988 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
989 TALLOC_FREE(subreq);
991 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
993 * Naive option to match our SMB1 code. Assume the
994 * symlink path that tripped us up was the last
995 * component and try again. Eventually we will have to
996 * deal with the returned path unprocessed component. JRA.
998 subreq = cli_smb2_create_fnum_send(
999 state, /* mem_ctx */
1000 state->ev, /* tevent_context */
1001 state->cli, /* cli_struct */
1002 state->fname, /* filename */
1003 0, /* create_flags */
1004 SMB2_IMPERSONATION_IMPERSONATION,
1005 DELETE_ACCESS, /* desired_access */
1006 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1007 FILE_SHARE_READ|
1008 FILE_SHARE_WRITE|
1009 FILE_SHARE_DELETE, /* share_access */
1010 FILE_OPEN, /* create_disposition */
1011 FILE_DELETE_ON_CLOSE|
1012 FILE_OPEN_REPARSE_POINT, /* create_options */
1013 state->in_cblobs); /* in_cblobs */
1014 if (tevent_req_nomem(subreq, req)) {
1015 return;
1017 tevent_req_set_callback(subreq, cli_smb2_unlink_opened2, req);
1018 return;
1021 if (tevent_req_nterror(req, status)) {
1022 return;
1025 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1026 if (tevent_req_nomem(subreq, req)) {
1027 return;
1029 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1032 static void cli_smb2_unlink_opened2(struct tevent_req *subreq)
1034 struct tevent_req *req = tevent_req_callback_data(
1035 subreq, struct tevent_req);
1036 struct cli_smb2_unlink_state *state = tevent_req_data(
1037 req, struct cli_smb2_unlink_state);
1038 uint16_t fnum;
1039 NTSTATUS status;
1041 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1042 TALLOC_FREE(subreq);
1043 if (tevent_req_nterror(req, status)) {
1044 return;
1047 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1048 if (tevent_req_nomem(subreq, req)) {
1049 return;
1051 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1054 static void cli_smb2_unlink_closed(struct tevent_req *subreq)
1056 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1057 tevent_req_simple_finish_ntstatus(subreq, status);
1060 NTSTATUS cli_smb2_unlink_recv(struct tevent_req *req)
1062 return tevent_req_simple_recv_ntstatus(req);
1065 NTSTATUS cli_smb2_unlink(
1066 struct cli_state *cli,
1067 const char *fname,
1068 const struct smb2_create_blobs *in_cblobs)
1070 TALLOC_CTX *frame = talloc_stackframe();
1071 struct tevent_context *ev;
1072 struct tevent_req *req;
1073 NTSTATUS status = NT_STATUS_NO_MEMORY;
1074 bool ok;
1076 if (smbXcli_conn_has_async_calls(cli->conn)) {
1078 * Can't use sync call while an async call is in flight
1080 status = NT_STATUS_INVALID_PARAMETER;
1081 goto fail;
1083 ev = samba_tevent_context_init(frame);
1084 if (ev == NULL) {
1085 goto fail;
1087 req = cli_smb2_unlink_send(frame, ev, cli, fname, in_cblobs);
1088 if (req == NULL) {
1089 goto fail;
1091 ok = tevent_req_poll_ntstatus(req, ev, &status);
1092 if (!ok) {
1093 goto fail;
1095 status = cli_smb2_unlink_recv(req);
1096 fail:
1097 cli->raw_status = status;
1098 TALLOC_FREE(frame);
1099 return status;
1102 /***************************************************************
1103 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1104 ***************************************************************/
1106 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
1107 uint32_t dir_data_length,
1108 struct file_info *finfo,
1109 uint32_t *next_offset)
1111 size_t namelen = 0;
1112 size_t slen = 0;
1113 size_t ret = 0;
1115 if (dir_data_length < 4) {
1116 return NT_STATUS_INFO_LENGTH_MISMATCH;
1119 *next_offset = IVAL(dir_data, 0);
1121 if (*next_offset > dir_data_length) {
1122 return NT_STATUS_INFO_LENGTH_MISMATCH;
1125 if (*next_offset != 0) {
1126 /* Ensure we only read what in this record. */
1127 dir_data_length = *next_offset;
1130 if (dir_data_length < 105) {
1131 return NT_STATUS_INFO_LENGTH_MISMATCH;
1134 finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
1135 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
1136 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
1137 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
1138 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
1139 finfo->allocated_size = IVAL2_TO_SMB_BIG_UINT(dir_data + 48, 0);
1140 finfo->mode = CVAL(dir_data + 56, 0);
1141 finfo->ino = IVAL2_TO_SMB_BIG_UINT(dir_data + 96, 0);
1142 namelen = IVAL(dir_data + 60,0);
1143 if (namelen > (dir_data_length - 104)) {
1144 return NT_STATUS_INFO_LENGTH_MISMATCH;
1146 slen = CVAL(dir_data + 68, 0);
1147 if (slen > 24) {
1148 return NT_STATUS_INFO_LENGTH_MISMATCH;
1150 ret = pull_string_talloc(finfo,
1151 dir_data,
1152 FLAGS2_UNICODE_STRINGS,
1153 &finfo->short_name,
1154 dir_data + 70,
1155 slen,
1156 STR_UNICODE);
1157 if (ret == (size_t)-1) {
1158 /* Bad conversion. */
1159 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1162 ret = pull_string_talloc(finfo,
1163 dir_data,
1164 FLAGS2_UNICODE_STRINGS,
1165 &finfo->name,
1166 dir_data + 104,
1167 namelen,
1168 STR_UNICODE);
1169 if (ret == (size_t)-1) {
1170 /* Bad conversion. */
1171 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1173 return NT_STATUS_OK;
1176 /*******************************************************************
1177 Given a filename - get its directory name
1178 ********************************************************************/
1180 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
1181 const char *dir,
1182 char **parent,
1183 const char **name)
1185 char *p;
1186 ptrdiff_t len;
1188 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
1190 if (p == NULL) {
1191 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
1192 return false;
1194 if (name) {
1195 *name = dir;
1197 return true;
1200 len = p-dir;
1202 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
1203 return false;
1205 (*parent)[len] = '\0';
1207 if (name) {
1208 *name = p+1;
1210 return true;
1213 /***************************************************************
1214 Wrapper that allows SMB2 to list a directory.
1215 Synchronous only.
1216 ***************************************************************/
1218 NTSTATUS cli_smb2_list(struct cli_state *cli,
1219 const char *pathname,
1220 uint16_t attribute,
1221 NTSTATUS (*fn)(const char *,
1222 struct file_info *,
1223 const char *,
1224 void *),
1225 void *state)
1227 NTSTATUS status;
1228 uint16_t fnum = 0xffff;
1229 char *parent_dir = NULL;
1230 const char *mask = NULL;
1231 struct smb2_hnd *ph = NULL;
1232 bool processed_file = false;
1233 TALLOC_CTX *frame = talloc_stackframe();
1234 TALLOC_CTX *subframe = NULL;
1235 bool mask_has_wild;
1236 uint32_t max_trans;
1237 uint32_t max_avail_len;
1238 bool ok;
1240 if (smbXcli_conn_has_async_calls(cli->conn)) {
1242 * Can't use sync call while an async call is in flight
1244 status = NT_STATUS_INVALID_PARAMETER;
1245 goto fail;
1248 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1249 status = NT_STATUS_INVALID_PARAMETER;
1250 goto fail;
1253 /* Get the directory name. */
1254 if (!windows_parent_dirname(frame,
1255 pathname,
1256 &parent_dir,
1257 &mask)) {
1258 status = NT_STATUS_NO_MEMORY;
1259 goto fail;
1262 mask_has_wild = ms_has_wild(mask);
1264 status = cli_smb2_create_fnum(cli,
1265 parent_dir,
1266 0, /* create_flags */
1267 SMB2_IMPERSONATION_IMPERSONATION,
1268 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
1269 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1270 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
1271 FILE_OPEN, /* create_disposition */
1272 FILE_DIRECTORY_FILE, /* create_options */
1273 NULL,
1274 &fnum,
1275 NULL,
1276 NULL,
1277 NULL);
1279 if (!NT_STATUS_IS_OK(status)) {
1280 goto fail;
1283 status = map_fnum_to_smb2_handle(cli,
1284 fnum,
1285 &ph);
1286 if (!NT_STATUS_IS_OK(status)) {
1287 goto fail;
1291 * ideally, use the max transaction size, but don't send a request
1292 * bigger than we have credits available for
1294 max_trans = smb2cli_conn_max_trans_size(cli->conn);
1295 ok = smb2cli_conn_req_possible(cli->conn, &max_avail_len);
1296 if (ok) {
1297 max_trans = MIN(max_trans, max_avail_len);
1300 do {
1301 uint8_t *dir_data = NULL;
1302 uint32_t dir_data_length = 0;
1303 uint32_t next_offset = 0;
1304 subframe = talloc_stackframe();
1306 status = smb2cli_query_directory(cli->conn,
1307 cli->timeout,
1308 cli->smb2.session,
1309 cli->smb2.tcon,
1310 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
1311 0, /* flags */
1312 0, /* file_index */
1313 ph->fid_persistent,
1314 ph->fid_volatile,
1315 mask,
1316 max_trans,
1317 subframe,
1318 &dir_data,
1319 &dir_data_length);
1321 if (!NT_STATUS_IS_OK(status)) {
1322 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1323 break;
1325 goto fail;
1328 do {
1329 struct file_info *finfo = talloc_zero(subframe,
1330 struct file_info);
1332 if (finfo == NULL) {
1333 status = NT_STATUS_NO_MEMORY;
1334 goto fail;
1337 status = parse_finfo_id_both_directory_info(dir_data,
1338 dir_data_length,
1339 finfo,
1340 &next_offset);
1342 if (!NT_STATUS_IS_OK(status)) {
1343 goto fail;
1346 if (dir_check_ftype((uint32_t)finfo->mode,
1347 (uint32_t)attribute)) {
1349 * Only process if attributes match.
1350 * On SMB1 server does this, so on
1351 * SMB2 we need to emulate in the
1352 * client.
1354 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1356 processed_file = true;
1358 status = fn(cli->dfs_mountpoint,
1359 finfo,
1360 pathname,
1361 state);
1363 if (!NT_STATUS_IS_OK(status)) {
1364 break;
1368 TALLOC_FREE(finfo);
1370 /* Move to next entry. */
1371 if (next_offset) {
1372 dir_data += next_offset;
1373 dir_data_length -= next_offset;
1375 } while (next_offset != 0);
1377 TALLOC_FREE(subframe);
1379 if (!mask_has_wild) {
1381 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1382 * when handed a non-wildcard path. Do it
1383 * for the server (with a non-wildcard path
1384 * there should only ever be one file returned.
1386 status = STATUS_NO_MORE_FILES;
1387 break;
1390 } while (NT_STATUS_IS_OK(status));
1392 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1393 status = NT_STATUS_OK;
1396 if (NT_STATUS_IS_OK(status) && !processed_file) {
1398 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1399 * if no files match. Emulate this in the client.
1401 status = NT_STATUS_NO_SUCH_FILE;
1404 fail:
1406 if (fnum != 0xffff) {
1407 cli_smb2_close_fnum(cli, fnum);
1410 cli->raw_status = status;
1412 TALLOC_FREE(subframe);
1413 TALLOC_FREE(frame);
1414 return status;
1417 /***************************************************************
1418 Wrapper that allows SMB2 to query a path info (basic level).
1419 Synchronous only.
1420 ***************************************************************/
1422 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1423 const char *name,
1424 SMB_STRUCT_STAT *sbuf,
1425 uint32_t *attributes)
1427 NTSTATUS status;
1428 struct smb_create_returns cr;
1429 uint16_t fnum = 0xffff;
1430 size_t namelen = strlen(name);
1432 if (smbXcli_conn_has_async_calls(cli->conn)) {
1434 * Can't use sync call while an async call is in flight
1436 return NT_STATUS_INVALID_PARAMETER;
1439 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1440 return NT_STATUS_INVALID_PARAMETER;
1443 /* SMB2 is pickier about pathnames. Ensure it doesn't
1444 end in a '\' */
1445 if (namelen > 0 && name[namelen-1] == '\\') {
1446 char *modname = talloc_strdup(talloc_tos(), name);
1447 modname[namelen-1] = '\0';
1448 name = modname;
1451 /* This is commonly used as a 'cd'. Try qpathinfo on
1452 a directory handle first. */
1454 status = cli_smb2_create_fnum(cli,
1455 name,
1456 0, /* create_flags */
1457 SMB2_IMPERSONATION_IMPERSONATION,
1458 FILE_READ_ATTRIBUTES, /* desired_access */
1459 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1460 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1461 FILE_OPEN, /* create_disposition */
1462 FILE_DIRECTORY_FILE, /* create_options */
1463 NULL,
1464 &fnum,
1465 &cr,
1466 NULL,
1467 NULL);
1469 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1470 /* Maybe a file ? */
1471 status = cli_smb2_create_fnum(cli,
1472 name,
1473 0, /* create_flags */
1474 SMB2_IMPERSONATION_IMPERSONATION,
1475 FILE_READ_ATTRIBUTES, /* desired_access */
1476 0, /* file attributes */
1477 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1478 FILE_OPEN, /* create_disposition */
1479 0, /* create_options */
1480 NULL,
1481 &fnum,
1482 &cr,
1483 NULL,
1484 NULL);
1487 if (!NT_STATUS_IS_OK(status)) {
1488 return status;
1491 status = cli_smb2_close_fnum(cli, fnum);
1493 ZERO_STRUCTP(sbuf);
1495 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1496 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1497 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1498 sbuf->st_ex_size = cr.end_of_file;
1499 *attributes = cr.file_attributes;
1501 return status;
1504 /***************************************************************
1505 Wrapper that allows SMB2 to check if a path is a directory.
1506 Synchronous only.
1507 ***************************************************************/
1509 NTSTATUS cli_smb2_chkpath(struct cli_state *cli,
1510 const char *name)
1512 NTSTATUS status;
1513 uint16_t fnum = 0xffff;
1515 if (smbXcli_conn_has_async_calls(cli->conn)) {
1517 * Can't use sync call while an async call is in flight
1519 return NT_STATUS_INVALID_PARAMETER;
1522 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1523 return NT_STATUS_INVALID_PARAMETER;
1526 /* Ensure this is a directory. */
1527 status = cli_smb2_create_fnum(cli,
1528 name,
1529 0, /* create_flags */
1530 SMB2_IMPERSONATION_IMPERSONATION,
1531 FILE_READ_ATTRIBUTES, /* desired_access */
1532 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1533 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1534 FILE_OPEN, /* create_disposition */
1535 FILE_DIRECTORY_FILE, /* create_options */
1536 NULL,
1537 &fnum,
1538 NULL,
1539 NULL,
1540 NULL);
1542 if (!NT_STATUS_IS_OK(status)) {
1543 return status;
1546 return cli_smb2_close_fnum(cli, fnum);
1549 struct cli_smb2_query_info_fnum_state {
1550 DATA_BLOB outbuf;
1553 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq);
1555 struct tevent_req *cli_smb2_query_info_fnum_send(
1556 TALLOC_CTX *mem_ctx,
1557 struct tevent_context *ev,
1558 struct cli_state *cli,
1559 uint16_t fnum,
1560 uint8_t in_info_type,
1561 uint8_t in_info_class,
1562 uint32_t in_max_output_length,
1563 const DATA_BLOB *in_input_buffer,
1564 uint32_t in_additional_info,
1565 uint32_t in_flags)
1567 struct tevent_req *req = NULL, *subreq = NULL;
1568 struct cli_smb2_query_info_fnum_state *state = NULL;
1569 struct smb2_hnd *ph = NULL;
1570 NTSTATUS status;
1572 req = tevent_req_create(
1573 mem_ctx, &state, struct cli_smb2_query_info_fnum_state);
1574 if (req == NULL) {
1575 return req;
1578 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1579 if (tevent_req_nterror(req, status)) {
1580 return tevent_req_post(req, ev);
1583 subreq = smb2cli_query_info_send(
1584 state,
1586 cli->conn,
1587 cli->timeout,
1588 cli->smb2.session,
1589 cli->smb2.tcon,
1590 in_info_type,
1591 in_info_class,
1592 in_max_output_length,
1593 in_input_buffer,
1594 in_additional_info,
1595 in_flags,
1596 ph->fid_persistent,
1597 ph->fid_volatile);
1598 if (tevent_req_nomem(subreq, req)) {
1599 return tevent_req_post(req, ev);
1601 tevent_req_set_callback(subreq, cli_smb2_query_info_fnum_done, req);
1602 return req;
1605 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq)
1607 struct tevent_req *req = tevent_req_callback_data(
1608 subreq, struct tevent_req);
1609 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1610 req, struct cli_smb2_query_info_fnum_state);
1611 DATA_BLOB outbuf;
1612 NTSTATUS status;
1614 status = smb2cli_query_info_recv(subreq, state, &outbuf);
1615 TALLOC_FREE(subreq);
1616 if (tevent_req_nterror(req, status)) {
1617 return;
1621 * We have to dup the memory here because outbuf.data is not
1622 * returned as a talloc object by smb2cli_query_info_recv.
1623 * It's a pointer into the received buffer.
1625 state->outbuf = data_blob_dup_talloc(state, outbuf);
1627 if ((outbuf.length != 0) &&
1628 tevent_req_nomem(state->outbuf.data, req)) {
1629 return;
1631 tevent_req_done(req);
1634 NTSTATUS cli_smb2_query_info_fnum_recv(
1635 struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *outbuf)
1637 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1638 req, struct cli_smb2_query_info_fnum_state);
1639 NTSTATUS status;
1641 if (tevent_req_is_nterror(req, &status)) {
1642 return status;
1644 *outbuf = (DATA_BLOB) {
1645 .data = talloc_move(mem_ctx, &state->outbuf.data),
1646 .length = state->outbuf.length,
1648 return NT_STATUS_OK;
1651 NTSTATUS cli_smb2_query_info_fnum(
1652 struct cli_state *cli,
1653 uint16_t fnum,
1654 uint8_t in_info_type,
1655 uint8_t in_info_class,
1656 uint32_t in_max_output_length,
1657 const DATA_BLOB *in_input_buffer,
1658 uint32_t in_additional_info,
1659 uint32_t in_flags,
1660 TALLOC_CTX *mem_ctx,
1661 DATA_BLOB *outbuf)
1663 TALLOC_CTX *frame = talloc_stackframe();
1664 struct tevent_context *ev = NULL;
1665 struct tevent_req *req = NULL;
1666 NTSTATUS status = NT_STATUS_NO_MEMORY;
1667 bool ok;
1669 if (smbXcli_conn_has_async_calls(cli->conn)) {
1671 * Can't use sync call while an async call is in flight
1673 status = NT_STATUS_INVALID_PARAMETER;
1674 goto fail;
1676 ev = samba_tevent_context_init(frame);
1677 if (ev == NULL) {
1678 goto fail;
1680 req = cli_smb2_query_info_fnum_send(
1681 frame,
1683 cli,
1684 fnum,
1685 in_info_type,
1686 in_info_class,
1687 in_max_output_length,
1688 in_input_buffer,
1689 in_additional_info,
1690 in_flags);
1691 if (req == NULL) {
1692 goto fail;
1694 ok = tevent_req_poll_ntstatus(req, ev, &status);
1695 if (!ok) {
1696 goto fail;
1698 status = cli_smb2_query_info_fnum_recv(req, mem_ctx, outbuf);
1699 fail:
1700 TALLOC_FREE(frame);
1701 return status;
1704 /***************************************************************
1705 Helper function for pathname operations.
1706 ***************************************************************/
1708 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1709 const char *name,
1710 uint32_t desired_access,
1711 uint16_t *pfnum)
1713 NTSTATUS status;
1714 size_t namelen = strlen(name);
1715 TALLOC_CTX *frame = talloc_stackframe();
1716 uint32_t create_options = 0;
1718 /* SMB2 is pickier about pathnames. Ensure it doesn't
1719 end in a '\' */
1720 if (namelen > 0 && name[namelen-1] == '\\') {
1721 char *modname = talloc_strdup(frame, name);
1722 if (modname == NULL) {
1723 status = NT_STATUS_NO_MEMORY;
1724 goto fail;
1726 modname[namelen-1] = '\0';
1727 name = modname;
1730 /* Try to open a file handle first. */
1731 status = cli_smb2_create_fnum(cli,
1732 name,
1733 0, /* create_flags */
1734 SMB2_IMPERSONATION_IMPERSONATION,
1735 desired_access,
1736 0, /* file attributes */
1737 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1738 FILE_OPEN, /* create_disposition */
1739 create_options,
1740 NULL,
1741 pfnum,
1742 NULL,
1743 NULL,
1744 NULL);
1746 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1748 * Naive option to match our SMB1 code. Assume the
1749 * symlink path that tripped us up was the last
1750 * component and try again. Eventually we will have to
1751 * deal with the returned path unprocessed component. JRA.
1753 create_options |= FILE_OPEN_REPARSE_POINT;
1754 status = cli_smb2_create_fnum(cli,
1755 name,
1756 0, /* create_flags */
1757 SMB2_IMPERSONATION_IMPERSONATION,
1758 desired_access,
1759 0, /* file attributes */
1760 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1761 FILE_OPEN, /* create_disposition */
1762 create_options,
1763 NULL,
1764 pfnum,
1765 NULL,
1766 NULL,
1767 NULL);
1770 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1771 create_options |= FILE_DIRECTORY_FILE;
1772 status = cli_smb2_create_fnum(cli,
1773 name,
1774 0, /* create_flags */
1775 SMB2_IMPERSONATION_IMPERSONATION,
1776 desired_access,
1777 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1778 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1779 FILE_OPEN, /* create_disposition */
1780 FILE_DIRECTORY_FILE, /* create_options */
1781 NULL,
1782 pfnum,
1783 NULL,
1784 NULL,
1785 NULL);
1788 fail:
1790 TALLOC_FREE(frame);
1791 return status;
1794 /***************************************************************
1795 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1796 Synchronous only.
1797 ***************************************************************/
1799 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1800 const char *name,
1801 fstring alt_name)
1803 NTSTATUS status;
1804 DATA_BLOB outbuf = data_blob_null;
1805 uint16_t fnum = 0xffff;
1806 struct smb2_hnd *ph = NULL;
1807 uint32_t altnamelen = 0;
1808 TALLOC_CTX *frame = talloc_stackframe();
1810 if (smbXcli_conn_has_async_calls(cli->conn)) {
1812 * Can't use sync call while an async call is in flight
1814 status = NT_STATUS_INVALID_PARAMETER;
1815 goto fail;
1818 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1819 status = NT_STATUS_INVALID_PARAMETER;
1820 goto fail;
1823 status = get_fnum_from_path(cli,
1824 name,
1825 FILE_READ_ATTRIBUTES,
1826 &fnum);
1828 if (!NT_STATUS_IS_OK(status)) {
1829 goto fail;
1832 status = map_fnum_to_smb2_handle(cli,
1833 fnum,
1834 &ph);
1835 if (!NT_STATUS_IS_OK(status)) {
1836 goto fail;
1839 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1840 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1842 status = smb2cli_query_info(cli->conn,
1843 cli->timeout,
1844 cli->smb2.session,
1845 cli->smb2.tcon,
1846 1, /* in_info_type */
1847 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1848 0xFFFF, /* in_max_output_length */
1849 NULL, /* in_input_buffer */
1850 0, /* in_additional_info */
1851 0, /* in_flags */
1852 ph->fid_persistent,
1853 ph->fid_volatile,
1854 frame,
1855 &outbuf);
1857 if (!NT_STATUS_IS_OK(status)) {
1858 goto fail;
1861 /* Parse the reply. */
1862 if (outbuf.length < 4) {
1863 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1864 goto fail;
1867 altnamelen = IVAL(outbuf.data, 0);
1868 if (altnamelen > outbuf.length - 4) {
1869 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1870 goto fail;
1873 if (altnamelen > 0) {
1874 size_t ret = 0;
1875 char *short_name = NULL;
1876 ret = pull_string_talloc(frame,
1877 outbuf.data,
1878 FLAGS2_UNICODE_STRINGS,
1879 &short_name,
1880 outbuf.data + 4,
1881 altnamelen,
1882 STR_UNICODE);
1883 if (ret == (size_t)-1) {
1884 /* Bad conversion. */
1885 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1886 goto fail;
1889 fstrcpy(alt_name, short_name);
1890 } else {
1891 alt_name[0] = '\0';
1894 status = NT_STATUS_OK;
1896 fail:
1898 if (fnum != 0xffff) {
1899 cli_smb2_close_fnum(cli, fnum);
1902 cli->raw_status = status;
1904 TALLOC_FREE(frame);
1905 return status;
1909 /***************************************************************
1910 Wrapper that allows SMB2 to query a fnum info (basic level).
1911 Synchronous only.
1912 ***************************************************************/
1914 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1915 uint16_t fnum,
1916 uint16_t *mode,
1917 off_t *size,
1918 struct timespec *create_time,
1919 struct timespec *access_time,
1920 struct timespec *write_time,
1921 struct timespec *change_time,
1922 SMB_INO_T *ino)
1924 NTSTATUS status;
1925 DATA_BLOB outbuf = data_blob_null;
1926 struct smb2_hnd *ph = NULL;
1927 TALLOC_CTX *frame = talloc_stackframe();
1929 if (smbXcli_conn_has_async_calls(cli->conn)) {
1931 * Can't use sync call while an async call is in flight
1933 status = NT_STATUS_INVALID_PARAMETER;
1934 goto fail;
1937 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1938 status = NT_STATUS_INVALID_PARAMETER;
1939 goto fail;
1942 status = map_fnum_to_smb2_handle(cli,
1943 fnum,
1944 &ph);
1945 if (!NT_STATUS_IS_OK(status)) {
1946 goto fail;
1949 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1950 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1952 status = smb2cli_query_info(cli->conn,
1953 cli->timeout,
1954 cli->smb2.session,
1955 cli->smb2.tcon,
1956 1, /* in_info_type */
1957 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1958 0xFFFF, /* in_max_output_length */
1959 NULL, /* in_input_buffer */
1960 0, /* in_additional_info */
1961 0, /* in_flags */
1962 ph->fid_persistent,
1963 ph->fid_volatile,
1964 frame,
1965 &outbuf);
1966 if (!NT_STATUS_IS_OK(status)) {
1967 goto fail;
1970 /* Parse the reply. */
1971 if (outbuf.length < 0x60) {
1972 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1973 goto fail;
1976 if (create_time) {
1977 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1979 if (access_time) {
1980 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1982 if (write_time) {
1983 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1985 if (change_time) {
1986 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1988 if (mode) {
1989 uint32_t attr = IVAL(outbuf.data, 0x20);
1990 *mode = (uint16_t)attr;
1992 if (size) {
1993 uint64_t file_size = BVAL(outbuf.data, 0x30);
1994 *size = (off_t)file_size;
1996 if (ino) {
1997 uint64_t file_index = BVAL(outbuf.data, 0x40);
1998 *ino = (SMB_INO_T)file_index;
2001 fail:
2003 cli->raw_status = status;
2005 TALLOC_FREE(frame);
2006 return status;
2009 /***************************************************************
2010 Wrapper that allows SMB2 to query an fnum.
2011 Implement on top of cli_smb2_qfileinfo_basic().
2012 Synchronous only.
2013 ***************************************************************/
2015 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
2016 uint16_t fnum,
2017 uint16_t *attr,
2018 off_t *size,
2019 time_t *change_time,
2020 time_t *access_time,
2021 time_t *write_time)
2023 struct timespec access_time_ts;
2024 struct timespec write_time_ts;
2025 struct timespec change_time_ts;
2026 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
2027 fnum,
2028 attr,
2029 size,
2030 NULL,
2031 &access_time_ts,
2032 &write_time_ts,
2033 &change_time_ts,
2034 NULL);
2036 cli->raw_status = status;
2038 if (!NT_STATUS_IS_OK(status)) {
2039 return status;
2042 if (change_time) {
2043 *change_time = change_time_ts.tv_sec;
2045 if (access_time) {
2046 *access_time = access_time_ts.tv_sec;
2048 if (write_time) {
2049 *write_time = write_time_ts.tv_sec;
2051 return NT_STATUS_OK;
2054 /***************************************************************
2055 Wrapper that allows SMB2 to get pathname attributes.
2056 Synchronous only.
2057 ***************************************************************/
2059 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
2060 const char *name,
2061 uint16_t *attr,
2062 off_t *size,
2063 time_t *write_time)
2065 NTSTATUS status;
2066 uint16_t fnum = 0xffff;
2067 struct smb2_hnd *ph = NULL;
2068 TALLOC_CTX *frame = talloc_stackframe();
2070 if (smbXcli_conn_has_async_calls(cli->conn)) {
2072 * Can't use sync call while an async call is in flight
2074 status = NT_STATUS_INVALID_PARAMETER;
2075 goto fail;
2078 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2079 status = NT_STATUS_INVALID_PARAMETER;
2080 goto fail;
2083 status = get_fnum_from_path(cli,
2084 name,
2085 FILE_READ_ATTRIBUTES,
2086 &fnum);
2088 if (!NT_STATUS_IS_OK(status)) {
2089 goto fail;
2092 status = map_fnum_to_smb2_handle(cli,
2093 fnum,
2094 &ph);
2095 if (!NT_STATUS_IS_OK(status)) {
2096 goto fail;
2098 status = cli_smb2_getattrE(cli,
2099 fnum,
2100 attr,
2101 size,
2102 NULL,
2103 NULL,
2104 write_time);
2105 if (!NT_STATUS_IS_OK(status)) {
2106 goto fail;
2109 fail:
2111 if (fnum != 0xffff) {
2112 cli_smb2_close_fnum(cli, fnum);
2115 cli->raw_status = status;
2117 TALLOC_FREE(frame);
2118 return status;
2121 /***************************************************************
2122 Wrapper that allows SMB2 to query a pathname info (basic level).
2123 Implement on top of cli_smb2_qfileinfo_basic().
2124 Synchronous only.
2125 ***************************************************************/
2127 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
2128 const char *name,
2129 struct timespec *create_time,
2130 struct timespec *access_time,
2131 struct timespec *write_time,
2132 struct timespec *change_time,
2133 off_t *size,
2134 uint16_t *mode,
2135 SMB_INO_T *ino)
2137 NTSTATUS status;
2138 struct smb2_hnd *ph = NULL;
2139 uint16_t fnum = 0xffff;
2140 TALLOC_CTX *frame = talloc_stackframe();
2142 if (smbXcli_conn_has_async_calls(cli->conn)) {
2144 * Can't use sync call while an async call is in flight
2146 status = NT_STATUS_INVALID_PARAMETER;
2147 goto fail;
2150 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2151 status = NT_STATUS_INVALID_PARAMETER;
2152 goto fail;
2155 status = get_fnum_from_path(cli,
2156 name,
2157 FILE_READ_ATTRIBUTES,
2158 &fnum);
2160 if (!NT_STATUS_IS_OK(status)) {
2161 goto fail;
2164 status = map_fnum_to_smb2_handle(cli,
2165 fnum,
2166 &ph);
2167 if (!NT_STATUS_IS_OK(status)) {
2168 goto fail;
2171 status = cli_smb2_qfileinfo_basic(cli,
2172 fnum,
2173 mode,
2174 size,
2175 create_time,
2176 access_time,
2177 write_time,
2178 change_time,
2179 ino);
2181 fail:
2183 if (fnum != 0xffff) {
2184 cli_smb2_close_fnum(cli, fnum);
2187 cli->raw_status = status;
2189 TALLOC_FREE(frame);
2190 return status;
2193 /***************************************************************
2194 Wrapper that allows SMB2 to query pathname streams.
2195 Synchronous only.
2196 ***************************************************************/
2198 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
2199 const char *name,
2200 TALLOC_CTX *mem_ctx,
2201 unsigned int *pnum_streams,
2202 struct stream_struct **pstreams)
2204 NTSTATUS status;
2205 struct smb2_hnd *ph = NULL;
2206 uint16_t fnum = 0xffff;
2207 DATA_BLOB outbuf = data_blob_null;
2208 TALLOC_CTX *frame = talloc_stackframe();
2210 if (smbXcli_conn_has_async_calls(cli->conn)) {
2212 * Can't use sync call while an async call is in flight
2214 status = NT_STATUS_INVALID_PARAMETER;
2215 goto fail;
2218 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2219 status = NT_STATUS_INVALID_PARAMETER;
2220 goto fail;
2223 status = get_fnum_from_path(cli,
2224 name,
2225 FILE_READ_ATTRIBUTES,
2226 &fnum);
2228 if (!NT_STATUS_IS_OK(status)) {
2229 goto fail;
2232 status = map_fnum_to_smb2_handle(cli,
2233 fnum,
2234 &ph);
2235 if (!NT_STATUS_IS_OK(status)) {
2236 goto fail;
2239 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2240 level 22 (SMB2_FILE_STREAM_INFORMATION). */
2242 status = smb2cli_query_info(cli->conn,
2243 cli->timeout,
2244 cli->smb2.session,
2245 cli->smb2.tcon,
2246 1, /* in_info_type */
2247 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
2248 0xFFFF, /* in_max_output_length */
2249 NULL, /* in_input_buffer */
2250 0, /* in_additional_info */
2251 0, /* in_flags */
2252 ph->fid_persistent,
2253 ph->fid_volatile,
2254 frame,
2255 &outbuf);
2257 if (!NT_STATUS_IS_OK(status)) {
2258 goto fail;
2261 /* Parse the reply. */
2262 if (!parse_streams_blob(mem_ctx,
2263 outbuf.data,
2264 outbuf.length,
2265 pnum_streams,
2266 pstreams)) {
2267 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2268 goto fail;
2271 fail:
2273 if (fnum != 0xffff) {
2274 cli_smb2_close_fnum(cli, fnum);
2277 cli->raw_status = status;
2279 TALLOC_FREE(frame);
2280 return status;
2283 /***************************************************************
2284 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2285 a pathname.
2286 Synchronous only.
2287 ***************************************************************/
2289 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
2290 const char *name,
2291 uint8_t in_info_type,
2292 uint8_t in_file_info_class,
2293 const DATA_BLOB *p_in_data)
2295 NTSTATUS status;
2296 uint16_t fnum = 0xffff;
2297 struct smb2_hnd *ph = NULL;
2298 TALLOC_CTX *frame = talloc_stackframe();
2300 if (smbXcli_conn_has_async_calls(cli->conn)) {
2302 * Can't use sync call while an async call is in flight
2304 status = NT_STATUS_INVALID_PARAMETER;
2305 goto fail;
2308 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2309 status = NT_STATUS_INVALID_PARAMETER;
2310 goto fail;
2313 status = get_fnum_from_path(cli,
2314 name,
2315 FILE_WRITE_ATTRIBUTES,
2316 &fnum);
2318 if (!NT_STATUS_IS_OK(status)) {
2319 goto fail;
2322 status = map_fnum_to_smb2_handle(cli,
2323 fnum,
2324 &ph);
2325 if (!NT_STATUS_IS_OK(status)) {
2326 goto fail;
2329 status = smb2cli_set_info(cli->conn,
2330 cli->timeout,
2331 cli->smb2.session,
2332 cli->smb2.tcon,
2333 in_info_type,
2334 in_file_info_class,
2335 p_in_data, /* in_input_buffer */
2336 0, /* in_additional_info */
2337 ph->fid_persistent,
2338 ph->fid_volatile);
2339 fail:
2341 if (fnum != 0xffff) {
2342 cli_smb2_close_fnum(cli, fnum);
2345 cli->raw_status = status;
2347 TALLOC_FREE(frame);
2348 return status;
2352 /***************************************************************
2353 Wrapper that allows SMB2 to set pathname attributes.
2354 Synchronous only.
2355 ***************************************************************/
2357 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
2358 const char *name,
2359 uint16_t attr,
2360 time_t mtime)
2362 uint8_t inbuf_store[40];
2363 DATA_BLOB inbuf = data_blob_null;
2365 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2366 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2368 inbuf.data = inbuf_store;
2369 inbuf.length = sizeof(inbuf_store);
2370 data_blob_clear(&inbuf);
2373 * SMB1 uses attr == 0 to clear all attributes
2374 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2375 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2376 * request attribute change.
2378 * SMB2 uses exactly the reverse. Unfortunately as the
2379 * cli_setatr() ABI is exposed inside libsmbclient,
2380 * we must make the SMB2 cli_smb2_setatr() call
2381 * export the same ABI as the SMB1 cli_setatr()
2382 * which calls it. This means reversing the sense
2383 * of the requested attr argument if it's zero
2384 * or FILE_ATTRIBUTE_NORMAL.
2386 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2389 if (attr == 0) {
2390 attr = FILE_ATTRIBUTE_NORMAL;
2391 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
2392 attr = 0;
2395 SSVAL(inbuf.data, 32, attr);
2396 if (mtime != 0) {
2397 put_long_date((char *)inbuf.data + 16,mtime);
2399 /* Set all the other times to -1. */
2400 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2401 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
2402 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
2404 return cli_smb2_setpathinfo(cli,
2405 name,
2406 1, /* in_info_type */
2407 /* in_file_info_class */
2408 SMB_FILE_BASIC_INFORMATION - 1000,
2409 &inbuf);
2413 /***************************************************************
2414 Wrapper that allows SMB2 to set file handle times.
2415 Synchronous only.
2416 ***************************************************************/
2418 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
2419 uint16_t fnum,
2420 time_t change_time,
2421 time_t access_time,
2422 time_t write_time)
2424 NTSTATUS status;
2425 struct smb2_hnd *ph = NULL;
2426 uint8_t inbuf_store[40];
2427 DATA_BLOB inbuf = data_blob_null;
2429 if (smbXcli_conn_has_async_calls(cli->conn)) {
2431 * Can't use sync call while an async call is in flight
2433 return NT_STATUS_INVALID_PARAMETER;
2436 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2437 return NT_STATUS_INVALID_PARAMETER;
2440 status = map_fnum_to_smb2_handle(cli,
2441 fnum,
2442 &ph);
2443 if (!NT_STATUS_IS_OK(status)) {
2444 return status;
2447 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2448 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2450 inbuf.data = inbuf_store;
2451 inbuf.length = sizeof(inbuf_store);
2452 data_blob_clear(&inbuf);
2454 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2455 if (change_time != 0) {
2456 put_long_date((char *)inbuf.data + 24, change_time);
2458 if (access_time != 0) {
2459 put_long_date((char *)inbuf.data + 8, access_time);
2461 if (write_time != 0) {
2462 put_long_date((char *)inbuf.data + 16, write_time);
2465 cli->raw_status = smb2cli_set_info(cli->conn,
2466 cli->timeout,
2467 cli->smb2.session,
2468 cli->smb2.tcon,
2469 1, /* in_info_type */
2470 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
2471 &inbuf, /* in_input_buffer */
2472 0, /* in_additional_info */
2473 ph->fid_persistent,
2474 ph->fid_volatile);
2476 return cli->raw_status;
2479 /***************************************************************
2480 Wrapper that allows SMB2 to query disk attributes (size).
2481 Synchronous only.
2482 ***************************************************************/
2484 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2485 uint64_t *bsize, uint64_t *total, uint64_t *avail)
2487 NTSTATUS status;
2488 uint16_t fnum = 0xffff;
2489 DATA_BLOB outbuf = data_blob_null;
2490 struct smb2_hnd *ph = NULL;
2491 uint32_t sectors_per_unit = 0;
2492 uint32_t bytes_per_sector = 0;
2493 uint64_t total_size = 0;
2494 uint64_t size_free = 0;
2495 TALLOC_CTX *frame = talloc_stackframe();
2497 if (smbXcli_conn_has_async_calls(cli->conn)) {
2499 * Can't use sync call while an async call is in flight
2501 status = NT_STATUS_INVALID_PARAMETER;
2502 goto fail;
2505 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2506 status = NT_STATUS_INVALID_PARAMETER;
2507 goto fail;
2510 /* First open the top level directory. */
2511 status = cli_smb2_create_fnum(cli,
2512 path,
2513 0, /* create_flags */
2514 SMB2_IMPERSONATION_IMPERSONATION,
2515 FILE_READ_ATTRIBUTES, /* desired_access */
2516 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2517 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2518 FILE_OPEN, /* create_disposition */
2519 FILE_DIRECTORY_FILE, /* create_options */
2520 NULL,
2521 &fnum,
2522 NULL,
2523 NULL,
2524 NULL);
2526 if (!NT_STATUS_IS_OK(status)) {
2527 goto fail;
2530 status = map_fnum_to_smb2_handle(cli,
2531 fnum,
2532 &ph);
2533 if (!NT_STATUS_IS_OK(status)) {
2534 goto fail;
2537 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2538 level 3 (SMB_FS_SIZE_INFORMATION). */
2540 status = smb2cli_query_info(cli->conn,
2541 cli->timeout,
2542 cli->smb2.session,
2543 cli->smb2.tcon,
2544 2, /* in_info_type */
2545 3, /* in_file_info_class */
2546 0xFFFF, /* in_max_output_length */
2547 NULL, /* in_input_buffer */
2548 0, /* in_additional_info */
2549 0, /* in_flags */
2550 ph->fid_persistent,
2551 ph->fid_volatile,
2552 frame,
2553 &outbuf);
2554 if (!NT_STATUS_IS_OK(status)) {
2555 goto fail;
2558 /* Parse the reply. */
2559 if (outbuf.length != 24) {
2560 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2561 goto fail;
2564 total_size = BVAL(outbuf.data, 0);
2565 size_free = BVAL(outbuf.data, 8);
2566 sectors_per_unit = IVAL(outbuf.data, 16);
2567 bytes_per_sector = IVAL(outbuf.data, 20);
2569 if (bsize) {
2570 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2572 if (total) {
2573 *total = total_size;
2575 if (avail) {
2576 *avail = size_free;
2579 status = NT_STATUS_OK;
2581 fail:
2583 if (fnum != 0xffff) {
2584 cli_smb2_close_fnum(cli, fnum);
2587 cli->raw_status = status;
2589 TALLOC_FREE(frame);
2590 return status;
2593 /***************************************************************
2594 Wrapper that allows SMB2 to query file system sizes.
2595 Synchronous only.
2596 ***************************************************************/
2598 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2599 uint64_t *total_allocation_units,
2600 uint64_t *caller_allocation_units,
2601 uint64_t *actual_allocation_units,
2602 uint64_t *sectors_per_allocation_unit,
2603 uint64_t *bytes_per_sector)
2605 NTSTATUS status;
2606 uint16_t fnum = 0xffff;
2607 DATA_BLOB outbuf = data_blob_null;
2608 struct smb2_hnd *ph = NULL;
2609 TALLOC_CTX *frame = talloc_stackframe();
2611 if (smbXcli_conn_has_async_calls(cli->conn)) {
2613 * Can't use sync call while an async call is in flight
2615 status = NT_STATUS_INVALID_PARAMETER;
2616 goto fail;
2619 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2620 status = NT_STATUS_INVALID_PARAMETER;
2621 goto fail;
2624 /* First open the top level directory. */
2625 status =
2626 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2627 SMB2_IMPERSONATION_IMPERSONATION,
2628 FILE_READ_ATTRIBUTES, /* desired_access */
2629 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2630 FILE_SHARE_READ | FILE_SHARE_WRITE |
2631 FILE_SHARE_DELETE, /* share_access */
2632 FILE_OPEN, /* create_disposition */
2633 FILE_DIRECTORY_FILE, /* create_options */
2634 NULL,
2635 &fnum,
2636 NULL,
2637 NULL,
2638 NULL);
2640 if (!NT_STATUS_IS_OK(status)) {
2641 goto fail;
2644 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2645 if (!NT_STATUS_IS_OK(status)) {
2646 goto fail;
2649 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2650 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2652 status = smb2cli_query_info(cli->conn,
2653 cli->timeout,
2654 cli->smb2.session,
2655 cli->smb2.tcon,
2656 SMB2_GETINFO_FS, /* in_info_type */
2657 /* in_file_info_class */
2658 SMB_FS_FULL_SIZE_INFORMATION - 1000,
2659 0xFFFF, /* in_max_output_length */
2660 NULL, /* in_input_buffer */
2661 0, /* in_additional_info */
2662 0, /* in_flags */
2663 ph->fid_persistent,
2664 ph->fid_volatile,
2665 frame,
2666 &outbuf);
2667 if (!NT_STATUS_IS_OK(status)) {
2668 goto fail;
2671 if (outbuf.length < 32) {
2672 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2673 goto fail;
2676 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2677 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2678 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2679 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2680 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2682 fail:
2684 if (fnum != 0xffff) {
2685 cli_smb2_close_fnum(cli, fnum);
2688 cli->raw_status = status;
2690 TALLOC_FREE(frame);
2691 return status;
2694 /***************************************************************
2695 Wrapper that allows SMB2 to query file system attributes.
2696 Synchronous only.
2697 ***************************************************************/
2699 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2701 NTSTATUS status;
2702 uint16_t fnum = 0xffff;
2703 DATA_BLOB outbuf = data_blob_null;
2704 struct smb2_hnd *ph = NULL;
2705 TALLOC_CTX *frame = talloc_stackframe();
2707 if (smbXcli_conn_has_async_calls(cli->conn)) {
2709 * Can't use sync call while an async call is in flight
2711 status = NT_STATUS_INVALID_PARAMETER;
2712 goto fail;
2715 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2716 status = NT_STATUS_INVALID_PARAMETER;
2717 goto fail;
2720 /* First open the top level directory. */
2721 status =
2722 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2723 SMB2_IMPERSONATION_IMPERSONATION,
2724 FILE_READ_ATTRIBUTES, /* desired_access */
2725 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2726 FILE_SHARE_READ | FILE_SHARE_WRITE |
2727 FILE_SHARE_DELETE, /* share_access */
2728 FILE_OPEN, /* create_disposition */
2729 FILE_DIRECTORY_FILE, /* create_options */
2730 NULL,
2731 &fnum,
2732 NULL,
2733 NULL,
2734 NULL);
2736 if (!NT_STATUS_IS_OK(status)) {
2737 goto fail;
2740 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2741 if (!NT_STATUS_IS_OK(status)) {
2742 goto fail;
2745 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2746 cli->smb2.tcon, 2, /* in_info_type */
2747 5, /* in_file_info_class */
2748 0xFFFF, /* in_max_output_length */
2749 NULL, /* in_input_buffer */
2750 0, /* in_additional_info */
2751 0, /* in_flags */
2752 ph->fid_persistent, ph->fid_volatile, frame,
2753 &outbuf);
2754 if (!NT_STATUS_IS_OK(status)) {
2755 goto fail;
2758 if (outbuf.length < 12) {
2759 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2760 goto fail;
2763 *fs_attr = IVAL(outbuf.data, 0);
2765 fail:
2767 if (fnum != 0xffff) {
2768 cli_smb2_close_fnum(cli, fnum);
2771 cli->raw_status = status;
2773 TALLOC_FREE(frame);
2774 return status;
2777 /***************************************************************
2778 Wrapper that allows SMB2 to query file system volume info.
2779 Synchronous only.
2780 ***************************************************************/
2782 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2783 TALLOC_CTX *mem_ctx,
2784 char **_volume_name,
2785 uint32_t *pserial_number,
2786 time_t *pdate)
2788 NTSTATUS status;
2789 uint16_t fnum = 0xffff;
2790 DATA_BLOB outbuf = data_blob_null;
2791 struct smb2_hnd *ph = NULL;
2792 uint32_t nlen;
2793 char *volume_name = NULL;
2794 TALLOC_CTX *frame = talloc_stackframe();
2796 if (smbXcli_conn_has_async_calls(cli->conn)) {
2798 * Can't use sync call while an async call is in flight
2800 status = NT_STATUS_INVALID_PARAMETER;
2801 goto fail;
2804 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2805 status = NT_STATUS_INVALID_PARAMETER;
2806 goto fail;
2809 /* First open the top level directory. */
2810 status =
2811 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2812 SMB2_IMPERSONATION_IMPERSONATION,
2813 FILE_READ_ATTRIBUTES, /* desired_access */
2814 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2815 FILE_SHARE_READ | FILE_SHARE_WRITE |
2816 FILE_SHARE_DELETE, /* share_access */
2817 FILE_OPEN, /* create_disposition */
2818 FILE_DIRECTORY_FILE, /* create_options */
2819 NULL,
2820 &fnum,
2821 NULL,
2822 NULL,
2823 NULL);
2825 if (!NT_STATUS_IS_OK(status)) {
2826 goto fail;
2829 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2830 if (!NT_STATUS_IS_OK(status)) {
2831 goto fail;
2834 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2835 level 1 (SMB_FS_VOLUME_INFORMATION). */
2837 status = smb2cli_query_info(cli->conn,
2838 cli->timeout,
2839 cli->smb2.session,
2840 cli->smb2.tcon,
2841 SMB2_GETINFO_FS, /* in_info_type */
2842 /* in_file_info_class */
2843 SMB_FS_VOLUME_INFORMATION - 1000,
2844 0xFFFF, /* in_max_output_length */
2845 NULL, /* in_input_buffer */
2846 0, /* in_additional_info */
2847 0, /* in_flags */
2848 ph->fid_persistent,
2849 ph->fid_volatile,
2850 frame,
2851 &outbuf);
2852 if (!NT_STATUS_IS_OK(status)) {
2853 goto fail;
2856 if (outbuf.length < 24) {
2857 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2858 goto fail;
2861 if (pdate) {
2862 struct timespec ts;
2863 ts = interpret_long_date((char *)outbuf.data);
2864 *pdate = ts.tv_sec;
2866 if (pserial_number) {
2867 *pserial_number = IVAL(outbuf.data,8);
2869 nlen = IVAL(outbuf.data,12);
2870 if (nlen + 18 < 18) {
2871 /* Integer wrap. */
2872 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2873 goto fail;
2876 * The next check is safe as we know outbuf.length >= 24
2877 * from above.
2879 if (nlen > (outbuf.length - 18)) {
2880 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2881 goto fail;
2884 clistr_pull_talloc(mem_ctx,
2885 (const char *)outbuf.data,
2887 &volume_name,
2888 outbuf.data + 18,
2889 nlen,
2890 STR_UNICODE);
2891 if (volume_name == NULL) {
2892 status = map_nt_error_from_unix(errno);
2893 goto fail;
2896 *_volume_name = volume_name;
2898 fail:
2900 if (fnum != 0xffff) {
2901 cli_smb2_close_fnum(cli, fnum);
2904 cli->raw_status = status;
2906 TALLOC_FREE(frame);
2907 return status;
2911 /***************************************************************
2912 Wrapper that allows SMB2 to query a security descriptor.
2913 Synchronous only.
2914 ***************************************************************/
2916 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2917 uint16_t fnum,
2918 uint32_t sec_info,
2919 TALLOC_CTX *mem_ctx,
2920 struct security_descriptor **ppsd)
2922 NTSTATUS status;
2923 DATA_BLOB outbuf = data_blob_null;
2924 struct smb2_hnd *ph = NULL;
2925 struct security_descriptor *lsd = NULL;
2926 TALLOC_CTX *frame = talloc_stackframe();
2928 if (smbXcli_conn_has_async_calls(cli->conn)) {
2930 * Can't use sync call while an async call is in flight
2932 status = NT_STATUS_INVALID_PARAMETER;
2933 goto fail;
2936 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2937 status = NT_STATUS_INVALID_PARAMETER;
2938 goto fail;
2941 status = map_fnum_to_smb2_handle(cli,
2942 fnum,
2943 &ph);
2944 if (!NT_STATUS_IS_OK(status)) {
2945 goto fail;
2948 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2950 status = smb2cli_query_info(cli->conn,
2951 cli->timeout,
2952 cli->smb2.session,
2953 cli->smb2.tcon,
2954 3, /* in_info_type */
2955 0, /* in_file_info_class */
2956 0xFFFF, /* in_max_output_length */
2957 NULL, /* in_input_buffer */
2958 sec_info, /* in_additional_info */
2959 0, /* in_flags */
2960 ph->fid_persistent,
2961 ph->fid_volatile,
2962 frame,
2963 &outbuf);
2965 if (!NT_STATUS_IS_OK(status)) {
2966 goto fail;
2969 /* Parse the reply. */
2970 status = unmarshall_sec_desc(mem_ctx,
2971 outbuf.data,
2972 outbuf.length,
2973 &lsd);
2975 if (!NT_STATUS_IS_OK(status)) {
2976 goto fail;
2979 if (ppsd != NULL) {
2980 *ppsd = lsd;
2981 } else {
2982 TALLOC_FREE(lsd);
2985 fail:
2987 cli->raw_status = status;
2989 TALLOC_FREE(frame);
2990 return status;
2993 /***************************************************************
2994 Wrapper that allows SMB2 to set a security descriptor.
2995 Synchronous only.
2996 ***************************************************************/
2998 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
2999 uint16_t fnum,
3000 uint32_t sec_info,
3001 const struct security_descriptor *sd)
3003 NTSTATUS status;
3004 DATA_BLOB inbuf = data_blob_null;
3005 struct smb2_hnd *ph = NULL;
3006 TALLOC_CTX *frame = talloc_stackframe();
3008 if (smbXcli_conn_has_async_calls(cli->conn)) {
3010 * Can't use sync call while an async call is in flight
3012 status = NT_STATUS_INVALID_PARAMETER;
3013 goto fail;
3016 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3017 status = NT_STATUS_INVALID_PARAMETER;
3018 goto fail;
3021 status = map_fnum_to_smb2_handle(cli,
3022 fnum,
3023 &ph);
3024 if (!NT_STATUS_IS_OK(status)) {
3025 goto fail;
3028 status = marshall_sec_desc(frame,
3030 &inbuf.data,
3031 &inbuf.length);
3033 if (!NT_STATUS_IS_OK(status)) {
3034 goto fail;
3037 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
3039 status = smb2cli_set_info(cli->conn,
3040 cli->timeout,
3041 cli->smb2.session,
3042 cli->smb2.tcon,
3043 3, /* in_info_type */
3044 0, /* in_file_info_class */
3045 &inbuf, /* in_input_buffer */
3046 sec_info, /* in_additional_info */
3047 ph->fid_persistent,
3048 ph->fid_volatile);
3050 fail:
3052 cli->raw_status = status;
3054 TALLOC_FREE(frame);
3055 return status;
3058 /***************************************************************
3059 Wrapper that allows SMB2 to query a security descriptor.
3060 Synchronous only.
3062 ***************************************************************/
3064 struct cli_smb2_mxac_state {
3065 struct tevent_context *ev;
3066 struct cli_state *cli;
3067 const char *fname;
3068 struct smb2_create_blobs in_cblobs;
3069 uint16_t fnum;
3070 NTSTATUS status;
3071 uint32_t mxac;
3074 static void cli_smb2_mxac_opened(struct tevent_req *subreq);
3075 static void cli_smb2_mxac_closed(struct tevent_req *subreq);
3077 struct tevent_req *cli_smb2_query_mxac_send(TALLOC_CTX *mem_ctx,
3078 struct tevent_context *ev,
3079 struct cli_state *cli,
3080 const char *fname)
3082 struct tevent_req *req = NULL, *subreq = NULL;
3083 struct cli_smb2_mxac_state *state = NULL;
3084 NTSTATUS status;
3086 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_mxac_state);
3087 if (req == NULL) {
3088 return NULL;
3090 *state = (struct cli_smb2_mxac_state) {
3091 state->ev = ev,
3092 state->cli = cli,
3093 state->fname = fname,
3096 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3097 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3098 return tevent_req_post(req, ev);
3101 status = smb2_create_blob_add(state,
3102 &state->in_cblobs,
3103 SMB2_CREATE_TAG_MXAC,
3104 data_blob(NULL, 0));
3105 if (tevent_req_nterror(req, status)) {
3106 return tevent_req_post(req, ev);
3109 subreq = cli_smb2_create_fnum_send(
3110 state,
3111 state->ev,
3112 state->cli,
3113 state->fname,
3114 0, /* create_flags */
3115 SMB2_IMPERSONATION_IMPERSONATION,
3116 FILE_READ_ATTRIBUTES,
3117 0, /* file attributes */
3118 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
3119 FILE_OPEN,
3120 0, /* create_options */
3121 &state->in_cblobs);
3122 if (tevent_req_nomem(subreq, req)) {
3123 return tevent_req_post(req, ev);
3125 tevent_req_set_callback(subreq, cli_smb2_mxac_opened, req);
3126 return req;
3129 static void cli_smb2_mxac_opened(struct tevent_req *subreq)
3131 struct tevent_req *req = tevent_req_callback_data(
3132 subreq, struct tevent_req);
3133 struct cli_smb2_mxac_state *state = tevent_req_data(
3134 req, struct cli_smb2_mxac_state);
3135 struct smb2_create_blobs out_cblobs = {0};
3136 struct smb2_create_blob *mxac_blob = NULL;
3137 NTSTATUS status;
3139 status = cli_smb2_create_fnum_recv(
3140 subreq, &state->fnum, NULL, state, &out_cblobs);
3141 TALLOC_FREE(subreq);
3143 if (tevent_req_nterror(req, status)) {
3144 return;
3147 mxac_blob = smb2_create_blob_find(&out_cblobs, SMB2_CREATE_TAG_MXAC);
3148 if (mxac_blob == NULL) {
3149 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3150 goto close;
3152 if (mxac_blob->data.length != 8) {
3153 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3154 goto close;
3157 state->status = NT_STATUS(IVAL(mxac_blob->data.data, 0));
3158 state->mxac = IVAL(mxac_blob->data.data, 4);
3160 close:
3161 subreq = cli_smb2_close_fnum_send(
3162 state, state->ev, state->cli, state->fnum);
3163 if (tevent_req_nomem(subreq, req)) {
3164 return;
3166 tevent_req_set_callback(subreq, cli_smb2_mxac_closed, req);
3168 return;
3171 static void cli_smb2_mxac_closed(struct tevent_req *subreq)
3173 struct tevent_req *req = tevent_req_callback_data(
3174 subreq, struct tevent_req);
3175 NTSTATUS status;
3177 status = cli_smb2_close_fnum_recv(subreq);
3178 if (tevent_req_nterror(req, status)) {
3179 return;
3182 tevent_req_done(req);
3185 NTSTATUS cli_smb2_query_mxac_recv(struct tevent_req *req, uint32_t *mxac)
3187 struct cli_smb2_mxac_state *state = tevent_req_data(
3188 req, struct cli_smb2_mxac_state);
3189 NTSTATUS status;
3191 if (tevent_req_is_nterror(req, &status)) {
3192 return status;
3195 if (!NT_STATUS_IS_OK(state->status)) {
3196 return state->status;
3199 *mxac = state->mxac;
3200 return NT_STATUS_OK;
3203 NTSTATUS cli_smb2_query_mxac(struct cli_state *cli,
3204 const char *fname,
3205 uint32_t *_mxac)
3207 TALLOC_CTX *frame = talloc_stackframe();
3208 struct tevent_context *ev = NULL;
3209 struct tevent_req *req = NULL;
3210 NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
3211 bool ok;
3213 if (smbXcli_conn_has_async_calls(cli->conn)) {
3215 * Can't use sync call while an async call is in flight
3217 status = NT_STATUS_INVALID_PARAMETER;
3218 goto fail;
3221 ev = samba_tevent_context_init(frame);
3222 if (ev == NULL) {
3223 goto fail;
3225 req = cli_smb2_query_mxac_send(frame, ev, cli, fname);
3226 if (req == NULL) {
3227 goto fail;
3229 ok = tevent_req_poll_ntstatus(req, ev, &status);
3230 if (!ok) {
3231 goto fail;
3233 status = cli_smb2_query_mxac_recv(req, _mxac);
3235 fail:
3236 cli->raw_status = status;
3237 TALLOC_FREE(frame);
3238 return status;
3241 /***************************************************************
3242 Wrapper that allows SMB2 to rename a file.
3243 Synchronous only.
3244 ***************************************************************/
3246 NTSTATUS cli_smb2_rename(struct cli_state *cli,
3247 const char *fname_src,
3248 const char *fname_dst,
3249 bool replace)
3251 NTSTATUS status;
3252 DATA_BLOB inbuf = data_blob_null;
3253 uint16_t fnum = 0xffff;
3254 struct smb2_hnd *ph = NULL;
3255 smb_ucs2_t *converted_str = NULL;
3256 size_t converted_size_bytes = 0;
3257 size_t namelen = 0;
3258 TALLOC_CTX *frame = talloc_stackframe();
3260 if (smbXcli_conn_has_async_calls(cli->conn)) {
3262 * Can't use sync call while an async call is in flight
3264 status = NT_STATUS_INVALID_PARAMETER;
3265 goto fail;
3268 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3269 status = NT_STATUS_INVALID_PARAMETER;
3270 goto fail;
3273 status = get_fnum_from_path(cli,
3274 fname_src,
3275 DELETE_ACCESS,
3276 &fnum);
3278 if (!NT_STATUS_IS_OK(status)) {
3279 goto fail;
3282 status = map_fnum_to_smb2_handle(cli,
3283 fnum,
3284 &ph);
3285 if (!NT_STATUS_IS_OK(status)) {
3286 goto fail;
3289 /* SMB2 is pickier about pathnames. Ensure it doesn't
3290 start in a '\' */
3291 if (*fname_dst == '\\') {
3292 fname_dst++;
3295 /* SMB2 is pickier about pathnames. Ensure it doesn't
3296 end in a '\' */
3297 namelen = strlen(fname_dst);
3298 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
3299 char *modname = talloc_strdup(frame, fname_dst);
3300 modname[namelen-1] = '\0';
3301 fname_dst = modname;
3304 if (!push_ucs2_talloc(frame,
3305 &converted_str,
3306 fname_dst,
3307 &converted_size_bytes)) {
3308 status = NT_STATUS_INVALID_PARAMETER;
3309 goto fail;
3312 /* W2K8 insists the dest name is not null
3313 terminated. Remove the last 2 zero bytes
3314 and reduce the name length. */
3316 if (converted_size_bytes < 2) {
3317 status = NT_STATUS_INVALID_PARAMETER;
3318 goto fail;
3320 converted_size_bytes -= 2;
3322 inbuf = data_blob_talloc_zero(frame,
3323 20 + converted_size_bytes);
3324 if (inbuf.data == NULL) {
3325 status = NT_STATUS_NO_MEMORY;
3326 goto fail;
3329 if (replace) {
3330 SCVAL(inbuf.data, 0, 1);
3333 SIVAL(inbuf.data, 16, converted_size_bytes);
3334 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
3336 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3337 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3339 status = smb2cli_set_info(cli->conn,
3340 cli->timeout,
3341 cli->smb2.session,
3342 cli->smb2.tcon,
3343 1, /* in_info_type */
3344 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
3345 &inbuf, /* in_input_buffer */
3346 0, /* in_additional_info */
3347 ph->fid_persistent,
3348 ph->fid_volatile);
3350 fail:
3352 if (fnum != 0xffff) {
3353 cli_smb2_close_fnum(cli, fnum);
3356 cli->raw_status = status;
3358 TALLOC_FREE(frame);
3359 return status;
3362 /***************************************************************
3363 Wrapper that allows SMB2 to set an EA on a fnum.
3364 Synchronous only.
3365 ***************************************************************/
3367 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
3368 uint16_t fnum,
3369 const char *ea_name,
3370 const char *ea_val,
3371 size_t ea_len)
3373 NTSTATUS status;
3374 DATA_BLOB inbuf = data_blob_null;
3375 size_t bloblen = 0;
3376 char *ea_name_ascii = NULL;
3377 size_t namelen = 0;
3378 struct smb2_hnd *ph = NULL;
3379 TALLOC_CTX *frame = talloc_stackframe();
3381 if (smbXcli_conn_has_async_calls(cli->conn)) {
3383 * Can't use sync call while an async call is in flight
3385 status = NT_STATUS_INVALID_PARAMETER;
3386 goto fail;
3389 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3390 status = NT_STATUS_INVALID_PARAMETER;
3391 goto fail;
3394 status = map_fnum_to_smb2_handle(cli,
3395 fnum,
3396 &ph);
3397 if (!NT_STATUS_IS_OK(status)) {
3398 goto fail;
3401 /* Marshall the SMB2 EA data. */
3402 if (ea_len > 0xFFFF) {
3403 status = NT_STATUS_INVALID_PARAMETER;
3404 goto fail;
3407 if (!push_ascii_talloc(frame,
3408 &ea_name_ascii,
3409 ea_name,
3410 &namelen)) {
3411 status = NT_STATUS_INVALID_PARAMETER;
3412 goto fail;
3415 if (namelen < 2 || namelen > 0xFF) {
3416 status = NT_STATUS_INVALID_PARAMETER;
3417 goto fail;
3420 bloblen = 8 + ea_len + namelen;
3421 /* Round up to a 4 byte boundary. */
3422 bloblen = ((bloblen + 3)&~3);
3424 inbuf = data_blob_talloc_zero(frame, bloblen);
3425 if (inbuf.data == NULL) {
3426 status = NT_STATUS_NO_MEMORY;
3427 goto fail;
3429 /* namelen doesn't include the NULL byte. */
3430 SCVAL(inbuf.data, 5, namelen - 1);
3431 SSVAL(inbuf.data, 6, ea_len);
3432 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
3433 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
3435 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3436 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3438 status = smb2cli_set_info(cli->conn,
3439 cli->timeout,
3440 cli->smb2.session,
3441 cli->smb2.tcon,
3442 1, /* in_info_type */
3443 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3444 &inbuf, /* in_input_buffer */
3445 0, /* in_additional_info */
3446 ph->fid_persistent,
3447 ph->fid_volatile);
3449 fail:
3451 cli->raw_status = status;
3453 TALLOC_FREE(frame);
3454 return status;
3457 /***************************************************************
3458 Wrapper that allows SMB2 to set an EA on a pathname.
3459 Synchronous only.
3460 ***************************************************************/
3462 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
3463 const char *name,
3464 const char *ea_name,
3465 const char *ea_val,
3466 size_t ea_len)
3468 NTSTATUS status;
3469 uint16_t fnum = 0xffff;
3471 if (smbXcli_conn_has_async_calls(cli->conn)) {
3473 * Can't use sync call while an async call is in flight
3475 status = NT_STATUS_INVALID_PARAMETER;
3476 goto fail;
3479 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3480 status = NT_STATUS_INVALID_PARAMETER;
3481 goto fail;
3484 status = get_fnum_from_path(cli,
3485 name,
3486 FILE_WRITE_EA,
3487 &fnum);
3489 if (!NT_STATUS_IS_OK(status)) {
3490 goto fail;
3493 status = cli_set_ea_fnum(cli,
3494 fnum,
3495 ea_name,
3496 ea_val,
3497 ea_len);
3498 if (!NT_STATUS_IS_OK(status)) {
3499 goto fail;
3502 fail:
3504 if (fnum != 0xffff) {
3505 cli_smb2_close_fnum(cli, fnum);
3508 cli->raw_status = status;
3510 return status;
3513 /***************************************************************
3514 Wrapper that allows SMB2 to get an EA list on a pathname.
3515 Synchronous only.
3516 ***************************************************************/
3518 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
3519 const char *name,
3520 TALLOC_CTX *ctx,
3521 size_t *pnum_eas,
3522 struct ea_struct **pea_array)
3524 NTSTATUS status;
3525 uint16_t fnum = 0xffff;
3526 DATA_BLOB outbuf = data_blob_null;
3527 struct smb2_hnd *ph = NULL;
3528 struct ea_list *ea_list = NULL;
3529 struct ea_list *eal = NULL;
3530 size_t ea_count = 0;
3531 TALLOC_CTX *frame = talloc_stackframe();
3533 *pnum_eas = 0;
3534 *pea_array = NULL;
3536 if (smbXcli_conn_has_async_calls(cli->conn)) {
3538 * Can't use sync call while an async call is in flight
3540 status = NT_STATUS_INVALID_PARAMETER;
3541 goto fail;
3544 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3545 status = NT_STATUS_INVALID_PARAMETER;
3546 goto fail;
3549 status = get_fnum_from_path(cli,
3550 name,
3551 FILE_READ_EA,
3552 &fnum);
3554 if (!NT_STATUS_IS_OK(status)) {
3555 goto fail;
3558 status = map_fnum_to_smb2_handle(cli,
3559 fnum,
3560 &ph);
3561 if (!NT_STATUS_IS_OK(status)) {
3562 goto fail;
3565 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3566 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3568 status = smb2cli_query_info(cli->conn,
3569 cli->timeout,
3570 cli->smb2.session,
3571 cli->smb2.tcon,
3572 1, /* in_info_type */
3573 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3574 0xFFFF, /* in_max_output_length */
3575 NULL, /* in_input_buffer */
3576 0, /* in_additional_info */
3577 0, /* in_flags */
3578 ph->fid_persistent,
3579 ph->fid_volatile,
3580 frame,
3581 &outbuf);
3583 if (!NT_STATUS_IS_OK(status)) {
3584 goto fail;
3587 /* Parse the reply. */
3588 ea_list = read_nttrans_ea_list(ctx,
3589 (const char *)outbuf.data,
3590 outbuf.length);
3591 if (ea_list == NULL) {
3592 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3593 goto fail;
3596 /* Convert to an array. */
3597 for (eal = ea_list; eal; eal = eal->next) {
3598 ea_count++;
3601 if (ea_count) {
3602 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
3603 if (*pea_array == NULL) {
3604 status = NT_STATUS_NO_MEMORY;
3605 goto fail;
3607 ea_count = 0;
3608 for (eal = ea_list; eal; eal = eal->next) {
3609 (*pea_array)[ea_count++] = eal->ea;
3611 *pnum_eas = ea_count;
3614 fail:
3616 if (fnum != 0xffff) {
3617 cli_smb2_close_fnum(cli, fnum);
3620 cli->raw_status = status;
3622 TALLOC_FREE(frame);
3623 return status;
3626 /***************************************************************
3627 Wrapper that allows SMB2 to get user quota.
3628 Synchronous only.
3629 ***************************************************************/
3631 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
3632 int quota_fnum,
3633 SMB_NTQUOTA_STRUCT *pqt)
3635 NTSTATUS status;
3636 DATA_BLOB inbuf = data_blob_null;
3637 DATA_BLOB info_blob = data_blob_null;
3638 DATA_BLOB outbuf = data_blob_null;
3639 struct smb2_hnd *ph = NULL;
3640 TALLOC_CTX *frame = talloc_stackframe();
3641 unsigned sid_len;
3642 unsigned int offset;
3643 struct smb2_query_quota_info query = {0};
3644 struct file_get_quota_info info = {0};
3645 enum ndr_err_code err;
3646 struct ndr_push *ndr_push = NULL;
3648 if (smbXcli_conn_has_async_calls(cli->conn)) {
3650 * Can't use sync call while an async call is in flight
3652 status = NT_STATUS_INVALID_PARAMETER;
3653 goto fail;
3656 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3657 status = NT_STATUS_INVALID_PARAMETER;
3658 goto fail;
3661 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3662 if (!NT_STATUS_IS_OK(status)) {
3663 goto fail;
3666 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
3668 query.return_single = 1;
3670 info.next_entry_offset = 0;
3671 info.sid_length = sid_len;
3672 info.sid = pqt->sid;
3674 err = ndr_push_struct_blob(
3675 &info_blob,
3676 frame,
3677 &info,
3678 (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
3680 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3681 status = NT_STATUS_INTERNAL_ERROR;
3682 goto fail;
3685 query.sid_list_length = info_blob.length;
3686 ndr_push = ndr_push_init_ctx(frame);
3687 if (!ndr_push) {
3688 status = NT_STATUS_NO_MEMORY;
3689 goto fail;
3692 err = ndr_push_smb2_query_quota_info(ndr_push,
3693 NDR_SCALARS | NDR_BUFFERS,
3694 &query);
3696 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3697 status = NT_STATUS_INTERNAL_ERROR;
3698 goto fail;
3701 err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3702 info_blob.length);
3704 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3705 status = NT_STATUS_INTERNAL_ERROR;
3706 goto fail;
3708 inbuf.data = ndr_push->data;
3709 inbuf.length = ndr_push->offset;
3711 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
3712 cli->smb2.tcon, 4, /* in_info_type */
3713 0, /* in_file_info_class */
3714 0xFFFF, /* in_max_output_length */
3715 &inbuf, /* in_input_buffer */
3716 0, /* in_additional_info */
3717 0, /* in_flags */
3718 ph->fid_persistent, ph->fid_volatile, frame,
3719 &outbuf);
3721 if (!NT_STATUS_IS_OK(status)) {
3722 goto fail;
3725 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3726 pqt)) {
3727 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3728 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3731 fail:
3732 cli->raw_status = status;
3734 TALLOC_FREE(frame);
3735 return status;
3738 /***************************************************************
3739 Wrapper that allows SMB2 to list user quota.
3740 Synchronous only.
3741 ***************************************************************/
3743 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3744 TALLOC_CTX *mem_ctx,
3745 int quota_fnum,
3746 SMB_NTQUOTA_LIST **pqt_list,
3747 bool first)
3749 NTSTATUS status;
3750 DATA_BLOB inbuf = data_blob_null;
3751 DATA_BLOB outbuf = data_blob_null;
3752 struct smb2_hnd *ph = NULL;
3753 TALLOC_CTX *frame = talloc_stackframe();
3754 struct smb2_query_quota_info info = {0};
3755 enum ndr_err_code err;
3757 if (smbXcli_conn_has_async_calls(cli->conn)) {
3759 * Can't use sync call while an async call is in flight
3761 status = NT_STATUS_INVALID_PARAMETER;
3762 goto cleanup;
3765 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3766 status = NT_STATUS_INVALID_PARAMETER;
3767 goto cleanup;
3770 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3771 if (!NT_STATUS_IS_OK(status)) {
3772 goto cleanup;
3776 info.restart_scan = first ? 1 : 0;
3778 err = ndr_push_struct_blob(
3779 &inbuf,
3780 frame,
3781 &info,
3782 (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3784 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3785 status = NT_STATUS_INTERNAL_ERROR;
3786 goto cleanup;
3789 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
3790 cli->smb2.tcon, 4, /* in_info_type */
3791 0, /* in_file_info_class */
3792 0xFFFF, /* in_max_output_length */
3793 &inbuf, /* in_input_buffer */
3794 0, /* in_additional_info */
3795 0, /* in_flags */
3796 ph->fid_persistent, ph->fid_volatile, frame,
3797 &outbuf);
3800 * safeguard against panic from calling parse_user_quota_list with
3801 * NULL buffer
3803 if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3804 status = NT_STATUS_NO_MORE_ENTRIES;
3807 if (!NT_STATUS_IS_OK(status)) {
3808 goto cleanup;
3811 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3812 pqt_list);
3814 cleanup:
3815 cli->raw_status = status;
3817 TALLOC_FREE(frame);
3818 return status;
3821 /***************************************************************
3822 Wrapper that allows SMB2 to get file system quota.
3823 Synchronous only.
3824 ***************************************************************/
3826 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3827 int quota_fnum,
3828 SMB_NTQUOTA_STRUCT *pqt)
3830 NTSTATUS status;
3831 DATA_BLOB outbuf = data_blob_null;
3832 struct smb2_hnd *ph = NULL;
3833 TALLOC_CTX *frame = talloc_stackframe();
3835 if (smbXcli_conn_has_async_calls(cli->conn)) {
3837 * Can't use sync call while an async call is in flight
3839 status = NT_STATUS_INVALID_PARAMETER;
3840 goto cleanup;
3843 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3844 status = NT_STATUS_INVALID_PARAMETER;
3845 goto cleanup;
3848 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3849 if (!NT_STATUS_IS_OK(status)) {
3850 goto cleanup;
3853 status = smb2cli_query_info(
3854 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3855 2, /* in_info_type */
3856 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3857 0xFFFF, /* in_max_output_length */
3858 NULL, /* in_input_buffer */
3859 0, /* in_additional_info */
3860 0, /* in_flags */
3861 ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
3863 if (!NT_STATUS_IS_OK(status)) {
3864 goto cleanup;
3867 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3869 cleanup:
3870 cli->raw_status = status;
3872 TALLOC_FREE(frame);
3873 return status;
3876 /***************************************************************
3877 Wrapper that allows SMB2 to set user quota.
3878 Synchronous only.
3879 ***************************************************************/
3881 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3882 int quota_fnum,
3883 SMB_NTQUOTA_LIST *qtl)
3885 NTSTATUS status;
3886 DATA_BLOB inbuf = data_blob_null;
3887 struct smb2_hnd *ph = NULL;
3888 TALLOC_CTX *frame = talloc_stackframe();
3890 if (smbXcli_conn_has_async_calls(cli->conn)) {
3892 * Can't use sync call while an async call is in flight
3894 status = NT_STATUS_INVALID_PARAMETER;
3895 goto cleanup;
3898 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3899 status = NT_STATUS_INVALID_PARAMETER;
3900 goto cleanup;
3903 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3904 if (!NT_STATUS_IS_OK(status)) {
3905 goto cleanup;
3908 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3909 if (!NT_STATUS_IS_OK(status)) {
3910 goto cleanup;
3913 status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
3914 cli->smb2.tcon, 4, /* in_info_type */
3915 0, /* in_file_info_class */
3916 &inbuf, /* in_input_buffer */
3917 0, /* in_additional_info */
3918 ph->fid_persistent, ph->fid_volatile);
3919 cleanup:
3921 cli->raw_status = status;
3923 TALLOC_FREE(frame);
3925 return status;
3928 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3929 int quota_fnum,
3930 SMB_NTQUOTA_STRUCT *pqt)
3932 NTSTATUS status;
3933 DATA_BLOB inbuf = data_blob_null;
3934 struct smb2_hnd *ph = NULL;
3935 TALLOC_CTX *frame = talloc_stackframe();
3937 if (smbXcli_conn_has_async_calls(cli->conn)) {
3939 * Can't use sync call while an async call is in flight
3941 status = NT_STATUS_INVALID_PARAMETER;
3942 goto cleanup;
3945 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3946 status = NT_STATUS_INVALID_PARAMETER;
3947 goto cleanup;
3950 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3951 if (!NT_STATUS_IS_OK(status)) {
3952 goto cleanup;
3955 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3956 if (!NT_STATUS_IS_OK(status)) {
3957 goto cleanup;
3960 status = smb2cli_set_info(
3961 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3962 2, /* in_info_type */
3963 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3964 &inbuf, /* in_input_buffer */
3965 0, /* in_additional_info */
3966 ph->fid_persistent, ph->fid_volatile);
3967 cleanup:
3968 cli->raw_status = status;
3970 TALLOC_FREE(frame);
3971 return status;
3974 struct cli_smb2_read_state {
3975 struct tevent_context *ev;
3976 struct cli_state *cli;
3977 struct smb2_hnd *ph;
3978 uint64_t start_offset;
3979 uint32_t size;
3980 uint32_t received;
3981 uint8_t *buf;
3984 static void cli_smb2_read_done(struct tevent_req *subreq);
3986 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3987 struct tevent_context *ev,
3988 struct cli_state *cli,
3989 uint16_t fnum,
3990 off_t offset,
3991 size_t size)
3993 NTSTATUS status;
3994 struct tevent_req *req, *subreq;
3995 struct cli_smb2_read_state *state;
3997 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3998 if (req == NULL) {
3999 return NULL;
4001 state->ev = ev;
4002 state->cli = cli;
4003 state->start_offset = (uint64_t)offset;
4004 state->size = (uint32_t)size;
4005 state->received = 0;
4006 state->buf = NULL;
4008 status = map_fnum_to_smb2_handle(cli,
4009 fnum,
4010 &state->ph);
4011 if (tevent_req_nterror(req, status)) {
4012 return tevent_req_post(req, ev);
4015 subreq = smb2cli_read_send(state,
4016 state->ev,
4017 state->cli->conn,
4018 state->cli->timeout,
4019 state->cli->smb2.session,
4020 state->cli->smb2.tcon,
4021 state->size,
4022 state->start_offset,
4023 state->ph->fid_persistent,
4024 state->ph->fid_volatile,
4025 0, /* minimum_count */
4026 0); /* remaining_bytes */
4028 if (tevent_req_nomem(subreq, req)) {
4029 return tevent_req_post(req, ev);
4031 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
4032 return req;
4035 static void cli_smb2_read_done(struct tevent_req *subreq)
4037 struct tevent_req *req = tevent_req_callback_data(
4038 subreq, struct tevent_req);
4039 struct cli_smb2_read_state *state = tevent_req_data(
4040 req, struct cli_smb2_read_state);
4041 NTSTATUS status;
4043 status = smb2cli_read_recv(subreq, state,
4044 &state->buf, &state->received);
4045 if (tevent_req_nterror(req, status)) {
4046 return;
4049 if (state->received > state->size) {
4050 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4051 return;
4054 tevent_req_done(req);
4057 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
4058 ssize_t *received,
4059 uint8_t **rcvbuf)
4061 NTSTATUS status;
4062 struct cli_smb2_read_state *state = tevent_req_data(
4063 req, struct cli_smb2_read_state);
4065 if (tevent_req_is_nterror(req, &status)) {
4066 state->cli->raw_status = status;
4067 return status;
4070 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
4071 * better make sure that you copy it away before you talloc_free(req).
4072 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
4074 *received = (ssize_t)state->received;
4075 *rcvbuf = state->buf;
4076 state->cli->raw_status = NT_STATUS_OK;
4077 return NT_STATUS_OK;
4080 struct cli_smb2_write_state {
4081 struct tevent_context *ev;
4082 struct cli_state *cli;
4083 struct smb2_hnd *ph;
4084 uint32_t flags;
4085 const uint8_t *buf;
4086 uint64_t offset;
4087 uint32_t size;
4088 uint32_t written;
4091 static void cli_smb2_write_written(struct tevent_req *req);
4093 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
4094 struct tevent_context *ev,
4095 struct cli_state *cli,
4096 uint16_t fnum,
4097 uint16_t mode,
4098 const uint8_t *buf,
4099 off_t offset,
4100 size_t size)
4102 NTSTATUS status;
4103 struct tevent_req *req, *subreq = NULL;
4104 struct cli_smb2_write_state *state = NULL;
4106 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
4107 if (req == NULL) {
4108 return NULL;
4110 state->ev = ev;
4111 state->cli = cli;
4112 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4113 state->flags = (uint32_t)mode;
4114 state->buf = buf;
4115 state->offset = (uint64_t)offset;
4116 state->size = (uint32_t)size;
4117 state->written = 0;
4119 status = map_fnum_to_smb2_handle(cli,
4120 fnum,
4121 &state->ph);
4122 if (tevent_req_nterror(req, status)) {
4123 return tevent_req_post(req, ev);
4126 subreq = smb2cli_write_send(state,
4127 state->ev,
4128 state->cli->conn,
4129 state->cli->timeout,
4130 state->cli->smb2.session,
4131 state->cli->smb2.tcon,
4132 state->size,
4133 state->offset,
4134 state->ph->fid_persistent,
4135 state->ph->fid_volatile,
4136 0, /* remaining_bytes */
4137 state->flags, /* flags */
4138 state->buf);
4140 if (tevent_req_nomem(subreq, req)) {
4141 return tevent_req_post(req, ev);
4143 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
4144 return req;
4147 static void cli_smb2_write_written(struct tevent_req *subreq)
4149 struct tevent_req *req = tevent_req_callback_data(
4150 subreq, struct tevent_req);
4151 struct cli_smb2_write_state *state = tevent_req_data(
4152 req, struct cli_smb2_write_state);
4153 NTSTATUS status;
4154 uint32_t written;
4156 status = smb2cli_write_recv(subreq, &written);
4157 TALLOC_FREE(subreq);
4158 if (tevent_req_nterror(req, status)) {
4159 return;
4162 state->written = written;
4164 tevent_req_done(req);
4167 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
4168 size_t *pwritten)
4170 struct cli_smb2_write_state *state = tevent_req_data(
4171 req, struct cli_smb2_write_state);
4172 NTSTATUS status;
4174 if (tevent_req_is_nterror(req, &status)) {
4175 state->cli->raw_status = status;
4176 tevent_req_received(req);
4177 return status;
4180 if (pwritten != NULL) {
4181 *pwritten = (size_t)state->written;
4183 state->cli->raw_status = NT_STATUS_OK;
4184 tevent_req_received(req);
4185 return NT_STATUS_OK;
4188 /***************************************************************
4189 Wrapper that allows SMB2 async write using an fnum.
4190 This is mostly cut-and-paste from Volker's code inside
4191 source3/libsmb/clireadwrite.c, adapted for SMB2.
4193 Done this way so I can reuse all the logic inside cli_push()
4194 for free :-).
4195 ***************************************************************/
4197 struct cli_smb2_writeall_state {
4198 struct tevent_context *ev;
4199 struct cli_state *cli;
4200 struct smb2_hnd *ph;
4201 uint32_t flags;
4202 const uint8_t *buf;
4203 uint64_t offset;
4204 uint32_t size;
4205 uint32_t written;
4208 static void cli_smb2_writeall_written(struct tevent_req *req);
4210 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
4211 struct tevent_context *ev,
4212 struct cli_state *cli,
4213 uint16_t fnum,
4214 uint16_t mode,
4215 const uint8_t *buf,
4216 off_t offset,
4217 size_t size)
4219 NTSTATUS status;
4220 struct tevent_req *req, *subreq = NULL;
4221 struct cli_smb2_writeall_state *state = NULL;
4222 uint32_t to_write;
4223 uint32_t max_size;
4224 bool ok;
4226 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
4227 if (req == NULL) {
4228 return NULL;
4230 state->ev = ev;
4231 state->cli = cli;
4232 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4233 state->flags = (uint32_t)mode;
4234 state->buf = buf;
4235 state->offset = (uint64_t)offset;
4236 state->size = (uint32_t)size;
4237 state->written = 0;
4239 status = map_fnum_to_smb2_handle(cli,
4240 fnum,
4241 &state->ph);
4242 if (tevent_req_nterror(req, status)) {
4243 return tevent_req_post(req, ev);
4246 to_write = state->size;
4247 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4248 to_write = MIN(max_size, to_write);
4249 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4250 if (ok) {
4251 to_write = MIN(max_size, to_write);
4254 subreq = smb2cli_write_send(state,
4255 state->ev,
4256 state->cli->conn,
4257 state->cli->timeout,
4258 state->cli->smb2.session,
4259 state->cli->smb2.tcon,
4260 to_write,
4261 state->offset,
4262 state->ph->fid_persistent,
4263 state->ph->fid_volatile,
4264 0, /* remaining_bytes */
4265 state->flags, /* flags */
4266 state->buf + state->written);
4268 if (tevent_req_nomem(subreq, req)) {
4269 return tevent_req_post(req, ev);
4271 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4272 return req;
4275 static void cli_smb2_writeall_written(struct tevent_req *subreq)
4277 struct tevent_req *req = tevent_req_callback_data(
4278 subreq, struct tevent_req);
4279 struct cli_smb2_writeall_state *state = tevent_req_data(
4280 req, struct cli_smb2_writeall_state);
4281 NTSTATUS status;
4282 uint32_t written, to_write;
4283 uint32_t max_size;
4284 bool ok;
4286 status = smb2cli_write_recv(subreq, &written);
4287 TALLOC_FREE(subreq);
4288 if (tevent_req_nterror(req, status)) {
4289 return;
4292 state->written += written;
4294 if (state->written > state->size) {
4295 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4296 return;
4299 to_write = state->size - state->written;
4301 if (to_write == 0) {
4302 tevent_req_done(req);
4303 return;
4306 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4307 to_write = MIN(max_size, to_write);
4308 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4309 if (ok) {
4310 to_write = MIN(max_size, to_write);
4313 subreq = smb2cli_write_send(state,
4314 state->ev,
4315 state->cli->conn,
4316 state->cli->timeout,
4317 state->cli->smb2.session,
4318 state->cli->smb2.tcon,
4319 to_write,
4320 state->offset + state->written,
4321 state->ph->fid_persistent,
4322 state->ph->fid_volatile,
4323 0, /* remaining_bytes */
4324 state->flags, /* flags */
4325 state->buf + state->written);
4327 if (tevent_req_nomem(subreq, req)) {
4328 return;
4330 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4333 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
4334 size_t *pwritten)
4336 struct cli_smb2_writeall_state *state = tevent_req_data(
4337 req, struct cli_smb2_writeall_state);
4338 NTSTATUS status;
4340 if (tevent_req_is_nterror(req, &status)) {
4341 state->cli->raw_status = status;
4342 return status;
4344 if (pwritten != NULL) {
4345 *pwritten = (size_t)state->written;
4347 state->cli->raw_status = NT_STATUS_OK;
4348 return NT_STATUS_OK;
4351 struct cli_smb2_splice_state {
4352 struct tevent_context *ev;
4353 struct cli_state *cli;
4354 struct smb2_hnd *src_ph;
4355 struct smb2_hnd *dst_ph;
4356 int (*splice_cb)(off_t n, void *priv);
4357 void *priv;
4358 off_t written;
4359 off_t size;
4360 off_t src_offset;
4361 off_t dst_offset;
4362 bool resized;
4363 struct req_resume_key_rsp resume_rsp;
4364 struct srv_copychunk_copy cc_copy;
4367 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4368 struct tevent_req *req);
4370 static void cli_splice_copychunk_done(struct tevent_req *subreq)
4372 struct tevent_req *req = tevent_req_callback_data(
4373 subreq, struct tevent_req);
4374 struct cli_smb2_splice_state *state =
4375 tevent_req_data(req,
4376 struct cli_smb2_splice_state);
4377 struct smbXcli_conn *conn = state->cli->conn;
4378 DATA_BLOB out_input_buffer = data_blob_null;
4379 DATA_BLOB out_output_buffer = data_blob_null;
4380 struct srv_copychunk_rsp cc_copy_rsp;
4381 enum ndr_err_code ndr_ret;
4382 NTSTATUS status;
4384 status = smb2cli_ioctl_recv(subreq, state,
4385 &out_input_buffer,
4386 &out_output_buffer);
4387 TALLOC_FREE(subreq);
4388 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
4389 state->resized) && tevent_req_nterror(req, status)) {
4390 return;
4393 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
4394 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
4395 if (ndr_ret != NDR_ERR_SUCCESS) {
4396 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4397 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4398 return;
4401 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
4402 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
4403 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
4404 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
4405 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
4406 tevent_req_nterror(req, status)) {
4407 return;
4410 state->resized = true;
4411 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
4412 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
4413 } else {
4414 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4415 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4416 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
4417 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4418 return;
4420 state->src_offset += cc_copy_rsp.total_bytes_written;
4421 state->dst_offset += cc_copy_rsp.total_bytes_written;
4422 state->written += cc_copy_rsp.total_bytes_written;
4423 if (!state->splice_cb(state->written, state->priv)) {
4424 tevent_req_nterror(req, NT_STATUS_CANCELLED);
4425 return;
4429 cli_splice_copychunk_send(state, req);
4432 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4433 struct tevent_req *req)
4435 struct tevent_req *subreq;
4436 enum ndr_err_code ndr_ret;
4437 struct smbXcli_conn *conn = state->cli->conn;
4438 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
4439 off_t src_offset = state->src_offset;
4440 off_t dst_offset = state->dst_offset;
4441 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
4442 state->size - state->written);
4443 DATA_BLOB in_input_buffer = data_blob_null;
4444 DATA_BLOB in_output_buffer = data_blob_null;
4446 if (state->size - state->written == 0) {
4447 tevent_req_done(req);
4448 return;
4451 cc_copy->chunk_count = 0;
4452 while (req_len) {
4453 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
4454 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
4455 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
4456 smb2cli_conn_cc_chunk_len(conn));
4457 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
4458 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4459 return;
4461 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
4462 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
4463 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
4464 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4465 return;
4467 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4468 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4469 cc_copy->chunk_count++;
4472 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
4473 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
4474 if (ndr_ret != NDR_ERR_SUCCESS) {
4475 DEBUG(0, ("failed to marshall copy chunk req\n"));
4476 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4477 return;
4480 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
4481 state->cli->timeout,
4482 state->cli->smb2.session,
4483 state->cli->smb2.tcon,
4484 state->dst_ph->fid_persistent, /* in_fid_persistent */
4485 state->dst_ph->fid_volatile, /* in_fid_volatile */
4486 FSCTL_SRV_COPYCHUNK_WRITE,
4487 0, /* in_max_input_length */
4488 &in_input_buffer,
4489 12, /* in_max_output_length */
4490 &in_output_buffer,
4491 SMB2_IOCTL_FLAG_IS_FSCTL);
4492 if (tevent_req_nomem(subreq, req)) {
4493 return;
4495 tevent_req_set_callback(subreq,
4496 cli_splice_copychunk_done,
4497 req);
4500 static void cli_splice_key_done(struct tevent_req *subreq)
4502 struct tevent_req *req = tevent_req_callback_data(
4503 subreq, struct tevent_req);
4504 struct cli_smb2_splice_state *state =
4505 tevent_req_data(req,
4506 struct cli_smb2_splice_state);
4507 enum ndr_err_code ndr_ret;
4508 NTSTATUS status;
4510 DATA_BLOB out_input_buffer = data_blob_null;
4511 DATA_BLOB out_output_buffer = data_blob_null;
4513 status = smb2cli_ioctl_recv(subreq, state,
4514 &out_input_buffer,
4515 &out_output_buffer);
4516 TALLOC_FREE(subreq);
4517 if (tevent_req_nterror(req, status)) {
4518 return;
4521 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
4522 state, &state->resume_rsp,
4523 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
4524 if (ndr_ret != NDR_ERR_SUCCESS) {
4525 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4526 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4527 return;
4530 memcpy(&state->cc_copy.source_key,
4531 &state->resume_rsp.resume_key,
4532 sizeof state->resume_rsp.resume_key);
4534 cli_splice_copychunk_send(state, req);
4537 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
4538 struct tevent_context *ev,
4539 struct cli_state *cli,
4540 uint16_t src_fnum, uint16_t dst_fnum,
4541 off_t size, off_t src_offset, off_t dst_offset,
4542 int (*splice_cb)(off_t n, void *priv),
4543 void *priv)
4545 struct tevent_req *req;
4546 struct tevent_req *subreq;
4547 struct cli_smb2_splice_state *state;
4548 NTSTATUS status;
4549 DATA_BLOB in_input_buffer = data_blob_null;
4550 DATA_BLOB in_output_buffer = data_blob_null;
4552 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
4553 if (req == NULL) {
4554 return NULL;
4556 state->cli = cli;
4557 state->ev = ev;
4558 state->splice_cb = splice_cb;
4559 state->priv = priv;
4560 state->size = size;
4561 state->written = 0;
4562 state->src_offset = src_offset;
4563 state->dst_offset = dst_offset;
4564 state->cc_copy.chunks = talloc_array(state,
4565 struct srv_copychunk,
4566 smb2cli_conn_cc_max_chunks(cli->conn));
4567 if (state->cc_copy.chunks == NULL) {
4568 return NULL;
4571 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
4572 if (tevent_req_nterror(req, status))
4573 return tevent_req_post(req, ev);
4575 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
4576 if (tevent_req_nterror(req, status))
4577 return tevent_req_post(req, ev);
4579 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
4580 cli->timeout,
4581 cli->smb2.session,
4582 cli->smb2.tcon,
4583 state->src_ph->fid_persistent, /* in_fid_persistent */
4584 state->src_ph->fid_volatile, /* in_fid_volatile */
4585 FSCTL_SRV_REQUEST_RESUME_KEY,
4586 0, /* in_max_input_length */
4587 &in_input_buffer,
4588 32, /* in_max_output_length */
4589 &in_output_buffer,
4590 SMB2_IOCTL_FLAG_IS_FSCTL);
4591 if (tevent_req_nomem(subreq, req)) {
4592 return NULL;
4594 tevent_req_set_callback(subreq,
4595 cli_splice_key_done,
4596 req);
4598 return req;
4601 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
4603 struct cli_smb2_splice_state *state = tevent_req_data(
4604 req, struct cli_smb2_splice_state);
4605 NTSTATUS status;
4607 if (tevent_req_is_nterror(req, &status)) {
4608 state->cli->raw_status = status;
4609 tevent_req_received(req);
4610 return status;
4612 if (written != NULL) {
4613 *written = state->written;
4615 state->cli->raw_status = NT_STATUS_OK;
4616 tevent_req_received(req);
4617 return NT_STATUS_OK;
4620 /***************************************************************
4621 SMB2 enum shadow copy data.
4622 ***************************************************************/
4624 struct cli_smb2_shadow_copy_data_fnum_state {
4625 struct cli_state *cli;
4626 uint16_t fnum;
4627 struct smb2_hnd *ph;
4628 DATA_BLOB out_input_buffer;
4629 DATA_BLOB out_output_buffer;
4632 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
4634 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
4635 TALLOC_CTX *mem_ctx,
4636 struct tevent_context *ev,
4637 struct cli_state *cli,
4638 uint16_t fnum,
4639 bool get_names)
4641 struct tevent_req *req, *subreq;
4642 struct cli_smb2_shadow_copy_data_fnum_state *state;
4643 NTSTATUS status;
4645 req = tevent_req_create(mem_ctx, &state,
4646 struct cli_smb2_shadow_copy_data_fnum_state);
4647 if (req == NULL) {
4648 return NULL;
4651 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4652 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4653 return tevent_req_post(req, ev);
4656 state->cli = cli;
4657 state->fnum = fnum;
4659 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4660 if (tevent_req_nterror(req, status)) {
4661 return tevent_req_post(req, ev);
4665 * TODO. Under SMB2 we should send a zero max_output_length
4666 * ioctl to get the required size, then send another ioctl
4667 * to get the data, but the current SMB1 implementation just
4668 * does one roundtrip with a 64K buffer size. Do the same
4669 * for now. JRA.
4672 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4673 state->cli->timeout,
4674 state->cli->smb2.session,
4675 state->cli->smb2.tcon,
4676 state->ph->fid_persistent, /* in_fid_persistent */
4677 state->ph->fid_volatile, /* in_fid_volatile */
4678 FSCTL_GET_SHADOW_COPY_DATA,
4679 0, /* in_max_input_length */
4680 NULL, /* in_input_buffer */
4681 get_names ?
4682 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
4683 NULL, /* in_output_buffer */
4684 SMB2_IOCTL_FLAG_IS_FSCTL);
4686 if (tevent_req_nomem(subreq, req)) {
4687 return tevent_req_post(req, ev);
4689 tevent_req_set_callback(subreq,
4690 cli_smb2_shadow_copy_data_fnum_done,
4691 req);
4693 return req;
4696 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4698 struct tevent_req *req = tevent_req_callback_data(
4699 subreq, struct tevent_req);
4700 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4701 req, struct cli_smb2_shadow_copy_data_fnum_state);
4702 NTSTATUS status;
4704 status = smb2cli_ioctl_recv(subreq, state,
4705 &state->out_input_buffer,
4706 &state->out_output_buffer);
4707 tevent_req_simple_finish_ntstatus(subreq, status);
4710 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4711 TALLOC_CTX *mem_ctx,
4712 bool get_names,
4713 char ***pnames,
4714 int *pnum_names)
4716 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4717 req, struct cli_smb2_shadow_copy_data_fnum_state);
4718 char **names = NULL;
4719 uint32_t num_names = 0;
4720 uint32_t num_names_returned = 0;
4721 uint32_t dlength = 0;
4722 uint32_t i;
4723 uint8_t *endp = NULL;
4724 NTSTATUS status;
4726 if (tevent_req_is_nterror(req, &status)) {
4727 return status;
4730 if (state->out_output_buffer.length < 16) {
4731 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4734 num_names = IVAL(state->out_output_buffer.data, 0);
4735 num_names_returned = IVAL(state->out_output_buffer.data, 4);
4736 dlength = IVAL(state->out_output_buffer.data, 8);
4738 if (num_names > 0x7FFFFFFF) {
4739 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4742 if (get_names == false) {
4743 *pnum_names = (int)num_names;
4744 return NT_STATUS_OK;
4746 if (num_names != num_names_returned) {
4747 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4749 if (dlength + 12 < 12) {
4750 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4753 * NB. The below is an allowable return if there are
4754 * more snapshots than the buffer size we told the
4755 * server we can receive. We currently don't support
4756 * this.
4758 if (dlength + 12 > state->out_output_buffer.length) {
4759 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4761 if (state->out_output_buffer.length +
4762 (2 * sizeof(SHADOW_COPY_LABEL)) <
4763 state->out_output_buffer.length) {
4764 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4767 names = talloc_array(mem_ctx, char *, num_names_returned);
4768 if (names == NULL) {
4769 return NT_STATUS_NO_MEMORY;
4772 endp = state->out_output_buffer.data +
4773 state->out_output_buffer.length;
4775 for (i=0; i<num_names_returned; i++) {
4776 bool ret;
4777 uint8_t *src;
4778 size_t converted_size;
4780 src = state->out_output_buffer.data + 12 +
4781 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4783 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4784 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4786 ret = convert_string_talloc(
4787 names, CH_UTF16LE, CH_UNIX,
4788 src, 2 * sizeof(SHADOW_COPY_LABEL),
4789 &names[i], &converted_size);
4790 if (!ret) {
4791 TALLOC_FREE(names);
4792 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4795 *pnum_names = num_names;
4796 *pnames = names;
4797 return NT_STATUS_OK;
4800 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4801 struct cli_state *cli,
4802 uint16_t fnum,
4803 bool get_names,
4804 char ***pnames,
4805 int *pnum_names)
4807 TALLOC_CTX *frame = talloc_stackframe();
4808 struct tevent_context *ev;
4809 struct tevent_req *req;
4810 NTSTATUS status = NT_STATUS_NO_MEMORY;
4812 if (smbXcli_conn_has_async_calls(cli->conn)) {
4814 * Can't use sync call while an async call is in flight
4816 status = NT_STATUS_INVALID_PARAMETER;
4817 goto fail;
4819 ev = samba_tevent_context_init(frame);
4820 if (ev == NULL) {
4821 goto fail;
4823 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4825 cli,
4826 fnum,
4827 get_names);
4828 if (req == NULL) {
4829 goto fail;
4831 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4832 goto fail;
4834 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4835 mem_ctx,
4836 get_names,
4837 pnames,
4838 pnum_names);
4839 fail:
4840 cli->raw_status = status;
4842 TALLOC_FREE(frame);
4843 return status;
4846 /***************************************************************
4847 Wrapper that allows SMB2 to truncate a file.
4848 Synchronous only.
4849 ***************************************************************/
4851 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4852 uint16_t fnum,
4853 uint64_t newsize)
4855 NTSTATUS status;
4856 DATA_BLOB inbuf = data_blob_null;
4857 struct smb2_hnd *ph = NULL;
4858 TALLOC_CTX *frame = talloc_stackframe();
4860 if (smbXcli_conn_has_async_calls(cli->conn)) {
4862 * Can't use sync call while an async call is in flight
4864 status = NT_STATUS_INVALID_PARAMETER;
4865 goto fail;
4868 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4869 status = NT_STATUS_INVALID_PARAMETER;
4870 goto fail;
4873 status = map_fnum_to_smb2_handle(cli,
4874 fnum,
4875 &ph);
4876 if (!NT_STATUS_IS_OK(status)) {
4877 goto fail;
4880 inbuf = data_blob_talloc_zero(frame, 8);
4881 if (inbuf.data == NULL) {
4882 status = NT_STATUS_NO_MEMORY;
4883 goto fail;
4886 SBVAL(inbuf.data, 0, newsize);
4888 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4889 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4891 status = smb2cli_set_info(cli->conn,
4892 cli->timeout,
4893 cli->smb2.session,
4894 cli->smb2.tcon,
4895 1, /* in_info_type */
4896 /* in_file_info_class */
4897 SMB_FILE_END_OF_FILE_INFORMATION - 1000,
4898 &inbuf, /* in_input_buffer */
4899 0, /* in_additional_info */
4900 ph->fid_persistent,
4901 ph->fid_volatile);
4903 fail:
4905 cli->raw_status = status;
4907 TALLOC_FREE(frame);
4908 return status;
4911 struct cli_smb2_notify_state {
4912 struct tevent_req *subreq;
4913 struct notify_change *changes;
4914 size_t num_changes;
4917 static void cli_smb2_notify_done(struct tevent_req *subreq);
4918 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4920 struct tevent_req *cli_smb2_notify_send(
4921 TALLOC_CTX *mem_ctx,
4922 struct tevent_context *ev,
4923 struct cli_state *cli,
4924 uint16_t fnum,
4925 uint32_t buffer_size,
4926 uint32_t completion_filter,
4927 bool recursive)
4929 struct tevent_req *req = NULL;
4930 struct cli_smb2_notify_state *state = NULL;
4931 struct smb2_hnd *ph = NULL;
4932 NTSTATUS status;
4934 req = tevent_req_create(mem_ctx, &state,
4935 struct cli_smb2_notify_state);
4936 if (req == NULL) {
4937 return NULL;
4940 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4941 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4942 return tevent_req_post(req, ev);
4945 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4946 if (tevent_req_nterror(req, status)) {
4947 return tevent_req_post(req, ev);
4950 state->subreq = smb2cli_notify_send(
4951 state,
4953 cli->conn,
4954 cli->timeout,
4955 cli->smb2.session,
4956 cli->smb2.tcon,
4957 buffer_size,
4958 ph->fid_persistent,
4959 ph->fid_volatile,
4960 completion_filter,
4961 recursive);
4962 if (tevent_req_nomem(state->subreq, req)) {
4963 return tevent_req_post(req, ev);
4965 tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4966 tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4967 return req;
4970 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4972 struct cli_smb2_notify_state *state = tevent_req_data(
4973 req, struct cli_smb2_notify_state);
4974 bool ok;
4976 ok = tevent_req_cancel(state->subreq);
4977 return ok;
4980 static void cli_smb2_notify_done(struct tevent_req *subreq)
4982 struct tevent_req *req = tevent_req_callback_data(
4983 subreq, struct tevent_req);
4984 struct cli_smb2_notify_state *state = tevent_req_data(
4985 req, struct cli_smb2_notify_state);
4986 uint8_t *base;
4987 uint32_t len;
4988 uint32_t ofs;
4989 NTSTATUS status;
4991 status = smb2cli_notify_recv(subreq, state, &base, &len);
4992 TALLOC_FREE(subreq);
4994 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4995 tevent_req_done(req);
4996 return;
4998 if (tevent_req_nterror(req, status)) {
4999 return;
5002 ofs = 0;
5004 while (len - ofs >= 12) {
5005 struct notify_change *tmp;
5006 struct notify_change *c;
5007 uint32_t next_ofs = IVAL(base, ofs);
5008 uint32_t file_name_length = IVAL(base, ofs+8);
5009 size_t namelen;
5010 bool ok;
5012 tmp = talloc_realloc(
5013 state,
5014 state->changes,
5015 struct notify_change,
5016 state->num_changes + 1);
5017 if (tevent_req_nomem(tmp, req)) {
5018 return;
5020 state->changes = tmp;
5021 c = &state->changes[state->num_changes];
5022 state->num_changes += 1;
5024 if (smb_buffer_oob(len, ofs, next_ofs) ||
5025 smb_buffer_oob(len, ofs+12, file_name_length)) {
5026 tevent_req_nterror(
5027 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
5028 return;
5031 c->action = IVAL(base, ofs+4);
5033 ok = convert_string_talloc(
5034 state->changes,
5035 CH_UTF16LE,
5036 CH_UNIX,
5037 base + ofs + 12,
5038 file_name_length,
5039 &c->name,
5040 &namelen);
5041 if (!ok) {
5042 tevent_req_nterror(
5043 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
5044 return;
5047 if (next_ofs == 0) {
5048 break;
5050 ofs += next_ofs;
5053 tevent_req_done(req);
5056 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
5057 TALLOC_CTX *mem_ctx,
5058 struct notify_change **pchanges,
5059 uint32_t *pnum_changes)
5061 struct cli_smb2_notify_state *state = tevent_req_data(
5062 req, struct cli_smb2_notify_state);
5063 NTSTATUS status;
5065 if (tevent_req_is_nterror(req, &status)) {
5066 return status;
5068 *pchanges = talloc_move(mem_ctx, &state->changes);
5069 *pnum_changes = state->num_changes;
5070 return NT_STATUS_OK;
5073 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
5074 uint32_t buffer_size, uint32_t completion_filter,
5075 bool recursive, TALLOC_CTX *mem_ctx,
5076 struct notify_change **pchanges,
5077 uint32_t *pnum_changes)
5079 TALLOC_CTX *frame = talloc_stackframe();
5080 struct tevent_context *ev;
5081 struct tevent_req *req;
5082 NTSTATUS status = NT_STATUS_NO_MEMORY;
5084 if (smbXcli_conn_has_async_calls(cli->conn)) {
5086 * Can't use sync call while an async call is in flight
5088 status = NT_STATUS_INVALID_PARAMETER;
5089 goto fail;
5091 ev = samba_tevent_context_init(frame);
5092 if (ev == NULL) {
5093 goto fail;
5095 req = cli_smb2_notify_send(
5096 frame,
5098 cli,
5099 fnum,
5100 buffer_size,
5101 completion_filter,
5102 recursive);
5103 if (req == NULL) {
5104 goto fail;
5106 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5107 goto fail;
5109 status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
5110 fail:
5111 TALLOC_FREE(frame);
5112 return status;
5115 struct cli_smb2_set_reparse_point_fnum_state {
5116 struct cli_state *cli;
5117 uint16_t fnum;
5118 struct smb2_hnd *ph;
5119 DATA_BLOB input_buffer;
5122 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
5124 struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
5125 TALLOC_CTX *mem_ctx,
5126 struct tevent_context *ev,
5127 struct cli_state *cli,
5128 uint16_t fnum,
5129 DATA_BLOB in_buf)
5131 struct tevent_req *req, *subreq;
5132 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
5133 NTSTATUS status;
5135 req = tevent_req_create(mem_ctx, &state,
5136 struct cli_smb2_set_reparse_point_fnum_state);
5137 if (req == NULL) {
5138 return NULL;
5141 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5142 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
5143 return tevent_req_post(req, ev);
5146 state->cli = cli;
5147 state->fnum = fnum;
5149 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
5150 if (tevent_req_nterror(req, status)) {
5151 return tevent_req_post(req, ev);
5154 state->input_buffer = data_blob_talloc(state,
5155 in_buf.data,
5156 in_buf.length);
5157 if (state->input_buffer.data == NULL) {
5158 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
5159 return tevent_req_post(req, ev);
5162 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
5163 state->cli->timeout,
5164 state->cli->smb2.session,
5165 state->cli->smb2.tcon,
5166 state->ph->fid_persistent, /* in_fid_persistent */
5167 state->ph->fid_volatile, /* in_fid_volatile */
5168 FSCTL_SET_REPARSE_POINT,
5169 0, /* in_max_input_length */
5170 &state->input_buffer ,
5172 NULL,
5173 SMB2_IOCTL_FLAG_IS_FSCTL);
5175 if (tevent_req_nomem(subreq, req)) {
5176 return tevent_req_post(req, ev);
5178 tevent_req_set_callback(subreq,
5179 cli_smb2_set_reparse_point_fnum_done,
5180 req);
5182 return req;
5185 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
5187 struct tevent_req *req = tevent_req_callback_data(
5188 subreq, struct tevent_req);
5189 struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
5190 req, struct cli_smb2_set_reparse_point_fnum_state);
5191 NTSTATUS status;
5193 status = smb2cli_ioctl_recv(subreq, state,
5194 NULL,
5195 NULL);
5196 TALLOC_FREE(subreq);
5197 if (tevent_req_nterror(req, status)) {
5198 return;
5200 tevent_req_done(req);
5203 NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
5205 return tevent_req_simple_recv_ntstatus(req);
5208 struct cli_smb2_get_reparse_point_fnum_state {
5209 struct cli_state *cli;
5210 uint16_t fnum;
5211 struct smb2_hnd *ph;
5212 DATA_BLOB output_buffer;
5215 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
5217 struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
5218 TALLOC_CTX *mem_ctx,
5219 struct tevent_context *ev,
5220 struct cli_state *cli,
5221 uint16_t fnum)
5223 struct tevent_req *req, *subreq;
5224 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
5225 NTSTATUS status;
5227 req = tevent_req_create(mem_ctx, &state,
5228 struct cli_smb2_get_reparse_point_fnum_state);
5229 if (req == NULL) {
5230 return NULL;
5233 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5234 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
5235 return tevent_req_post(req, ev);
5238 state->cli = cli;
5239 state->fnum = fnum;
5241 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
5242 if (tevent_req_nterror(req, status)) {
5243 return tevent_req_post(req, ev);
5246 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
5247 state->cli->timeout,
5248 state->cli->smb2.session,
5249 state->cli->smb2.tcon,
5250 state->ph->fid_persistent, /* in_fid_persistent */
5251 state->ph->fid_volatile, /* in_fid_volatile */
5252 FSCTL_GET_REPARSE_POINT,
5253 0, /* in_max_input_length */
5254 NULL,
5255 64*1024,
5256 NULL,
5257 SMB2_IOCTL_FLAG_IS_FSCTL);
5259 if (tevent_req_nomem(subreq, req)) {
5260 return tevent_req_post(req, ev);
5262 tevent_req_set_callback(subreq,
5263 cli_smb2_get_reparse_point_fnum_done,
5264 req);
5266 return req;
5269 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
5271 struct tevent_req *req = tevent_req_callback_data(
5272 subreq, struct tevent_req);
5273 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
5274 req, struct cli_smb2_get_reparse_point_fnum_state);
5275 NTSTATUS status;
5277 status = smb2cli_ioctl_recv(subreq, state,
5278 NULL,
5279 &state->output_buffer);
5280 TALLOC_FREE(subreq);
5281 if (tevent_req_nterror(req, status)) {
5282 state->cli->raw_status = status;
5283 return;
5285 tevent_req_done(req);
5288 NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
5289 TALLOC_CTX *mem_ctx,
5290 DATA_BLOB *output)
5292 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
5293 req, struct cli_smb2_get_reparse_point_fnum_state);
5295 if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
5296 tevent_req_received(req);
5297 return state->cli->raw_status;
5299 *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
5300 if (output->data == NULL) {
5301 tevent_req_received(req);
5302 return NT_STATUS_NO_MEMORY;
5304 tevent_req_received(req);
5305 return NT_STATUS_OK;