s4:kdc: strictly have 2 16-bit parts in krbtgt kvnos
[Samba.git] / source3 / libsmb / cli_smb2_fnum.c
blob13d23ed6566418f8ab9d2f85983ae21926eeb162
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"
45 #include "lib/util/string_wrappers.h"
47 struct smb2_hnd {
48 uint64_t fid_persistent;
49 uint64_t fid_volatile;
53 * Handle mapping code.
56 /***************************************************************
57 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
58 Ensures handle is owned by cli struct.
59 ***************************************************************/
61 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
62 const struct smb2_hnd *ph, /* In */
63 uint16_t *pfnum) /* Out */
65 int ret;
66 struct idr_context *idp = cli->smb2.open_handles;
67 struct smb2_hnd *owned_h = talloc_memdup(cli,
68 ph,
69 sizeof(struct smb2_hnd));
71 if (owned_h == NULL) {
72 return NT_STATUS_NO_MEMORY;
75 if (idp == NULL) {
76 /* Lazy init */
77 cli->smb2.open_handles = idr_init(cli);
78 if (cli->smb2.open_handles == NULL) {
79 TALLOC_FREE(owned_h);
80 return NT_STATUS_NO_MEMORY;
82 idp = cli->smb2.open_handles;
85 ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
86 if (ret == -1) {
87 TALLOC_FREE(owned_h);
88 return NT_STATUS_NO_MEMORY;
91 *pfnum = (uint16_t)ret;
92 return NT_STATUS_OK;
95 /***************************************************************
96 Return the smb2_hnd pointer associated with the given fnum.
97 ***************************************************************/
99 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
100 uint16_t fnum, /* In */
101 struct smb2_hnd **pph) /* Out */
103 struct idr_context *idp = cli->smb2.open_handles;
105 if (idp == NULL) {
106 return NT_STATUS_INVALID_PARAMETER;
108 *pph = (struct smb2_hnd *)idr_find(idp, fnum);
109 if (*pph == NULL) {
110 return NT_STATUS_INVALID_HANDLE;
112 return NT_STATUS_OK;
115 /***************************************************************
116 Delete the fnum to smb2_hnd mapping. Zeros out handle on
117 successful return.
118 ***************************************************************/
120 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
121 struct smb2_hnd **pph, /* In */
122 uint16_t fnum) /* In */
124 struct idr_context *idp = cli->smb2.open_handles;
125 struct smb2_hnd *ph;
127 if (idp == NULL) {
128 return NT_STATUS_INVALID_PARAMETER;
131 ph = (struct smb2_hnd *)idr_find(idp, fnum);
132 if (ph != *pph) {
133 return NT_STATUS_INVALID_PARAMETER;
135 idr_remove(idp, fnum);
136 TALLOC_FREE(*pph);
137 return NT_STATUS_OK;
140 /***************************************************************
141 Oplock mapping code.
142 ***************************************************************/
144 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
146 if (create_flags & REQUEST_BATCH_OPLOCK) {
147 return SMB2_OPLOCK_LEVEL_BATCH;
148 } else if (create_flags & REQUEST_OPLOCK) {
149 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
152 /* create_flags doesn't do a level2 request. */
153 return SMB2_OPLOCK_LEVEL_NONE;
156 /***************************************************************
157 Small wrapper that allows SMB2 create to return a uint16_t fnum.
158 ***************************************************************/
160 struct cli_smb2_create_fnum_state {
161 struct cli_state *cli;
162 struct smb2_create_blobs in_cblobs;
163 struct smb2_create_blobs out_cblobs;
164 struct smb_create_returns cr;
165 uint16_t fnum;
166 struct tevent_req *subreq;
169 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
170 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
172 struct tevent_req *cli_smb2_create_fnum_send(
173 TALLOC_CTX *mem_ctx,
174 struct tevent_context *ev,
175 struct cli_state *cli,
176 const char *fname,
177 uint32_t create_flags,
178 uint32_t impersonation_level,
179 uint32_t desired_access,
180 uint32_t file_attributes,
181 uint32_t share_access,
182 uint32_t create_disposition,
183 uint32_t create_options,
184 const struct smb2_create_blobs *in_cblobs)
186 struct tevent_req *req, *subreq;
187 struct cli_smb2_create_fnum_state *state;
188 size_t fname_len = 0;
189 const char *startp = NULL;
190 const char *endp = NULL;
191 time_t tstamp = (time_t)0;
192 NTSTATUS status;
194 req = tevent_req_create(mem_ctx, &state,
195 struct cli_smb2_create_fnum_state);
196 if (req == NULL) {
197 return NULL;
199 state->cli = cli;
201 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
202 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
203 return tevent_req_post(req, ev);
206 if (cli->backup_intent) {
207 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
210 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
211 fname_len = strlen(fname);
212 if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
213 size_t len_before_gmt = startp - fname;
214 size_t len_after_gmt = fname + fname_len - endp;
215 DATA_BLOB twrp_blob;
216 NTTIME ntt;
218 char *new_fname = talloc_array(state, char,
219 len_before_gmt + len_after_gmt + 1);
221 if (tevent_req_nomem(new_fname, req)) {
222 return tevent_req_post(req, ev);
225 memcpy(new_fname, fname, len_before_gmt);
226 memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
227 fname = new_fname;
228 fname_len = len_before_gmt + len_after_gmt;
230 unix_to_nt_time(&ntt, tstamp);
231 twrp_blob = data_blob_const((const void *)&ntt, 8);
233 status = smb2_create_blob_add(
234 state,
235 &state->in_cblobs,
236 SMB2_CREATE_TAG_TWRP,
237 twrp_blob);
238 if (!NT_STATUS_IS_OK(status)) {
239 tevent_req_nterror(req, status);
240 return tevent_req_post(req, ev);
244 if (in_cblobs != NULL) {
245 uint32_t i;
246 for (i=0; i<in_cblobs->num_blobs; i++) {
247 struct smb2_create_blob *b = &in_cblobs->blobs[i];
248 status = smb2_create_blob_add(
249 state, &state->in_cblobs, b->tag, b->data);
250 if (!NT_STATUS_IS_OK(status)) {
251 tevent_req_nterror(req, status);
252 return tevent_req_post(req, ev);
257 /* SMB2 is pickier about pathnames. Ensure it doesn't
258 start in a '\' */
259 if (*fname == '\\') {
260 fname++;
261 fname_len--;
264 /* Or end in a '\' */
265 if (fname_len > 0 && fname[fname_len-1] == '\\') {
266 char *new_fname = talloc_strdup(state, fname);
267 if (tevent_req_nomem(new_fname, req)) {
268 return tevent_req_post(req, ev);
270 new_fname[fname_len-1] = '\0';
271 fname = new_fname;
274 subreq = smb2cli_create_send(state, ev,
275 cli->conn,
276 cli->timeout,
277 cli->smb2.session,
278 cli->smb2.tcon,
279 fname,
280 flags_to_smb2_oplock(create_flags),
281 impersonation_level,
282 desired_access,
283 file_attributes,
284 share_access,
285 create_disposition,
286 create_options,
287 &state->in_cblobs);
288 if (tevent_req_nomem(subreq, req)) {
289 return tevent_req_post(req, ev);
291 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
293 state->subreq = subreq;
294 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
296 return req;
299 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
301 struct tevent_req *req = tevent_req_callback_data(
302 subreq, struct tevent_req);
303 struct cli_smb2_create_fnum_state *state = tevent_req_data(
304 req, struct cli_smb2_create_fnum_state);
305 struct smb2_hnd h;
306 NTSTATUS status;
308 status = smb2cli_create_recv(
309 subreq,
310 &h.fid_persistent,
311 &h.fid_volatile, &state->cr,
312 state,
313 &state->out_cblobs);
314 TALLOC_FREE(subreq);
315 if (tevent_req_nterror(req, status)) {
316 return;
319 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
320 if (tevent_req_nterror(req, status)) {
321 return;
323 tevent_req_done(req);
326 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
328 struct cli_smb2_create_fnum_state *state = tevent_req_data(
329 req, struct cli_smb2_create_fnum_state);
330 return tevent_req_cancel(state->subreq);
333 NTSTATUS cli_smb2_create_fnum_recv(
334 struct tevent_req *req,
335 uint16_t *pfnum,
336 struct smb_create_returns *cr,
337 TALLOC_CTX *mem_ctx,
338 struct smb2_create_blobs *out_cblobs)
340 struct cli_smb2_create_fnum_state *state = tevent_req_data(
341 req, struct cli_smb2_create_fnum_state);
342 NTSTATUS status;
344 if (tevent_req_is_nterror(req, &status)) {
345 state->cli->raw_status = status;
346 return status;
348 if (pfnum != NULL) {
349 *pfnum = state->fnum;
351 if (cr != NULL) {
352 *cr = state->cr;
354 if (out_cblobs != NULL) {
355 *out_cblobs = (struct smb2_create_blobs) {
356 .num_blobs = state->out_cblobs.num_blobs,
357 .blobs = talloc_move(
358 mem_ctx, &state->out_cblobs.blobs),
361 state->cli->raw_status = NT_STATUS_OK;
362 return NT_STATUS_OK;
365 NTSTATUS cli_smb2_create_fnum(
366 struct cli_state *cli,
367 const char *fname,
368 uint32_t create_flags,
369 uint32_t impersonation_level,
370 uint32_t desired_access,
371 uint32_t file_attributes,
372 uint32_t share_access,
373 uint32_t create_disposition,
374 uint32_t create_options,
375 const struct smb2_create_blobs *in_cblobs,
376 uint16_t *pfid,
377 struct smb_create_returns *cr,
378 TALLOC_CTX *mem_ctx,
379 struct smb2_create_blobs *out_cblobs)
381 TALLOC_CTX *frame = talloc_stackframe();
382 struct tevent_context *ev;
383 struct tevent_req *req;
384 NTSTATUS status = NT_STATUS_NO_MEMORY;
386 if (smbXcli_conn_has_async_calls(cli->conn)) {
388 * Can't use sync call while an async call is in flight
390 status = NT_STATUS_INVALID_PARAMETER;
391 goto fail;
393 ev = samba_tevent_context_init(frame);
394 if (ev == NULL) {
395 goto fail;
397 req = cli_smb2_create_fnum_send(
398 frame,
400 cli,
401 fname,
402 create_flags,
403 impersonation_level,
404 desired_access,
405 file_attributes,
406 share_access,
407 create_disposition,
408 create_options,
409 in_cblobs);
410 if (req == NULL) {
411 goto fail;
413 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
414 goto fail;
416 status = cli_smb2_create_fnum_recv(req, pfid, cr, mem_ctx, out_cblobs);
417 fail:
418 TALLOC_FREE(frame);
419 return status;
422 /***************************************************************
423 Small wrapper that allows SMB2 close to use a uint16_t fnum.
424 ***************************************************************/
426 struct cli_smb2_close_fnum_state {
427 struct cli_state *cli;
428 uint16_t fnum;
429 struct smb2_hnd *ph;
432 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
434 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
435 struct tevent_context *ev,
436 struct cli_state *cli,
437 uint16_t fnum)
439 struct tevent_req *req, *subreq;
440 struct cli_smb2_close_fnum_state *state;
441 NTSTATUS status;
443 req = tevent_req_create(mem_ctx, &state,
444 struct cli_smb2_close_fnum_state);
445 if (req == NULL) {
446 return NULL;
448 state->cli = cli;
449 state->fnum = fnum;
451 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
452 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
453 return tevent_req_post(req, ev);
456 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
457 if (tevent_req_nterror(req, status)) {
458 return tevent_req_post(req, ev);
461 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
462 cli->smb2.session, cli->smb2.tcon,
463 0, state->ph->fid_persistent,
464 state->ph->fid_volatile);
465 if (tevent_req_nomem(subreq, req)) {
466 return tevent_req_post(req, ev);
468 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
469 return req;
472 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
474 struct tevent_req *req = tevent_req_callback_data(
475 subreq, struct tevent_req);
476 struct cli_smb2_close_fnum_state *state = tevent_req_data(
477 req, struct cli_smb2_close_fnum_state);
478 NTSTATUS status;
480 status = smb2cli_close_recv(subreq);
481 if (tevent_req_nterror(req, status)) {
482 return;
485 /* Delete the fnum -> handle mapping. */
486 status = delete_smb2_handle_mapping(state->cli, &state->ph,
487 state->fnum);
488 if (tevent_req_nterror(req, status)) {
489 return;
491 tevent_req_done(req);
494 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
496 struct cli_smb2_close_fnum_state *state = tevent_req_data(
497 req, struct cli_smb2_close_fnum_state);
498 NTSTATUS status = NT_STATUS_OK;
500 if (tevent_req_is_nterror(req, &status)) {
501 state->cli->raw_status = status;
503 tevent_req_received(req);
504 return status;
507 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
509 TALLOC_CTX *frame = talloc_stackframe();
510 struct tevent_context *ev;
511 struct tevent_req *req;
512 NTSTATUS status = NT_STATUS_NO_MEMORY;
514 if (smbXcli_conn_has_async_calls(cli->conn)) {
516 * Can't use sync call while an async call is in flight
518 status = NT_STATUS_INVALID_PARAMETER;
519 goto fail;
521 ev = samba_tevent_context_init(frame);
522 if (ev == NULL) {
523 goto fail;
525 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
526 if (req == NULL) {
527 goto fail;
529 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
530 goto fail;
532 status = cli_smb2_close_fnum_recv(req);
533 fail:
534 TALLOC_FREE(frame);
535 return status;
538 struct cli_smb2_set_info_fnum_state {
539 uint8_t dummy;
542 static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq);
544 struct tevent_req *cli_smb2_set_info_fnum_send(
545 TALLOC_CTX *mem_ctx,
546 struct tevent_context *ev,
547 struct cli_state *cli,
548 uint16_t fnum,
549 uint8_t in_info_type,
550 uint8_t in_info_class,
551 const DATA_BLOB *in_input_buffer,
552 uint32_t in_additional_info)
554 struct tevent_req *req = NULL, *subreq = NULL;
555 struct cli_smb2_set_info_fnum_state *state = NULL;
556 struct smb2_hnd *ph = NULL;
557 NTSTATUS status;
559 req = tevent_req_create(
560 mem_ctx, &state, struct cli_smb2_set_info_fnum_state);
561 if (req == NULL) {
562 return NULL;
565 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
566 if (tevent_req_nterror(req, status)) {
567 return tevent_req_post(req, ev);
570 subreq = smb2cli_set_info_send(
571 state,
573 cli->conn,
574 cli->timeout,
575 cli->smb2.session,
576 cli->smb2.tcon,
577 in_info_type,
578 in_info_class,
579 in_input_buffer,
580 in_additional_info,
581 ph->fid_persistent,
582 ph->fid_volatile);
583 if (tevent_req_nomem(subreq, req)) {
584 return tevent_req_post(req, ev);
586 tevent_req_set_callback(subreq, cli_smb2_set_info_fnum_done, req);
587 return req;
590 static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq)
592 NTSTATUS status = smb2cli_set_info_recv(subreq);
593 tevent_req_simple_finish_ntstatus(subreq, status);
596 NTSTATUS cli_smb2_set_info_fnum_recv(struct tevent_req *req)
598 return tevent_req_simple_recv_ntstatus(req);
601 NTSTATUS cli_smb2_set_info_fnum(
602 struct cli_state *cli,
603 uint16_t fnum,
604 uint8_t in_info_type,
605 uint8_t in_info_class,
606 const DATA_BLOB *in_input_buffer,
607 uint32_t in_additional_info)
609 TALLOC_CTX *frame = talloc_stackframe();
610 struct tevent_context *ev = NULL;
611 struct tevent_req *req = NULL;
612 NTSTATUS status = NT_STATUS_NO_MEMORY;
613 bool ok;
615 if (smbXcli_conn_has_async_calls(cli->conn)) {
617 * Can't use sync call while an async call is in flight
619 status = NT_STATUS_INVALID_PARAMETER;
620 goto fail;
622 ev = samba_tevent_context_init(frame);
623 if (ev == NULL) {
624 goto fail;
626 req = cli_smb2_set_info_fnum_send(
627 frame,
629 cli,
630 fnum,
631 in_info_type,
632 in_info_class,
633 in_input_buffer,
634 in_additional_info);
635 if (req == NULL) {
636 goto fail;
638 ok = tevent_req_poll_ntstatus(req, ev, &status);
639 if (!ok) {
640 goto fail;
642 status = cli_smb2_set_info_fnum_recv(req);
643 fail:
644 TALLOC_FREE(frame);
645 return status;
648 struct cli_smb2_delete_on_close_state {
649 struct cli_state *cli;
650 uint8_t data[1];
651 DATA_BLOB inbuf;
654 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
656 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
657 struct tevent_context *ev,
658 struct cli_state *cli,
659 uint16_t fnum,
660 bool flag)
662 struct tevent_req *req = NULL;
663 struct cli_smb2_delete_on_close_state *state = NULL;
664 struct tevent_req *subreq = NULL;
665 uint8_t in_info_type;
666 uint8_t in_file_info_class;
668 req = tevent_req_create(mem_ctx, &state,
669 struct cli_smb2_delete_on_close_state);
670 if (req == NULL) {
671 return NULL;
673 state->cli = cli;
675 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
676 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
677 return tevent_req_post(req, ev);
681 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
682 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
684 in_info_type = 1;
685 in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
686 /* Setup data array. */
687 SCVAL(&state->data[0], 0, flag ? 1 : 0);
688 state->inbuf.data = &state->data[0];
689 state->inbuf.length = 1;
691 subreq = cli_smb2_set_info_fnum_send(
692 state,
694 cli,
695 fnum,
696 in_info_type,
697 in_file_info_class,
698 &state->inbuf,
700 if (tevent_req_nomem(subreq, req)) {
701 return tevent_req_post(req, ev);
703 tevent_req_set_callback(subreq,
704 cli_smb2_delete_on_close_done,
705 req);
706 return req;
709 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
711 NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
712 tevent_req_simple_finish_ntstatus(subreq, status);
715 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
717 struct cli_smb2_delete_on_close_state *state =
718 tevent_req_data(req,
719 struct cli_smb2_delete_on_close_state);
720 NTSTATUS status;
722 if (tevent_req_is_nterror(req, &status)) {
723 state->cli->raw_status = status;
724 tevent_req_received(req);
725 return status;
728 state->cli->raw_status = NT_STATUS_OK;
729 tevent_req_received(req);
730 return NT_STATUS_OK;
733 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
735 TALLOC_CTX *frame = talloc_stackframe();
736 struct tevent_context *ev;
737 struct tevent_req *req;
738 NTSTATUS status = NT_STATUS_NO_MEMORY;
740 if (smbXcli_conn_has_async_calls(cli->conn)) {
742 * Can't use sync call while an async call is in flight
744 status = NT_STATUS_INVALID_PARAMETER;
745 goto fail;
747 ev = samba_tevent_context_init(frame);
748 if (ev == NULL) {
749 goto fail;
751 req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
752 if (req == NULL) {
753 goto fail;
755 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
756 goto fail;
758 status = cli_smb2_delete_on_close_recv(req);
759 fail:
760 TALLOC_FREE(frame);
761 return status;
764 struct cli_smb2_mkdir_state {
765 struct tevent_context *ev;
766 struct cli_state *cli;
769 static void cli_smb2_mkdir_opened(struct tevent_req *subreq);
770 static void cli_smb2_mkdir_closed(struct tevent_req *subreq);
772 struct tevent_req *cli_smb2_mkdir_send(
773 TALLOC_CTX *mem_ctx,
774 struct tevent_context *ev,
775 struct cli_state *cli,
776 const char *dname)
778 struct tevent_req *req = NULL, *subreq = NULL;
779 struct cli_smb2_mkdir_state *state = NULL;
781 req = tevent_req_create(
782 mem_ctx, &state, struct cli_smb2_mkdir_state);
783 if (req == NULL) {
784 return NULL;
786 state->ev = ev;
787 state->cli = cli;
789 /* Ensure this is a directory. */
790 subreq = cli_smb2_create_fnum_send(
791 state, /* mem_ctx */
792 ev, /* ev */
793 cli, /* cli */
794 dname, /* fname */
795 0, /* create_flags */
796 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level */
797 FILE_READ_ATTRIBUTES, /* desired_access */
798 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
799 FILE_SHARE_READ|
800 FILE_SHARE_WRITE, /* share_access */
801 FILE_CREATE, /* create_disposition */
802 FILE_DIRECTORY_FILE, /* create_options */
803 NULL); /* in_cblobs */
804 if (tevent_req_nomem(subreq, req)) {
805 return tevent_req_post(req, ev);
807 tevent_req_set_callback(subreq, cli_smb2_mkdir_opened, req);
808 return req;
811 static void cli_smb2_mkdir_opened(struct tevent_req *subreq)
813 struct tevent_req *req = tevent_req_callback_data(
814 subreq, struct tevent_req);
815 struct cli_smb2_mkdir_state *state = tevent_req_data(
816 req, struct cli_smb2_mkdir_state);
817 NTSTATUS status;
818 uint16_t fnum = 0xffff;
820 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
821 TALLOC_FREE(subreq);
822 if (tevent_req_nterror(req, status)) {
823 return;
826 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
827 if (tevent_req_nomem(subreq, req)) {
828 return;
830 tevent_req_set_callback(subreq, cli_smb2_mkdir_closed, req);
833 static void cli_smb2_mkdir_closed(struct tevent_req *subreq)
835 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
836 tevent_req_simple_finish_ntstatus(subreq, status);
839 NTSTATUS cli_smb2_mkdir_recv(struct tevent_req *req)
841 return tevent_req_simple_recv_ntstatus(req);
844 struct cli_smb2_rmdir_state {
845 struct tevent_context *ev;
846 struct cli_state *cli;
847 const char *dname;
848 const struct smb2_create_blobs *in_cblobs;
849 uint16_t fnum;
850 NTSTATUS status;
853 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq);
854 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq);
855 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq);
856 static void cli_smb2_rmdir_closed(struct tevent_req *subreq);
858 struct tevent_req *cli_smb2_rmdir_send(
859 TALLOC_CTX *mem_ctx,
860 struct tevent_context *ev,
861 struct cli_state *cli,
862 const char *dname,
863 const struct smb2_create_blobs *in_cblobs)
865 struct tevent_req *req = NULL, *subreq = NULL;
866 struct cli_smb2_rmdir_state *state = NULL;
868 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_rmdir_state);
869 if (req == NULL) {
870 return NULL;
872 state->ev = ev;
873 state->cli = cli;
874 state->dname = dname;
875 state->in_cblobs = in_cblobs;
877 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
878 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
879 return tevent_req_post(req, ev);
882 subreq = cli_smb2_create_fnum_send(
883 state,
884 state->ev,
885 state->cli,
886 state->dname,
887 0, /* create_flags */
888 SMB2_IMPERSONATION_IMPERSONATION,
889 DELETE_ACCESS, /* desired_access */
890 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
891 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
892 FILE_OPEN, /* create_disposition */
893 FILE_DIRECTORY_FILE, /* create_options */
894 state->in_cblobs); /* in_cblobs */
895 if (tevent_req_nomem(subreq, req)) {
896 return tevent_req_post(req, ev);
898 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened1, req);
899 return req;
902 static void cli_smb2_rmdir_opened1(struct tevent_req *subreq)
904 struct tevent_req *req = tevent_req_callback_data(
905 subreq, struct tevent_req);
906 struct cli_smb2_rmdir_state *state = tevent_req_data(
907 req, struct cli_smb2_rmdir_state);
908 NTSTATUS status;
910 status = cli_smb2_create_fnum_recv(
911 subreq, &state->fnum, NULL, NULL, NULL);
912 TALLOC_FREE(subreq);
914 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
916 * Naive option to match our SMB1 code. Assume the
917 * symlink path that tripped us up was the last
918 * component and try again. Eventually we will have to
919 * deal with the returned path unprocessed component. JRA.
921 subreq = cli_smb2_create_fnum_send(
922 state,
923 state->ev,
924 state->cli,
925 state->dname,
926 0, /* create_flags */
927 SMB2_IMPERSONATION_IMPERSONATION,
928 DELETE_ACCESS, /* desired_access */
929 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
930 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
931 FILE_OPEN, /* create_disposition */
932 FILE_DIRECTORY_FILE|
933 FILE_DELETE_ON_CLOSE|
934 FILE_OPEN_REPARSE_POINT, /* create_options */
935 state->in_cblobs); /* in_cblobs */
936 if (tevent_req_nomem(subreq, req)) {
937 return;
939 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened2, req);
940 return;
943 if (tevent_req_nterror(req, status)) {
944 return;
947 subreq = cli_smb2_delete_on_close_send(
948 state, state->ev, state->cli, state->fnum, true);
949 if (tevent_req_nomem(subreq, req)) {
950 return;
952 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
955 static void cli_smb2_rmdir_opened2(struct tevent_req *subreq)
957 struct tevent_req *req = tevent_req_callback_data(
958 subreq, struct tevent_req);
959 struct cli_smb2_rmdir_state *state = tevent_req_data(
960 req, struct cli_smb2_rmdir_state);
961 NTSTATUS status;
963 status = cli_smb2_create_fnum_recv(
964 subreq, &state->fnum, NULL, NULL, NULL);
965 TALLOC_FREE(subreq);
966 if (tevent_req_nterror(req, status)) {
967 return;
970 subreq = cli_smb2_delete_on_close_send(
971 state, state->ev, state->cli, state->fnum, true);
972 if (tevent_req_nomem(subreq, req)) {
973 return;
975 tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
978 static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq)
980 struct tevent_req *req = tevent_req_callback_data(
981 subreq, struct tevent_req);
982 struct cli_smb2_rmdir_state *state = tevent_req_data(
983 req, struct cli_smb2_rmdir_state);
985 state->status = cli_smb2_delete_on_close_recv(subreq);
986 TALLOC_FREE(subreq);
989 * Close the fd even if the set_disp failed
992 subreq = cli_smb2_close_fnum_send(
993 state, state->ev, state->cli, state->fnum);
994 if (tevent_req_nomem(subreq, req)) {
995 return;
997 tevent_req_set_callback(subreq, cli_smb2_rmdir_closed, req);
1000 static void cli_smb2_rmdir_closed(struct tevent_req *subreq)
1002 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1003 tevent_req_simple_finish_ntstatus(subreq, status);
1006 NTSTATUS cli_smb2_rmdir_recv(struct tevent_req *req)
1008 struct cli_smb2_rmdir_state *state = tevent_req_data(
1009 req, struct cli_smb2_rmdir_state);
1010 NTSTATUS status;
1012 if (tevent_req_is_nterror(req, &status)) {
1013 return status;
1015 return state->status;
1018 /***************************************************************
1019 Small wrapper that allows SMB2 to unlink a pathname.
1020 ***************************************************************/
1022 struct cli_smb2_unlink_state {
1023 struct tevent_context *ev;
1024 struct cli_state *cli;
1025 const char *fname;
1026 const struct smb2_create_blobs *in_cblobs;
1029 static void cli_smb2_unlink_opened1(struct tevent_req *subreq);
1030 static void cli_smb2_unlink_opened2(struct tevent_req *subreq);
1031 static void cli_smb2_unlink_closed(struct tevent_req *subreq);
1033 struct tevent_req *cli_smb2_unlink_send(
1034 TALLOC_CTX *mem_ctx,
1035 struct tevent_context *ev,
1036 struct cli_state *cli,
1037 const char *fname,
1038 const struct smb2_create_blobs *in_cblobs)
1040 struct tevent_req *req = NULL, *subreq = NULL;
1041 struct cli_smb2_unlink_state *state = NULL;
1043 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_unlink_state);
1044 if (req == NULL) {
1045 return NULL;
1047 state->ev = ev;
1048 state->cli = cli;
1049 state->fname = fname;
1050 state->in_cblobs = in_cblobs;
1052 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1053 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1054 return tevent_req_post(req, ev);
1057 subreq = cli_smb2_create_fnum_send(
1058 state, /* mem_ctx */
1059 state->ev, /* tevent_context */
1060 state->cli, /* cli_struct */
1061 state->fname, /* filename */
1062 0, /* create_flags */
1063 SMB2_IMPERSONATION_IMPERSONATION,
1064 DELETE_ACCESS, /* desired_access */
1065 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1066 FILE_SHARE_READ|
1067 FILE_SHARE_WRITE|
1068 FILE_SHARE_DELETE, /* share_access */
1069 FILE_OPEN, /* create_disposition */
1070 FILE_DELETE_ON_CLOSE, /* create_options */
1071 state->in_cblobs); /* in_cblobs */
1072 if (tevent_req_nomem(subreq, req)) {
1073 return tevent_req_post(req, ev);
1075 tevent_req_set_callback(subreq, cli_smb2_unlink_opened1, req);
1076 return req;
1079 static void cli_smb2_unlink_opened1(struct tevent_req *subreq)
1081 struct tevent_req *req = tevent_req_callback_data(
1082 subreq, struct tevent_req);
1083 struct cli_smb2_unlink_state *state = tevent_req_data(
1084 req, struct cli_smb2_unlink_state);
1085 uint16_t fnum = 0xffff;
1086 NTSTATUS status;
1088 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1089 TALLOC_FREE(subreq);
1091 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1093 * Naive option to match our SMB1 code. Assume the
1094 * symlink path that tripped us up was the last
1095 * component and try again. Eventually we will have to
1096 * deal with the returned path unprocessed component. JRA.
1098 subreq = cli_smb2_create_fnum_send(
1099 state, /* mem_ctx */
1100 state->ev, /* tevent_context */
1101 state->cli, /* cli_struct */
1102 state->fname, /* filename */
1103 0, /* create_flags */
1104 SMB2_IMPERSONATION_IMPERSONATION,
1105 DELETE_ACCESS, /* desired_access */
1106 FILE_ATTRIBUTE_NORMAL, /* file attributes */
1107 FILE_SHARE_READ|
1108 FILE_SHARE_WRITE|
1109 FILE_SHARE_DELETE, /* share_access */
1110 FILE_OPEN, /* create_disposition */
1111 FILE_DELETE_ON_CLOSE|
1112 FILE_OPEN_REPARSE_POINT, /* create_options */
1113 state->in_cblobs); /* in_cblobs */
1114 if (tevent_req_nomem(subreq, req)) {
1115 return;
1117 tevent_req_set_callback(subreq, cli_smb2_unlink_opened2, req);
1118 return;
1121 if (tevent_req_nterror(req, status)) {
1122 return;
1125 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1126 if (tevent_req_nomem(subreq, req)) {
1127 return;
1129 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1132 static void cli_smb2_unlink_opened2(struct tevent_req *subreq)
1134 struct tevent_req *req = tevent_req_callback_data(
1135 subreq, struct tevent_req);
1136 struct cli_smb2_unlink_state *state = tevent_req_data(
1137 req, struct cli_smb2_unlink_state);
1138 uint16_t fnum = 0xffff;
1139 NTSTATUS status;
1141 status = cli_smb2_create_fnum_recv(subreq, &fnum, NULL, NULL, NULL);
1142 TALLOC_FREE(subreq);
1143 if (tevent_req_nterror(req, status)) {
1144 return;
1147 subreq = cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum);
1148 if (tevent_req_nomem(subreq, req)) {
1149 return;
1151 tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
1154 static void cli_smb2_unlink_closed(struct tevent_req *subreq)
1156 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1157 tevent_req_simple_finish_ntstatus(subreq, status);
1160 NTSTATUS cli_smb2_unlink_recv(struct tevent_req *req)
1162 return tevent_req_simple_recv_ntstatus(req);
1165 /***************************************************************
1166 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
1167 ***************************************************************/
1169 static NTSTATUS parse_finfo_id_both_directory_info(const uint8_t *dir_data,
1170 uint32_t dir_data_length,
1171 struct file_info *finfo,
1172 uint32_t *next_offset)
1174 size_t namelen = 0;
1175 size_t slen = 0;
1176 size_t ret = 0;
1178 if (dir_data_length < 4) {
1179 return NT_STATUS_INFO_LENGTH_MISMATCH;
1182 *next_offset = IVAL(dir_data, 0);
1184 if (*next_offset > dir_data_length) {
1185 return NT_STATUS_INFO_LENGTH_MISMATCH;
1188 if (*next_offset != 0) {
1189 /* Ensure we only read what in this record. */
1190 dir_data_length = *next_offset;
1193 if (dir_data_length < 105) {
1194 return NT_STATUS_INFO_LENGTH_MISMATCH;
1197 finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
1198 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
1199 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
1200 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
1201 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
1202 finfo->allocated_size = IVAL2_TO_SMB_BIG_UINT(dir_data + 48, 0);
1203 finfo->attr = IVAL(dir_data + 56, 0);
1204 finfo->ino = IVAL2_TO_SMB_BIG_UINT(dir_data + 96, 0);
1205 namelen = IVAL(dir_data + 60,0);
1206 if (namelen > (dir_data_length - 104)) {
1207 return NT_STATUS_INFO_LENGTH_MISMATCH;
1209 slen = CVAL(dir_data + 68, 0);
1210 if (slen > 24) {
1211 return NT_STATUS_INFO_LENGTH_MISMATCH;
1213 ret = pull_string_talloc(finfo,
1214 dir_data,
1215 FLAGS2_UNICODE_STRINGS,
1216 &finfo->short_name,
1217 dir_data + 70,
1218 slen,
1219 STR_UNICODE);
1220 if (ret == (size_t)-1) {
1221 /* Bad conversion. */
1222 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1225 ret = pull_string_talloc(finfo,
1226 dir_data,
1227 FLAGS2_UNICODE_STRINGS,
1228 &finfo->name,
1229 dir_data + 104,
1230 namelen,
1231 STR_UNICODE);
1232 if (ret == (size_t)-1) {
1233 /* Bad conversion. */
1234 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1237 if (finfo->name == NULL) {
1238 /* Bad conversion. */
1239 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1242 return NT_STATUS_OK;
1245 /*******************************************************************
1246 Given a filename - get its directory name
1247 ********************************************************************/
1249 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
1250 const char *dir,
1251 char **parent,
1252 const char **name)
1254 char *p;
1255 ptrdiff_t len;
1257 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
1259 if (p == NULL) {
1260 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
1261 return false;
1263 if (name) {
1264 *name = dir;
1266 return true;
1269 len = p-dir;
1271 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
1272 return false;
1274 (*parent)[len] = '\0';
1276 if (name) {
1277 *name = p+1;
1279 return true;
1282 struct cli_smb2_list_dir_data {
1283 uint8_t *data;
1284 uint32_t length;
1287 struct cli_smb2_list_state {
1288 struct tevent_context *ev;
1289 struct cli_state *cli;
1290 const char *mask;
1292 uint16_t fnum;
1294 NTSTATUS status;
1295 struct cli_smb2_list_dir_data *response;
1296 uint32_t offset;
1299 static void cli_smb2_list_opened(struct tevent_req *subreq);
1300 static void cli_smb2_list_done(struct tevent_req *subreq);
1301 static void cli_smb2_list_closed(struct tevent_req *subreq);
1303 struct tevent_req *cli_smb2_list_send(
1304 TALLOC_CTX *mem_ctx,
1305 struct tevent_context *ev,
1306 struct cli_state *cli,
1307 const char *pathname)
1309 struct tevent_req *req = NULL, *subreq = NULL;
1310 struct cli_smb2_list_state *state = NULL;
1311 char *parent = NULL;
1312 bool ok;
1314 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_list_state);
1315 if (req == NULL) {
1316 return NULL;
1318 state->ev = ev;
1319 state->cli = cli;
1320 state->status = NT_STATUS_OK;
1322 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1323 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1324 return tevent_req_post(req, ev);
1327 ok = windows_parent_dirname(state, pathname, &parent, &state->mask);
1328 if (!ok) {
1329 tevent_req_oom(req);
1330 return tevent_req_post(req, ev);
1333 subreq = cli_smb2_create_fnum_send(
1334 state, /* mem_ctx */
1335 ev, /* ev */
1336 cli, /* cli */
1337 parent, /* fname */
1338 0, /* create_flags */
1339 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level */
1340 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE, /* desired_access */
1341 FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
1342 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
1343 FILE_OPEN, /* create_disposition */
1344 FILE_DIRECTORY_FILE, /* create_options */
1345 NULL); /* in_cblobs */
1346 if (tevent_req_nomem(subreq, req)) {
1347 return tevent_req_post(req, ev);
1349 tevent_req_set_callback(subreq, cli_smb2_list_opened, req);
1350 return req;
1353 static void cli_smb2_list_opened(struct tevent_req *subreq)
1355 struct tevent_req *req = tevent_req_callback_data(
1356 subreq, struct tevent_req);
1357 struct cli_smb2_list_state *state = tevent_req_data(
1358 req, struct cli_smb2_list_state);
1359 NTSTATUS status;
1361 status = cli_smb2_create_fnum_recv(
1362 subreq, &state->fnum, NULL, NULL, NULL);
1363 TALLOC_FREE(subreq);
1364 if (tevent_req_nterror(req, status)) {
1365 return;
1369 * Make our caller get back to us via cli_smb2_list_recv(),
1370 * triggering the smb2_query_directory_send()
1372 tevent_req_defer_callback(req, state->ev);
1373 tevent_req_notify_callback(req);
1376 static void cli_smb2_list_done(struct tevent_req *subreq)
1378 struct tevent_req *req = tevent_req_callback_data(
1379 subreq, struct tevent_req);
1380 struct cli_smb2_list_state *state = tevent_req_data(
1381 req, struct cli_smb2_list_state);
1382 struct cli_smb2_list_dir_data *response = NULL;
1384 response = talloc(state, struct cli_smb2_list_dir_data);
1385 if (tevent_req_nomem(response, req)) {
1386 return;
1389 state->status = smb2cli_query_directory_recv(
1390 subreq, response, &response->data, &response->length);
1391 TALLOC_FREE(subreq);
1393 if (NT_STATUS_IS_OK(state->status)) {
1394 state->response = response;
1395 state->offset = 0;
1397 tevent_req_defer_callback(req, state->ev);
1398 tevent_req_notify_callback(req);
1399 return;
1402 TALLOC_FREE(response);
1404 subreq = cli_smb2_close_fnum_send(
1405 state, state->ev, state->cli, state->fnum);
1406 if (tevent_req_nomem(subreq, req)) {
1407 return;
1409 tevent_req_set_callback(subreq, cli_smb2_list_closed, req);
1412 static void cli_smb2_list_closed(struct tevent_req *subreq)
1414 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1415 tevent_req_simple_finish_ntstatus(subreq, status);
1419 * Return the next finfo directory.
1421 * This parses the blob returned from QUERY_DIRECTORY step by step. If
1422 * the blob ends, this triggers a fresh QUERY_DIRECTORY and returns
1423 * NT_STATUS_RETRY, which will then trigger the caller again when the
1424 * QUERY_DIRECTORY has returned with another buffer. This way we
1425 * guarantee that no asynchronous request is open after this call
1426 * returns an entry, so that other synchronous requests can be issued
1427 * on the same connection while the directoy listing proceeds.
1429 NTSTATUS cli_smb2_list_recv(
1430 struct tevent_req *req,
1431 TALLOC_CTX *mem_ctx,
1432 struct file_info **pfinfo)
1434 struct cli_smb2_list_state *state = tevent_req_data(
1435 req, struct cli_smb2_list_state);
1436 struct cli_smb2_list_dir_data *response = NULL;
1437 struct file_info *finfo = NULL;
1438 NTSTATUS status;
1439 uint32_t next_offset = 0;
1440 bool in_progress;
1442 in_progress = tevent_req_is_in_progress(req);
1444 if (!in_progress) {
1445 if (!tevent_req_is_nterror(req, &status)) {
1446 status = NT_STATUS_NO_MORE_FILES;
1448 goto fail;
1451 response = state->response;
1452 if (response == NULL) {
1453 struct tevent_req *subreq = NULL;
1454 struct cli_state *cli = state->cli;
1455 struct smb2_hnd *ph = NULL;
1456 uint32_t max_trans, max_avail_len;
1457 bool ok;
1459 if (!NT_STATUS_IS_OK(state->status)) {
1460 status = state->status;
1461 goto fail;
1464 status = map_fnum_to_smb2_handle(cli, state->fnum, &ph);
1465 if (!NT_STATUS_IS_OK(status)) {
1466 goto fail;
1469 max_trans = smb2cli_conn_max_trans_size(cli->conn);
1470 ok = smb2cli_conn_req_possible(cli->conn, &max_avail_len);
1471 if (ok) {
1472 max_trans = MIN(max_trans, max_avail_len);
1475 subreq = smb2cli_query_directory_send(
1476 state, /* mem_ctx */
1477 state->ev, /* ev */
1478 cli->conn, /* conn */
1479 cli->timeout, /* timeout_msec */
1480 cli->smb2.session, /* session */
1481 cli->smb2.tcon, /* tcon */
1482 SMB2_FIND_ID_BOTH_DIRECTORY_INFO, /* level */
1483 0, /* flags */
1484 0, /* file_index */
1485 ph->fid_persistent, /* fid_persistent */
1486 ph->fid_volatile, /* fid_volatile */
1487 state->mask, /* mask */
1488 max_trans); /* outbuf_len */
1489 if (subreq == NULL) {
1490 status = NT_STATUS_NO_MEMORY;
1491 goto fail;
1493 tevent_req_set_callback(subreq, cli_smb2_list_done, req);
1494 return NT_STATUS_RETRY;
1497 SMB_ASSERT(response->length > state->offset);
1499 finfo = talloc_zero(mem_ctx, struct file_info);
1500 if (finfo == NULL) {
1501 status = NT_STATUS_NO_MEMORY;
1502 goto fail;
1505 status = parse_finfo_id_both_directory_info(
1506 response->data + state->offset,
1507 response->length - state->offset,
1508 finfo,
1509 &next_offset);
1510 if (!NT_STATUS_IS_OK(status)) {
1511 goto fail;
1514 status = is_bad_finfo_name(state->cli, finfo);
1515 if (!NT_STATUS_IS_OK(status)) {
1516 goto fail;
1520 * parse_finfo_id_both_directory_info() checks for overflow,
1521 * no need to check again here.
1523 state->offset += next_offset;
1525 if (next_offset == 0) {
1526 TALLOC_FREE(state->response);
1529 tevent_req_defer_callback(req, state->ev);
1530 tevent_req_notify_callback(req);
1532 *pfinfo = finfo;
1533 return NT_STATUS_OK;
1535 fail:
1536 TALLOC_FREE(finfo);
1537 tevent_req_received(req);
1538 return status;
1541 /***************************************************************
1542 Wrapper that allows SMB2 to query a path info (basic level).
1543 Synchronous only.
1544 ***************************************************************/
1546 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1547 const char *name,
1548 SMB_STRUCT_STAT *sbuf,
1549 uint32_t *attributes)
1551 NTSTATUS status;
1552 struct smb_create_returns cr;
1553 uint16_t fnum = 0xffff;
1554 size_t namelen = strlen(name);
1556 if (smbXcli_conn_has_async_calls(cli->conn)) {
1558 * Can't use sync call while an async call is in flight
1560 return NT_STATUS_INVALID_PARAMETER;
1563 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1564 return NT_STATUS_INVALID_PARAMETER;
1567 /* SMB2 is pickier about pathnames. Ensure it doesn't
1568 end in a '\' */
1569 if (namelen > 0 && name[namelen-1] == '\\') {
1570 char *modname = talloc_strndup(talloc_tos(), name, namelen-1);
1571 if (modname == NULL) {
1572 return NT_STATUS_NO_MEMORY;
1574 name = modname;
1577 /* This is commonly used as a 'cd'. Try qpathinfo on
1578 a directory handle first. */
1580 status = cli_smb2_create_fnum(cli,
1581 name,
1582 0, /* create_flags */
1583 SMB2_IMPERSONATION_IMPERSONATION,
1584 FILE_READ_ATTRIBUTES, /* desired_access */
1585 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1586 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1587 FILE_OPEN, /* create_disposition */
1588 FILE_DIRECTORY_FILE, /* create_options */
1589 NULL,
1590 &fnum,
1591 &cr,
1592 NULL,
1593 NULL);
1595 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1596 /* Maybe a file ? */
1597 status = cli_smb2_create_fnum(cli,
1598 name,
1599 0, /* create_flags */
1600 SMB2_IMPERSONATION_IMPERSONATION,
1601 FILE_READ_ATTRIBUTES, /* desired_access */
1602 0, /* file attributes */
1603 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1604 FILE_OPEN, /* create_disposition */
1605 0, /* create_options */
1606 NULL,
1607 &fnum,
1608 &cr,
1609 NULL,
1610 NULL);
1613 if (!NT_STATUS_IS_OK(status)) {
1614 return status;
1617 status = cli_smb2_close_fnum(cli, fnum);
1619 ZERO_STRUCTP(sbuf);
1621 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1622 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1623 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1624 sbuf->st_ex_size = cr.end_of_file;
1625 *attributes = cr.file_attributes;
1627 return status;
1630 struct cli_smb2_query_info_fnum_state {
1631 DATA_BLOB outbuf;
1634 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq);
1636 struct tevent_req *cli_smb2_query_info_fnum_send(
1637 TALLOC_CTX *mem_ctx,
1638 struct tevent_context *ev,
1639 struct cli_state *cli,
1640 uint16_t fnum,
1641 uint8_t in_info_type,
1642 uint8_t in_info_class,
1643 uint32_t in_max_output_length,
1644 const DATA_BLOB *in_input_buffer,
1645 uint32_t in_additional_info,
1646 uint32_t in_flags)
1648 struct tevent_req *req = NULL, *subreq = NULL;
1649 struct cli_smb2_query_info_fnum_state *state = NULL;
1650 struct smb2_hnd *ph = NULL;
1651 NTSTATUS status;
1653 req = tevent_req_create(
1654 mem_ctx, &state, struct cli_smb2_query_info_fnum_state);
1655 if (req == NULL) {
1656 return req;
1659 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1660 if (tevent_req_nterror(req, status)) {
1661 return tevent_req_post(req, ev);
1664 subreq = smb2cli_query_info_send(
1665 state,
1667 cli->conn,
1668 cli->timeout,
1669 cli->smb2.session,
1670 cli->smb2.tcon,
1671 in_info_type,
1672 in_info_class,
1673 in_max_output_length,
1674 in_input_buffer,
1675 in_additional_info,
1676 in_flags,
1677 ph->fid_persistent,
1678 ph->fid_volatile);
1679 if (tevent_req_nomem(subreq, req)) {
1680 return tevent_req_post(req, ev);
1682 tevent_req_set_callback(subreq, cli_smb2_query_info_fnum_done, req);
1683 return req;
1686 static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq)
1688 struct tevent_req *req = tevent_req_callback_data(
1689 subreq, struct tevent_req);
1690 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1691 req, struct cli_smb2_query_info_fnum_state);
1692 DATA_BLOB outbuf;
1693 NTSTATUS status;
1695 status = smb2cli_query_info_recv(subreq, state, &outbuf);
1696 TALLOC_FREE(subreq);
1697 if (tevent_req_nterror(req, status)) {
1698 return;
1702 * We have to dup the memory here because outbuf.data is not
1703 * returned as a talloc object by smb2cli_query_info_recv.
1704 * It's a pointer into the received buffer.
1706 state->outbuf = data_blob_dup_talloc(state, outbuf);
1708 if ((outbuf.length != 0) &&
1709 tevent_req_nomem(state->outbuf.data, req)) {
1710 return;
1712 tevent_req_done(req);
1715 NTSTATUS cli_smb2_query_info_fnum_recv(
1716 struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *outbuf)
1718 struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
1719 req, struct cli_smb2_query_info_fnum_state);
1720 NTSTATUS status;
1722 if (tevent_req_is_nterror(req, &status)) {
1723 return status;
1725 *outbuf = (DATA_BLOB) {
1726 .data = talloc_move(mem_ctx, &state->outbuf.data),
1727 .length = state->outbuf.length,
1729 return NT_STATUS_OK;
1732 NTSTATUS cli_smb2_query_info_fnum(
1733 struct cli_state *cli,
1734 uint16_t fnum,
1735 uint8_t in_info_type,
1736 uint8_t in_info_class,
1737 uint32_t in_max_output_length,
1738 const DATA_BLOB *in_input_buffer,
1739 uint32_t in_additional_info,
1740 uint32_t in_flags,
1741 TALLOC_CTX *mem_ctx,
1742 DATA_BLOB *outbuf)
1744 TALLOC_CTX *frame = talloc_stackframe();
1745 struct tevent_context *ev = NULL;
1746 struct tevent_req *req = NULL;
1747 NTSTATUS status = NT_STATUS_NO_MEMORY;
1748 bool ok;
1750 if (smbXcli_conn_has_async_calls(cli->conn)) {
1752 * Can't use sync call while an async call is in flight
1754 status = NT_STATUS_INVALID_PARAMETER;
1755 goto fail;
1757 ev = samba_tevent_context_init(frame);
1758 if (ev == NULL) {
1759 goto fail;
1761 req = cli_smb2_query_info_fnum_send(
1762 frame,
1764 cli,
1765 fnum,
1766 in_info_type,
1767 in_info_class,
1768 in_max_output_length,
1769 in_input_buffer,
1770 in_additional_info,
1771 in_flags);
1772 if (req == NULL) {
1773 goto fail;
1775 ok = tevent_req_poll_ntstatus(req, ev, &status);
1776 if (!ok) {
1777 goto fail;
1779 status = cli_smb2_query_info_fnum_recv(req, mem_ctx, outbuf);
1780 fail:
1781 TALLOC_FREE(frame);
1782 return status;
1785 /***************************************************************
1786 Helper function for pathname operations.
1787 ***************************************************************/
1789 struct get_fnum_from_path_state {
1790 struct tevent_context *ev;
1791 struct cli_state *cli;
1792 const char *name;
1793 uint32_t desired_access;
1794 uint16_t fnum;
1797 static void get_fnum_from_path_opened_file(struct tevent_req *subreq);
1798 static void get_fnum_from_path_opened_reparse(struct tevent_req *subreq);
1799 static void get_fnum_from_path_opened_dir(struct tevent_req *subreq);
1801 static struct tevent_req *get_fnum_from_path_send(
1802 TALLOC_CTX *mem_ctx,
1803 struct tevent_context *ev,
1804 struct cli_state *cli,
1805 const char *name,
1806 uint32_t desired_access)
1808 struct tevent_req *req = NULL, *subreq = NULL;
1809 struct get_fnum_from_path_state *state = NULL;
1810 size_t namelen = strlen(name);
1812 req = tevent_req_create(
1813 mem_ctx, &state, struct get_fnum_from_path_state);
1814 if (req == NULL) {
1815 return NULL;
1817 state->ev = ev;
1818 state->cli = cli;
1819 state->name = name;
1820 state->desired_access = desired_access;
1823 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
1824 * '\'
1826 if (namelen > 0 && name[namelen-1] == '\\') {
1827 state->name = talloc_strndup(state, name, namelen-1);
1828 if (tevent_req_nomem(state->name, req)) {
1829 return tevent_req_post(req, ev);
1833 subreq = cli_smb2_create_fnum_send(
1834 state, /* mem_ctx, */
1835 ev, /* ev */
1836 cli, /* cli */
1837 state->name, /* fname */
1838 0, /* create_flags */
1839 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level */
1840 desired_access, /* desired_access */
1841 0, /* file_attributes */
1842 FILE_SHARE_READ|
1843 FILE_SHARE_WRITE|
1844 FILE_SHARE_DELETE, /* share_access */
1845 FILE_OPEN, /* create_disposition */
1846 0, /* create_options */
1847 NULL); /* in_cblobs */
1848 if (tevent_req_nomem(subreq, req)) {
1849 return tevent_req_post(req, ev);
1851 tevent_req_set_callback(subreq, get_fnum_from_path_opened_file, req);
1852 return req;
1855 static void get_fnum_from_path_opened_file(struct tevent_req *subreq)
1857 struct tevent_req *req = tevent_req_callback_data(
1858 subreq, struct tevent_req);
1859 struct get_fnum_from_path_state *state = tevent_req_data(
1860 req, struct get_fnum_from_path_state);
1861 NTSTATUS status;
1863 status = cli_smb2_create_fnum_recv(
1864 subreq, &state->fnum, NULL, NULL, NULL);
1865 TALLOC_FREE(subreq);
1867 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1869 * Naive option to match our SMB1 code. Assume the
1870 * symlink path that tripped us up was the last
1871 * component and try again. Eventually we will have to
1872 * deal with the returned path unprocessed component. JRA.
1874 subreq = cli_smb2_create_fnum_send(
1875 state, /* mem_ctx, */
1876 state->ev, /* ev */
1877 state->cli, /* cli */
1878 state->name, /* fname */
1879 0, /* create_flags */
1880 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation */
1881 state->desired_access, /* desired_access */
1882 0, /* file_attributes */
1883 FILE_SHARE_READ|
1884 FILE_SHARE_WRITE|
1885 FILE_SHARE_DELETE, /* share_access */
1886 FILE_OPEN, /* create_disposition */
1887 FILE_OPEN_REPARSE_POINT, /* create_options */
1888 NULL); /* in_cblobs */
1889 if (tevent_req_nomem(subreq, req)) {
1890 return;
1892 tevent_req_set_callback(
1893 subreq, get_fnum_from_path_opened_reparse, req);
1894 return;
1897 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1898 subreq = cli_smb2_create_fnum_send(
1899 state, /* mem_ctx, */
1900 state->ev, /* ev */
1901 state->cli, /* cli */
1902 state->name, /* fname */
1903 0, /* create_flags */
1904 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation */
1905 state->desired_access, /* desired_access */
1906 0, /* file_attributes */
1907 FILE_SHARE_READ|
1908 FILE_SHARE_WRITE|
1909 FILE_SHARE_DELETE, /* share_access */
1910 FILE_OPEN, /* create_disposition */
1911 FILE_DIRECTORY_FILE, /* create_options */
1912 NULL); /* in_cblobs */
1913 if (tevent_req_nomem(subreq, req)) {
1914 return;
1916 tevent_req_set_callback(
1917 subreq, get_fnum_from_path_opened_dir, req);
1918 return;
1921 if (tevent_req_nterror(req, status)) {
1922 return;
1924 tevent_req_done(req);
1927 static void get_fnum_from_path_opened_reparse(struct tevent_req *subreq)
1929 struct tevent_req *req = tevent_req_callback_data(
1930 subreq, struct tevent_req);
1931 struct get_fnum_from_path_state *state = tevent_req_data(
1932 req, struct get_fnum_from_path_state);
1933 NTSTATUS status = cli_smb2_create_fnum_recv(
1934 subreq, &state->fnum, NULL, NULL, NULL);
1935 tevent_req_simple_finish_ntstatus(subreq, status);
1938 static void get_fnum_from_path_opened_dir(struct tevent_req *subreq)
1940 /* Abstraction violation, but these two are just the same... */
1941 get_fnum_from_path_opened_reparse(subreq);
1944 static NTSTATUS get_fnum_from_path_recv(
1945 struct tevent_req *req, uint16_t *pfnum)
1947 struct get_fnum_from_path_state *state = tevent_req_data(
1948 req, struct get_fnum_from_path_state);
1949 NTSTATUS status = NT_STATUS_OK;
1951 if (!tevent_req_is_nterror(req, &status)) {
1952 *pfnum = state->fnum;
1954 tevent_req_received(req);
1955 return status;
1958 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1959 const char *name,
1960 uint32_t desired_access,
1961 uint16_t *pfnum)
1963 TALLOC_CTX *frame = talloc_stackframe();
1964 struct tevent_context *ev = NULL;
1965 struct tevent_req *req = NULL;
1966 NTSTATUS status = NT_STATUS_NO_MEMORY;
1968 if (smbXcli_conn_has_async_calls(cli->conn)) {
1969 status = NT_STATUS_INVALID_PARAMETER;
1970 goto fail;
1972 ev = samba_tevent_context_init(frame);
1973 if (ev == NULL) {
1974 goto fail;
1976 req = get_fnum_from_path_send(frame, ev, cli, name, desired_access);
1977 if (req == NULL) {
1978 goto fail;
1980 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1981 goto fail;
1983 status = get_fnum_from_path_recv(req, pfnum);
1984 fail:
1985 TALLOC_FREE(frame);
1986 return status;
1989 /***************************************************************
1990 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1991 Synchronous only.
1992 ***************************************************************/
1994 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1995 const char *name,
1996 fstring alt_name)
1998 NTSTATUS status;
1999 DATA_BLOB outbuf = data_blob_null;
2000 uint16_t fnum = 0xffff;
2001 uint32_t altnamelen = 0;
2002 TALLOC_CTX *frame = talloc_stackframe();
2004 if (smbXcli_conn_has_async_calls(cli->conn)) {
2006 * Can't use sync call while an async call is in flight
2008 status = NT_STATUS_INVALID_PARAMETER;
2009 goto fail;
2012 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2013 status = NT_STATUS_INVALID_PARAMETER;
2014 goto fail;
2017 status = get_fnum_from_path(cli,
2018 name,
2019 FILE_READ_ATTRIBUTES,
2020 &fnum);
2022 if (!NT_STATUS_IS_OK(status)) {
2023 goto fail;
2026 status = cli_smb2_query_info_fnum(
2027 cli,
2028 fnum,
2029 1, /* in_info_type */
2030 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
2031 0xFFFF, /* in_max_output_length */
2032 NULL, /* in_input_buffer */
2033 0, /* in_additional_info */
2034 0, /* in_flags */
2035 frame,
2036 &outbuf);
2038 if (!NT_STATUS_IS_OK(status)) {
2039 goto fail;
2042 /* Parse the reply. */
2043 if (outbuf.length < 4) {
2044 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2045 goto fail;
2048 altnamelen = IVAL(outbuf.data, 0);
2049 if (altnamelen > outbuf.length - 4) {
2050 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2051 goto fail;
2054 if (altnamelen > 0) {
2055 size_t ret = 0;
2056 char *short_name = NULL;
2057 ret = pull_string_talloc(frame,
2058 outbuf.data,
2059 FLAGS2_UNICODE_STRINGS,
2060 &short_name,
2061 outbuf.data + 4,
2062 altnamelen,
2063 STR_UNICODE);
2064 if (ret == (size_t)-1) {
2065 /* Bad conversion. */
2066 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2067 goto fail;
2070 fstrcpy(alt_name, short_name);
2071 } else {
2072 alt_name[0] = '\0';
2075 status = NT_STATUS_OK;
2077 fail:
2079 if (fnum != 0xffff) {
2080 cli_smb2_close_fnum(cli, fnum);
2083 cli->raw_status = status;
2085 TALLOC_FREE(frame);
2086 return status;
2089 /***************************************************************
2090 Wrapper that allows SMB2 to get pathname attributes.
2091 Synchronous only.
2092 ***************************************************************/
2094 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
2095 const char *name,
2096 uint32_t *pattr,
2097 off_t *size,
2098 time_t *write_time)
2100 NTSTATUS status;
2101 uint16_t fnum = 0xffff;
2102 struct smb2_hnd *ph = NULL;
2103 struct timespec write_time_ts;
2104 TALLOC_CTX *frame = talloc_stackframe();
2106 if (smbXcli_conn_has_async_calls(cli->conn)) {
2108 * Can't use sync call while an async call is in flight
2110 status = NT_STATUS_INVALID_PARAMETER;
2111 goto fail;
2114 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2115 status = NT_STATUS_INVALID_PARAMETER;
2116 goto fail;
2119 status = get_fnum_from_path(cli,
2120 name,
2121 FILE_READ_ATTRIBUTES,
2122 &fnum);
2124 if (!NT_STATUS_IS_OK(status)) {
2125 goto fail;
2128 status = map_fnum_to_smb2_handle(cli,
2129 fnum,
2130 &ph);
2131 if (!NT_STATUS_IS_OK(status)) {
2132 goto fail;
2134 status = cli_qfileinfo_basic(
2135 cli,
2136 fnum,
2137 pattr,
2138 size,
2139 NULL, /* create_time */
2140 NULL, /* access_time */
2141 &write_time_ts,
2142 NULL, /* change_time */
2143 NULL); /* ino */
2144 if (!NT_STATUS_IS_OK(status)) {
2145 goto fail;
2147 if (write_time != NULL) {
2148 *write_time = write_time_ts.tv_sec;
2151 fail:
2153 if (fnum != 0xffff) {
2154 cli_smb2_close_fnum(cli, fnum);
2157 cli->raw_status = status;
2159 TALLOC_FREE(frame);
2160 return status;
2163 /***************************************************************
2164 Wrapper that allows SMB2 to query a pathname info (basic level).
2165 Implement on top of cli_qfileinfo_basic().
2166 Synchronous only.
2167 ***************************************************************/
2169 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
2170 const char *name,
2171 struct timespec *create_time,
2172 struct timespec *access_time,
2173 struct timespec *write_time,
2174 struct timespec *change_time,
2175 off_t *size,
2176 uint32_t *pattr,
2177 SMB_INO_T *ino)
2179 NTSTATUS status;
2180 struct smb2_hnd *ph = NULL;
2181 uint16_t fnum = 0xffff;
2182 TALLOC_CTX *frame = talloc_stackframe();
2184 if (smbXcli_conn_has_async_calls(cli->conn)) {
2186 * Can't use sync call while an async call is in flight
2188 status = NT_STATUS_INVALID_PARAMETER;
2189 goto fail;
2192 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2193 status = NT_STATUS_INVALID_PARAMETER;
2194 goto fail;
2197 status = get_fnum_from_path(cli,
2198 name,
2199 FILE_READ_ATTRIBUTES,
2200 &fnum);
2202 if (!NT_STATUS_IS_OK(status)) {
2203 goto fail;
2206 status = map_fnum_to_smb2_handle(cli,
2207 fnum,
2208 &ph);
2209 if (!NT_STATUS_IS_OK(status)) {
2210 goto fail;
2213 status = cli_qfileinfo_basic(
2214 cli,
2215 fnum,
2216 pattr,
2217 size,
2218 create_time,
2219 access_time,
2220 write_time,
2221 change_time,
2222 ino);
2224 fail:
2226 if (fnum != 0xffff) {
2227 cli_smb2_close_fnum(cli, fnum);
2230 cli->raw_status = status;
2232 TALLOC_FREE(frame);
2233 return status;
2236 /***************************************************************
2237 Wrapper that allows SMB2 to query pathname streams.
2238 Synchronous only.
2239 ***************************************************************/
2241 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
2242 const char *name,
2243 TALLOC_CTX *mem_ctx,
2244 unsigned int *pnum_streams,
2245 struct stream_struct **pstreams)
2247 NTSTATUS status;
2248 uint16_t fnum = 0xffff;
2249 DATA_BLOB outbuf = data_blob_null;
2250 TALLOC_CTX *frame = talloc_stackframe();
2252 if (smbXcli_conn_has_async_calls(cli->conn)) {
2254 * Can't use sync call while an async call is in flight
2256 status = NT_STATUS_INVALID_PARAMETER;
2257 goto fail;
2260 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2261 status = NT_STATUS_INVALID_PARAMETER;
2262 goto fail;
2265 status = get_fnum_from_path(cli,
2266 name,
2267 FILE_READ_ATTRIBUTES,
2268 &fnum);
2270 if (!NT_STATUS_IS_OK(status)) {
2271 goto fail;
2274 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2275 level 22 (SMB2_FILE_STREAM_INFORMATION). */
2277 status = cli_smb2_query_info_fnum(
2278 cli,
2279 fnum,
2280 1, /* in_info_type */
2281 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
2282 0xFFFF, /* in_max_output_length */
2283 NULL, /* in_input_buffer */
2284 0, /* in_additional_info */
2285 0, /* in_flags */
2286 frame,
2287 &outbuf);
2289 if (!NT_STATUS_IS_OK(status)) {
2290 goto fail;
2293 /* Parse the reply. */
2294 if (!parse_streams_blob(mem_ctx,
2295 outbuf.data,
2296 outbuf.length,
2297 pnum_streams,
2298 pstreams)) {
2299 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2300 goto fail;
2303 fail:
2305 if (fnum != 0xffff) {
2306 cli_smb2_close_fnum(cli, fnum);
2309 cli->raw_status = status;
2311 TALLOC_FREE(frame);
2312 return status;
2315 /***************************************************************
2316 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
2317 a pathname.
2318 Synchronous only.
2319 ***************************************************************/
2321 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
2322 const char *name,
2323 uint8_t in_info_type,
2324 uint8_t in_file_info_class,
2325 const DATA_BLOB *p_in_data)
2327 NTSTATUS status;
2328 uint16_t fnum = 0xffff;
2329 TALLOC_CTX *frame = talloc_stackframe();
2331 if (smbXcli_conn_has_async_calls(cli->conn)) {
2333 * Can't use sync call while an async call is in flight
2335 status = NT_STATUS_INVALID_PARAMETER;
2336 goto fail;
2339 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2340 status = NT_STATUS_INVALID_PARAMETER;
2341 goto fail;
2344 status = get_fnum_from_path(cli,
2345 name,
2346 FILE_WRITE_ATTRIBUTES,
2347 &fnum);
2349 if (!NT_STATUS_IS_OK(status)) {
2350 goto fail;
2353 status = cli_smb2_set_info_fnum(
2354 cli,
2355 fnum,
2356 in_info_type,
2357 in_file_info_class,
2358 p_in_data, /* in_input_buffer */
2359 0); /* in_additional_info */
2360 fail:
2362 if (fnum != 0xffff) {
2363 cli_smb2_close_fnum(cli, fnum);
2366 cli->raw_status = status;
2368 TALLOC_FREE(frame);
2369 return status;
2373 /***************************************************************
2374 Wrapper that allows SMB2 to set pathname attributes.
2375 Synchronous only.
2376 ***************************************************************/
2378 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
2379 const char *name,
2380 uint32_t attr,
2381 time_t mtime)
2383 uint8_t inbuf_store[40];
2384 DATA_BLOB inbuf = data_blob_null;
2386 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2387 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2389 inbuf.data = inbuf_store;
2390 inbuf.length = sizeof(inbuf_store);
2391 data_blob_clear(&inbuf);
2394 * SMB1 uses attr == 0 to clear all attributes
2395 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
2396 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
2397 * request attribute change.
2399 * SMB2 uses exactly the reverse. Unfortunately as the
2400 * cli_setatr() ABI is exposed inside libsmbclient,
2401 * we must make the SMB2 cli_smb2_setatr() call
2402 * export the same ABI as the SMB1 cli_setatr()
2403 * which calls it. This means reversing the sense
2404 * of the requested attr argument if it's zero
2405 * or FILE_ATTRIBUTE_NORMAL.
2407 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
2410 if (attr == 0) {
2411 attr = FILE_ATTRIBUTE_NORMAL;
2412 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
2413 attr = 0;
2416 SIVAL(inbuf.data, 32, attr);
2417 if (mtime != 0) {
2418 put_long_date((char *)inbuf.data + 16,mtime);
2420 /* Set all the other times to -1. */
2421 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2422 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
2423 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
2425 return cli_smb2_setpathinfo(cli,
2426 name,
2427 1, /* in_info_type */
2428 /* in_file_info_class */
2429 SMB_FILE_BASIC_INFORMATION - 1000,
2430 &inbuf);
2434 /***************************************************************
2435 Wrapper that allows SMB2 to set file handle times.
2436 Synchronous only.
2437 ***************************************************************/
2439 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
2440 uint16_t fnum,
2441 time_t change_time,
2442 time_t access_time,
2443 time_t write_time)
2445 uint8_t inbuf_store[40];
2446 DATA_BLOB inbuf = data_blob_null;
2448 if (smbXcli_conn_has_async_calls(cli->conn)) {
2450 * Can't use sync call while an async call is in flight
2452 return NT_STATUS_INVALID_PARAMETER;
2455 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2456 return NT_STATUS_INVALID_PARAMETER;
2459 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2460 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
2462 inbuf.data = inbuf_store;
2463 inbuf.length = sizeof(inbuf_store);
2464 data_blob_clear(&inbuf);
2466 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
2467 if (change_time != 0) {
2468 put_long_date((char *)inbuf.data + 24, change_time);
2470 if (access_time != 0) {
2471 put_long_date((char *)inbuf.data + 8, access_time);
2473 if (write_time != 0) {
2474 put_long_date((char *)inbuf.data + 16, write_time);
2477 cli->raw_status = cli_smb2_set_info_fnum(
2478 cli,
2479 fnum,
2480 1, /* in_info_type */
2481 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
2482 &inbuf, /* in_input_buffer */
2483 0); /* in_additional_info */
2485 return cli->raw_status;
2488 /***************************************************************
2489 Wrapper that allows SMB2 to query disk attributes (size).
2490 Synchronous only.
2491 ***************************************************************/
2493 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
2494 uint64_t *bsize, uint64_t *total, uint64_t *avail)
2496 NTSTATUS status;
2497 uint16_t fnum = 0xffff;
2498 DATA_BLOB outbuf = data_blob_null;
2499 uint32_t sectors_per_unit = 0;
2500 uint32_t bytes_per_sector = 0;
2501 uint64_t total_size = 0;
2502 uint64_t size_free = 0;
2503 TALLOC_CTX *frame = talloc_stackframe();
2505 if (smbXcli_conn_has_async_calls(cli->conn)) {
2507 * Can't use sync call while an async call is in flight
2509 status = NT_STATUS_INVALID_PARAMETER;
2510 goto fail;
2513 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2514 status = NT_STATUS_INVALID_PARAMETER;
2515 goto fail;
2518 /* First open the top level directory. */
2519 status = cli_smb2_create_fnum(cli,
2520 path,
2521 0, /* create_flags */
2522 SMB2_IMPERSONATION_IMPERSONATION,
2523 FILE_READ_ATTRIBUTES, /* desired_access */
2524 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2525 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2526 FILE_OPEN, /* create_disposition */
2527 FILE_DIRECTORY_FILE, /* create_options */
2528 NULL,
2529 &fnum,
2530 NULL,
2531 NULL,
2532 NULL);
2534 if (!NT_STATUS_IS_OK(status)) {
2535 goto fail;
2538 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2539 level 3 (SMB_FS_SIZE_INFORMATION). */
2541 status = cli_smb2_query_info_fnum(
2542 cli,
2543 fnum,
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 frame,
2551 &outbuf);
2552 if (!NT_STATUS_IS_OK(status)) {
2553 goto fail;
2556 /* Parse the reply. */
2557 if (outbuf.length != 24) {
2558 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2559 goto fail;
2562 total_size = BVAL(outbuf.data, 0);
2563 size_free = BVAL(outbuf.data, 8);
2564 sectors_per_unit = IVAL(outbuf.data, 16);
2565 bytes_per_sector = IVAL(outbuf.data, 20);
2567 if (bsize) {
2568 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2570 if (total) {
2571 *total = total_size;
2573 if (avail) {
2574 *avail = size_free;
2577 status = NT_STATUS_OK;
2579 fail:
2581 if (fnum != 0xffff) {
2582 cli_smb2_close_fnum(cli, fnum);
2585 cli->raw_status = status;
2587 TALLOC_FREE(frame);
2588 return status;
2591 /***************************************************************
2592 Wrapper that allows SMB2 to query file system sizes.
2593 Synchronous only.
2594 ***************************************************************/
2596 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2597 uint64_t *total_allocation_units,
2598 uint64_t *caller_allocation_units,
2599 uint64_t *actual_allocation_units,
2600 uint64_t *sectors_per_allocation_unit,
2601 uint64_t *bytes_per_sector)
2603 NTSTATUS status;
2604 uint16_t fnum = 0xffff;
2605 DATA_BLOB outbuf = data_blob_null;
2606 TALLOC_CTX *frame = talloc_stackframe();
2608 if (smbXcli_conn_has_async_calls(cli->conn)) {
2610 * Can't use sync call while an async call is in flight
2612 status = NT_STATUS_INVALID_PARAMETER;
2613 goto fail;
2616 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2617 status = NT_STATUS_INVALID_PARAMETER;
2618 goto fail;
2621 /* First open the top level directory. */
2622 status =
2623 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2624 SMB2_IMPERSONATION_IMPERSONATION,
2625 FILE_READ_ATTRIBUTES, /* desired_access */
2626 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2627 FILE_SHARE_READ | FILE_SHARE_WRITE |
2628 FILE_SHARE_DELETE, /* share_access */
2629 FILE_OPEN, /* create_disposition */
2630 FILE_DIRECTORY_FILE, /* create_options */
2631 NULL,
2632 &fnum,
2633 NULL,
2634 NULL,
2635 NULL);
2637 if (!NT_STATUS_IS_OK(status)) {
2638 goto fail;
2641 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2642 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2644 status = cli_smb2_query_info_fnum(
2645 cli,
2646 fnum,
2647 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2648 SMB_FS_FULL_SIZE_INFORMATION - 1000, /* in_file_info_class */
2649 0xFFFF, /* in_max_output_length */
2650 NULL, /* in_input_buffer */
2651 0, /* in_additional_info */
2652 0, /* in_flags */
2653 frame,
2654 &outbuf);
2655 if (!NT_STATUS_IS_OK(status)) {
2656 goto fail;
2659 if (outbuf.length < 32) {
2660 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2661 goto fail;
2664 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2665 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2666 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2667 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2668 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2670 fail:
2672 if (fnum != 0xffff) {
2673 cli_smb2_close_fnum(cli, fnum);
2676 cli->raw_status = status;
2678 TALLOC_FREE(frame);
2679 return status;
2682 /***************************************************************
2683 Wrapper that allows SMB2 to query file system attributes.
2684 Synchronous only.
2685 ***************************************************************/
2687 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2689 NTSTATUS status;
2690 uint16_t fnum = 0xffff;
2691 DATA_BLOB outbuf = data_blob_null;
2692 TALLOC_CTX *frame = talloc_stackframe();
2694 if (smbXcli_conn_has_async_calls(cli->conn)) {
2696 * Can't use sync call while an async call is in flight
2698 status = NT_STATUS_INVALID_PARAMETER;
2699 goto fail;
2702 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2703 status = NT_STATUS_INVALID_PARAMETER;
2704 goto fail;
2707 /* First open the top level directory. */
2708 status =
2709 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2710 SMB2_IMPERSONATION_IMPERSONATION,
2711 FILE_READ_ATTRIBUTES, /* desired_access */
2712 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2713 FILE_SHARE_READ | FILE_SHARE_WRITE |
2714 FILE_SHARE_DELETE, /* share_access */
2715 FILE_OPEN, /* create_disposition */
2716 FILE_DIRECTORY_FILE, /* create_options */
2717 NULL,
2718 &fnum,
2719 NULL,
2720 NULL,
2721 NULL);
2723 if (!NT_STATUS_IS_OK(status)) {
2724 goto fail;
2727 status = cli_smb2_query_info_fnum(
2728 cli,
2729 fnum,
2730 2, /* in_info_type */
2731 5, /* in_file_info_class */
2732 0xFFFF, /* in_max_output_length */
2733 NULL, /* in_input_buffer */
2734 0, /* in_additional_info */
2735 0, /* in_flags */
2736 frame,
2737 &outbuf);
2738 if (!NT_STATUS_IS_OK(status)) {
2739 goto fail;
2742 if (outbuf.length < 12) {
2743 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2744 goto fail;
2747 *fs_attr = IVAL(outbuf.data, 0);
2749 fail:
2751 if (fnum != 0xffff) {
2752 cli_smb2_close_fnum(cli, fnum);
2755 cli->raw_status = status;
2757 TALLOC_FREE(frame);
2758 return status;
2761 /***************************************************************
2762 Wrapper that allows SMB2 to query file system volume info.
2763 Synchronous only.
2764 ***************************************************************/
2766 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2767 TALLOC_CTX *mem_ctx,
2768 char **_volume_name,
2769 uint32_t *pserial_number,
2770 time_t *pdate)
2772 NTSTATUS status;
2773 uint16_t fnum = 0xffff;
2774 DATA_BLOB outbuf = data_blob_null;
2775 uint32_t nlen;
2776 char *volume_name = NULL;
2777 TALLOC_CTX *frame = talloc_stackframe();
2779 if (smbXcli_conn_has_async_calls(cli->conn)) {
2781 * Can't use sync call while an async call is in flight
2783 status = NT_STATUS_INVALID_PARAMETER;
2784 goto fail;
2787 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2788 status = NT_STATUS_INVALID_PARAMETER;
2789 goto fail;
2792 /* First open the top level directory. */
2793 status =
2794 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2795 SMB2_IMPERSONATION_IMPERSONATION,
2796 FILE_READ_ATTRIBUTES, /* desired_access */
2797 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2798 FILE_SHARE_READ | FILE_SHARE_WRITE |
2799 FILE_SHARE_DELETE, /* share_access */
2800 FILE_OPEN, /* create_disposition */
2801 FILE_DIRECTORY_FILE, /* create_options */
2802 NULL,
2803 &fnum,
2804 NULL,
2805 NULL,
2806 NULL);
2808 if (!NT_STATUS_IS_OK(status)) {
2809 goto fail;
2812 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2813 level 1 (SMB_FS_VOLUME_INFORMATION). */
2815 status = cli_smb2_query_info_fnum(
2816 cli,
2817 fnum,
2818 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
2819 /* in_file_info_class */
2820 SMB_FS_VOLUME_INFORMATION - 1000,
2821 0xFFFF, /* in_max_output_length */
2822 NULL, /* in_input_buffer */
2823 0, /* in_additional_info */
2824 0, /* in_flags */
2825 frame,
2826 &outbuf);
2827 if (!NT_STATUS_IS_OK(status)) {
2828 goto fail;
2831 if (outbuf.length < 24) {
2832 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2833 goto fail;
2836 if (pdate) {
2837 struct timespec ts;
2838 ts = interpret_long_date((char *)outbuf.data);
2839 *pdate = ts.tv_sec;
2841 if (pserial_number) {
2842 *pserial_number = IVAL(outbuf.data,8);
2844 nlen = IVAL(outbuf.data,12);
2845 if (nlen + 18 < 18) {
2846 /* Integer wrap. */
2847 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2848 goto fail;
2851 * The next check is safe as we know outbuf.length >= 24
2852 * from above.
2854 if (nlen > (outbuf.length - 18)) {
2855 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2856 goto fail;
2859 pull_string_talloc(mem_ctx,
2860 (const char *)outbuf.data,
2862 &volume_name,
2863 outbuf.data + 18,
2864 nlen,
2865 STR_UNICODE);
2866 if (volume_name == NULL) {
2867 status = map_nt_error_from_unix(errno);
2868 goto fail;
2871 *_volume_name = volume_name;
2873 fail:
2875 if (fnum != 0xffff) {
2876 cli_smb2_close_fnum(cli, fnum);
2879 cli->raw_status = status;
2881 TALLOC_FREE(frame);
2882 return status;
2885 struct cli_smb2_mxac_state {
2886 struct tevent_context *ev;
2887 struct cli_state *cli;
2888 const char *fname;
2889 struct smb2_create_blobs in_cblobs;
2890 uint16_t fnum;
2891 NTSTATUS status;
2892 uint32_t mxac;
2895 static void cli_smb2_mxac_opened(struct tevent_req *subreq);
2896 static void cli_smb2_mxac_closed(struct tevent_req *subreq);
2898 struct tevent_req *cli_smb2_query_mxac_send(TALLOC_CTX *mem_ctx,
2899 struct tevent_context *ev,
2900 struct cli_state *cli,
2901 const char *fname)
2903 struct tevent_req *req = NULL, *subreq = NULL;
2904 struct cli_smb2_mxac_state *state = NULL;
2905 NTSTATUS status;
2907 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_mxac_state);
2908 if (req == NULL) {
2909 return NULL;
2911 *state = (struct cli_smb2_mxac_state) {
2912 .ev = ev,
2913 .cli = cli,
2914 .fname = fname,
2917 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2918 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2919 return tevent_req_post(req, ev);
2922 status = smb2_create_blob_add(state,
2923 &state->in_cblobs,
2924 SMB2_CREATE_TAG_MXAC,
2925 data_blob(NULL, 0));
2926 if (tevent_req_nterror(req, status)) {
2927 return tevent_req_post(req, ev);
2930 subreq = cli_smb2_create_fnum_send(
2931 state,
2932 state->ev,
2933 state->cli,
2934 state->fname,
2935 0, /* create_flags */
2936 SMB2_IMPERSONATION_IMPERSONATION,
2937 FILE_READ_ATTRIBUTES,
2938 0, /* file attributes */
2939 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
2940 FILE_OPEN,
2941 0, /* create_options */
2942 &state->in_cblobs);
2943 if (tevent_req_nomem(subreq, req)) {
2944 return tevent_req_post(req, ev);
2946 tevent_req_set_callback(subreq, cli_smb2_mxac_opened, req);
2947 return req;
2950 static void cli_smb2_mxac_opened(struct tevent_req *subreq)
2952 struct tevent_req *req = tevent_req_callback_data(
2953 subreq, struct tevent_req);
2954 struct cli_smb2_mxac_state *state = tevent_req_data(
2955 req, struct cli_smb2_mxac_state);
2956 struct smb2_create_blobs out_cblobs = {0};
2957 struct smb2_create_blob *mxac_blob = NULL;
2958 NTSTATUS status;
2960 status = cli_smb2_create_fnum_recv(
2961 subreq, &state->fnum, NULL, state, &out_cblobs);
2962 TALLOC_FREE(subreq);
2964 if (tevent_req_nterror(req, status)) {
2965 return;
2968 mxac_blob = smb2_create_blob_find(&out_cblobs, SMB2_CREATE_TAG_MXAC);
2969 if (mxac_blob == NULL) {
2970 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2971 goto close;
2973 if (mxac_blob->data.length != 8) {
2974 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2975 goto close;
2978 state->status = NT_STATUS(IVAL(mxac_blob->data.data, 0));
2979 state->mxac = IVAL(mxac_blob->data.data, 4);
2981 close:
2982 subreq = cli_smb2_close_fnum_send(
2983 state, state->ev, state->cli, state->fnum);
2984 if (tevent_req_nomem(subreq, req)) {
2985 return;
2987 tevent_req_set_callback(subreq, cli_smb2_mxac_closed, req);
2989 return;
2992 static void cli_smb2_mxac_closed(struct tevent_req *subreq)
2994 struct tevent_req *req = tevent_req_callback_data(
2995 subreq, struct tevent_req);
2996 NTSTATUS status;
2998 status = cli_smb2_close_fnum_recv(subreq);
2999 if (tevent_req_nterror(req, status)) {
3000 return;
3003 tevent_req_done(req);
3006 NTSTATUS cli_smb2_query_mxac_recv(struct tevent_req *req, uint32_t *mxac)
3008 struct cli_smb2_mxac_state *state = tevent_req_data(
3009 req, struct cli_smb2_mxac_state);
3010 NTSTATUS status;
3012 if (tevent_req_is_nterror(req, &status)) {
3013 return status;
3016 if (!NT_STATUS_IS_OK(state->status)) {
3017 return state->status;
3020 *mxac = state->mxac;
3021 return NT_STATUS_OK;
3024 NTSTATUS cli_smb2_query_mxac(struct cli_state *cli,
3025 const char *fname,
3026 uint32_t *_mxac)
3028 TALLOC_CTX *frame = talloc_stackframe();
3029 struct tevent_context *ev = NULL;
3030 struct tevent_req *req = NULL;
3031 NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
3032 bool ok;
3034 if (smbXcli_conn_has_async_calls(cli->conn)) {
3036 * Can't use sync call while an async call is in flight
3038 status = NT_STATUS_INVALID_PARAMETER;
3039 goto fail;
3042 ev = samba_tevent_context_init(frame);
3043 if (ev == NULL) {
3044 goto fail;
3046 req = cli_smb2_query_mxac_send(frame, ev, cli, fname);
3047 if (req == NULL) {
3048 goto fail;
3050 ok = tevent_req_poll_ntstatus(req, ev, &status);
3051 if (!ok) {
3052 goto fail;
3054 status = cli_smb2_query_mxac_recv(req, _mxac);
3056 fail:
3057 cli->raw_status = status;
3058 TALLOC_FREE(frame);
3059 return status;
3062 struct cli_smb2_rename_fnum_state {
3063 DATA_BLOB inbuf;
3066 static void cli_smb2_rename_fnum_done(struct tevent_req *subreq);
3068 static struct tevent_req *cli_smb2_rename_fnum_send(
3069 TALLOC_CTX *mem_ctx,
3070 struct tevent_context *ev,
3071 struct cli_state *cli,
3072 uint16_t fnum,
3073 const char *fname_dst,
3074 bool replace)
3076 struct tevent_req *req = NULL, *subreq = NULL;
3077 struct cli_smb2_rename_fnum_state *state = NULL;
3078 size_t namelen = strlen(fname_dst);
3079 smb_ucs2_t *converted_str = NULL;
3080 size_t converted_size_bytes = 0;
3081 size_t inbuf_size;
3082 bool ok;
3084 req = tevent_req_create(
3085 mem_ctx, &state, struct cli_smb2_rename_fnum_state);
3086 if (req == NULL) {
3087 return NULL;
3091 * SMB2 is pickier about pathnames. Ensure it doesn't start in
3092 * a '\'
3094 if (*fname_dst == '\\') {
3095 fname_dst++;
3099 * SMB2 is pickier about pathnames. Ensure it doesn't end in a
3100 * '\'
3102 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
3103 fname_dst = talloc_strndup(state, fname_dst, namelen-1);
3104 if (tevent_req_nomem(fname_dst, req)) {
3105 return tevent_req_post(req, ev);
3109 ok = push_ucs2_talloc(
3110 state, &converted_str, fname_dst, &converted_size_bytes);
3111 if (!ok) {
3112 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3113 return tevent_req_post(req, ev);
3117 * W2K8 insists the dest name is not null terminated. Remove
3118 * the last 2 zero bytes and reduce the name length.
3120 if (converted_size_bytes < 2) {
3121 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3122 return tevent_req_post(req, ev);
3124 converted_size_bytes -= 2;
3126 inbuf_size = 20 + converted_size_bytes;
3127 if (inbuf_size < 20) {
3128 /* Integer wrap check. */
3129 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3130 return tevent_req_post(req, ev);
3134 * The Windows 10 SMB2 server has a minimum length
3135 * for a SMB2_FILE_RENAME_INFORMATION buffer of
3136 * 24 bytes. It returns NT_STATUS_INFO_LENGTH_MISMATCH
3137 * if the length is less. This isn't an alignment
3138 * issue as Windows client happily 2-byte align
3139 * for larget target name sizes. Also the Windows 10
3140 * SMB1 server doesn't have this restriction.
3142 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14403
3144 inbuf_size = MAX(inbuf_size, 24);
3146 state->inbuf = data_blob_talloc_zero(state, inbuf_size);
3147 if (tevent_req_nomem(state->inbuf.data, req)) {
3148 return tevent_req_post(req, ev);
3151 if (replace) {
3152 SCVAL(state->inbuf.data, 0, 1);
3155 SIVAL(state->inbuf.data, 16, converted_size_bytes);
3156 memcpy(state->inbuf.data + 20, converted_str, converted_size_bytes);
3158 TALLOC_FREE(converted_str);
3160 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
3161 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
3163 subreq = cli_smb2_set_info_fnum_send(
3164 state, /* mem_ctx */
3165 ev, /* ev */
3166 cli, /* cli */
3167 fnum, /* fnum */
3168 1, /* in_info_type */
3169 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
3170 &state->inbuf, /* in_input_buffer */
3171 0); /* in_additional_info */
3172 if (tevent_req_nomem(subreq, req)) {
3173 return tevent_req_post(req, ev);
3175 tevent_req_set_callback(subreq, cli_smb2_rename_fnum_done, req);
3176 return req;
3179 static void cli_smb2_rename_fnum_done(struct tevent_req *subreq)
3181 NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
3182 tevent_req_simple_finish_ntstatus(subreq, status);
3185 static NTSTATUS cli_smb2_rename_fnum_recv(struct tevent_req *req)
3187 return tevent_req_simple_recv_ntstatus(req);
3190 /***************************************************************
3191 Wrapper that allows SMB2 to rename a file.
3192 ***************************************************************/
3194 struct cli_smb2_rename_state {
3195 struct tevent_context *ev;
3196 struct cli_state *cli;
3197 const char *fname_dst;
3198 bool replace;
3199 uint16_t fnum;
3201 NTSTATUS rename_status;
3204 static void cli_smb2_rename_opened(struct tevent_req *subreq);
3205 static void cli_smb2_rename_renamed(struct tevent_req *subreq);
3206 static void cli_smb2_rename_closed(struct tevent_req *subreq);
3208 struct tevent_req *cli_smb2_rename_send(
3209 TALLOC_CTX *mem_ctx,
3210 struct tevent_context *ev,
3211 struct cli_state *cli,
3212 const char *fname_src,
3213 const char *fname_dst,
3214 bool replace)
3216 struct tevent_req *req = NULL, *subreq = NULL;
3217 struct cli_smb2_rename_state *state = NULL;
3218 NTSTATUS status;
3220 req = tevent_req_create(
3221 mem_ctx, &state, struct cli_smb2_rename_state);
3222 if (req == NULL) {
3223 return NULL;
3227 * Strip a MSDFS path from fname_dst if we were given one.
3229 status = cli_dfs_target_check(state,
3230 cli,
3231 fname_src,
3232 fname_dst,
3233 &fname_dst);
3234 if (tevent_req_nterror(req, status)) {
3235 return tevent_req_post(req, ev);
3238 state->ev = ev;
3239 state->cli = cli;
3240 state->fname_dst = fname_dst;
3241 state->replace = replace;
3243 subreq = get_fnum_from_path_send(
3244 state, ev, cli, fname_src, DELETE_ACCESS);
3245 if (tevent_req_nomem(subreq, req)) {
3246 return tevent_req_post(req, ev);
3248 tevent_req_set_callback(subreq, cli_smb2_rename_opened, req);
3249 return req;
3252 static void cli_smb2_rename_opened(struct tevent_req *subreq)
3254 struct tevent_req *req = tevent_req_callback_data(
3255 subreq, struct tevent_req);
3256 struct cli_smb2_rename_state *state = tevent_req_data(
3257 req, struct cli_smb2_rename_state);
3258 NTSTATUS status;
3260 status = get_fnum_from_path_recv(subreq, &state->fnum);
3261 TALLOC_FREE(subreq);
3262 if (tevent_req_nterror(req, status)) {
3263 return;
3266 subreq = cli_smb2_rename_fnum_send(
3267 state,
3268 state->ev,
3269 state->cli,
3270 state->fnum,
3271 state->fname_dst,
3272 state->replace);
3273 if (tevent_req_nomem(subreq, req)) {
3274 return;
3276 tevent_req_set_callback(subreq, cli_smb2_rename_renamed, req);
3279 static void cli_smb2_rename_renamed(struct tevent_req *subreq)
3281 struct tevent_req *req = tevent_req_callback_data(
3282 subreq, struct tevent_req);
3283 struct cli_smb2_rename_state *state = tevent_req_data(
3284 req, struct cli_smb2_rename_state);
3286 state->rename_status = cli_smb2_rename_fnum_recv(subreq);
3287 TALLOC_FREE(subreq);
3289 subreq = cli_smb2_close_fnum_send(
3290 state, state->ev, state->cli, state->fnum);
3291 if (tevent_req_nomem(subreq, req)) {
3292 return;
3294 tevent_req_set_callback(subreq, cli_smb2_rename_closed, req);
3297 static void cli_smb2_rename_closed(struct tevent_req *subreq)
3299 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
3300 tevent_req_simple_finish_ntstatus(subreq, status);
3303 NTSTATUS cli_smb2_rename_recv(struct tevent_req *req)
3305 struct cli_smb2_rename_state *state = tevent_req_data(
3306 req, struct cli_smb2_rename_state);
3307 NTSTATUS status = NT_STATUS_OK;
3309 if (!tevent_req_is_nterror(req, &status)) {
3310 status = state->rename_status;
3312 tevent_req_received(req);
3313 return status;
3316 /***************************************************************
3317 Wrapper that allows SMB2 to set an EA on a fnum.
3318 Synchronous only.
3319 ***************************************************************/
3321 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
3322 uint16_t fnum,
3323 const char *ea_name,
3324 const char *ea_val,
3325 size_t ea_len)
3327 NTSTATUS status;
3328 DATA_BLOB inbuf = data_blob_null;
3329 size_t bloblen = 0;
3330 char *ea_name_ascii = NULL;
3331 size_t namelen = 0;
3332 TALLOC_CTX *frame = talloc_stackframe();
3334 if (smbXcli_conn_has_async_calls(cli->conn)) {
3336 * Can't use sync call while an async call is in flight
3338 status = NT_STATUS_INVALID_PARAMETER;
3339 goto fail;
3342 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3343 status = NT_STATUS_INVALID_PARAMETER;
3344 goto fail;
3347 /* Marshall the SMB2 EA data. */
3348 if (ea_len > 0xFFFF) {
3349 status = NT_STATUS_INVALID_PARAMETER;
3350 goto fail;
3353 if (!push_ascii_talloc(frame,
3354 &ea_name_ascii,
3355 ea_name,
3356 &namelen)) {
3357 status = NT_STATUS_INVALID_PARAMETER;
3358 goto fail;
3361 if (namelen < 2 || namelen > 0xFF) {
3362 status = NT_STATUS_INVALID_PARAMETER;
3363 goto fail;
3366 bloblen = 8 + ea_len + namelen;
3367 /* Round up to a 4 byte boundary. */
3368 bloblen = ((bloblen + 3)&~3);
3370 inbuf = data_blob_talloc_zero(frame, bloblen);
3371 if (inbuf.data == NULL) {
3372 status = NT_STATUS_NO_MEMORY;
3373 goto fail;
3375 /* namelen doesn't include the NULL byte. */
3376 SCVAL(inbuf.data, 5, namelen - 1);
3377 SSVAL(inbuf.data, 6, ea_len);
3378 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
3379 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
3381 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3382 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3384 status = cli_smb2_set_info_fnum(
3385 cli,
3386 fnum,
3387 1, /* in_info_type */
3388 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3389 &inbuf, /* in_input_buffer */
3390 0); /* in_additional_info */
3392 fail:
3394 cli->raw_status = status;
3396 TALLOC_FREE(frame);
3397 return status;
3400 /***************************************************************
3401 Wrapper that allows SMB2 to set an EA on a pathname.
3402 Synchronous only.
3403 ***************************************************************/
3405 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
3406 const char *name,
3407 const char *ea_name,
3408 const char *ea_val,
3409 size_t ea_len)
3411 NTSTATUS status;
3412 uint16_t fnum = 0xffff;
3414 if (smbXcli_conn_has_async_calls(cli->conn)) {
3416 * Can't use sync call while an async call is in flight
3418 status = NT_STATUS_INVALID_PARAMETER;
3419 goto fail;
3422 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3423 status = NT_STATUS_INVALID_PARAMETER;
3424 goto fail;
3427 status = get_fnum_from_path(cli,
3428 name,
3429 FILE_WRITE_EA,
3430 &fnum);
3432 if (!NT_STATUS_IS_OK(status)) {
3433 goto fail;
3436 status = cli_set_ea_fnum(cli,
3437 fnum,
3438 ea_name,
3439 ea_val,
3440 ea_len);
3441 if (!NT_STATUS_IS_OK(status)) {
3442 goto fail;
3445 fail:
3447 if (fnum != 0xffff) {
3448 cli_smb2_close_fnum(cli, fnum);
3451 cli->raw_status = status;
3453 return status;
3456 /***************************************************************
3457 Wrapper that allows SMB2 to get an EA list on a pathname.
3458 Synchronous only.
3459 ***************************************************************/
3461 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
3462 const char *name,
3463 TALLOC_CTX *ctx,
3464 size_t *pnum_eas,
3465 struct ea_struct **pea_array)
3467 NTSTATUS status;
3468 uint16_t fnum = 0xffff;
3469 DATA_BLOB outbuf = data_blob_null;
3470 struct ea_list *ea_list = NULL;
3471 struct ea_list *eal = NULL;
3472 size_t ea_count = 0;
3473 TALLOC_CTX *frame = talloc_stackframe();
3475 *pnum_eas = 0;
3476 *pea_array = NULL;
3478 if (smbXcli_conn_has_async_calls(cli->conn)) {
3480 * Can't use sync call while an async call is in flight
3482 status = NT_STATUS_INVALID_PARAMETER;
3483 goto fail;
3486 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3487 status = NT_STATUS_INVALID_PARAMETER;
3488 goto fail;
3491 status = get_fnum_from_path(cli,
3492 name,
3493 FILE_READ_EA,
3494 &fnum);
3496 if (!NT_STATUS_IS_OK(status)) {
3497 goto fail;
3500 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
3501 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
3503 status = cli_smb2_query_info_fnum(
3504 cli,
3505 fnum,
3506 1, /* in_info_type */
3507 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
3508 0xFFFF, /* in_max_output_length */
3509 NULL, /* in_input_buffer */
3510 0, /* in_additional_info */
3511 0, /* in_flags */
3512 frame,
3513 &outbuf);
3515 if (!NT_STATUS_IS_OK(status)) {
3516 goto fail;
3519 /* Parse the reply. */
3520 ea_list = read_nttrans_ea_list(ctx,
3521 (const char *)outbuf.data,
3522 outbuf.length);
3523 if (ea_list == NULL) {
3524 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3525 goto fail;
3528 /* Convert to an array. */
3529 for (eal = ea_list; eal; eal = eal->next) {
3530 ea_count++;
3533 if (ea_count) {
3534 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
3535 if (*pea_array == NULL) {
3536 status = NT_STATUS_NO_MEMORY;
3537 goto fail;
3539 ea_count = 0;
3540 for (eal = ea_list; eal; eal = eal->next) {
3541 (*pea_array)[ea_count++] = eal->ea;
3543 *pnum_eas = ea_count;
3546 fail:
3548 if (fnum != 0xffff) {
3549 cli_smb2_close_fnum(cli, fnum);
3552 cli->raw_status = status;
3554 TALLOC_FREE(frame);
3555 return status;
3558 /***************************************************************
3559 Wrapper that allows SMB2 to get user quota.
3560 Synchronous only.
3561 ***************************************************************/
3563 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
3564 int quota_fnum,
3565 SMB_NTQUOTA_STRUCT *pqt)
3567 NTSTATUS status;
3568 DATA_BLOB inbuf = data_blob_null;
3569 DATA_BLOB info_blob = data_blob_null;
3570 DATA_BLOB outbuf = data_blob_null;
3571 TALLOC_CTX *frame = talloc_stackframe();
3572 unsigned sid_len;
3573 unsigned int offset;
3574 struct smb2_query_quota_info query = {0};
3575 struct file_get_quota_info info = {0};
3576 enum ndr_err_code err;
3577 struct ndr_push *ndr_push = NULL;
3579 if (smbXcli_conn_has_async_calls(cli->conn)) {
3581 * Can't use sync call while an async call is in flight
3583 status = NT_STATUS_INVALID_PARAMETER;
3584 goto fail;
3587 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3588 status = NT_STATUS_INVALID_PARAMETER;
3589 goto fail;
3592 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
3594 query.return_single = 1;
3596 info.next_entry_offset = 0;
3597 info.sid_length = sid_len;
3598 info.sid = pqt->sid;
3600 err = ndr_push_struct_blob(
3601 &info_blob,
3602 frame,
3603 &info,
3604 (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
3606 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3607 status = NT_STATUS_INTERNAL_ERROR;
3608 goto fail;
3611 query.sid_list_length = info_blob.length;
3612 ndr_push = ndr_push_init_ctx(frame);
3613 if (!ndr_push) {
3614 status = NT_STATUS_NO_MEMORY;
3615 goto fail;
3618 err = ndr_push_smb2_query_quota_info(ndr_push,
3619 NDR_SCALARS | NDR_BUFFERS,
3620 &query);
3622 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3623 status = NT_STATUS_INTERNAL_ERROR;
3624 goto fail;
3627 err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3628 info_blob.length);
3630 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3631 status = NT_STATUS_INTERNAL_ERROR;
3632 goto fail;
3634 inbuf.data = ndr_push->data;
3635 inbuf.length = ndr_push->offset;
3637 status = cli_smb2_query_info_fnum(
3638 cli,
3639 quota_fnum,
3640 4, /* in_info_type */
3641 0, /* in_file_info_class */
3642 0xFFFF, /* in_max_output_length */
3643 &inbuf, /* in_input_buffer */
3644 0, /* in_additional_info */
3645 0, /* in_flags */
3646 frame,
3647 &outbuf);
3649 if (!NT_STATUS_IS_OK(status)) {
3650 goto fail;
3653 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3654 pqt)) {
3655 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3656 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3659 fail:
3660 cli->raw_status = status;
3662 TALLOC_FREE(frame);
3663 return status;
3666 /***************************************************************
3667 Wrapper that allows SMB2 to list user quota.
3668 Synchronous only.
3669 ***************************************************************/
3671 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3672 TALLOC_CTX *mem_ctx,
3673 int quota_fnum,
3674 SMB_NTQUOTA_LIST **pqt_list,
3675 bool first)
3677 NTSTATUS status;
3678 DATA_BLOB inbuf = data_blob_null;
3679 DATA_BLOB outbuf = data_blob_null;
3680 TALLOC_CTX *frame = talloc_stackframe();
3681 struct smb2_query_quota_info info = {0};
3682 enum ndr_err_code err;
3684 if (smbXcli_conn_has_async_calls(cli->conn)) {
3686 * Can't use sync call while an async call is in flight
3688 status = NT_STATUS_INVALID_PARAMETER;
3689 goto cleanup;
3692 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3693 status = NT_STATUS_INVALID_PARAMETER;
3694 goto cleanup;
3697 info.restart_scan = first ? 1 : 0;
3699 err = ndr_push_struct_blob(
3700 &inbuf,
3701 frame,
3702 &info,
3703 (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3705 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3706 status = NT_STATUS_INTERNAL_ERROR;
3707 goto cleanup;
3710 status = cli_smb2_query_info_fnum(
3711 cli,
3712 quota_fnum,
3713 4, /* in_info_type */
3714 0, /* in_file_info_class */
3715 0xFFFF, /* in_max_output_length */
3716 &inbuf, /* in_input_buffer */
3717 0, /* in_additional_info */
3718 0, /* in_flags */
3719 frame,
3720 &outbuf);
3723 * safeguard against panic from calling parse_user_quota_list with
3724 * NULL buffer
3726 if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3727 status = NT_STATUS_NO_MORE_ENTRIES;
3730 if (!NT_STATUS_IS_OK(status)) {
3731 goto cleanup;
3734 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3735 pqt_list);
3737 cleanup:
3738 cli->raw_status = status;
3740 TALLOC_FREE(frame);
3741 return status;
3744 /***************************************************************
3745 Wrapper that allows SMB2 to get file system quota.
3746 Synchronous only.
3747 ***************************************************************/
3749 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3750 int quota_fnum,
3751 SMB_NTQUOTA_STRUCT *pqt)
3753 NTSTATUS status;
3754 DATA_BLOB outbuf = data_blob_null;
3755 TALLOC_CTX *frame = talloc_stackframe();
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 = cli_smb2_query_info_fnum(
3771 cli,
3772 quota_fnum,
3773 2, /* in_info_type */
3774 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3775 0xFFFF, /* in_max_output_length */
3776 NULL, /* in_input_buffer */
3777 0, /* in_additional_info */
3778 0, /* in_flags */
3779 frame,
3780 &outbuf);
3782 if (!NT_STATUS_IS_OK(status)) {
3783 goto cleanup;
3786 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3788 cleanup:
3789 cli->raw_status = status;
3791 TALLOC_FREE(frame);
3792 return status;
3795 /***************************************************************
3796 Wrapper that allows SMB2 to set user quota.
3797 Synchronous only.
3798 ***************************************************************/
3800 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3801 int quota_fnum,
3802 SMB_NTQUOTA_LIST *qtl)
3804 NTSTATUS status;
3805 DATA_BLOB inbuf = data_blob_null;
3806 TALLOC_CTX *frame = talloc_stackframe();
3808 if (smbXcli_conn_has_async_calls(cli->conn)) {
3810 * Can't use sync call while an async call is in flight
3812 status = NT_STATUS_INVALID_PARAMETER;
3813 goto cleanup;
3816 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3817 status = NT_STATUS_INVALID_PARAMETER;
3818 goto cleanup;
3821 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3822 if (!NT_STATUS_IS_OK(status)) {
3823 goto cleanup;
3826 status = cli_smb2_set_info_fnum(
3827 cli,
3828 quota_fnum,
3829 4, /* in_info_type */
3830 0, /* in_file_info_class */
3831 &inbuf, /* in_input_buffer */
3832 0); /* in_additional_info */
3833 cleanup:
3835 cli->raw_status = status;
3837 TALLOC_FREE(frame);
3839 return status;
3842 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3843 int quota_fnum,
3844 SMB_NTQUOTA_STRUCT *pqt)
3846 NTSTATUS status;
3847 DATA_BLOB inbuf = data_blob_null;
3848 TALLOC_CTX *frame = talloc_stackframe();
3850 if (smbXcli_conn_has_async_calls(cli->conn)) {
3852 * Can't use sync call while an async call is in flight
3854 status = NT_STATUS_INVALID_PARAMETER;
3855 goto cleanup;
3858 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3859 status = NT_STATUS_INVALID_PARAMETER;
3860 goto cleanup;
3863 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3864 if (!NT_STATUS_IS_OK(status)) {
3865 goto cleanup;
3868 status = cli_smb2_set_info_fnum(
3869 cli,
3870 quota_fnum,
3871 2, /* in_info_type */
3872 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3873 &inbuf, /* in_input_buffer */
3874 0); /* in_additional_info */
3875 cleanup:
3876 cli->raw_status = status;
3878 TALLOC_FREE(frame);
3879 return status;
3882 struct cli_smb2_read_state {
3883 struct tevent_context *ev;
3884 struct cli_state *cli;
3885 struct smb2_hnd *ph;
3886 uint64_t start_offset;
3887 uint32_t size;
3888 uint32_t received;
3889 uint8_t *buf;
3892 static void cli_smb2_read_done(struct tevent_req *subreq);
3894 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3895 struct tevent_context *ev,
3896 struct cli_state *cli,
3897 uint16_t fnum,
3898 off_t offset,
3899 size_t size)
3901 NTSTATUS status;
3902 struct tevent_req *req, *subreq;
3903 struct cli_smb2_read_state *state;
3905 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3906 if (req == NULL) {
3907 return NULL;
3909 state->ev = ev;
3910 state->cli = cli;
3911 state->start_offset = (uint64_t)offset;
3912 state->size = (uint32_t)size;
3913 state->received = 0;
3914 state->buf = NULL;
3916 status = map_fnum_to_smb2_handle(cli,
3917 fnum,
3918 &state->ph);
3919 if (tevent_req_nterror(req, status)) {
3920 return tevent_req_post(req, ev);
3923 subreq = smb2cli_read_send(state,
3924 state->ev,
3925 state->cli->conn,
3926 state->cli->timeout,
3927 state->cli->smb2.session,
3928 state->cli->smb2.tcon,
3929 state->size,
3930 state->start_offset,
3931 state->ph->fid_persistent,
3932 state->ph->fid_volatile,
3933 0, /* minimum_count */
3934 0); /* remaining_bytes */
3936 if (tevent_req_nomem(subreq, req)) {
3937 return tevent_req_post(req, ev);
3939 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3940 return req;
3943 static void cli_smb2_read_done(struct tevent_req *subreq)
3945 struct tevent_req *req = tevent_req_callback_data(
3946 subreq, struct tevent_req);
3947 struct cli_smb2_read_state *state = tevent_req_data(
3948 req, struct cli_smb2_read_state);
3949 NTSTATUS status;
3951 status = smb2cli_read_recv(subreq, state,
3952 &state->buf, &state->received);
3953 if (tevent_req_nterror(req, status)) {
3954 return;
3957 if (state->received > state->size) {
3958 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3959 return;
3962 tevent_req_done(req);
3965 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
3966 ssize_t *received,
3967 uint8_t **rcvbuf)
3969 NTSTATUS status;
3970 struct cli_smb2_read_state *state = tevent_req_data(
3971 req, struct cli_smb2_read_state);
3973 if (tevent_req_is_nterror(req, &status)) {
3974 state->cli->raw_status = status;
3975 return status;
3978 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3979 * better make sure that you copy it away before you talloc_free(req).
3980 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3982 *received = (ssize_t)state->received;
3983 *rcvbuf = state->buf;
3984 state->cli->raw_status = NT_STATUS_OK;
3985 return NT_STATUS_OK;
3988 struct cli_smb2_write_state {
3989 struct tevent_context *ev;
3990 struct cli_state *cli;
3991 struct smb2_hnd *ph;
3992 uint32_t flags;
3993 const uint8_t *buf;
3994 uint64_t offset;
3995 uint32_t size;
3996 uint32_t written;
3999 static void cli_smb2_write_written(struct tevent_req *req);
4001 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
4002 struct tevent_context *ev,
4003 struct cli_state *cli,
4004 uint16_t fnum,
4005 uint16_t mode,
4006 const uint8_t *buf,
4007 off_t offset,
4008 size_t size)
4010 NTSTATUS status;
4011 struct tevent_req *req, *subreq = NULL;
4012 struct cli_smb2_write_state *state = NULL;
4014 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
4015 if (req == NULL) {
4016 return NULL;
4018 state->ev = ev;
4019 state->cli = cli;
4020 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4021 state->flags = (uint32_t)mode;
4022 state->buf = buf;
4023 state->offset = (uint64_t)offset;
4024 state->size = (uint32_t)size;
4025 state->written = 0;
4027 status = map_fnum_to_smb2_handle(cli,
4028 fnum,
4029 &state->ph);
4030 if (tevent_req_nterror(req, status)) {
4031 return tevent_req_post(req, ev);
4034 subreq = smb2cli_write_send(state,
4035 state->ev,
4036 state->cli->conn,
4037 state->cli->timeout,
4038 state->cli->smb2.session,
4039 state->cli->smb2.tcon,
4040 state->size,
4041 state->offset,
4042 state->ph->fid_persistent,
4043 state->ph->fid_volatile,
4044 0, /* remaining_bytes */
4045 state->flags, /* flags */
4046 state->buf);
4048 if (tevent_req_nomem(subreq, req)) {
4049 return tevent_req_post(req, ev);
4051 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
4052 return req;
4055 static void cli_smb2_write_written(struct tevent_req *subreq)
4057 struct tevent_req *req = tevent_req_callback_data(
4058 subreq, struct tevent_req);
4059 struct cli_smb2_write_state *state = tevent_req_data(
4060 req, struct cli_smb2_write_state);
4061 NTSTATUS status;
4062 uint32_t written;
4064 status = smb2cli_write_recv(subreq, &written);
4065 TALLOC_FREE(subreq);
4066 if (tevent_req_nterror(req, status)) {
4067 return;
4070 state->written = written;
4072 tevent_req_done(req);
4075 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
4076 size_t *pwritten)
4078 struct cli_smb2_write_state *state = tevent_req_data(
4079 req, struct cli_smb2_write_state);
4080 NTSTATUS status;
4082 if (tevent_req_is_nterror(req, &status)) {
4083 state->cli->raw_status = status;
4084 tevent_req_received(req);
4085 return status;
4088 if (pwritten != NULL) {
4089 *pwritten = (size_t)state->written;
4091 state->cli->raw_status = NT_STATUS_OK;
4092 tevent_req_received(req);
4093 return NT_STATUS_OK;
4096 /***************************************************************
4097 Wrapper that allows SMB2 async write using an fnum.
4098 This is mostly cut-and-paste from Volker's code inside
4099 source3/libsmb/clireadwrite.c, adapted for SMB2.
4101 Done this way so I can reuse all the logic inside cli_push()
4102 for free :-).
4103 ***************************************************************/
4105 struct cli_smb2_writeall_state {
4106 struct tevent_context *ev;
4107 struct cli_state *cli;
4108 struct smb2_hnd *ph;
4109 uint32_t flags;
4110 const uint8_t *buf;
4111 uint64_t offset;
4112 uint32_t size;
4113 uint32_t written;
4116 static void cli_smb2_writeall_written(struct tevent_req *req);
4118 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
4119 struct tevent_context *ev,
4120 struct cli_state *cli,
4121 uint16_t fnum,
4122 uint16_t mode,
4123 const uint8_t *buf,
4124 off_t offset,
4125 size_t size)
4127 NTSTATUS status;
4128 struct tevent_req *req, *subreq = NULL;
4129 struct cli_smb2_writeall_state *state = NULL;
4130 uint32_t to_write;
4131 uint32_t max_size;
4132 bool ok;
4134 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
4135 if (req == NULL) {
4136 return NULL;
4138 state->ev = ev;
4139 state->cli = cli;
4140 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
4141 state->flags = (uint32_t)mode;
4142 state->buf = buf;
4143 state->offset = (uint64_t)offset;
4144 state->size = (uint32_t)size;
4145 state->written = 0;
4147 status = map_fnum_to_smb2_handle(cli,
4148 fnum,
4149 &state->ph);
4150 if (tevent_req_nterror(req, status)) {
4151 return tevent_req_post(req, ev);
4154 to_write = state->size;
4155 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4156 to_write = MIN(max_size, to_write);
4157 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4158 if (ok) {
4159 to_write = MIN(max_size, to_write);
4162 subreq = smb2cli_write_send(state,
4163 state->ev,
4164 state->cli->conn,
4165 state->cli->timeout,
4166 state->cli->smb2.session,
4167 state->cli->smb2.tcon,
4168 to_write,
4169 state->offset,
4170 state->ph->fid_persistent,
4171 state->ph->fid_volatile,
4172 0, /* remaining_bytes */
4173 state->flags, /* flags */
4174 state->buf + state->written);
4176 if (tevent_req_nomem(subreq, req)) {
4177 return tevent_req_post(req, ev);
4179 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4180 return req;
4183 static void cli_smb2_writeall_written(struct tevent_req *subreq)
4185 struct tevent_req *req = tevent_req_callback_data(
4186 subreq, struct tevent_req);
4187 struct cli_smb2_writeall_state *state = tevent_req_data(
4188 req, struct cli_smb2_writeall_state);
4189 NTSTATUS status;
4190 uint32_t written, to_write;
4191 uint32_t max_size;
4192 bool ok;
4194 status = smb2cli_write_recv(subreq, &written);
4195 TALLOC_FREE(subreq);
4196 if (tevent_req_nterror(req, status)) {
4197 return;
4200 state->written += written;
4202 if (state->written > state->size) {
4203 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4204 return;
4207 to_write = state->size - state->written;
4209 if (to_write == 0) {
4210 tevent_req_done(req);
4211 return;
4214 max_size = smb2cli_conn_max_write_size(state->cli->conn);
4215 to_write = MIN(max_size, to_write);
4216 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
4217 if (ok) {
4218 to_write = MIN(max_size, to_write);
4221 subreq = smb2cli_write_send(state,
4222 state->ev,
4223 state->cli->conn,
4224 state->cli->timeout,
4225 state->cli->smb2.session,
4226 state->cli->smb2.tcon,
4227 to_write,
4228 state->offset + state->written,
4229 state->ph->fid_persistent,
4230 state->ph->fid_volatile,
4231 0, /* remaining_bytes */
4232 state->flags, /* flags */
4233 state->buf + state->written);
4235 if (tevent_req_nomem(subreq, req)) {
4236 return;
4238 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
4241 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
4242 size_t *pwritten)
4244 struct cli_smb2_writeall_state *state = tevent_req_data(
4245 req, struct cli_smb2_writeall_state);
4246 NTSTATUS status;
4248 if (tevent_req_is_nterror(req, &status)) {
4249 state->cli->raw_status = status;
4250 return status;
4252 if (pwritten != NULL) {
4253 *pwritten = (size_t)state->written;
4255 state->cli->raw_status = NT_STATUS_OK;
4256 return NT_STATUS_OK;
4259 struct cli_smb2_splice_state {
4260 struct tevent_context *ev;
4261 struct cli_state *cli;
4262 struct smb2_hnd *src_ph;
4263 struct smb2_hnd *dst_ph;
4264 int (*splice_cb)(off_t n, void *priv);
4265 void *priv;
4266 off_t written;
4267 off_t size;
4268 off_t src_offset;
4269 off_t dst_offset;
4270 bool resized;
4271 struct req_resume_key_rsp resume_rsp;
4272 struct srv_copychunk_copy cc_copy;
4275 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4276 struct tevent_req *req);
4278 static void cli_splice_copychunk_done(struct tevent_req *subreq)
4280 struct tevent_req *req = tevent_req_callback_data(
4281 subreq, struct tevent_req);
4282 struct cli_smb2_splice_state *state =
4283 tevent_req_data(req,
4284 struct cli_smb2_splice_state);
4285 struct smbXcli_conn *conn = state->cli->conn;
4286 DATA_BLOB out_input_buffer = data_blob_null;
4287 DATA_BLOB out_output_buffer = data_blob_null;
4288 struct srv_copychunk_rsp cc_copy_rsp;
4289 enum ndr_err_code ndr_ret;
4290 NTSTATUS status;
4292 status = smb2cli_ioctl_recv(subreq, state,
4293 &out_input_buffer,
4294 &out_output_buffer);
4295 TALLOC_FREE(subreq);
4296 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
4297 state->resized) && tevent_req_nterror(req, status)) {
4298 return;
4301 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
4302 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
4303 if (ndr_ret != NDR_ERR_SUCCESS) {
4304 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
4305 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4306 return;
4309 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
4310 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
4311 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
4312 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
4313 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
4314 tevent_req_nterror(req, status)) {
4315 return;
4318 state->resized = true;
4319 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
4320 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
4321 } else {
4322 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4323 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
4324 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
4325 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4326 return;
4328 state->src_offset += cc_copy_rsp.total_bytes_written;
4329 state->dst_offset += cc_copy_rsp.total_bytes_written;
4330 state->written += cc_copy_rsp.total_bytes_written;
4331 if (!state->splice_cb(state->written, state->priv)) {
4332 tevent_req_nterror(req, NT_STATUS_CANCELLED);
4333 return;
4337 cli_splice_copychunk_send(state, req);
4340 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
4341 struct tevent_req *req)
4343 struct tevent_req *subreq;
4344 enum ndr_err_code ndr_ret;
4345 struct smbXcli_conn *conn = state->cli->conn;
4346 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
4347 off_t src_offset = state->src_offset;
4348 off_t dst_offset = state->dst_offset;
4349 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
4350 state->size - state->written);
4351 DATA_BLOB in_input_buffer = data_blob_null;
4352 DATA_BLOB in_output_buffer = data_blob_null;
4354 if (state->size - state->written == 0) {
4355 tevent_req_done(req);
4356 return;
4359 cc_copy->chunk_count = 0;
4360 while (req_len) {
4361 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
4362 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
4363 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
4364 smb2cli_conn_cc_chunk_len(conn));
4365 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
4366 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4367 return;
4369 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
4370 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
4371 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
4372 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
4373 return;
4375 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4376 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
4377 cc_copy->chunk_count++;
4380 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
4381 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
4382 if (ndr_ret != NDR_ERR_SUCCESS) {
4383 DEBUG(0, ("failed to marshall copy chunk req\n"));
4384 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4385 return;
4388 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
4389 state->cli->timeout,
4390 state->cli->smb2.session,
4391 state->cli->smb2.tcon,
4392 state->dst_ph->fid_persistent, /* in_fid_persistent */
4393 state->dst_ph->fid_volatile, /* in_fid_volatile */
4394 FSCTL_SRV_COPYCHUNK_WRITE,
4395 0, /* in_max_input_length */
4396 &in_input_buffer,
4397 12, /* in_max_output_length */
4398 &in_output_buffer,
4399 SMB2_IOCTL_FLAG_IS_FSCTL);
4400 if (tevent_req_nomem(subreq, req)) {
4401 return;
4403 tevent_req_set_callback(subreq,
4404 cli_splice_copychunk_done,
4405 req);
4408 static void cli_splice_key_done(struct tevent_req *subreq)
4410 struct tevent_req *req = tevent_req_callback_data(
4411 subreq, struct tevent_req);
4412 struct cli_smb2_splice_state *state =
4413 tevent_req_data(req,
4414 struct cli_smb2_splice_state);
4415 enum ndr_err_code ndr_ret;
4416 NTSTATUS status;
4418 DATA_BLOB out_input_buffer = data_blob_null;
4419 DATA_BLOB out_output_buffer = data_blob_null;
4421 status = smb2cli_ioctl_recv(subreq, state,
4422 &out_input_buffer,
4423 &out_output_buffer);
4424 TALLOC_FREE(subreq);
4425 if (tevent_req_nterror(req, status)) {
4426 return;
4429 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
4430 state, &state->resume_rsp,
4431 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
4432 if (ndr_ret != NDR_ERR_SUCCESS) {
4433 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
4434 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4435 return;
4438 memcpy(&state->cc_copy.source_key,
4439 &state->resume_rsp.resume_key,
4440 sizeof state->resume_rsp.resume_key);
4442 cli_splice_copychunk_send(state, req);
4445 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
4446 struct tevent_context *ev,
4447 struct cli_state *cli,
4448 uint16_t src_fnum, uint16_t dst_fnum,
4449 off_t size, off_t src_offset, off_t dst_offset,
4450 int (*splice_cb)(off_t n, void *priv),
4451 void *priv)
4453 struct tevent_req *req;
4454 struct tevent_req *subreq;
4455 struct cli_smb2_splice_state *state;
4456 NTSTATUS status;
4457 DATA_BLOB in_input_buffer = data_blob_null;
4458 DATA_BLOB in_output_buffer = data_blob_null;
4460 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
4461 if (req == NULL) {
4462 return NULL;
4464 state->cli = cli;
4465 state->ev = ev;
4466 state->splice_cb = splice_cb;
4467 state->priv = priv;
4468 state->size = size;
4469 state->written = 0;
4470 state->src_offset = src_offset;
4471 state->dst_offset = dst_offset;
4472 state->cc_copy.chunks = talloc_array(state,
4473 struct srv_copychunk,
4474 smb2cli_conn_cc_max_chunks(cli->conn));
4475 if (state->cc_copy.chunks == NULL) {
4476 return NULL;
4479 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
4480 if (tevent_req_nterror(req, status))
4481 return tevent_req_post(req, ev);
4483 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
4484 if (tevent_req_nterror(req, status))
4485 return tevent_req_post(req, ev);
4487 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
4488 cli->timeout,
4489 cli->smb2.session,
4490 cli->smb2.tcon,
4491 state->src_ph->fid_persistent, /* in_fid_persistent */
4492 state->src_ph->fid_volatile, /* in_fid_volatile */
4493 FSCTL_SRV_REQUEST_RESUME_KEY,
4494 0, /* in_max_input_length */
4495 &in_input_buffer,
4496 32, /* in_max_output_length */
4497 &in_output_buffer,
4498 SMB2_IOCTL_FLAG_IS_FSCTL);
4499 if (tevent_req_nomem(subreq, req)) {
4500 return NULL;
4502 tevent_req_set_callback(subreq,
4503 cli_splice_key_done,
4504 req);
4506 return req;
4509 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
4511 struct cli_smb2_splice_state *state = tevent_req_data(
4512 req, struct cli_smb2_splice_state);
4513 NTSTATUS status;
4515 if (tevent_req_is_nterror(req, &status)) {
4516 state->cli->raw_status = status;
4517 tevent_req_received(req);
4518 return status;
4520 if (written != NULL) {
4521 *written = state->written;
4523 state->cli->raw_status = NT_STATUS_OK;
4524 tevent_req_received(req);
4525 return NT_STATUS_OK;
4528 /***************************************************************
4529 SMB2 enum shadow copy data.
4530 ***************************************************************/
4532 struct cli_smb2_shadow_copy_data_fnum_state {
4533 struct cli_state *cli;
4534 uint16_t fnum;
4535 struct smb2_hnd *ph;
4536 DATA_BLOB out_input_buffer;
4537 DATA_BLOB out_output_buffer;
4540 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
4542 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
4543 TALLOC_CTX *mem_ctx,
4544 struct tevent_context *ev,
4545 struct cli_state *cli,
4546 uint16_t fnum,
4547 bool get_names)
4549 struct tevent_req *req, *subreq;
4550 struct cli_smb2_shadow_copy_data_fnum_state *state;
4551 NTSTATUS status;
4553 req = tevent_req_create(mem_ctx, &state,
4554 struct cli_smb2_shadow_copy_data_fnum_state);
4555 if (req == NULL) {
4556 return NULL;
4559 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4560 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4561 return tevent_req_post(req, ev);
4564 state->cli = cli;
4565 state->fnum = fnum;
4567 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4568 if (tevent_req_nterror(req, status)) {
4569 return tevent_req_post(req, ev);
4573 * TODO. Under SMB2 we should send a zero max_output_length
4574 * ioctl to get the required size, then send another ioctl
4575 * to get the data, but the current SMB1 implementation just
4576 * does one roundtrip with a 64K buffer size. Do the same
4577 * for now. JRA.
4580 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4581 state->cli->timeout,
4582 state->cli->smb2.session,
4583 state->cli->smb2.tcon,
4584 state->ph->fid_persistent, /* in_fid_persistent */
4585 state->ph->fid_volatile, /* in_fid_volatile */
4586 FSCTL_GET_SHADOW_COPY_DATA,
4587 0, /* in_max_input_length */
4588 NULL, /* in_input_buffer */
4589 get_names ?
4590 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
4591 NULL, /* in_output_buffer */
4592 SMB2_IOCTL_FLAG_IS_FSCTL);
4594 if (tevent_req_nomem(subreq, req)) {
4595 return tevent_req_post(req, ev);
4597 tevent_req_set_callback(subreq,
4598 cli_smb2_shadow_copy_data_fnum_done,
4599 req);
4601 return req;
4604 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4606 struct tevent_req *req = tevent_req_callback_data(
4607 subreq, struct tevent_req);
4608 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4609 req, struct cli_smb2_shadow_copy_data_fnum_state);
4610 NTSTATUS status;
4612 status = smb2cli_ioctl_recv(subreq, state,
4613 &state->out_input_buffer,
4614 &state->out_output_buffer);
4615 tevent_req_simple_finish_ntstatus(subreq, status);
4618 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4619 TALLOC_CTX *mem_ctx,
4620 bool get_names,
4621 char ***pnames,
4622 int *pnum_names)
4624 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4625 req, struct cli_smb2_shadow_copy_data_fnum_state);
4626 char **names = NULL;
4627 uint32_t num_names = 0;
4628 uint32_t num_names_returned = 0;
4629 uint32_t dlength = 0;
4630 uint32_t i;
4631 uint8_t *endp = NULL;
4632 NTSTATUS status;
4634 if (tevent_req_is_nterror(req, &status)) {
4635 return status;
4638 if (state->out_output_buffer.length < 16) {
4639 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4642 num_names = IVAL(state->out_output_buffer.data, 0);
4643 num_names_returned = IVAL(state->out_output_buffer.data, 4);
4644 dlength = IVAL(state->out_output_buffer.data, 8);
4646 if (num_names > 0x7FFFFFFF) {
4647 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4650 if (get_names == false) {
4651 *pnum_names = (int)num_names;
4652 return NT_STATUS_OK;
4654 if (num_names != num_names_returned) {
4655 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4657 if (dlength + 12 < 12) {
4658 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4661 * NB. The below is an allowable return if there are
4662 * more snapshots than the buffer size we told the
4663 * server we can receive. We currently don't support
4664 * this.
4666 if (dlength + 12 > state->out_output_buffer.length) {
4667 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4669 if (state->out_output_buffer.length +
4670 (2 * sizeof(SHADOW_COPY_LABEL)) <
4671 state->out_output_buffer.length) {
4672 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4675 names = talloc_array(mem_ctx, char *, num_names_returned);
4676 if (names == NULL) {
4677 return NT_STATUS_NO_MEMORY;
4680 endp = state->out_output_buffer.data +
4681 state->out_output_buffer.length;
4683 for (i=0; i<num_names_returned; i++) {
4684 bool ret;
4685 uint8_t *src;
4686 size_t converted_size;
4688 src = state->out_output_buffer.data + 12 +
4689 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4691 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4692 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4694 ret = convert_string_talloc(
4695 names, CH_UTF16LE, CH_UNIX,
4696 src, 2 * sizeof(SHADOW_COPY_LABEL),
4697 &names[i], &converted_size);
4698 if (!ret) {
4699 TALLOC_FREE(names);
4700 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4703 *pnum_names = num_names;
4704 *pnames = names;
4705 return NT_STATUS_OK;
4708 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4709 struct cli_state *cli,
4710 uint16_t fnum,
4711 bool get_names,
4712 char ***pnames,
4713 int *pnum_names)
4715 TALLOC_CTX *frame = talloc_stackframe();
4716 struct tevent_context *ev;
4717 struct tevent_req *req;
4718 NTSTATUS status = NT_STATUS_NO_MEMORY;
4720 if (smbXcli_conn_has_async_calls(cli->conn)) {
4722 * Can't use sync call while an async call is in flight
4724 status = NT_STATUS_INVALID_PARAMETER;
4725 goto fail;
4727 ev = samba_tevent_context_init(frame);
4728 if (ev == NULL) {
4729 goto fail;
4731 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4733 cli,
4734 fnum,
4735 get_names);
4736 if (req == NULL) {
4737 goto fail;
4739 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4740 goto fail;
4742 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4743 mem_ctx,
4744 get_names,
4745 pnames,
4746 pnum_names);
4747 fail:
4748 cli->raw_status = status;
4750 TALLOC_FREE(frame);
4751 return status;
4754 /***************************************************************
4755 Wrapper that allows SMB2 to truncate a file.
4756 Synchronous only.
4757 ***************************************************************/
4759 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4760 uint16_t fnum,
4761 uint64_t newsize)
4763 NTSTATUS status;
4764 uint8_t buf[8] = {0};
4765 DATA_BLOB inbuf = { .data = buf, .length = sizeof(buf) };
4766 TALLOC_CTX *frame = talloc_stackframe();
4768 if (smbXcli_conn_has_async_calls(cli->conn)) {
4770 * Can't use sync call while an async call is in flight
4772 status = NT_STATUS_INVALID_PARAMETER;
4773 goto fail;
4776 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4777 status = NT_STATUS_INVALID_PARAMETER;
4778 goto fail;
4781 SBVAL(buf, 0, newsize);
4783 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4784 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4786 status = cli_smb2_set_info_fnum(
4787 cli,
4788 fnum,
4789 1, /* in_info_type */
4790 SMB_FILE_END_OF_FILE_INFORMATION-1000, /* in_file_info_class */
4791 &inbuf, /* in_input_buffer */
4794 fail:
4796 cli->raw_status = status;
4798 TALLOC_FREE(frame);
4799 return status;
4802 struct cli_smb2_notify_state {
4803 struct tevent_req *subreq;
4804 struct notify_change *changes;
4805 size_t num_changes;
4808 static void cli_smb2_notify_done(struct tevent_req *subreq);
4809 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4811 struct tevent_req *cli_smb2_notify_send(
4812 TALLOC_CTX *mem_ctx,
4813 struct tevent_context *ev,
4814 struct cli_state *cli,
4815 uint16_t fnum,
4816 uint32_t buffer_size,
4817 uint32_t completion_filter,
4818 bool recursive)
4820 struct tevent_req *req = NULL;
4821 struct cli_smb2_notify_state *state = NULL;
4822 struct smb2_hnd *ph = NULL;
4823 NTSTATUS status;
4825 req = tevent_req_create(mem_ctx, &state,
4826 struct cli_smb2_notify_state);
4827 if (req == NULL) {
4828 return NULL;
4831 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4832 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4833 return tevent_req_post(req, ev);
4836 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4837 if (tevent_req_nterror(req, status)) {
4838 return tevent_req_post(req, ev);
4841 state->subreq = smb2cli_notify_send(
4842 state,
4844 cli->conn,
4845 cli->timeout,
4846 cli->smb2.session,
4847 cli->smb2.tcon,
4848 buffer_size,
4849 ph->fid_persistent,
4850 ph->fid_volatile,
4851 completion_filter,
4852 recursive);
4853 if (tevent_req_nomem(state->subreq, req)) {
4854 return tevent_req_post(req, ev);
4856 tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4857 tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4858 return req;
4861 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4863 struct cli_smb2_notify_state *state = tevent_req_data(
4864 req, struct cli_smb2_notify_state);
4865 bool ok;
4867 ok = tevent_req_cancel(state->subreq);
4868 return ok;
4871 static void cli_smb2_notify_done(struct tevent_req *subreq)
4873 struct tevent_req *req = tevent_req_callback_data(
4874 subreq, struct tevent_req);
4875 struct cli_smb2_notify_state *state = tevent_req_data(
4876 req, struct cli_smb2_notify_state);
4877 uint8_t *base;
4878 uint32_t len;
4879 uint32_t ofs;
4880 NTSTATUS status;
4882 status = smb2cli_notify_recv(subreq, state, &base, &len);
4883 TALLOC_FREE(subreq);
4885 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4886 tevent_req_done(req);
4887 return;
4889 if (tevent_req_nterror(req, status)) {
4890 return;
4893 ofs = 0;
4895 while (len - ofs >= 12) {
4896 struct notify_change *tmp;
4897 struct notify_change *c;
4898 uint32_t next_ofs = IVAL(base, ofs);
4899 uint32_t file_name_length = IVAL(base, ofs+8);
4900 size_t namelen;
4901 bool ok;
4903 tmp = talloc_realloc(
4904 state,
4905 state->changes,
4906 struct notify_change,
4907 state->num_changes + 1);
4908 if (tevent_req_nomem(tmp, req)) {
4909 return;
4911 state->changes = tmp;
4912 c = &state->changes[state->num_changes];
4913 state->num_changes += 1;
4915 if (smb_buffer_oob(len, ofs, next_ofs) ||
4916 smb_buffer_oob(len, ofs+12, file_name_length)) {
4917 tevent_req_nterror(
4918 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4919 return;
4922 c->action = IVAL(base, ofs+4);
4924 ok = convert_string_talloc(
4925 state->changes,
4926 CH_UTF16LE,
4927 CH_UNIX,
4928 base + ofs + 12,
4929 file_name_length,
4930 &c->name,
4931 &namelen);
4932 if (!ok) {
4933 tevent_req_nterror(
4934 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4935 return;
4938 if (next_ofs == 0) {
4939 break;
4941 ofs += next_ofs;
4944 tevent_req_done(req);
4947 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
4948 TALLOC_CTX *mem_ctx,
4949 struct notify_change **pchanges,
4950 uint32_t *pnum_changes)
4952 struct cli_smb2_notify_state *state = tevent_req_data(
4953 req, struct cli_smb2_notify_state);
4954 NTSTATUS status;
4956 if (tevent_req_is_nterror(req, &status)) {
4957 return status;
4959 *pchanges = talloc_move(mem_ctx, &state->changes);
4960 *pnum_changes = state->num_changes;
4961 return NT_STATUS_OK;
4964 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
4965 uint32_t buffer_size, uint32_t completion_filter,
4966 bool recursive, TALLOC_CTX *mem_ctx,
4967 struct notify_change **pchanges,
4968 uint32_t *pnum_changes)
4970 TALLOC_CTX *frame = talloc_stackframe();
4971 struct tevent_context *ev;
4972 struct tevent_req *req;
4973 NTSTATUS status = NT_STATUS_NO_MEMORY;
4975 if (smbXcli_conn_has_async_calls(cli->conn)) {
4977 * Can't use sync call while an async call is in flight
4979 status = NT_STATUS_INVALID_PARAMETER;
4980 goto fail;
4982 ev = samba_tevent_context_init(frame);
4983 if (ev == NULL) {
4984 goto fail;
4986 req = cli_smb2_notify_send(
4987 frame,
4989 cli,
4990 fnum,
4991 buffer_size,
4992 completion_filter,
4993 recursive);
4994 if (req == NULL) {
4995 goto fail;
4997 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4998 goto fail;
5000 status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
5001 fail:
5002 TALLOC_FREE(frame);
5003 return status;
5006 struct cli_smb2_set_reparse_point_fnum_state {
5007 struct cli_state *cli;
5008 uint16_t fnum;
5009 struct smb2_hnd *ph;
5010 DATA_BLOB input_buffer;
5013 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
5015 struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
5016 TALLOC_CTX *mem_ctx,
5017 struct tevent_context *ev,
5018 struct cli_state *cli,
5019 uint16_t fnum,
5020 DATA_BLOB in_buf)
5022 struct tevent_req *req, *subreq;
5023 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
5024 NTSTATUS status;
5026 req = tevent_req_create(mem_ctx, &state,
5027 struct cli_smb2_set_reparse_point_fnum_state);
5028 if (req == NULL) {
5029 return NULL;
5032 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5033 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
5034 return tevent_req_post(req, ev);
5037 state->cli = cli;
5038 state->fnum = fnum;
5040 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
5041 if (tevent_req_nterror(req, status)) {
5042 return tevent_req_post(req, ev);
5045 state->input_buffer = data_blob_talloc(state,
5046 in_buf.data,
5047 in_buf.length);
5048 if (state->input_buffer.data == NULL) {
5049 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
5050 return tevent_req_post(req, ev);
5053 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
5054 state->cli->timeout,
5055 state->cli->smb2.session,
5056 state->cli->smb2.tcon,
5057 state->ph->fid_persistent, /* in_fid_persistent */
5058 state->ph->fid_volatile, /* in_fid_volatile */
5059 FSCTL_SET_REPARSE_POINT,
5060 0, /* in_max_input_length */
5061 &state->input_buffer ,
5063 NULL,
5064 SMB2_IOCTL_FLAG_IS_FSCTL);
5066 if (tevent_req_nomem(subreq, req)) {
5067 return tevent_req_post(req, ev);
5069 tevent_req_set_callback(subreq,
5070 cli_smb2_set_reparse_point_fnum_done,
5071 req);
5073 return req;
5076 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
5078 struct tevent_req *req = tevent_req_callback_data(
5079 subreq, struct tevent_req);
5080 struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
5081 req, struct cli_smb2_set_reparse_point_fnum_state);
5082 NTSTATUS status;
5084 status = smb2cli_ioctl_recv(subreq, state,
5085 NULL,
5086 NULL);
5087 TALLOC_FREE(subreq);
5088 if (tevent_req_nterror(req, status)) {
5089 return;
5091 tevent_req_done(req);
5094 NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
5096 return tevent_req_simple_recv_ntstatus(req);
5099 struct cli_smb2_get_reparse_point_fnum_state {
5100 struct cli_state *cli;
5101 uint16_t fnum;
5102 struct smb2_hnd *ph;
5103 DATA_BLOB output_buffer;
5106 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
5108 struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
5109 TALLOC_CTX *mem_ctx,
5110 struct tevent_context *ev,
5111 struct cli_state *cli,
5112 uint16_t fnum)
5114 struct tevent_req *req, *subreq;
5115 struct cli_smb2_get_reparse_point_fnum_state *state = NULL;
5116 NTSTATUS status;
5118 req = tevent_req_create(mem_ctx, &state,
5119 struct cli_smb2_get_reparse_point_fnum_state);
5120 if (req == NULL) {
5121 return NULL;
5124 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5125 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
5126 return tevent_req_post(req, ev);
5129 state->cli = cli;
5130 state->fnum = fnum;
5132 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
5133 if (tevent_req_nterror(req, status)) {
5134 return tevent_req_post(req, ev);
5137 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
5138 state->cli->timeout,
5139 state->cli->smb2.session,
5140 state->cli->smb2.tcon,
5141 state->ph->fid_persistent, /* in_fid_persistent */
5142 state->ph->fid_volatile, /* in_fid_volatile */
5143 FSCTL_GET_REPARSE_POINT,
5144 0, /* in_max_input_length */
5145 NULL,
5146 64*1024,
5147 NULL,
5148 SMB2_IOCTL_FLAG_IS_FSCTL);
5150 if (tevent_req_nomem(subreq, req)) {
5151 return tevent_req_post(req, ev);
5153 tevent_req_set_callback(subreq,
5154 cli_smb2_get_reparse_point_fnum_done,
5155 req);
5157 return req;
5160 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
5162 struct tevent_req *req = tevent_req_callback_data(
5163 subreq, struct tevent_req);
5164 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
5165 req, struct cli_smb2_get_reparse_point_fnum_state);
5166 struct cli_state *cli = state->cli;
5167 NTSTATUS status;
5169 status = smb2cli_ioctl_recv(subreq, state,
5170 NULL,
5171 &state->output_buffer);
5172 TALLOC_FREE(subreq);
5173 if (tevent_req_nterror(req, status)) {
5174 cli->raw_status = status;
5175 return;
5177 tevent_req_done(req);
5180 NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
5181 TALLOC_CTX *mem_ctx,
5182 DATA_BLOB *output)
5184 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
5185 req, struct cli_smb2_get_reparse_point_fnum_state);
5187 if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
5188 NTSTATUS status = state->cli->raw_status;
5189 tevent_req_received(req);
5190 return status;
5192 *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
5193 if (output->data == NULL) {
5194 tevent_req_received(req);
5195 return NT_STATUS_NO_MEMORY;
5197 tevent_req_received(req);
5198 return NT_STATUS_OK;