selftest:Samba4: report when samba is started and ready
[Samba.git] / source3 / libsmb / cli_smb2_fnum.c
blobe7b89a44e58ea2eea9f96a8586b25ddde9ab44d0
1 /*
2 Unix SMB/CIFS implementation.
3 smb2 lib
4 Copyright (C) Jeremy Allison 2013
5 Copyright (C) Volker Lendecke 2013
6 Copyright (C) Stefan Metzmacher 2013
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This code is a thin wrapper around the existing
24 cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c,
25 but allows the handles to be mapped to uint16_t fnums,
26 which are easier for smbclient to use.
29 #include "includes.h"
30 #include "client.h"
31 #include "async_smb.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "cli_smb2_fnum.h"
34 #include "trans2.h"
35 #include "clirap.h"
36 #include "../libcli/smb/smb2_create_blob.h"
37 #include "libsmb/proto.h"
38 #include "lib/util/tevent_ntstatus.h"
39 #include "../libcli/security/security.h"
40 #include "../librpc/gen_ndr/ndr_security.h"
41 #include "lib/util_ea.h"
42 #include "librpc/gen_ndr/ndr_ioctl.h"
43 #include "ntioctl.h"
44 #include "librpc/gen_ndr/ndr_quota.h"
46 struct smb2_hnd {
47 uint64_t fid_persistent;
48 uint64_t fid_volatile;
52 * Handle mapping code.
55 /***************************************************************
56 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
57 Ensures handle is owned by cli struct.
58 ***************************************************************/
60 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
61 const struct smb2_hnd *ph, /* In */
62 uint16_t *pfnum) /* Out */
64 int ret;
65 struct idr_context *idp = cli->smb2.open_handles;
66 struct smb2_hnd *owned_h = talloc_memdup(cli,
67 ph,
68 sizeof(struct smb2_hnd));
70 if (owned_h == NULL) {
71 return NT_STATUS_NO_MEMORY;
74 if (idp == NULL) {
75 /* Lazy init */
76 cli->smb2.open_handles = idr_init(cli);
77 if (cli->smb2.open_handles == NULL) {
78 TALLOC_FREE(owned_h);
79 return NT_STATUS_NO_MEMORY;
81 idp = cli->smb2.open_handles;
84 ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
85 if (ret == -1) {
86 TALLOC_FREE(owned_h);
87 return NT_STATUS_NO_MEMORY;
90 *pfnum = (uint16_t)ret;
91 return NT_STATUS_OK;
94 /***************************************************************
95 Return the smb2_hnd pointer associated with the given fnum.
96 ***************************************************************/
98 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
99 uint16_t fnum, /* In */
100 struct smb2_hnd **pph) /* Out */
102 struct idr_context *idp = cli->smb2.open_handles;
104 if (idp == NULL) {
105 return NT_STATUS_INVALID_PARAMETER;
107 *pph = (struct smb2_hnd *)idr_find(idp, fnum);
108 if (*pph == NULL) {
109 return NT_STATUS_INVALID_HANDLE;
111 return NT_STATUS_OK;
114 /***************************************************************
115 Delete the fnum to smb2_hnd mapping. Zeros out handle on
116 successful return.
117 ***************************************************************/
119 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
120 struct smb2_hnd **pph, /* In */
121 uint16_t fnum) /* In */
123 struct idr_context *idp = cli->smb2.open_handles;
124 struct smb2_hnd *ph;
126 if (idp == NULL) {
127 return NT_STATUS_INVALID_PARAMETER;
130 ph = (struct smb2_hnd *)idr_find(idp, fnum);
131 if (ph != *pph) {
132 return NT_STATUS_INVALID_PARAMETER;
134 idr_remove(idp, fnum);
135 TALLOC_FREE(*pph);
136 return NT_STATUS_OK;
139 /***************************************************************
140 Oplock mapping code.
141 ***************************************************************/
143 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
145 if (create_flags & REQUEST_BATCH_OPLOCK) {
146 return SMB2_OPLOCK_LEVEL_BATCH;
147 } else if (create_flags & REQUEST_OPLOCK) {
148 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
151 /* create_flags doesn't do a level2 request. */
152 return SMB2_OPLOCK_LEVEL_NONE;
155 /***************************************************************
156 Small wrapper that allows SMB2 create to return a uint16_t fnum.
157 ***************************************************************/
159 struct cli_smb2_create_fnum_state {
160 struct cli_state *cli;
161 struct smb_create_returns cr;
162 uint16_t fnum;
163 struct tevent_req *subreq;
166 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
167 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
169 struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
170 struct tevent_context *ev,
171 struct cli_state *cli,
172 const char *fname,
173 uint32_t create_flags,
174 uint32_t impersonation_level,
175 uint32_t desired_access,
176 uint32_t file_attributes,
177 uint32_t share_access,
178 uint32_t create_disposition,
179 uint32_t create_options)
181 struct tevent_req *req, *subreq;
182 struct cli_smb2_create_fnum_state *state;
183 size_t fname_len = 0;
184 const char *startp = NULL;
185 const char *endp = NULL;
186 time_t tstamp = (time_t)0;
187 struct smb2_create_blobs *cblobs = NULL;
189 req = tevent_req_create(mem_ctx, &state,
190 struct cli_smb2_create_fnum_state);
191 if (req == NULL) {
192 return NULL;
194 state->cli = cli;
196 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
197 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
198 return tevent_req_post(req, ev);
201 if (cli->backup_intent) {
202 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
205 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
206 fname_len = strlen(fname);
207 if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
208 size_t len_before_gmt = startp - fname;
209 size_t len_after_gmt = fname + fname_len - endp;
210 DATA_BLOB twrp_blob;
211 NTTIME ntt;
212 NTSTATUS status;
214 char *new_fname = talloc_array(state, char,
215 len_before_gmt + len_after_gmt + 1);
217 if (tevent_req_nomem(new_fname, req)) {
218 return tevent_req_post(req, ev);
221 memcpy(new_fname, fname, len_before_gmt);
222 memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
223 fname = new_fname;
224 fname_len = len_before_gmt + len_after_gmt;
226 unix_to_nt_time(&ntt, tstamp);
227 twrp_blob = data_blob_const((const void *)&ntt, 8);
229 cblobs = talloc_zero(state, struct smb2_create_blobs);
230 if (tevent_req_nomem(cblobs, req)) {
231 return tevent_req_post(req, ev);
234 status = smb2_create_blob_add(state, cblobs,
235 SMB2_CREATE_TAG_TWRP, twrp_blob);
236 if (!NT_STATUS_IS_OK(status)) {
237 tevent_req_nterror(req, status);
238 return tevent_req_post(req, ev);
242 /* SMB2 is pickier about pathnames. Ensure it doesn't
243 start in a '\' */
244 if (*fname == '\\') {
245 fname++;
246 fname_len--;
249 /* Or end in a '\' */
250 if (fname_len > 0 && fname[fname_len-1] == '\\') {
251 char *new_fname = talloc_strdup(state, fname);
252 if (tevent_req_nomem(new_fname, req)) {
253 return tevent_req_post(req, ev);
255 new_fname[fname_len-1] = '\0';
256 fname = new_fname;
259 subreq = smb2cli_create_send(state, ev,
260 cli->conn,
261 cli->timeout,
262 cli->smb2.session,
263 cli->smb2.tcon,
264 fname,
265 flags_to_smb2_oplock(create_flags),
266 impersonation_level,
267 desired_access,
268 file_attributes,
269 share_access,
270 create_disposition,
271 create_options,
272 cblobs);
273 if (tevent_req_nomem(subreq, req)) {
274 return tevent_req_post(req, ev);
276 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
278 state->subreq = subreq;
279 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
281 return req;
284 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
286 struct tevent_req *req = tevent_req_callback_data(
287 subreq, struct tevent_req);
288 struct cli_smb2_create_fnum_state *state = tevent_req_data(
289 req, struct cli_smb2_create_fnum_state);
290 struct smb2_hnd h;
291 NTSTATUS status;
293 status = smb2cli_create_recv(subreq, &h.fid_persistent,
294 &h.fid_volatile, &state->cr, NULL, NULL);
295 TALLOC_FREE(subreq);
296 if (tevent_req_nterror(req, status)) {
297 return;
300 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
301 if (tevent_req_nterror(req, status)) {
302 return;
304 tevent_req_done(req);
307 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
309 struct cli_smb2_create_fnum_state *state = tevent_req_data(
310 req, struct cli_smb2_create_fnum_state);
311 return tevent_req_cancel(state->subreq);
314 NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum,
315 struct smb_create_returns *cr)
317 struct cli_smb2_create_fnum_state *state = tevent_req_data(
318 req, struct cli_smb2_create_fnum_state);
319 NTSTATUS status;
321 if (tevent_req_is_nterror(req, &status)) {
322 state->cli->raw_status = status;
323 return status;
325 if (pfnum != NULL) {
326 *pfnum = state->fnum;
328 if (cr != NULL) {
329 *cr = state->cr;
331 state->cli->raw_status = NT_STATUS_OK;
332 return NT_STATUS_OK;
335 NTSTATUS cli_smb2_create_fnum(struct cli_state *cli,
336 const char *fname,
337 uint32_t create_flags,
338 uint32_t impersonation_level,
339 uint32_t desired_access,
340 uint32_t file_attributes,
341 uint32_t share_access,
342 uint32_t create_disposition,
343 uint32_t create_options,
344 uint16_t *pfid,
345 struct smb_create_returns *cr)
347 TALLOC_CTX *frame = talloc_stackframe();
348 struct tevent_context *ev;
349 struct tevent_req *req;
350 NTSTATUS status = NT_STATUS_NO_MEMORY;
352 if (smbXcli_conn_has_async_calls(cli->conn)) {
354 * Can't use sync call while an async call is in flight
356 status = NT_STATUS_INVALID_PARAMETER;
357 goto fail;
359 ev = samba_tevent_context_init(frame);
360 if (ev == NULL) {
361 goto fail;
363 req = cli_smb2_create_fnum_send(frame, ev, cli, fname, create_flags,
364 impersonation_level,
365 desired_access, file_attributes,
366 share_access, create_disposition,
367 create_options);
368 if (req == NULL) {
369 goto fail;
371 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
372 goto fail;
374 status = cli_smb2_create_fnum_recv(req, pfid, cr);
375 fail:
376 TALLOC_FREE(frame);
377 return status;
380 /***************************************************************
381 Small wrapper that allows SMB2 close to use a uint16_t fnum.
382 ***************************************************************/
384 struct cli_smb2_close_fnum_state {
385 struct cli_state *cli;
386 uint16_t fnum;
387 struct smb2_hnd *ph;
390 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
392 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
393 struct tevent_context *ev,
394 struct cli_state *cli,
395 uint16_t fnum)
397 struct tevent_req *req, *subreq;
398 struct cli_smb2_close_fnum_state *state;
399 NTSTATUS status;
401 req = tevent_req_create(mem_ctx, &state,
402 struct cli_smb2_close_fnum_state);
403 if (req == NULL) {
404 return NULL;
406 state->cli = cli;
407 state->fnum = fnum;
409 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
410 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
411 return tevent_req_post(req, ev);
414 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
415 if (tevent_req_nterror(req, status)) {
416 return tevent_req_post(req, ev);
419 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
420 cli->smb2.session, cli->smb2.tcon,
421 0, state->ph->fid_persistent,
422 state->ph->fid_volatile);
423 if (tevent_req_nomem(subreq, req)) {
424 return tevent_req_post(req, ev);
426 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
427 return req;
430 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
432 struct tevent_req *req = tevent_req_callback_data(
433 subreq, struct tevent_req);
434 struct cli_smb2_close_fnum_state *state = tevent_req_data(
435 req, struct cli_smb2_close_fnum_state);
436 NTSTATUS status;
438 status = smb2cli_close_recv(subreq);
439 if (tevent_req_nterror(req, status)) {
440 return;
443 /* Delete the fnum -> handle mapping. */
444 status = delete_smb2_handle_mapping(state->cli, &state->ph,
445 state->fnum);
446 if (tevent_req_nterror(req, status)) {
447 return;
449 tevent_req_done(req);
452 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
454 struct cli_smb2_close_fnum_state *state = tevent_req_data(
455 req, struct cli_smb2_close_fnum_state);
456 NTSTATUS status = NT_STATUS_OK;
458 if (tevent_req_is_nterror(req, &status)) {
459 state->cli->raw_status = status;
461 tevent_req_received(req);
462 return status;
465 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
467 TALLOC_CTX *frame = talloc_stackframe();
468 struct tevent_context *ev;
469 struct tevent_req *req;
470 NTSTATUS status = NT_STATUS_NO_MEMORY;
472 if (smbXcli_conn_has_async_calls(cli->conn)) {
474 * Can't use sync call while an async call is in flight
476 status = NT_STATUS_INVALID_PARAMETER;
477 goto fail;
479 ev = samba_tevent_context_init(frame);
480 if (ev == NULL) {
481 goto fail;
483 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
484 if (req == NULL) {
485 goto fail;
487 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
488 goto fail;
490 status = cli_smb2_close_fnum_recv(req);
491 fail:
492 TALLOC_FREE(frame);
493 return status;
496 struct cli_smb2_delete_on_close_state {
497 struct cli_state *cli;
498 uint16_t fnum;
499 struct smb2_hnd *ph;
500 uint8_t data[1];
501 DATA_BLOB inbuf;
504 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
506 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
507 struct tevent_context *ev,
508 struct cli_state *cli,
509 uint16_t fnum,
510 bool flag)
512 struct tevent_req *req = NULL;
513 struct cli_smb2_delete_on_close_state *state = NULL;
514 struct tevent_req *subreq = NULL;
515 uint8_t in_info_type;
516 uint8_t in_file_info_class;
517 NTSTATUS status;
519 req = tevent_req_create(mem_ctx, &state,
520 struct cli_smb2_delete_on_close_state);
521 if (req == NULL) {
522 return NULL;
524 state->cli = cli;
525 state->fnum = fnum;
527 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
528 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
529 return tevent_req_post(req, ev);
532 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
533 if (tevent_req_nterror(req, status)) {
534 return tevent_req_post(req, ev);
538 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
539 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
541 in_info_type = 1;
542 in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
543 /* Setup data array. */
544 SCVAL(&state->data[0], 0, flag ? 1 : 0);
545 state->inbuf.data = &state->data[0];
546 state->inbuf.length = 1;
548 subreq = smb2cli_set_info_send(state, ev,
549 cli->conn,
550 cli->timeout,
551 cli->smb2.session,
552 cli->smb2.tcon,
553 in_info_type,
554 in_file_info_class,
555 &state->inbuf, /* in_input_buffer */
556 0, /* in_additional_info */
557 state->ph->fid_persistent,
558 state->ph->fid_volatile);
559 if (tevent_req_nomem(subreq, req)) {
560 return tevent_req_post(req, ev);
562 tevent_req_set_callback(subreq,
563 cli_smb2_delete_on_close_done,
564 req);
565 return req;
568 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
570 NTSTATUS status = smb2cli_set_info_recv(subreq);
571 tevent_req_simple_finish_ntstatus(subreq, status);
574 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
576 struct cli_smb2_delete_on_close_state *state =
577 tevent_req_data(req,
578 struct cli_smb2_delete_on_close_state);
579 NTSTATUS status;
581 if (tevent_req_is_nterror(req, &status)) {
582 state->cli->raw_status = status;
583 tevent_req_received(req);
584 return status;
587 state->cli->raw_status = NT_STATUS_OK;
588 tevent_req_received(req);
589 return NT_STATUS_OK;
592 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
594 TALLOC_CTX *frame = talloc_stackframe();
595 struct tevent_context *ev;
596 struct tevent_req *req;
597 NTSTATUS status = NT_STATUS_NO_MEMORY;
599 if (smbXcli_conn_has_async_calls(cli->conn)) {
601 * Can't use sync call while an async call is in flight
603 status = NT_STATUS_INVALID_PARAMETER;
604 goto fail;
606 ev = samba_tevent_context_init(frame);
607 if (ev == NULL) {
608 goto fail;
610 req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
611 if (req == NULL) {
612 goto fail;
614 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
615 goto fail;
617 status = cli_smb2_delete_on_close_recv(req);
618 fail:
619 TALLOC_FREE(frame);
620 return status;
623 /***************************************************************
624 Small wrapper that allows SMB2 to create a directory
625 Synchronous only.
626 ***************************************************************/
628 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
630 NTSTATUS status;
631 uint16_t fnum;
633 if (smbXcli_conn_has_async_calls(cli->conn)) {
635 * Can't use sync call while an async call is in flight
637 return NT_STATUS_INVALID_PARAMETER;
640 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
641 return NT_STATUS_INVALID_PARAMETER;
644 status = cli_smb2_create_fnum(cli,
645 dname,
646 0, /* create_flags */
647 SMB2_IMPERSONATION_IMPERSONATION,
648 FILE_READ_ATTRIBUTES, /* desired_access */
649 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
650 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
651 FILE_CREATE, /* create_disposition */
652 FILE_DIRECTORY_FILE, /* create_options */
653 &fnum,
654 NULL);
656 if (!NT_STATUS_IS_OK(status)) {
657 return status;
659 return cli_smb2_close_fnum(cli, fnum);
662 /***************************************************************
663 Small wrapper that allows SMB2 to delete a directory
664 Synchronous only.
665 ***************************************************************/
667 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
669 NTSTATUS status;
670 uint16_t fnum;
672 if (smbXcli_conn_has_async_calls(cli->conn)) {
674 * Can't use sync call while an async call is in flight
676 return NT_STATUS_INVALID_PARAMETER;
679 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
680 return NT_STATUS_INVALID_PARAMETER;
683 status = cli_smb2_create_fnum(cli,
684 dname,
685 0, /* create_flags */
686 SMB2_IMPERSONATION_IMPERSONATION,
687 DELETE_ACCESS, /* desired_access */
688 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
689 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
690 FILE_OPEN, /* create_disposition */
691 FILE_DIRECTORY_FILE, /* create_options */
692 &fnum,
693 NULL);
695 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
697 * Naive option to match our SMB1 code. Assume the
698 * symlink path that tripped us up was the last
699 * component and try again. Eventually we will have to
700 * deal with the returned path unprocessed component. JRA.
702 status = cli_smb2_create_fnum(cli,
703 dname,
704 0, /* create_flags */
705 SMB2_IMPERSONATION_IMPERSONATION,
706 DELETE_ACCESS, /* desired_access */
707 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
708 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
709 FILE_OPEN, /* create_disposition */
710 FILE_DIRECTORY_FILE|
711 FILE_DELETE_ON_CLOSE|
712 FILE_OPEN_REPARSE_POINT, /* create_options */
713 &fnum,
714 NULL);
717 if (!NT_STATUS_IS_OK(status)) {
718 return status;
721 status = cli_smb2_delete_on_close(cli, fnum, true);
722 if (!NT_STATUS_IS_OK(status)) {
723 cli_smb2_close_fnum(cli, fnum);
724 return status;
727 return cli_smb2_close_fnum(cli, fnum);
730 /***************************************************************
731 Small wrapper that allows SMB2 to unlink a pathname.
732 Synchronous only.
733 ***************************************************************/
735 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
737 NTSTATUS status;
738 uint16_t fnum;
740 if (smbXcli_conn_has_async_calls(cli->conn)) {
742 * Can't use sync call while an async call is in flight
744 return NT_STATUS_INVALID_PARAMETER;
747 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
748 return NT_STATUS_INVALID_PARAMETER;
751 status = cli_smb2_create_fnum(cli,
752 fname,
753 0, /* create_flags */
754 SMB2_IMPERSONATION_IMPERSONATION,
755 DELETE_ACCESS, /* desired_access */
756 FILE_ATTRIBUTE_NORMAL, /* file attributes */
757 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
758 FILE_OPEN, /* create_disposition */
759 FILE_DELETE_ON_CLOSE, /* create_options */
760 &fnum,
761 NULL);
763 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
765 * Naive option to match our SMB1 code. Assume the
766 * symlink path that tripped us up was the last
767 * component and try again. Eventually we will have to
768 * deal with the returned path unprocessed component. JRA.
770 status = cli_smb2_create_fnum(cli,
771 fname,
772 0, /* create_flags */
773 SMB2_IMPERSONATION_IMPERSONATION,
774 DELETE_ACCESS, /* desired_access */
775 FILE_ATTRIBUTE_NORMAL, /* file attributes */
776 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
777 FILE_OPEN, /* create_disposition */
778 FILE_DELETE_ON_CLOSE|
779 FILE_OPEN_REPARSE_POINT, /* create_options */
780 &fnum,
781 NULL);
784 if (!NT_STATUS_IS_OK(status)) {
785 return status;
787 return cli_smb2_close_fnum(cli, fnum);
790 /***************************************************************
791 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
792 ***************************************************************/
794 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
795 uint32_t dir_data_length,
796 struct file_info *finfo,
797 uint32_t *next_offset)
799 size_t namelen = 0;
800 size_t slen = 0;
801 size_t ret = 0;
803 if (dir_data_length < 4) {
804 return NT_STATUS_INFO_LENGTH_MISMATCH;
807 *next_offset = IVAL(dir_data, 0);
809 if (*next_offset > dir_data_length) {
810 return NT_STATUS_INFO_LENGTH_MISMATCH;
813 if (*next_offset != 0) {
814 /* Ensure we only read what in this record. */
815 dir_data_length = *next_offset;
818 if (dir_data_length < 105) {
819 return NT_STATUS_INFO_LENGTH_MISMATCH;
822 finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
823 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
824 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
825 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
826 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
827 finfo->allocated_size = IVAL2_TO_SMB_BIG_UINT(dir_data + 48, 0);
828 finfo->mode = CVAL(dir_data + 56, 0);
829 finfo->ino = IVAL2_TO_SMB_BIG_UINT(dir_data + 96, 0);
830 namelen = IVAL(dir_data + 60,0);
831 if (namelen > (dir_data_length - 104)) {
832 return NT_STATUS_INFO_LENGTH_MISMATCH;
834 slen = CVAL(dir_data + 68, 0);
835 if (slen > 24) {
836 return NT_STATUS_INFO_LENGTH_MISMATCH;
838 ret = pull_string_talloc(finfo,
839 dir_data,
840 FLAGS2_UNICODE_STRINGS,
841 &finfo->short_name,
842 dir_data + 70,
843 slen,
844 STR_UNICODE);
845 if (ret == (size_t)-1) {
846 /* Bad conversion. */
847 return NT_STATUS_INVALID_NETWORK_RESPONSE;
850 ret = pull_string_talloc(finfo,
851 dir_data,
852 FLAGS2_UNICODE_STRINGS,
853 &finfo->name,
854 dir_data + 104,
855 namelen,
856 STR_UNICODE);
857 if (ret == (size_t)-1) {
858 /* Bad conversion. */
859 return NT_STATUS_INVALID_NETWORK_RESPONSE;
861 return NT_STATUS_OK;
864 /*******************************************************************
865 Given a filename - get its directory name
866 ********************************************************************/
868 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
869 const char *dir,
870 char **parent,
871 const char **name)
873 char *p;
874 ptrdiff_t len;
876 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
878 if (p == NULL) {
879 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
880 return false;
882 if (name) {
883 *name = dir;
885 return true;
888 len = p-dir;
890 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
891 return false;
893 (*parent)[len] = '\0';
895 if (name) {
896 *name = p+1;
898 return true;
901 /***************************************************************
902 Wrapper that allows SMB2 to list a directory.
903 Synchronous only.
904 ***************************************************************/
906 NTSTATUS cli_smb2_list(struct cli_state *cli,
907 const char *pathname,
908 uint16_t attribute,
909 NTSTATUS (*fn)(const char *,
910 struct file_info *,
911 const char *,
912 void *),
913 void *state)
915 NTSTATUS status;
916 uint16_t fnum = 0xffff;
917 char *parent_dir = NULL;
918 const char *mask = NULL;
919 struct smb2_hnd *ph = NULL;
920 bool processed_file = false;
921 TALLOC_CTX *frame = talloc_stackframe();
922 TALLOC_CTX *subframe = NULL;
923 bool mask_has_wild;
924 uint32_t max_trans;
925 uint32_t max_avail_len;
926 bool ok;
928 if (smbXcli_conn_has_async_calls(cli->conn)) {
930 * Can't use sync call while an async call is in flight
932 status = NT_STATUS_INVALID_PARAMETER;
933 goto fail;
936 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
937 status = NT_STATUS_INVALID_PARAMETER;
938 goto fail;
941 /* Get the directory name. */
942 if (!windows_parent_dirname(frame,
943 pathname,
944 &parent_dir,
945 &mask)) {
946 status = NT_STATUS_NO_MEMORY;
947 goto fail;
950 mask_has_wild = ms_has_wild(mask);
952 status = cli_smb2_create_fnum(cli,
953 parent_dir,
954 0, /* create_flags */
955 SMB2_IMPERSONATION_IMPERSONATION,
956 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
957 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
958 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
959 FILE_OPEN, /* create_disposition */
960 FILE_DIRECTORY_FILE, /* create_options */
961 &fnum,
962 NULL);
964 if (!NT_STATUS_IS_OK(status)) {
965 goto fail;
968 status = map_fnum_to_smb2_handle(cli,
969 fnum,
970 &ph);
971 if (!NT_STATUS_IS_OK(status)) {
972 goto fail;
976 * ideally, use the max transaction size, but don't send a request
977 * bigger than we have credits available for
979 max_trans = smb2cli_conn_max_trans_size(cli->conn);
980 ok = smb2cli_conn_req_possible(cli->conn, &max_avail_len);
981 if (ok) {
982 max_trans = MIN(max_trans, max_avail_len);
985 do {
986 uint8_t *dir_data = NULL;
987 uint32_t dir_data_length = 0;
988 uint32_t next_offset = 0;
989 subframe = talloc_stackframe();
991 status = smb2cli_query_directory(cli->conn,
992 cli->timeout,
993 cli->smb2.session,
994 cli->smb2.tcon,
995 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
996 0, /* flags */
997 0, /* file_index */
998 ph->fid_persistent,
999 ph->fid_volatile,
1000 mask,
1001 max_trans,
1002 subframe,
1003 &dir_data,
1004 &dir_data_length);
1006 if (!NT_STATUS_IS_OK(status)) {
1007 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1008 break;
1010 goto fail;
1013 do {
1014 struct file_info *finfo = talloc_zero(subframe,
1015 struct file_info);
1017 if (finfo == NULL) {
1018 status = NT_STATUS_NO_MEMORY;
1019 goto fail;
1022 status = parse_finfo_id_both_directory_info(dir_data,
1023 dir_data_length,
1024 finfo,
1025 &next_offset);
1027 if (!NT_STATUS_IS_OK(status)) {
1028 goto fail;
1031 if (dir_check_ftype((uint32_t)finfo->mode,
1032 (uint32_t)attribute)) {
1034 * Only process if attributes match.
1035 * On SMB1 server does this, so on
1036 * SMB2 we need to emulate in the
1037 * client.
1039 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1041 processed_file = true;
1043 status = fn(cli->dfs_mountpoint,
1044 finfo,
1045 pathname,
1046 state);
1048 if (!NT_STATUS_IS_OK(status)) {
1049 break;
1053 TALLOC_FREE(finfo);
1055 /* Move to next entry. */
1056 if (next_offset) {
1057 dir_data += next_offset;
1058 dir_data_length -= next_offset;
1060 } while (next_offset != 0);
1062 TALLOC_FREE(subframe);
1064 if (!mask_has_wild) {
1066 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1067 * when handed a non-wildcard path. Do it
1068 * for the server (with a non-wildcard path
1069 * there should only ever be one file returned.
1071 status = STATUS_NO_MORE_FILES;
1072 break;
1075 } while (NT_STATUS_IS_OK(status));
1077 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1078 status = NT_STATUS_OK;
1081 if (NT_STATUS_IS_OK(status) && !processed_file) {
1083 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1084 * if no files match. Emulate this in the client.
1086 status = NT_STATUS_NO_SUCH_FILE;
1089 fail:
1091 if (fnum != 0xffff) {
1092 cli_smb2_close_fnum(cli, fnum);
1095 cli->raw_status = status;
1097 TALLOC_FREE(subframe);
1098 TALLOC_FREE(frame);
1099 return status;
1102 /***************************************************************
1103 Wrapper that allows SMB2 to query a path info (basic level).
1104 Synchronous only.
1105 ***************************************************************/
1107 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1108 const char *name,
1109 SMB_STRUCT_STAT *sbuf,
1110 uint32_t *attributes)
1112 NTSTATUS status;
1113 struct smb_create_returns cr;
1114 uint16_t fnum = 0xffff;
1115 size_t namelen = strlen(name);
1117 if (smbXcli_conn_has_async_calls(cli->conn)) {
1119 * Can't use sync call while an async call is in flight
1121 return NT_STATUS_INVALID_PARAMETER;
1124 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1125 return NT_STATUS_INVALID_PARAMETER;
1128 /* SMB2 is pickier about pathnames. Ensure it doesn't
1129 end in a '\' */
1130 if (namelen > 0 && name[namelen-1] == '\\') {
1131 char *modname = talloc_strdup(talloc_tos(), name);
1132 modname[namelen-1] = '\0';
1133 name = modname;
1136 /* This is commonly used as a 'cd'. Try qpathinfo on
1137 a directory handle first. */
1139 status = cli_smb2_create_fnum(cli,
1140 name,
1141 0, /* create_flags */
1142 SMB2_IMPERSONATION_IMPERSONATION,
1143 FILE_READ_ATTRIBUTES, /* desired_access */
1144 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1145 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1146 FILE_OPEN, /* create_disposition */
1147 FILE_DIRECTORY_FILE, /* create_options */
1148 &fnum,
1149 &cr);
1151 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1152 /* Maybe a file ? */
1153 status = cli_smb2_create_fnum(cli,
1154 name,
1155 0, /* create_flags */
1156 SMB2_IMPERSONATION_IMPERSONATION,
1157 FILE_READ_ATTRIBUTES, /* desired_access */
1158 0, /* file attributes */
1159 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1160 FILE_OPEN, /* create_disposition */
1161 0, /* create_options */
1162 &fnum,
1163 &cr);
1166 if (!NT_STATUS_IS_OK(status)) {
1167 return status;
1170 status = cli_smb2_close_fnum(cli, fnum);
1172 ZERO_STRUCTP(sbuf);
1174 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1175 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1176 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1177 sbuf->st_ex_size = cr.end_of_file;
1178 *attributes = cr.file_attributes;
1180 return status;
1183 /***************************************************************
1184 Wrapper that allows SMB2 to check if a path is a directory.
1185 Synchronous only.
1186 ***************************************************************/
1188 NTSTATUS cli_smb2_chkpath(struct cli_state *cli,
1189 const char *name)
1191 NTSTATUS status;
1192 uint16_t fnum = 0xffff;
1194 if (smbXcli_conn_has_async_calls(cli->conn)) {
1196 * Can't use sync call while an async call is in flight
1198 return NT_STATUS_INVALID_PARAMETER;
1201 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1202 return NT_STATUS_INVALID_PARAMETER;
1205 /* Ensure this is a directory. */
1206 status = cli_smb2_create_fnum(cli,
1207 name,
1208 0, /* create_flags */
1209 SMB2_IMPERSONATION_IMPERSONATION,
1210 FILE_READ_ATTRIBUTES, /* desired_access */
1211 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1212 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1213 FILE_OPEN, /* create_disposition */
1214 FILE_DIRECTORY_FILE, /* create_options */
1215 &fnum,
1216 NULL);
1218 if (!NT_STATUS_IS_OK(status)) {
1219 return status;
1222 return cli_smb2_close_fnum(cli, fnum);
1225 /***************************************************************
1226 Helper function for pathname operations.
1227 ***************************************************************/
1229 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1230 const char *name,
1231 uint32_t desired_access,
1232 uint16_t *pfnum)
1234 NTSTATUS status;
1235 size_t namelen = strlen(name);
1236 TALLOC_CTX *frame = talloc_stackframe();
1237 uint32_t create_options = 0;
1239 /* SMB2 is pickier about pathnames. Ensure it doesn't
1240 end in a '\' */
1241 if (namelen > 0 && name[namelen-1] == '\\') {
1242 char *modname = talloc_strdup(frame, name);
1243 if (modname == NULL) {
1244 status = NT_STATUS_NO_MEMORY;
1245 goto fail;
1247 modname[namelen-1] = '\0';
1248 name = modname;
1251 /* Try to open a file handle first. */
1252 status = cli_smb2_create_fnum(cli,
1253 name,
1254 0, /* create_flags */
1255 SMB2_IMPERSONATION_IMPERSONATION,
1256 desired_access,
1257 0, /* file attributes */
1258 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1259 FILE_OPEN, /* create_disposition */
1260 create_options,
1261 pfnum,
1262 NULL);
1264 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1266 * Naive option to match our SMB1 code. Assume the
1267 * symlink path that tripped us up was the last
1268 * component and try again. Eventually we will have to
1269 * deal with the returned path unprocessed component. JRA.
1271 create_options |= FILE_OPEN_REPARSE_POINT;
1272 status = cli_smb2_create_fnum(cli,
1273 name,
1274 0, /* create_flags */
1275 SMB2_IMPERSONATION_IMPERSONATION,
1276 desired_access,
1277 0, /* file attributes */
1278 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1279 FILE_OPEN, /* create_disposition */
1280 create_options,
1281 pfnum,
1282 NULL);
1285 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1286 create_options |= FILE_DIRECTORY_FILE;
1287 status = cli_smb2_create_fnum(cli,
1288 name,
1289 0, /* create_flags */
1290 SMB2_IMPERSONATION_IMPERSONATION,
1291 desired_access,
1292 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1293 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1294 FILE_OPEN, /* create_disposition */
1295 FILE_DIRECTORY_FILE, /* create_options */
1296 pfnum,
1297 NULL);
1300 fail:
1302 TALLOC_FREE(frame);
1303 return status;
1306 /***************************************************************
1307 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1308 Synchronous only.
1309 ***************************************************************/
1311 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1312 const char *name,
1313 fstring alt_name)
1315 NTSTATUS status;
1316 DATA_BLOB outbuf = data_blob_null;
1317 uint16_t fnum = 0xffff;
1318 struct smb2_hnd *ph = NULL;
1319 uint32_t altnamelen = 0;
1320 TALLOC_CTX *frame = talloc_stackframe();
1322 if (smbXcli_conn_has_async_calls(cli->conn)) {
1324 * Can't use sync call while an async call is in flight
1326 status = NT_STATUS_INVALID_PARAMETER;
1327 goto fail;
1330 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1331 status = NT_STATUS_INVALID_PARAMETER;
1332 goto fail;
1335 status = get_fnum_from_path(cli,
1336 name,
1337 FILE_READ_ATTRIBUTES,
1338 &fnum);
1340 if (!NT_STATUS_IS_OK(status)) {
1341 goto fail;
1344 status = map_fnum_to_smb2_handle(cli,
1345 fnum,
1346 &ph);
1347 if (!NT_STATUS_IS_OK(status)) {
1348 goto fail;
1351 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1352 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1354 status = smb2cli_query_info(cli->conn,
1355 cli->timeout,
1356 cli->smb2.session,
1357 cli->smb2.tcon,
1358 1, /* in_info_type */
1359 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1360 0xFFFF, /* in_max_output_length */
1361 NULL, /* in_input_buffer */
1362 0, /* in_additional_info */
1363 0, /* in_flags */
1364 ph->fid_persistent,
1365 ph->fid_volatile,
1366 frame,
1367 &outbuf);
1369 if (!NT_STATUS_IS_OK(status)) {
1370 goto fail;
1373 /* Parse the reply. */
1374 if (outbuf.length < 4) {
1375 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1376 goto fail;
1379 altnamelen = IVAL(outbuf.data, 0);
1380 if (altnamelen > outbuf.length - 4) {
1381 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1382 goto fail;
1385 if (altnamelen > 0) {
1386 size_t ret = 0;
1387 char *short_name = NULL;
1388 ret = pull_string_talloc(frame,
1389 outbuf.data,
1390 FLAGS2_UNICODE_STRINGS,
1391 &short_name,
1392 outbuf.data + 4,
1393 altnamelen,
1394 STR_UNICODE);
1395 if (ret == (size_t)-1) {
1396 /* Bad conversion. */
1397 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1398 goto fail;
1401 fstrcpy(alt_name, short_name);
1402 } else {
1403 alt_name[0] = '\0';
1406 status = NT_STATUS_OK;
1408 fail:
1410 if (fnum != 0xffff) {
1411 cli_smb2_close_fnum(cli, fnum);
1414 cli->raw_status = status;
1416 TALLOC_FREE(frame);
1417 return status;
1421 /***************************************************************
1422 Wrapper that allows SMB2 to query a fnum info (basic level).
1423 Synchronous only.
1424 ***************************************************************/
1426 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1427 uint16_t fnum,
1428 uint16_t *mode,
1429 off_t *size,
1430 struct timespec *create_time,
1431 struct timespec *access_time,
1432 struct timespec *write_time,
1433 struct timespec *change_time,
1434 SMB_INO_T *ino)
1436 NTSTATUS status;
1437 DATA_BLOB outbuf = data_blob_null;
1438 struct smb2_hnd *ph = NULL;
1439 TALLOC_CTX *frame = talloc_stackframe();
1441 if (smbXcli_conn_has_async_calls(cli->conn)) {
1443 * Can't use sync call while an async call is in flight
1445 status = NT_STATUS_INVALID_PARAMETER;
1446 goto fail;
1449 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1450 status = NT_STATUS_INVALID_PARAMETER;
1451 goto fail;
1454 status = map_fnum_to_smb2_handle(cli,
1455 fnum,
1456 &ph);
1457 if (!NT_STATUS_IS_OK(status)) {
1458 goto fail;
1461 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1462 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1464 status = smb2cli_query_info(cli->conn,
1465 cli->timeout,
1466 cli->smb2.session,
1467 cli->smb2.tcon,
1468 1, /* in_info_type */
1469 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1470 0xFFFF, /* in_max_output_length */
1471 NULL, /* in_input_buffer */
1472 0, /* in_additional_info */
1473 0, /* in_flags */
1474 ph->fid_persistent,
1475 ph->fid_volatile,
1476 frame,
1477 &outbuf);
1478 if (!NT_STATUS_IS_OK(status)) {
1479 goto fail;
1482 /* Parse the reply. */
1483 if (outbuf.length < 0x60) {
1484 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1485 goto fail;
1488 if (create_time) {
1489 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1491 if (access_time) {
1492 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1494 if (write_time) {
1495 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1497 if (change_time) {
1498 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1500 if (mode) {
1501 uint32_t attr = IVAL(outbuf.data, 0x20);
1502 *mode = (uint16_t)attr;
1504 if (size) {
1505 uint64_t file_size = BVAL(outbuf.data, 0x30);
1506 *size = (off_t)file_size;
1508 if (ino) {
1509 uint64_t file_index = BVAL(outbuf.data, 0x40);
1510 *ino = (SMB_INO_T)file_index;
1513 fail:
1515 cli->raw_status = status;
1517 TALLOC_FREE(frame);
1518 return status;
1521 /***************************************************************
1522 Wrapper that allows SMB2 to query an fnum.
1523 Implement on top of cli_smb2_qfileinfo_basic().
1524 Synchronous only.
1525 ***************************************************************/
1527 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1528 uint16_t fnum,
1529 uint16_t *attr,
1530 off_t *size,
1531 time_t *change_time,
1532 time_t *access_time,
1533 time_t *write_time)
1535 struct timespec access_time_ts;
1536 struct timespec write_time_ts;
1537 struct timespec change_time_ts;
1538 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1539 fnum,
1540 attr,
1541 size,
1542 NULL,
1543 &access_time_ts,
1544 &write_time_ts,
1545 &change_time_ts,
1546 NULL);
1548 cli->raw_status = status;
1550 if (!NT_STATUS_IS_OK(status)) {
1551 return status;
1554 if (change_time) {
1555 *change_time = change_time_ts.tv_sec;
1557 if (access_time) {
1558 *access_time = access_time_ts.tv_sec;
1560 if (write_time) {
1561 *write_time = write_time_ts.tv_sec;
1563 return NT_STATUS_OK;
1566 /***************************************************************
1567 Wrapper that allows SMB2 to get pathname attributes.
1568 Synchronous only.
1569 ***************************************************************/
1571 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1572 const char *name,
1573 uint16_t *attr,
1574 off_t *size,
1575 time_t *write_time)
1577 NTSTATUS status;
1578 uint16_t fnum = 0xffff;
1579 struct smb2_hnd *ph = NULL;
1580 TALLOC_CTX *frame = talloc_stackframe();
1582 if (smbXcli_conn_has_async_calls(cli->conn)) {
1584 * Can't use sync call while an async call is in flight
1586 status = NT_STATUS_INVALID_PARAMETER;
1587 goto fail;
1590 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1591 status = NT_STATUS_INVALID_PARAMETER;
1592 goto fail;
1595 status = get_fnum_from_path(cli,
1596 name,
1597 FILE_READ_ATTRIBUTES,
1598 &fnum);
1600 if (!NT_STATUS_IS_OK(status)) {
1601 goto fail;
1604 status = map_fnum_to_smb2_handle(cli,
1605 fnum,
1606 &ph);
1607 if (!NT_STATUS_IS_OK(status)) {
1608 goto fail;
1610 status = cli_smb2_getattrE(cli,
1611 fnum,
1612 attr,
1613 size,
1614 NULL,
1615 NULL,
1616 write_time);
1617 if (!NT_STATUS_IS_OK(status)) {
1618 goto fail;
1621 fail:
1623 if (fnum != 0xffff) {
1624 cli_smb2_close_fnum(cli, fnum);
1627 cli->raw_status = status;
1629 TALLOC_FREE(frame);
1630 return status;
1633 /***************************************************************
1634 Wrapper that allows SMB2 to query a pathname info (basic level).
1635 Implement on top of cli_smb2_qfileinfo_basic().
1636 Synchronous only.
1637 ***************************************************************/
1639 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1640 const char *name,
1641 struct timespec *create_time,
1642 struct timespec *access_time,
1643 struct timespec *write_time,
1644 struct timespec *change_time,
1645 off_t *size,
1646 uint16_t *mode,
1647 SMB_INO_T *ino)
1649 NTSTATUS status;
1650 struct smb2_hnd *ph = NULL;
1651 uint16_t fnum = 0xffff;
1652 TALLOC_CTX *frame = talloc_stackframe();
1654 if (smbXcli_conn_has_async_calls(cli->conn)) {
1656 * Can't use sync call while an async call is in flight
1658 status = NT_STATUS_INVALID_PARAMETER;
1659 goto fail;
1662 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1663 status = NT_STATUS_INVALID_PARAMETER;
1664 goto fail;
1667 status = get_fnum_from_path(cli,
1668 name,
1669 FILE_READ_ATTRIBUTES,
1670 &fnum);
1672 if (!NT_STATUS_IS_OK(status)) {
1673 goto fail;
1676 status = map_fnum_to_smb2_handle(cli,
1677 fnum,
1678 &ph);
1679 if (!NT_STATUS_IS_OK(status)) {
1680 goto fail;
1683 status = cli_smb2_qfileinfo_basic(cli,
1684 fnum,
1685 mode,
1686 size,
1687 create_time,
1688 access_time,
1689 write_time,
1690 change_time,
1691 ino);
1693 fail:
1695 if (fnum != 0xffff) {
1696 cli_smb2_close_fnum(cli, fnum);
1699 cli->raw_status = status;
1701 TALLOC_FREE(frame);
1702 return status;
1705 /***************************************************************
1706 Wrapper that allows SMB2 to query pathname streams.
1707 Synchronous only.
1708 ***************************************************************/
1710 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1711 const char *name,
1712 TALLOC_CTX *mem_ctx,
1713 unsigned int *pnum_streams,
1714 struct stream_struct **pstreams)
1716 NTSTATUS status;
1717 struct smb2_hnd *ph = NULL;
1718 uint16_t fnum = 0xffff;
1719 DATA_BLOB outbuf = data_blob_null;
1720 TALLOC_CTX *frame = talloc_stackframe();
1722 if (smbXcli_conn_has_async_calls(cli->conn)) {
1724 * Can't use sync call while an async call is in flight
1726 status = NT_STATUS_INVALID_PARAMETER;
1727 goto fail;
1730 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1731 status = NT_STATUS_INVALID_PARAMETER;
1732 goto fail;
1735 status = get_fnum_from_path(cli,
1736 name,
1737 FILE_READ_ATTRIBUTES,
1738 &fnum);
1740 if (!NT_STATUS_IS_OK(status)) {
1741 goto fail;
1744 status = map_fnum_to_smb2_handle(cli,
1745 fnum,
1746 &ph);
1747 if (!NT_STATUS_IS_OK(status)) {
1748 goto fail;
1751 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1752 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1754 status = smb2cli_query_info(cli->conn,
1755 cli->timeout,
1756 cli->smb2.session,
1757 cli->smb2.tcon,
1758 1, /* in_info_type */
1759 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1760 0xFFFF, /* in_max_output_length */
1761 NULL, /* in_input_buffer */
1762 0, /* in_additional_info */
1763 0, /* in_flags */
1764 ph->fid_persistent,
1765 ph->fid_volatile,
1766 frame,
1767 &outbuf);
1769 if (!NT_STATUS_IS_OK(status)) {
1770 goto fail;
1773 /* Parse the reply. */
1774 if (!parse_streams_blob(mem_ctx,
1775 outbuf.data,
1776 outbuf.length,
1777 pnum_streams,
1778 pstreams)) {
1779 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1780 goto fail;
1783 fail:
1785 if (fnum != 0xffff) {
1786 cli_smb2_close_fnum(cli, fnum);
1789 cli->raw_status = status;
1791 TALLOC_FREE(frame);
1792 return status;
1795 /***************************************************************
1796 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
1797 a pathname.
1798 Synchronous only.
1799 ***************************************************************/
1801 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
1802 const char *name,
1803 uint8_t in_info_type,
1804 uint8_t in_file_info_class,
1805 const DATA_BLOB *p_in_data)
1807 NTSTATUS status;
1808 uint16_t fnum = 0xffff;
1809 struct smb2_hnd *ph = NULL;
1810 TALLOC_CTX *frame = talloc_stackframe();
1812 if (smbXcli_conn_has_async_calls(cli->conn)) {
1814 * Can't use sync call while an async call is in flight
1816 status = NT_STATUS_INVALID_PARAMETER;
1817 goto fail;
1820 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1821 status = NT_STATUS_INVALID_PARAMETER;
1822 goto fail;
1825 status = get_fnum_from_path(cli,
1826 name,
1827 FILE_WRITE_ATTRIBUTES,
1828 &fnum);
1830 if (!NT_STATUS_IS_OK(status)) {
1831 goto fail;
1834 status = map_fnum_to_smb2_handle(cli,
1835 fnum,
1836 &ph);
1837 if (!NT_STATUS_IS_OK(status)) {
1838 goto fail;
1841 status = smb2cli_set_info(cli->conn,
1842 cli->timeout,
1843 cli->smb2.session,
1844 cli->smb2.tcon,
1845 in_info_type,
1846 in_file_info_class,
1847 p_in_data, /* in_input_buffer */
1848 0, /* in_additional_info */
1849 ph->fid_persistent,
1850 ph->fid_volatile);
1851 fail:
1853 if (fnum != 0xffff) {
1854 cli_smb2_close_fnum(cli, fnum);
1857 cli->raw_status = status;
1859 TALLOC_FREE(frame);
1860 return status;
1864 /***************************************************************
1865 Wrapper that allows SMB2 to set pathname attributes.
1866 Synchronous only.
1867 ***************************************************************/
1869 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1870 const char *name,
1871 uint16_t attr,
1872 time_t mtime)
1874 uint8_t inbuf_store[40];
1875 DATA_BLOB inbuf = data_blob_null;
1877 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1878 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1880 inbuf.data = inbuf_store;
1881 inbuf.length = sizeof(inbuf_store);
1882 data_blob_clear(&inbuf);
1885 * SMB1 uses attr == 0 to clear all attributes
1886 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
1887 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
1888 * request attribute change.
1890 * SMB2 uses exactly the reverse. Unfortunately as the
1891 * cli_setatr() ABI is exposed inside libsmbclient,
1892 * we must make the SMB2 cli_smb2_setatr() call
1893 * export the same ABI as the SMB1 cli_setatr()
1894 * which calls it. This means reversing the sense
1895 * of the requested attr argument if it's zero
1896 * or FILE_ATTRIBUTE_NORMAL.
1898 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
1901 if (attr == 0) {
1902 attr = FILE_ATTRIBUTE_NORMAL;
1903 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
1904 attr = 0;
1907 SSVAL(inbuf.data, 32, attr);
1908 if (mtime != 0) {
1909 put_long_date((char *)inbuf.data + 16,mtime);
1911 /* Set all the other times to -1. */
1912 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1913 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1914 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1916 return cli_smb2_setpathinfo(cli,
1917 name,
1918 1, /* in_info_type */
1919 /* in_file_info_class */
1920 SMB_FILE_BASIC_INFORMATION - 1000,
1921 &inbuf);
1925 /***************************************************************
1926 Wrapper that allows SMB2 to set file handle times.
1927 Synchronous only.
1928 ***************************************************************/
1930 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1931 uint16_t fnum,
1932 time_t change_time,
1933 time_t access_time,
1934 time_t write_time)
1936 NTSTATUS status;
1937 struct smb2_hnd *ph = NULL;
1938 uint8_t inbuf_store[40];
1939 DATA_BLOB inbuf = data_blob_null;
1941 if (smbXcli_conn_has_async_calls(cli->conn)) {
1943 * Can't use sync call while an async call is in flight
1945 return NT_STATUS_INVALID_PARAMETER;
1948 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1949 return NT_STATUS_INVALID_PARAMETER;
1952 status = map_fnum_to_smb2_handle(cli,
1953 fnum,
1954 &ph);
1955 if (!NT_STATUS_IS_OK(status)) {
1956 return status;
1959 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1960 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1962 inbuf.data = inbuf_store;
1963 inbuf.length = sizeof(inbuf_store);
1964 data_blob_clear(&inbuf);
1966 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1967 if (change_time != 0) {
1968 put_long_date((char *)inbuf.data + 24, change_time);
1970 if (access_time != 0) {
1971 put_long_date((char *)inbuf.data + 8, access_time);
1973 if (write_time != 0) {
1974 put_long_date((char *)inbuf.data + 16, write_time);
1977 cli->raw_status = smb2cli_set_info(cli->conn,
1978 cli->timeout,
1979 cli->smb2.session,
1980 cli->smb2.tcon,
1981 1, /* in_info_type */
1982 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1983 &inbuf, /* in_input_buffer */
1984 0, /* in_additional_info */
1985 ph->fid_persistent,
1986 ph->fid_volatile);
1988 return cli->raw_status;
1991 /***************************************************************
1992 Wrapper that allows SMB2 to query disk attributes (size).
1993 Synchronous only.
1994 ***************************************************************/
1996 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
1997 uint64_t *bsize, uint64_t *total, uint64_t *avail)
1999 NTSTATUS status;
2000 uint16_t fnum = 0xffff;
2001 DATA_BLOB outbuf = data_blob_null;
2002 struct smb2_hnd *ph = NULL;
2003 uint32_t sectors_per_unit = 0;
2004 uint32_t bytes_per_sector = 0;
2005 uint64_t total_size = 0;
2006 uint64_t size_free = 0;
2007 TALLOC_CTX *frame = talloc_stackframe();
2009 if (smbXcli_conn_has_async_calls(cli->conn)) {
2011 * Can't use sync call while an async call is in flight
2013 status = NT_STATUS_INVALID_PARAMETER;
2014 goto fail;
2017 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2018 status = NT_STATUS_INVALID_PARAMETER;
2019 goto fail;
2022 /* First open the top level directory. */
2023 status = cli_smb2_create_fnum(cli,
2024 path,
2025 0, /* create_flags */
2026 SMB2_IMPERSONATION_IMPERSONATION,
2027 FILE_READ_ATTRIBUTES, /* desired_access */
2028 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2029 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
2030 FILE_OPEN, /* create_disposition */
2031 FILE_DIRECTORY_FILE, /* create_options */
2032 &fnum,
2033 NULL);
2035 if (!NT_STATUS_IS_OK(status)) {
2036 goto fail;
2039 status = map_fnum_to_smb2_handle(cli,
2040 fnum,
2041 &ph);
2042 if (!NT_STATUS_IS_OK(status)) {
2043 goto fail;
2046 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2047 level 3 (SMB_FS_SIZE_INFORMATION). */
2049 status = smb2cli_query_info(cli->conn,
2050 cli->timeout,
2051 cli->smb2.session,
2052 cli->smb2.tcon,
2053 2, /* in_info_type */
2054 3, /* in_file_info_class */
2055 0xFFFF, /* in_max_output_length */
2056 NULL, /* in_input_buffer */
2057 0, /* in_additional_info */
2058 0, /* in_flags */
2059 ph->fid_persistent,
2060 ph->fid_volatile,
2061 frame,
2062 &outbuf);
2063 if (!NT_STATUS_IS_OK(status)) {
2064 goto fail;
2067 /* Parse the reply. */
2068 if (outbuf.length != 24) {
2069 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2070 goto fail;
2073 total_size = BVAL(outbuf.data, 0);
2074 size_free = BVAL(outbuf.data, 8);
2075 sectors_per_unit = IVAL(outbuf.data, 16);
2076 bytes_per_sector = IVAL(outbuf.data, 20);
2078 if (bsize) {
2079 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2081 if (total) {
2082 *total = total_size;
2084 if (avail) {
2085 *avail = size_free;
2088 status = NT_STATUS_OK;
2090 fail:
2092 if (fnum != 0xffff) {
2093 cli_smb2_close_fnum(cli, fnum);
2096 cli->raw_status = status;
2098 TALLOC_FREE(frame);
2099 return status;
2102 /***************************************************************
2103 Wrapper that allows SMB2 to query file system sizes.
2104 Synchronous only.
2105 ***************************************************************/
2107 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2108 uint64_t *total_allocation_units,
2109 uint64_t *caller_allocation_units,
2110 uint64_t *actual_allocation_units,
2111 uint64_t *sectors_per_allocation_unit,
2112 uint64_t *bytes_per_sector)
2114 NTSTATUS status;
2115 uint16_t fnum = 0xffff;
2116 DATA_BLOB outbuf = data_blob_null;
2117 struct smb2_hnd *ph = NULL;
2118 TALLOC_CTX *frame = talloc_stackframe();
2120 if (smbXcli_conn_has_async_calls(cli->conn)) {
2122 * Can't use sync call while an async call is in flight
2124 status = NT_STATUS_INVALID_PARAMETER;
2125 goto fail;
2128 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2129 status = NT_STATUS_INVALID_PARAMETER;
2130 goto fail;
2133 /* First open the top level directory. */
2134 status =
2135 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2136 SMB2_IMPERSONATION_IMPERSONATION,
2137 FILE_READ_ATTRIBUTES, /* desired_access */
2138 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2139 FILE_SHARE_READ | FILE_SHARE_WRITE |
2140 FILE_SHARE_DELETE, /* share_access */
2141 FILE_OPEN, /* create_disposition */
2142 FILE_DIRECTORY_FILE, /* create_options */
2143 &fnum,
2144 NULL);
2146 if (!NT_STATUS_IS_OK(status)) {
2147 goto fail;
2150 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2151 if (!NT_STATUS_IS_OK(status)) {
2152 goto fail;
2155 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2156 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2158 status = smb2cli_query_info(cli->conn,
2159 cli->timeout,
2160 cli->smb2.session,
2161 cli->smb2.tcon,
2162 SMB2_GETINFO_FS, /* in_info_type */
2163 /* in_file_info_class */
2164 SMB_FS_FULL_SIZE_INFORMATION - 1000,
2165 0xFFFF, /* in_max_output_length */
2166 NULL, /* in_input_buffer */
2167 0, /* in_additional_info */
2168 0, /* in_flags */
2169 ph->fid_persistent,
2170 ph->fid_volatile,
2171 frame,
2172 &outbuf);
2173 if (!NT_STATUS_IS_OK(status)) {
2174 goto fail;
2177 if (outbuf.length < 32) {
2178 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2179 goto fail;
2182 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2183 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2184 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2185 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2186 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2188 fail:
2190 if (fnum != 0xffff) {
2191 cli_smb2_close_fnum(cli, fnum);
2194 cli->raw_status = status;
2196 TALLOC_FREE(frame);
2197 return status;
2200 /***************************************************************
2201 Wrapper that allows SMB2 to query file system attributes.
2202 Synchronous only.
2203 ***************************************************************/
2205 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2207 NTSTATUS status;
2208 uint16_t fnum = 0xffff;
2209 DATA_BLOB outbuf = data_blob_null;
2210 struct smb2_hnd *ph = NULL;
2211 TALLOC_CTX *frame = talloc_stackframe();
2213 if (smbXcli_conn_has_async_calls(cli->conn)) {
2215 * Can't use sync call while an async call is in flight
2217 status = NT_STATUS_INVALID_PARAMETER;
2218 goto fail;
2221 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2222 status = NT_STATUS_INVALID_PARAMETER;
2223 goto fail;
2226 /* First open the top level directory. */
2227 status =
2228 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2229 SMB2_IMPERSONATION_IMPERSONATION,
2230 FILE_READ_ATTRIBUTES, /* desired_access */
2231 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2232 FILE_SHARE_READ | FILE_SHARE_WRITE |
2233 FILE_SHARE_DELETE, /* share_access */
2234 FILE_OPEN, /* create_disposition */
2235 FILE_DIRECTORY_FILE, /* create_options */
2236 &fnum,
2237 NULL);
2239 if (!NT_STATUS_IS_OK(status)) {
2240 goto fail;
2243 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2244 if (!NT_STATUS_IS_OK(status)) {
2245 goto fail;
2248 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2249 cli->smb2.tcon, 2, /* in_info_type */
2250 5, /* in_file_info_class */
2251 0xFFFF, /* in_max_output_length */
2252 NULL, /* in_input_buffer */
2253 0, /* in_additional_info */
2254 0, /* in_flags */
2255 ph->fid_persistent, ph->fid_volatile, frame,
2256 &outbuf);
2257 if (!NT_STATUS_IS_OK(status)) {
2258 goto fail;
2261 if (outbuf.length < 12) {
2262 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2263 goto fail;
2266 *fs_attr = IVAL(outbuf.data, 0);
2268 fail:
2270 if (fnum != 0xffff) {
2271 cli_smb2_close_fnum(cli, fnum);
2274 cli->raw_status = status;
2276 TALLOC_FREE(frame);
2277 return status;
2280 /***************************************************************
2281 Wrapper that allows SMB2 to query file system volume info.
2282 Synchronous only.
2283 ***************************************************************/
2285 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2286 TALLOC_CTX *mem_ctx,
2287 char **_volume_name,
2288 uint32_t *pserial_number,
2289 time_t *pdate)
2291 NTSTATUS status;
2292 uint16_t fnum = 0xffff;
2293 DATA_BLOB outbuf = data_blob_null;
2294 struct smb2_hnd *ph = NULL;
2295 uint32_t nlen;
2296 char *volume_name = NULL;
2297 TALLOC_CTX *frame = talloc_stackframe();
2299 if (smbXcli_conn_has_async_calls(cli->conn)) {
2301 * Can't use sync call while an async call is in flight
2303 status = NT_STATUS_INVALID_PARAMETER;
2304 goto fail;
2307 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2308 status = NT_STATUS_INVALID_PARAMETER;
2309 goto fail;
2312 /* First open the top level directory. */
2313 status =
2314 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2315 SMB2_IMPERSONATION_IMPERSONATION,
2316 FILE_READ_ATTRIBUTES, /* desired_access */
2317 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2318 FILE_SHARE_READ | FILE_SHARE_WRITE |
2319 FILE_SHARE_DELETE, /* share_access */
2320 FILE_OPEN, /* create_disposition */
2321 FILE_DIRECTORY_FILE, /* create_options */
2322 &fnum,
2323 NULL);
2325 if (!NT_STATUS_IS_OK(status)) {
2326 goto fail;
2329 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2330 if (!NT_STATUS_IS_OK(status)) {
2331 goto fail;
2334 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2335 level 1 (SMB_FS_VOLUME_INFORMATION). */
2337 status = smb2cli_query_info(cli->conn,
2338 cli->timeout,
2339 cli->smb2.session,
2340 cli->smb2.tcon,
2341 SMB2_GETINFO_FS, /* in_info_type */
2342 /* in_file_info_class */
2343 SMB_FS_VOLUME_INFORMATION - 1000,
2344 0xFFFF, /* in_max_output_length */
2345 NULL, /* in_input_buffer */
2346 0, /* in_additional_info */
2347 0, /* in_flags */
2348 ph->fid_persistent,
2349 ph->fid_volatile,
2350 frame,
2351 &outbuf);
2352 if (!NT_STATUS_IS_OK(status)) {
2353 goto fail;
2356 if (outbuf.length < 24) {
2357 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2358 goto fail;
2361 if (pdate) {
2362 struct timespec ts;
2363 ts = interpret_long_date((char *)outbuf.data);
2364 *pdate = ts.tv_sec;
2366 if (pserial_number) {
2367 *pserial_number = IVAL(outbuf.data,8);
2369 nlen = IVAL(outbuf.data,12);
2370 if (nlen + 18 < 18) {
2371 /* Integer wrap. */
2372 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2373 goto fail;
2376 * The next check is safe as we know outbuf.length >= 24
2377 * from above.
2379 if (nlen > (outbuf.length - 18)) {
2380 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2381 goto fail;
2384 clistr_pull_talloc(mem_ctx,
2385 (const char *)outbuf.data,
2387 &volume_name,
2388 outbuf.data + 18,
2389 nlen,
2390 STR_UNICODE);
2391 if (volume_name == NULL) {
2392 status = map_nt_error_from_unix(errno);
2393 goto fail;
2396 *_volume_name = volume_name;
2398 fail:
2400 if (fnum != 0xffff) {
2401 cli_smb2_close_fnum(cli, fnum);
2404 cli->raw_status = status;
2406 TALLOC_FREE(frame);
2407 return status;
2411 /***************************************************************
2412 Wrapper that allows SMB2 to query a security descriptor.
2413 Synchronous only.
2414 ***************************************************************/
2416 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2417 uint16_t fnum,
2418 uint32_t sec_info,
2419 TALLOC_CTX *mem_ctx,
2420 struct security_descriptor **ppsd)
2422 NTSTATUS status;
2423 DATA_BLOB outbuf = data_blob_null;
2424 struct smb2_hnd *ph = NULL;
2425 struct security_descriptor *lsd = NULL;
2426 TALLOC_CTX *frame = talloc_stackframe();
2428 if (smbXcli_conn_has_async_calls(cli->conn)) {
2430 * Can't use sync call while an async call is in flight
2432 status = NT_STATUS_INVALID_PARAMETER;
2433 goto fail;
2436 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2437 status = NT_STATUS_INVALID_PARAMETER;
2438 goto fail;
2441 status = map_fnum_to_smb2_handle(cli,
2442 fnum,
2443 &ph);
2444 if (!NT_STATUS_IS_OK(status)) {
2445 goto fail;
2448 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2450 status = smb2cli_query_info(cli->conn,
2451 cli->timeout,
2452 cli->smb2.session,
2453 cli->smb2.tcon,
2454 3, /* in_info_type */
2455 0, /* in_file_info_class */
2456 0xFFFF, /* in_max_output_length */
2457 NULL, /* in_input_buffer */
2458 sec_info, /* in_additional_info */
2459 0, /* in_flags */
2460 ph->fid_persistent,
2461 ph->fid_volatile,
2462 frame,
2463 &outbuf);
2465 if (!NT_STATUS_IS_OK(status)) {
2466 goto fail;
2469 /* Parse the reply. */
2470 status = unmarshall_sec_desc(mem_ctx,
2471 outbuf.data,
2472 outbuf.length,
2473 &lsd);
2475 if (!NT_STATUS_IS_OK(status)) {
2476 goto fail;
2479 if (ppsd != NULL) {
2480 *ppsd = lsd;
2481 } else {
2482 TALLOC_FREE(lsd);
2485 fail:
2487 cli->raw_status = status;
2489 TALLOC_FREE(frame);
2490 return status;
2493 /***************************************************************
2494 Wrapper that allows SMB2 to set a security descriptor.
2495 Synchronous only.
2496 ***************************************************************/
2498 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
2499 uint16_t fnum,
2500 uint32_t sec_info,
2501 const struct security_descriptor *sd)
2503 NTSTATUS status;
2504 DATA_BLOB inbuf = data_blob_null;
2505 struct smb2_hnd *ph = NULL;
2506 TALLOC_CTX *frame = talloc_stackframe();
2508 if (smbXcli_conn_has_async_calls(cli->conn)) {
2510 * Can't use sync call while an async call is in flight
2512 status = NT_STATUS_INVALID_PARAMETER;
2513 goto fail;
2516 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2517 status = NT_STATUS_INVALID_PARAMETER;
2518 goto fail;
2521 status = map_fnum_to_smb2_handle(cli,
2522 fnum,
2523 &ph);
2524 if (!NT_STATUS_IS_OK(status)) {
2525 goto fail;
2528 status = marshall_sec_desc(frame,
2530 &inbuf.data,
2531 &inbuf.length);
2533 if (!NT_STATUS_IS_OK(status)) {
2534 goto fail;
2537 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2539 status = smb2cli_set_info(cli->conn,
2540 cli->timeout,
2541 cli->smb2.session,
2542 cli->smb2.tcon,
2543 3, /* in_info_type */
2544 0, /* in_file_info_class */
2545 &inbuf, /* in_input_buffer */
2546 sec_info, /* in_additional_info */
2547 ph->fid_persistent,
2548 ph->fid_volatile);
2550 fail:
2552 cli->raw_status = status;
2554 TALLOC_FREE(frame);
2555 return status;
2558 /***************************************************************
2559 Wrapper that allows SMB2 to rename a file.
2560 Synchronous only.
2561 ***************************************************************/
2563 NTSTATUS cli_smb2_rename(struct cli_state *cli,
2564 const char *fname_src,
2565 const char *fname_dst,
2566 bool replace)
2568 NTSTATUS status;
2569 DATA_BLOB inbuf = data_blob_null;
2570 uint16_t fnum = 0xffff;
2571 struct smb2_hnd *ph = NULL;
2572 smb_ucs2_t *converted_str = NULL;
2573 size_t converted_size_bytes = 0;
2574 size_t namelen = 0;
2575 TALLOC_CTX *frame = talloc_stackframe();
2577 if (smbXcli_conn_has_async_calls(cli->conn)) {
2579 * Can't use sync call while an async call is in flight
2581 status = NT_STATUS_INVALID_PARAMETER;
2582 goto fail;
2585 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2586 status = NT_STATUS_INVALID_PARAMETER;
2587 goto fail;
2590 status = get_fnum_from_path(cli,
2591 fname_src,
2592 DELETE_ACCESS,
2593 &fnum);
2595 if (!NT_STATUS_IS_OK(status)) {
2596 goto fail;
2599 status = map_fnum_to_smb2_handle(cli,
2600 fnum,
2601 &ph);
2602 if (!NT_STATUS_IS_OK(status)) {
2603 goto fail;
2606 /* SMB2 is pickier about pathnames. Ensure it doesn't
2607 start in a '\' */
2608 if (*fname_dst == '\\') {
2609 fname_dst++;
2612 /* SMB2 is pickier about pathnames. Ensure it doesn't
2613 end in a '\' */
2614 namelen = strlen(fname_dst);
2615 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2616 char *modname = talloc_strdup(frame, fname_dst);
2617 modname[namelen-1] = '\0';
2618 fname_dst = modname;
2621 if (!push_ucs2_talloc(frame,
2622 &converted_str,
2623 fname_dst,
2624 &converted_size_bytes)) {
2625 status = NT_STATUS_INVALID_PARAMETER;
2626 goto fail;
2629 /* W2K8 insists the dest name is not null
2630 terminated. Remove the last 2 zero bytes
2631 and reduce the name length. */
2633 if (converted_size_bytes < 2) {
2634 status = NT_STATUS_INVALID_PARAMETER;
2635 goto fail;
2637 converted_size_bytes -= 2;
2639 inbuf = data_blob_talloc_zero(frame,
2640 20 + converted_size_bytes);
2641 if (inbuf.data == NULL) {
2642 status = NT_STATUS_NO_MEMORY;
2643 goto fail;
2646 if (replace) {
2647 SCVAL(inbuf.data, 0, 1);
2650 SIVAL(inbuf.data, 16, converted_size_bytes);
2651 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2653 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2654 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2656 status = smb2cli_set_info(cli->conn,
2657 cli->timeout,
2658 cli->smb2.session,
2659 cli->smb2.tcon,
2660 1, /* in_info_type */
2661 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2662 &inbuf, /* in_input_buffer */
2663 0, /* in_additional_info */
2664 ph->fid_persistent,
2665 ph->fid_volatile);
2667 fail:
2669 if (fnum != 0xffff) {
2670 cli_smb2_close_fnum(cli, fnum);
2673 cli->raw_status = status;
2675 TALLOC_FREE(frame);
2676 return status;
2679 /***************************************************************
2680 Wrapper that allows SMB2 to set an EA on a fnum.
2681 Synchronous only.
2682 ***************************************************************/
2684 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2685 uint16_t fnum,
2686 const char *ea_name,
2687 const char *ea_val,
2688 size_t ea_len)
2690 NTSTATUS status;
2691 DATA_BLOB inbuf = data_blob_null;
2692 size_t bloblen = 0;
2693 char *ea_name_ascii = NULL;
2694 size_t namelen = 0;
2695 struct smb2_hnd *ph = NULL;
2696 TALLOC_CTX *frame = talloc_stackframe();
2698 if (smbXcli_conn_has_async_calls(cli->conn)) {
2700 * Can't use sync call while an async call is in flight
2702 status = NT_STATUS_INVALID_PARAMETER;
2703 goto fail;
2706 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2707 status = NT_STATUS_INVALID_PARAMETER;
2708 goto fail;
2711 status = map_fnum_to_smb2_handle(cli,
2712 fnum,
2713 &ph);
2714 if (!NT_STATUS_IS_OK(status)) {
2715 goto fail;
2718 /* Marshall the SMB2 EA data. */
2719 if (ea_len > 0xFFFF) {
2720 status = NT_STATUS_INVALID_PARAMETER;
2721 goto fail;
2724 if (!push_ascii_talloc(frame,
2725 &ea_name_ascii,
2726 ea_name,
2727 &namelen)) {
2728 status = NT_STATUS_INVALID_PARAMETER;
2729 goto fail;
2732 if (namelen < 2 || namelen > 0xFF) {
2733 status = NT_STATUS_INVALID_PARAMETER;
2734 goto fail;
2737 bloblen = 8 + ea_len + namelen;
2738 /* Round up to a 4 byte boundary. */
2739 bloblen = ((bloblen + 3)&~3);
2741 inbuf = data_blob_talloc_zero(frame, bloblen);
2742 if (inbuf.data == NULL) {
2743 status = NT_STATUS_NO_MEMORY;
2744 goto fail;
2746 /* namelen doesn't include the NULL byte. */
2747 SCVAL(inbuf.data, 5, namelen - 1);
2748 SSVAL(inbuf.data, 6, ea_len);
2749 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2750 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2752 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2753 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2755 status = smb2cli_set_info(cli->conn,
2756 cli->timeout,
2757 cli->smb2.session,
2758 cli->smb2.tcon,
2759 1, /* in_info_type */
2760 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2761 &inbuf, /* in_input_buffer */
2762 0, /* in_additional_info */
2763 ph->fid_persistent,
2764 ph->fid_volatile);
2766 fail:
2768 cli->raw_status = status;
2770 TALLOC_FREE(frame);
2771 return status;
2774 /***************************************************************
2775 Wrapper that allows SMB2 to set an EA on a pathname.
2776 Synchronous only.
2777 ***************************************************************/
2779 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2780 const char *name,
2781 const char *ea_name,
2782 const char *ea_val,
2783 size_t ea_len)
2785 NTSTATUS status;
2786 uint16_t fnum = 0xffff;
2788 if (smbXcli_conn_has_async_calls(cli->conn)) {
2790 * Can't use sync call while an async call is in flight
2792 status = NT_STATUS_INVALID_PARAMETER;
2793 goto fail;
2796 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2797 status = NT_STATUS_INVALID_PARAMETER;
2798 goto fail;
2801 status = get_fnum_from_path(cli,
2802 name,
2803 FILE_WRITE_EA,
2804 &fnum);
2806 if (!NT_STATUS_IS_OK(status)) {
2807 goto fail;
2810 status = cli_set_ea_fnum(cli,
2811 fnum,
2812 ea_name,
2813 ea_val,
2814 ea_len);
2815 if (!NT_STATUS_IS_OK(status)) {
2816 goto fail;
2819 fail:
2821 if (fnum != 0xffff) {
2822 cli_smb2_close_fnum(cli, fnum);
2825 cli->raw_status = status;
2827 return status;
2830 /***************************************************************
2831 Wrapper that allows SMB2 to get an EA list on a pathname.
2832 Synchronous only.
2833 ***************************************************************/
2835 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2836 const char *name,
2837 TALLOC_CTX *ctx,
2838 size_t *pnum_eas,
2839 struct ea_struct **pea_array)
2841 NTSTATUS status;
2842 uint16_t fnum = 0xffff;
2843 DATA_BLOB outbuf = data_blob_null;
2844 struct smb2_hnd *ph = NULL;
2845 struct ea_list *ea_list = NULL;
2846 struct ea_list *eal = NULL;
2847 size_t ea_count = 0;
2848 TALLOC_CTX *frame = talloc_stackframe();
2850 *pnum_eas = 0;
2851 *pea_array = NULL;
2853 if (smbXcli_conn_has_async_calls(cli->conn)) {
2855 * Can't use sync call while an async call is in flight
2857 status = NT_STATUS_INVALID_PARAMETER;
2858 goto fail;
2861 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2862 status = NT_STATUS_INVALID_PARAMETER;
2863 goto fail;
2866 status = get_fnum_from_path(cli,
2867 name,
2868 FILE_READ_EA,
2869 &fnum);
2871 if (!NT_STATUS_IS_OK(status)) {
2872 goto fail;
2875 status = map_fnum_to_smb2_handle(cli,
2876 fnum,
2877 &ph);
2878 if (!NT_STATUS_IS_OK(status)) {
2879 goto fail;
2882 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2883 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2885 status = smb2cli_query_info(cli->conn,
2886 cli->timeout,
2887 cli->smb2.session,
2888 cli->smb2.tcon,
2889 1, /* in_info_type */
2890 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2891 0xFFFF, /* in_max_output_length */
2892 NULL, /* in_input_buffer */
2893 0, /* in_additional_info */
2894 0, /* in_flags */
2895 ph->fid_persistent,
2896 ph->fid_volatile,
2897 frame,
2898 &outbuf);
2900 if (!NT_STATUS_IS_OK(status)) {
2901 goto fail;
2904 /* Parse the reply. */
2905 ea_list = read_nttrans_ea_list(ctx,
2906 (const char *)outbuf.data,
2907 outbuf.length);
2908 if (ea_list == NULL) {
2909 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2910 goto fail;
2913 /* Convert to an array. */
2914 for (eal = ea_list; eal; eal = eal->next) {
2915 ea_count++;
2918 if (ea_count) {
2919 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2920 if (*pea_array == NULL) {
2921 status = NT_STATUS_NO_MEMORY;
2922 goto fail;
2924 ea_count = 0;
2925 for (eal = ea_list; eal; eal = eal->next) {
2926 (*pea_array)[ea_count++] = eal->ea;
2928 *pnum_eas = ea_count;
2931 fail:
2933 if (fnum != 0xffff) {
2934 cli_smb2_close_fnum(cli, fnum);
2937 cli->raw_status = status;
2939 TALLOC_FREE(frame);
2940 return status;
2943 /***************************************************************
2944 Wrapper that allows SMB2 to get user quota.
2945 Synchronous only.
2946 ***************************************************************/
2948 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
2949 int quota_fnum,
2950 SMB_NTQUOTA_STRUCT *pqt)
2952 NTSTATUS status;
2953 DATA_BLOB inbuf = data_blob_null;
2954 DATA_BLOB info_blob = data_blob_null;
2955 DATA_BLOB outbuf = data_blob_null;
2956 struct smb2_hnd *ph = NULL;
2957 TALLOC_CTX *frame = talloc_stackframe();
2958 unsigned sid_len;
2959 unsigned int offset;
2960 struct smb2_query_quota_info query = {0};
2961 struct file_get_quota_info info = {0};
2962 enum ndr_err_code err;
2963 struct ndr_push *ndr_push = NULL;
2965 if (smbXcli_conn_has_async_calls(cli->conn)) {
2967 * Can't use sync call while an async call is in flight
2969 status = NT_STATUS_INVALID_PARAMETER;
2970 goto fail;
2973 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2974 status = NT_STATUS_INVALID_PARAMETER;
2975 goto fail;
2978 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2979 if (!NT_STATUS_IS_OK(status)) {
2980 goto fail;
2983 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
2985 query.return_single = 1;
2987 info.next_entry_offset = 0;
2988 info.sid_length = sid_len;
2989 info.sid = pqt->sid;
2991 err = ndr_push_struct_blob(
2992 &info_blob,
2993 frame,
2994 &info,
2995 (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
2997 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
2998 status = NT_STATUS_INTERNAL_ERROR;
2999 goto fail;
3002 query.sid_list_length = info_blob.length;
3003 ndr_push = ndr_push_init_ctx(frame);
3004 if (!ndr_push) {
3005 status = NT_STATUS_NO_MEMORY;
3006 goto fail;
3009 err = ndr_push_smb2_query_quota_info(ndr_push,
3010 NDR_SCALARS | NDR_BUFFERS,
3011 &query);
3013 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3014 status = NT_STATUS_INTERNAL_ERROR;
3015 goto fail;
3018 err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
3019 info_blob.length);
3021 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3022 status = NT_STATUS_INTERNAL_ERROR;
3023 goto fail;
3025 inbuf.data = ndr_push->data;
3026 inbuf.length = ndr_push->offset;
3028 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
3029 cli->smb2.tcon, 4, /* in_info_type */
3030 0, /* in_file_info_class */
3031 0xFFFF, /* in_max_output_length */
3032 &inbuf, /* in_input_buffer */
3033 0, /* in_additional_info */
3034 0, /* in_flags */
3035 ph->fid_persistent, ph->fid_volatile, frame,
3036 &outbuf);
3038 if (!NT_STATUS_IS_OK(status)) {
3039 goto fail;
3042 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3043 pqt)) {
3044 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3045 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3048 fail:
3049 cli->raw_status = status;
3051 TALLOC_FREE(frame);
3052 return status;
3055 /***************************************************************
3056 Wrapper that allows SMB2 to list user quota.
3057 Synchronous only.
3058 ***************************************************************/
3060 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3061 TALLOC_CTX *mem_ctx,
3062 int quota_fnum,
3063 SMB_NTQUOTA_LIST **pqt_list,
3064 bool first)
3066 NTSTATUS status;
3067 DATA_BLOB inbuf = data_blob_null;
3068 DATA_BLOB outbuf = data_blob_null;
3069 struct smb2_hnd *ph = NULL;
3070 TALLOC_CTX *frame = talloc_stackframe();
3071 struct smb2_query_quota_info info = {0};
3072 enum ndr_err_code err;
3074 if (smbXcli_conn_has_async_calls(cli->conn)) {
3076 * Can't use sync call while an async call is in flight
3078 status = NT_STATUS_INVALID_PARAMETER;
3079 goto cleanup;
3082 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3083 status = NT_STATUS_INVALID_PARAMETER;
3084 goto cleanup;
3087 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3088 if (!NT_STATUS_IS_OK(status)) {
3089 goto cleanup;
3093 info.restart_scan = first ? 1 : 0;
3095 err = ndr_push_struct_blob(
3096 &inbuf,
3097 frame,
3098 &info,
3099 (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3101 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3102 status = NT_STATUS_INTERNAL_ERROR;
3103 goto cleanup;
3106 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
3107 cli->smb2.tcon, 4, /* in_info_type */
3108 0, /* in_file_info_class */
3109 0xFFFF, /* in_max_output_length */
3110 &inbuf, /* in_input_buffer */
3111 0, /* in_additional_info */
3112 0, /* in_flags */
3113 ph->fid_persistent, ph->fid_volatile, frame,
3114 &outbuf);
3117 * safeguard against panic from calling parse_user_quota_list with
3118 * NULL buffer
3120 if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3121 status = NT_STATUS_NO_MORE_ENTRIES;
3124 if (!NT_STATUS_IS_OK(status)) {
3125 goto cleanup;
3128 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3129 pqt_list);
3131 cleanup:
3132 cli->raw_status = status;
3134 TALLOC_FREE(frame);
3135 return status;
3138 /***************************************************************
3139 Wrapper that allows SMB2 to get file system quota.
3140 Synchronous only.
3141 ***************************************************************/
3143 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3144 int quota_fnum,
3145 SMB_NTQUOTA_STRUCT *pqt)
3147 NTSTATUS status;
3148 DATA_BLOB outbuf = data_blob_null;
3149 struct smb2_hnd *ph = NULL;
3150 TALLOC_CTX *frame = talloc_stackframe();
3152 if (smbXcli_conn_has_async_calls(cli->conn)) {
3154 * Can't use sync call while an async call is in flight
3156 status = NT_STATUS_INVALID_PARAMETER;
3157 goto cleanup;
3160 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3161 status = NT_STATUS_INVALID_PARAMETER;
3162 goto cleanup;
3165 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3166 if (!NT_STATUS_IS_OK(status)) {
3167 goto cleanup;
3170 status = smb2cli_query_info(
3171 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3172 2, /* in_info_type */
3173 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3174 0xFFFF, /* in_max_output_length */
3175 NULL, /* in_input_buffer */
3176 0, /* in_additional_info */
3177 0, /* in_flags */
3178 ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
3180 if (!NT_STATUS_IS_OK(status)) {
3181 goto cleanup;
3184 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3186 cleanup:
3187 cli->raw_status = status;
3189 TALLOC_FREE(frame);
3190 return status;
3193 /***************************************************************
3194 Wrapper that allows SMB2 to set user quota.
3195 Synchronous only.
3196 ***************************************************************/
3198 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3199 int quota_fnum,
3200 SMB_NTQUOTA_LIST *qtl)
3202 NTSTATUS status;
3203 DATA_BLOB inbuf = data_blob_null;
3204 struct smb2_hnd *ph = NULL;
3205 TALLOC_CTX *frame = talloc_stackframe();
3207 if (smbXcli_conn_has_async_calls(cli->conn)) {
3209 * Can't use sync call while an async call is in flight
3211 status = NT_STATUS_INVALID_PARAMETER;
3212 goto cleanup;
3215 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3216 status = NT_STATUS_INVALID_PARAMETER;
3217 goto cleanup;
3220 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3221 if (!NT_STATUS_IS_OK(status)) {
3222 goto cleanup;
3225 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3226 if (!NT_STATUS_IS_OK(status)) {
3227 goto cleanup;
3230 status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
3231 cli->smb2.tcon, 4, /* in_info_type */
3232 0, /* in_file_info_class */
3233 &inbuf, /* in_input_buffer */
3234 0, /* in_additional_info */
3235 ph->fid_persistent, ph->fid_volatile);
3236 cleanup:
3238 cli->raw_status = status;
3240 TALLOC_FREE(frame);
3242 return status;
3245 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3246 int quota_fnum,
3247 SMB_NTQUOTA_STRUCT *pqt)
3249 NTSTATUS status;
3250 DATA_BLOB inbuf = data_blob_null;
3251 struct smb2_hnd *ph = NULL;
3252 TALLOC_CTX *frame = talloc_stackframe();
3254 if (smbXcli_conn_has_async_calls(cli->conn)) {
3256 * Can't use sync call while an async call is in flight
3258 status = NT_STATUS_INVALID_PARAMETER;
3259 goto cleanup;
3262 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3263 status = NT_STATUS_INVALID_PARAMETER;
3264 goto cleanup;
3267 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3268 if (!NT_STATUS_IS_OK(status)) {
3269 goto cleanup;
3272 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3273 if (!NT_STATUS_IS_OK(status)) {
3274 goto cleanup;
3277 status = smb2cli_set_info(
3278 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3279 2, /* in_info_type */
3280 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3281 &inbuf, /* in_input_buffer */
3282 0, /* in_additional_info */
3283 ph->fid_persistent, ph->fid_volatile);
3284 cleanup:
3285 cli->raw_status = status;
3287 TALLOC_FREE(frame);
3288 return status;
3291 struct cli_smb2_read_state {
3292 struct tevent_context *ev;
3293 struct cli_state *cli;
3294 struct smb2_hnd *ph;
3295 uint64_t start_offset;
3296 uint32_t size;
3297 uint32_t received;
3298 uint8_t *buf;
3301 static void cli_smb2_read_done(struct tevent_req *subreq);
3303 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3304 struct tevent_context *ev,
3305 struct cli_state *cli,
3306 uint16_t fnum,
3307 off_t offset,
3308 size_t size)
3310 NTSTATUS status;
3311 struct tevent_req *req, *subreq;
3312 struct cli_smb2_read_state *state;
3314 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3315 if (req == NULL) {
3316 return NULL;
3318 state->ev = ev;
3319 state->cli = cli;
3320 state->start_offset = (uint64_t)offset;
3321 state->size = (uint32_t)size;
3322 state->received = 0;
3323 state->buf = NULL;
3325 status = map_fnum_to_smb2_handle(cli,
3326 fnum,
3327 &state->ph);
3328 if (tevent_req_nterror(req, status)) {
3329 return tevent_req_post(req, ev);
3332 subreq = smb2cli_read_send(state,
3333 state->ev,
3334 state->cli->conn,
3335 state->cli->timeout,
3336 state->cli->smb2.session,
3337 state->cli->smb2.tcon,
3338 state->size,
3339 state->start_offset,
3340 state->ph->fid_persistent,
3341 state->ph->fid_volatile,
3342 0, /* minimum_count */
3343 0); /* remaining_bytes */
3345 if (tevent_req_nomem(subreq, req)) {
3346 return tevent_req_post(req, ev);
3348 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3349 return req;
3352 static void cli_smb2_read_done(struct tevent_req *subreq)
3354 struct tevent_req *req = tevent_req_callback_data(
3355 subreq, struct tevent_req);
3356 struct cli_smb2_read_state *state = tevent_req_data(
3357 req, struct cli_smb2_read_state);
3358 NTSTATUS status;
3360 status = smb2cli_read_recv(subreq, state,
3361 &state->buf, &state->received);
3362 if (tevent_req_nterror(req, status)) {
3363 return;
3366 if (state->received > state->size) {
3367 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3368 return;
3371 tevent_req_done(req);
3374 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
3375 ssize_t *received,
3376 uint8_t **rcvbuf)
3378 NTSTATUS status;
3379 struct cli_smb2_read_state *state = tevent_req_data(
3380 req, struct cli_smb2_read_state);
3382 if (tevent_req_is_nterror(req, &status)) {
3383 state->cli->raw_status = status;
3384 return status;
3387 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3388 * better make sure that you copy it away before you talloc_free(req).
3389 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3391 *received = (ssize_t)state->received;
3392 *rcvbuf = state->buf;
3393 state->cli->raw_status = NT_STATUS_OK;
3394 return NT_STATUS_OK;
3397 struct cli_smb2_write_state {
3398 struct tevent_context *ev;
3399 struct cli_state *cli;
3400 struct smb2_hnd *ph;
3401 uint32_t flags;
3402 const uint8_t *buf;
3403 uint64_t offset;
3404 uint32_t size;
3405 uint32_t written;
3408 static void cli_smb2_write_written(struct tevent_req *req);
3410 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
3411 struct tevent_context *ev,
3412 struct cli_state *cli,
3413 uint16_t fnum,
3414 uint16_t mode,
3415 const uint8_t *buf,
3416 off_t offset,
3417 size_t size)
3419 NTSTATUS status;
3420 struct tevent_req *req, *subreq = NULL;
3421 struct cli_smb2_write_state *state = NULL;
3423 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
3424 if (req == NULL) {
3425 return NULL;
3427 state->ev = ev;
3428 state->cli = cli;
3429 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3430 state->flags = (uint32_t)mode;
3431 state->buf = buf;
3432 state->offset = (uint64_t)offset;
3433 state->size = (uint32_t)size;
3434 state->written = 0;
3436 status = map_fnum_to_smb2_handle(cli,
3437 fnum,
3438 &state->ph);
3439 if (tevent_req_nterror(req, status)) {
3440 return tevent_req_post(req, ev);
3443 subreq = smb2cli_write_send(state,
3444 state->ev,
3445 state->cli->conn,
3446 state->cli->timeout,
3447 state->cli->smb2.session,
3448 state->cli->smb2.tcon,
3449 state->size,
3450 state->offset,
3451 state->ph->fid_persistent,
3452 state->ph->fid_volatile,
3453 0, /* remaining_bytes */
3454 state->flags, /* flags */
3455 state->buf);
3457 if (tevent_req_nomem(subreq, req)) {
3458 return tevent_req_post(req, ev);
3460 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
3461 return req;
3464 static void cli_smb2_write_written(struct tevent_req *subreq)
3466 struct tevent_req *req = tevent_req_callback_data(
3467 subreq, struct tevent_req);
3468 struct cli_smb2_write_state *state = tevent_req_data(
3469 req, struct cli_smb2_write_state);
3470 NTSTATUS status;
3471 uint32_t written;
3473 status = smb2cli_write_recv(subreq, &written);
3474 TALLOC_FREE(subreq);
3475 if (tevent_req_nterror(req, status)) {
3476 return;
3479 state->written = written;
3481 tevent_req_done(req);
3484 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
3485 size_t *pwritten)
3487 struct cli_smb2_write_state *state = tevent_req_data(
3488 req, struct cli_smb2_write_state);
3489 NTSTATUS status;
3491 if (tevent_req_is_nterror(req, &status)) {
3492 state->cli->raw_status = status;
3493 tevent_req_received(req);
3494 return status;
3497 if (pwritten != NULL) {
3498 *pwritten = (size_t)state->written;
3500 state->cli->raw_status = NT_STATUS_OK;
3501 tevent_req_received(req);
3502 return NT_STATUS_OK;
3505 /***************************************************************
3506 Wrapper that allows SMB2 async write using an fnum.
3507 This is mostly cut-and-paste from Volker's code inside
3508 source3/libsmb/clireadwrite.c, adapted for SMB2.
3510 Done this way so I can reuse all the logic inside cli_push()
3511 for free :-).
3512 ***************************************************************/
3514 struct cli_smb2_writeall_state {
3515 struct tevent_context *ev;
3516 struct cli_state *cli;
3517 struct smb2_hnd *ph;
3518 uint32_t flags;
3519 const uint8_t *buf;
3520 uint64_t offset;
3521 uint32_t size;
3522 uint32_t written;
3525 static void cli_smb2_writeall_written(struct tevent_req *req);
3527 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
3528 struct tevent_context *ev,
3529 struct cli_state *cli,
3530 uint16_t fnum,
3531 uint16_t mode,
3532 const uint8_t *buf,
3533 off_t offset,
3534 size_t size)
3536 NTSTATUS status;
3537 struct tevent_req *req, *subreq = NULL;
3538 struct cli_smb2_writeall_state *state = NULL;
3539 uint32_t to_write;
3540 uint32_t max_size;
3541 bool ok;
3543 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
3544 if (req == NULL) {
3545 return NULL;
3547 state->ev = ev;
3548 state->cli = cli;
3549 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3550 state->flags = (uint32_t)mode;
3551 state->buf = buf;
3552 state->offset = (uint64_t)offset;
3553 state->size = (uint32_t)size;
3554 state->written = 0;
3556 status = map_fnum_to_smb2_handle(cli,
3557 fnum,
3558 &state->ph);
3559 if (tevent_req_nterror(req, status)) {
3560 return tevent_req_post(req, ev);
3563 to_write = state->size;
3564 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3565 to_write = MIN(max_size, to_write);
3566 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3567 if (ok) {
3568 to_write = MIN(max_size, to_write);
3571 subreq = smb2cli_write_send(state,
3572 state->ev,
3573 state->cli->conn,
3574 state->cli->timeout,
3575 state->cli->smb2.session,
3576 state->cli->smb2.tcon,
3577 to_write,
3578 state->offset,
3579 state->ph->fid_persistent,
3580 state->ph->fid_volatile,
3581 0, /* remaining_bytes */
3582 state->flags, /* flags */
3583 state->buf + state->written);
3585 if (tevent_req_nomem(subreq, req)) {
3586 return tevent_req_post(req, ev);
3588 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3589 return req;
3592 static void cli_smb2_writeall_written(struct tevent_req *subreq)
3594 struct tevent_req *req = tevent_req_callback_data(
3595 subreq, struct tevent_req);
3596 struct cli_smb2_writeall_state *state = tevent_req_data(
3597 req, struct cli_smb2_writeall_state);
3598 NTSTATUS status;
3599 uint32_t written, to_write;
3600 uint32_t max_size;
3601 bool ok;
3603 status = smb2cli_write_recv(subreq, &written);
3604 TALLOC_FREE(subreq);
3605 if (tevent_req_nterror(req, status)) {
3606 return;
3609 state->written += written;
3611 if (state->written > state->size) {
3612 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3613 return;
3616 to_write = state->size - state->written;
3618 if (to_write == 0) {
3619 tevent_req_done(req);
3620 return;
3623 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3624 to_write = MIN(max_size, to_write);
3625 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3626 if (ok) {
3627 to_write = MIN(max_size, to_write);
3630 subreq = smb2cli_write_send(state,
3631 state->ev,
3632 state->cli->conn,
3633 state->cli->timeout,
3634 state->cli->smb2.session,
3635 state->cli->smb2.tcon,
3636 to_write,
3637 state->offset + state->written,
3638 state->ph->fid_persistent,
3639 state->ph->fid_volatile,
3640 0, /* remaining_bytes */
3641 state->flags, /* flags */
3642 state->buf + state->written);
3644 if (tevent_req_nomem(subreq, req)) {
3645 return;
3647 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3650 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
3651 size_t *pwritten)
3653 struct cli_smb2_writeall_state *state = tevent_req_data(
3654 req, struct cli_smb2_writeall_state);
3655 NTSTATUS status;
3657 if (tevent_req_is_nterror(req, &status)) {
3658 state->cli->raw_status = status;
3659 return status;
3661 if (pwritten != NULL) {
3662 *pwritten = (size_t)state->written;
3664 state->cli->raw_status = NT_STATUS_OK;
3665 return NT_STATUS_OK;
3668 struct cli_smb2_splice_state {
3669 struct tevent_context *ev;
3670 struct cli_state *cli;
3671 struct smb2_hnd *src_ph;
3672 struct smb2_hnd *dst_ph;
3673 int (*splice_cb)(off_t n, void *priv);
3674 void *priv;
3675 off_t written;
3676 off_t size;
3677 off_t src_offset;
3678 off_t dst_offset;
3679 bool resized;
3680 struct req_resume_key_rsp resume_rsp;
3681 struct srv_copychunk_copy cc_copy;
3684 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3685 struct tevent_req *req);
3687 static void cli_splice_copychunk_done(struct tevent_req *subreq)
3689 struct tevent_req *req = tevent_req_callback_data(
3690 subreq, struct tevent_req);
3691 struct cli_smb2_splice_state *state =
3692 tevent_req_data(req,
3693 struct cli_smb2_splice_state);
3694 struct smbXcli_conn *conn = state->cli->conn;
3695 DATA_BLOB out_input_buffer = data_blob_null;
3696 DATA_BLOB out_output_buffer = data_blob_null;
3697 struct srv_copychunk_rsp cc_copy_rsp;
3698 enum ndr_err_code ndr_ret;
3699 NTSTATUS status;
3701 status = smb2cli_ioctl_recv(subreq, state,
3702 &out_input_buffer,
3703 &out_output_buffer);
3704 TALLOC_FREE(subreq);
3705 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
3706 state->resized) && tevent_req_nterror(req, status)) {
3707 return;
3710 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
3711 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
3712 if (ndr_ret != NDR_ERR_SUCCESS) {
3713 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3714 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3715 return;
3718 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
3719 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
3720 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
3721 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
3722 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
3723 tevent_req_nterror(req, status)) {
3724 return;
3727 state->resized = true;
3728 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
3729 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
3730 } else {
3731 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3732 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3733 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
3734 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3735 return;
3737 state->src_offset += cc_copy_rsp.total_bytes_written;
3738 state->dst_offset += cc_copy_rsp.total_bytes_written;
3739 state->written += cc_copy_rsp.total_bytes_written;
3740 if (!state->splice_cb(state->written, state->priv)) {
3741 tevent_req_nterror(req, NT_STATUS_CANCELLED);
3742 return;
3746 cli_splice_copychunk_send(state, req);
3749 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3750 struct tevent_req *req)
3752 struct tevent_req *subreq;
3753 enum ndr_err_code ndr_ret;
3754 struct smbXcli_conn *conn = state->cli->conn;
3755 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
3756 off_t src_offset = state->src_offset;
3757 off_t dst_offset = state->dst_offset;
3758 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
3759 state->size - state->written);
3760 DATA_BLOB in_input_buffer = data_blob_null;
3761 DATA_BLOB in_output_buffer = data_blob_null;
3763 if (state->size - state->written == 0) {
3764 tevent_req_done(req);
3765 return;
3768 cc_copy->chunk_count = 0;
3769 while (req_len) {
3770 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
3771 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
3772 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
3773 smb2cli_conn_cc_chunk_len(conn));
3774 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
3775 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3776 return;
3778 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
3779 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
3780 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
3781 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3782 return;
3784 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3785 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3786 cc_copy->chunk_count++;
3789 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
3790 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
3791 if (ndr_ret != NDR_ERR_SUCCESS) {
3792 DEBUG(0, ("failed to marshall copy chunk req\n"));
3793 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3794 return;
3797 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
3798 state->cli->timeout,
3799 state->cli->smb2.session,
3800 state->cli->smb2.tcon,
3801 state->dst_ph->fid_persistent, /* in_fid_persistent */
3802 state->dst_ph->fid_volatile, /* in_fid_volatile */
3803 FSCTL_SRV_COPYCHUNK_WRITE,
3804 0, /* in_max_input_length */
3805 &in_input_buffer,
3806 12, /* in_max_output_length */
3807 &in_output_buffer,
3808 SMB2_IOCTL_FLAG_IS_FSCTL);
3809 if (tevent_req_nomem(subreq, req)) {
3810 return;
3812 tevent_req_set_callback(subreq,
3813 cli_splice_copychunk_done,
3814 req);
3817 static void cli_splice_key_done(struct tevent_req *subreq)
3819 struct tevent_req *req = tevent_req_callback_data(
3820 subreq, struct tevent_req);
3821 struct cli_smb2_splice_state *state =
3822 tevent_req_data(req,
3823 struct cli_smb2_splice_state);
3824 enum ndr_err_code ndr_ret;
3825 NTSTATUS status;
3827 DATA_BLOB out_input_buffer = data_blob_null;
3828 DATA_BLOB out_output_buffer = data_blob_null;
3830 status = smb2cli_ioctl_recv(subreq, state,
3831 &out_input_buffer,
3832 &out_output_buffer);
3833 TALLOC_FREE(subreq);
3834 if (tevent_req_nterror(req, status)) {
3835 return;
3838 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
3839 state, &state->resume_rsp,
3840 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
3841 if (ndr_ret != NDR_ERR_SUCCESS) {
3842 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3843 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3844 return;
3847 memcpy(&state->cc_copy.source_key,
3848 &state->resume_rsp.resume_key,
3849 sizeof state->resume_rsp.resume_key);
3851 cli_splice_copychunk_send(state, req);
3854 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
3855 struct tevent_context *ev,
3856 struct cli_state *cli,
3857 uint16_t src_fnum, uint16_t dst_fnum,
3858 off_t size, off_t src_offset, off_t dst_offset,
3859 int (*splice_cb)(off_t n, void *priv),
3860 void *priv)
3862 struct tevent_req *req;
3863 struct tevent_req *subreq;
3864 struct cli_smb2_splice_state *state;
3865 NTSTATUS status;
3866 DATA_BLOB in_input_buffer = data_blob_null;
3867 DATA_BLOB in_output_buffer = data_blob_null;
3869 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
3870 if (req == NULL) {
3871 return NULL;
3873 state->cli = cli;
3874 state->ev = ev;
3875 state->splice_cb = splice_cb;
3876 state->priv = priv;
3877 state->size = size;
3878 state->written = 0;
3879 state->src_offset = src_offset;
3880 state->dst_offset = dst_offset;
3881 state->cc_copy.chunks = talloc_array(state,
3882 struct srv_copychunk,
3883 smb2cli_conn_cc_max_chunks(cli->conn));
3884 if (state->cc_copy.chunks == NULL) {
3885 return NULL;
3888 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
3889 if (tevent_req_nterror(req, status))
3890 return tevent_req_post(req, ev);
3892 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
3893 if (tevent_req_nterror(req, status))
3894 return tevent_req_post(req, ev);
3896 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
3897 cli->timeout,
3898 cli->smb2.session,
3899 cli->smb2.tcon,
3900 state->src_ph->fid_persistent, /* in_fid_persistent */
3901 state->src_ph->fid_volatile, /* in_fid_volatile */
3902 FSCTL_SRV_REQUEST_RESUME_KEY,
3903 0, /* in_max_input_length */
3904 &in_input_buffer,
3905 32, /* in_max_output_length */
3906 &in_output_buffer,
3907 SMB2_IOCTL_FLAG_IS_FSCTL);
3908 if (tevent_req_nomem(subreq, req)) {
3909 return NULL;
3911 tevent_req_set_callback(subreq,
3912 cli_splice_key_done,
3913 req);
3915 return req;
3918 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
3920 struct cli_smb2_splice_state *state = tevent_req_data(
3921 req, struct cli_smb2_splice_state);
3922 NTSTATUS status;
3924 if (tevent_req_is_nterror(req, &status)) {
3925 state->cli->raw_status = status;
3926 tevent_req_received(req);
3927 return status;
3929 if (written != NULL) {
3930 *written = state->written;
3932 state->cli->raw_status = NT_STATUS_OK;
3933 tevent_req_received(req);
3934 return NT_STATUS_OK;
3937 /***************************************************************
3938 SMB2 enum shadow copy data.
3939 ***************************************************************/
3941 struct cli_smb2_shadow_copy_data_fnum_state {
3942 struct cli_state *cli;
3943 uint16_t fnum;
3944 struct smb2_hnd *ph;
3945 DATA_BLOB out_input_buffer;
3946 DATA_BLOB out_output_buffer;
3949 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
3951 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
3952 TALLOC_CTX *mem_ctx,
3953 struct tevent_context *ev,
3954 struct cli_state *cli,
3955 uint16_t fnum,
3956 bool get_names)
3958 struct tevent_req *req, *subreq;
3959 struct cli_smb2_shadow_copy_data_fnum_state *state;
3960 NTSTATUS status;
3962 req = tevent_req_create(mem_ctx, &state,
3963 struct cli_smb2_shadow_copy_data_fnum_state);
3964 if (req == NULL) {
3965 return NULL;
3968 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3969 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3970 return tevent_req_post(req, ev);
3973 state->cli = cli;
3974 state->fnum = fnum;
3976 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
3977 if (tevent_req_nterror(req, status)) {
3978 return tevent_req_post(req, ev);
3982 * TODO. Under SMB2 we should send a zero max_output_length
3983 * ioctl to get the required size, then send another ioctl
3984 * to get the data, but the current SMB1 implementation just
3985 * does one roundtrip with a 64K buffer size. Do the same
3986 * for now. JRA.
3989 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
3990 state->cli->timeout,
3991 state->cli->smb2.session,
3992 state->cli->smb2.tcon,
3993 state->ph->fid_persistent, /* in_fid_persistent */
3994 state->ph->fid_volatile, /* in_fid_volatile */
3995 FSCTL_GET_SHADOW_COPY_DATA,
3996 0, /* in_max_input_length */
3997 NULL, /* in_input_buffer */
3998 get_names ?
3999 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
4000 NULL, /* in_output_buffer */
4001 SMB2_IOCTL_FLAG_IS_FSCTL);
4003 if (tevent_req_nomem(subreq, req)) {
4004 return tevent_req_post(req, ev);
4006 tevent_req_set_callback(subreq,
4007 cli_smb2_shadow_copy_data_fnum_done,
4008 req);
4010 return req;
4013 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
4015 struct tevent_req *req = tevent_req_callback_data(
4016 subreq, struct tevent_req);
4017 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4018 req, struct cli_smb2_shadow_copy_data_fnum_state);
4019 NTSTATUS status;
4021 status = smb2cli_ioctl_recv(subreq, state,
4022 &state->out_input_buffer,
4023 &state->out_output_buffer);
4024 TALLOC_FREE(subreq);
4025 if (tevent_req_nterror(req, status)) {
4026 return;
4028 tevent_req_done(req);
4031 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
4032 TALLOC_CTX *mem_ctx,
4033 bool get_names,
4034 char ***pnames,
4035 int *pnum_names)
4037 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4038 req, struct cli_smb2_shadow_copy_data_fnum_state);
4039 char **names = NULL;
4040 uint32_t num_names = 0;
4041 uint32_t num_names_returned = 0;
4042 uint32_t dlength = 0;
4043 uint32_t i;
4044 uint8_t *endp = NULL;
4045 NTSTATUS status;
4047 if (tevent_req_is_nterror(req, &status)) {
4048 return status;
4051 if (state->out_output_buffer.length < 16) {
4052 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4055 num_names = IVAL(state->out_output_buffer.data, 0);
4056 num_names_returned = IVAL(state->out_output_buffer.data, 4);
4057 dlength = IVAL(state->out_output_buffer.data, 8);
4059 if (num_names > 0x7FFFFFFF) {
4060 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4063 if (get_names == false) {
4064 *pnum_names = (int)num_names;
4065 return NT_STATUS_OK;
4067 if (num_names != num_names_returned) {
4068 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4070 if (dlength + 12 < 12) {
4071 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4074 * NB. The below is an allowable return if there are
4075 * more snapshots than the buffer size we told the
4076 * server we can receive. We currently don't support
4077 * this.
4079 if (dlength + 12 > state->out_output_buffer.length) {
4080 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4082 if (state->out_output_buffer.length +
4083 (2 * sizeof(SHADOW_COPY_LABEL)) <
4084 state->out_output_buffer.length) {
4085 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4088 names = talloc_array(mem_ctx, char *, num_names_returned);
4089 if (names == NULL) {
4090 return NT_STATUS_NO_MEMORY;
4093 endp = state->out_output_buffer.data +
4094 state->out_output_buffer.length;
4096 for (i=0; i<num_names_returned; i++) {
4097 bool ret;
4098 uint8_t *src;
4099 size_t converted_size;
4101 src = state->out_output_buffer.data + 12 +
4102 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4104 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4105 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4107 ret = convert_string_talloc(
4108 names, CH_UTF16LE, CH_UNIX,
4109 src, 2 * sizeof(SHADOW_COPY_LABEL),
4110 &names[i], &converted_size);
4111 if (!ret) {
4112 TALLOC_FREE(names);
4113 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4116 *pnum_names = num_names;
4117 *pnames = names;
4118 return NT_STATUS_OK;
4121 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4122 struct cli_state *cli,
4123 uint16_t fnum,
4124 bool get_names,
4125 char ***pnames,
4126 int *pnum_names)
4128 TALLOC_CTX *frame = talloc_stackframe();
4129 struct tevent_context *ev;
4130 struct tevent_req *req;
4131 NTSTATUS status = NT_STATUS_NO_MEMORY;
4133 if (smbXcli_conn_has_async_calls(cli->conn)) {
4135 * Can't use sync call while an async call is in flight
4137 status = NT_STATUS_INVALID_PARAMETER;
4138 goto fail;
4140 ev = samba_tevent_context_init(frame);
4141 if (ev == NULL) {
4142 goto fail;
4144 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4146 cli,
4147 fnum,
4148 get_names);
4149 if (req == NULL) {
4150 goto fail;
4152 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4153 goto fail;
4155 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4156 mem_ctx,
4157 get_names,
4158 pnames,
4159 pnum_names);
4160 fail:
4161 cli->raw_status = status;
4163 TALLOC_FREE(frame);
4164 return status;
4167 /***************************************************************
4168 Wrapper that allows SMB2 to truncate a file.
4169 Synchronous only.
4170 ***************************************************************/
4172 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4173 uint16_t fnum,
4174 uint64_t newsize)
4176 NTSTATUS status;
4177 DATA_BLOB inbuf = data_blob_null;
4178 struct smb2_hnd *ph = NULL;
4179 TALLOC_CTX *frame = talloc_stackframe();
4181 if (smbXcli_conn_has_async_calls(cli->conn)) {
4183 * Can't use sync call while an async call is in flight
4185 status = NT_STATUS_INVALID_PARAMETER;
4186 goto fail;
4189 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4190 status = NT_STATUS_INVALID_PARAMETER;
4191 goto fail;
4194 status = map_fnum_to_smb2_handle(cli,
4195 fnum,
4196 &ph);
4197 if (!NT_STATUS_IS_OK(status)) {
4198 goto fail;
4201 inbuf = data_blob_talloc_zero(frame, 8);
4202 if (inbuf.data == NULL) {
4203 status = NT_STATUS_NO_MEMORY;
4204 goto fail;
4207 SBVAL(inbuf.data, 0, newsize);
4209 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4210 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4212 status = smb2cli_set_info(cli->conn,
4213 cli->timeout,
4214 cli->smb2.session,
4215 cli->smb2.tcon,
4216 1, /* in_info_type */
4217 /* in_file_info_class */
4218 SMB_FILE_END_OF_FILE_INFORMATION - 1000,
4219 &inbuf, /* in_input_buffer */
4220 0, /* in_additional_info */
4221 ph->fid_persistent,
4222 ph->fid_volatile);
4224 fail:
4226 cli->raw_status = status;
4228 TALLOC_FREE(frame);
4229 return status;
4232 struct cli_smb2_notify_state {
4233 struct tevent_req *subreq;
4234 struct notify_change *changes;
4235 size_t num_changes;
4238 static void cli_smb2_notify_done(struct tevent_req *subreq);
4239 static bool cli_smb2_notify_cancel(struct tevent_req *req);
4241 struct tevent_req *cli_smb2_notify_send(
4242 TALLOC_CTX *mem_ctx,
4243 struct tevent_context *ev,
4244 struct cli_state *cli,
4245 uint16_t fnum,
4246 uint32_t buffer_size,
4247 uint32_t completion_filter,
4248 bool recursive)
4250 struct tevent_req *req = NULL;
4251 struct cli_smb2_notify_state *state = NULL;
4252 struct smb2_hnd *ph = NULL;
4253 NTSTATUS status;
4255 req = tevent_req_create(mem_ctx, &state,
4256 struct cli_smb2_notify_state);
4257 if (req == NULL) {
4258 return NULL;
4261 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4262 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4263 return tevent_req_post(req, ev);
4266 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4267 if (tevent_req_nterror(req, status)) {
4268 return tevent_req_post(req, ev);
4271 state->subreq = smb2cli_notify_send(
4272 state,
4274 cli->conn,
4275 cli->timeout,
4276 cli->smb2.session,
4277 cli->smb2.tcon,
4278 buffer_size,
4279 ph->fid_persistent,
4280 ph->fid_volatile,
4281 completion_filter,
4282 recursive);
4283 if (tevent_req_nomem(state->subreq, req)) {
4284 return tevent_req_post(req, ev);
4286 tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
4287 tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
4288 return req;
4291 static bool cli_smb2_notify_cancel(struct tevent_req *req)
4293 struct cli_smb2_notify_state *state = tevent_req_data(
4294 req, struct cli_smb2_notify_state);
4295 bool ok;
4297 ok = tevent_req_cancel(state->subreq);
4298 return ok;
4301 static void cli_smb2_notify_done(struct tevent_req *subreq)
4303 struct tevent_req *req = tevent_req_callback_data(
4304 subreq, struct tevent_req);
4305 struct cli_smb2_notify_state *state = tevent_req_data(
4306 req, struct cli_smb2_notify_state);
4307 uint8_t *base;
4308 uint32_t len;
4309 uint32_t ofs;
4310 NTSTATUS status;
4312 status = smb2cli_notify_recv(subreq, state, &base, &len);
4313 TALLOC_FREE(subreq);
4315 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4316 tevent_req_done(req);
4317 return;
4319 if (tevent_req_nterror(req, status)) {
4320 return;
4323 ofs = 0;
4325 while (len - ofs >= 12) {
4326 struct notify_change *tmp;
4327 struct notify_change *c;
4328 uint32_t next_ofs = IVAL(base, ofs);
4329 uint32_t file_name_length = IVAL(base, ofs+8);
4330 size_t namelen;
4331 bool ok;
4333 tmp = talloc_realloc(
4334 state,
4335 state->changes,
4336 struct notify_change,
4337 state->num_changes + 1);
4338 if (tevent_req_nomem(tmp, req)) {
4339 return;
4341 state->changes = tmp;
4342 c = &state->changes[state->num_changes];
4343 state->num_changes += 1;
4345 if (smb_buffer_oob(len, ofs, next_ofs) ||
4346 smb_buffer_oob(len, ofs+12, file_name_length)) {
4347 tevent_req_nterror(
4348 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4349 return;
4352 c->action = IVAL(base, ofs+4);
4354 ok = convert_string_talloc(
4355 state->changes,
4356 CH_UTF16LE,
4357 CH_UNIX,
4358 base + ofs + 12,
4359 file_name_length,
4360 &c->name,
4361 &namelen);
4362 if (!ok) {
4363 tevent_req_nterror(
4364 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4365 return;
4368 if (next_ofs == 0) {
4369 break;
4371 ofs += next_ofs;
4374 tevent_req_done(req);
4377 NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
4378 TALLOC_CTX *mem_ctx,
4379 struct notify_change **pchanges,
4380 uint32_t *pnum_changes)
4382 struct cli_smb2_notify_state *state = tevent_req_data(
4383 req, struct cli_smb2_notify_state);
4384 NTSTATUS status;
4386 if (tevent_req_is_nterror(req, &status)) {
4387 return status;
4389 *pchanges = talloc_move(mem_ctx, &state->changes);
4390 *pnum_changes = state->num_changes;
4391 return NT_STATUS_OK;
4394 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
4395 uint32_t buffer_size, uint32_t completion_filter,
4396 bool recursive, TALLOC_CTX *mem_ctx,
4397 struct notify_change **pchanges,
4398 uint32_t *pnum_changes)
4400 TALLOC_CTX *frame = talloc_stackframe();
4401 struct tevent_context *ev;
4402 struct tevent_req *req;
4403 NTSTATUS status = NT_STATUS_NO_MEMORY;
4405 if (smbXcli_conn_has_async_calls(cli->conn)) {
4407 * Can't use sync call while an async call is in flight
4409 status = NT_STATUS_INVALID_PARAMETER;
4410 goto fail;
4412 ev = samba_tevent_context_init(frame);
4413 if (ev == NULL) {
4414 goto fail;
4416 req = cli_smb2_notify_send(
4417 frame,
4419 cli,
4420 fnum,
4421 buffer_size,
4422 completion_filter,
4423 recursive);
4424 if (req == NULL) {
4425 goto fail;
4427 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4428 goto fail;
4430 status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
4431 fail:
4432 TALLOC_FREE(frame);
4433 return status;
4436 struct cli_smb2_set_reparse_point_fnum_state {
4437 struct cli_state *cli;
4438 uint16_t fnum;
4439 struct smb2_hnd *ph;
4440 DATA_BLOB input_buffer;
4443 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
4445 struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
4446 TALLOC_CTX *mem_ctx,
4447 struct tevent_context *ev,
4448 struct cli_state *cli,
4449 uint16_t fnum,
4450 DATA_BLOB in_buf)
4452 struct tevent_req *req, *subreq;
4453 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
4454 NTSTATUS status;
4456 req = tevent_req_create(mem_ctx, &state,
4457 struct cli_smb2_set_reparse_point_fnum_state);
4458 if (req == NULL) {
4459 return NULL;
4462 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4463 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4464 return tevent_req_post(req, ev);
4467 state->cli = cli;
4468 state->fnum = fnum;
4470 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4471 if (tevent_req_nterror(req, status)) {
4472 return tevent_req_post(req, ev);
4475 state->input_buffer = data_blob_talloc(state,
4476 in_buf.data,
4477 in_buf.length);
4478 if (state->input_buffer.data == NULL) {
4479 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4480 return tevent_req_post(req, ev);
4483 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4484 state->cli->timeout,
4485 state->cli->smb2.session,
4486 state->cli->smb2.tcon,
4487 state->ph->fid_persistent, /* in_fid_persistent */
4488 state->ph->fid_volatile, /* in_fid_volatile */
4489 FSCTL_SET_REPARSE_POINT,
4490 0, /* in_max_input_length */
4491 &state->input_buffer ,
4493 NULL,
4494 SMB2_IOCTL_FLAG_IS_FSCTL);
4496 if (tevent_req_nomem(subreq, req)) {
4497 return tevent_req_post(req, ev);
4499 tevent_req_set_callback(subreq,
4500 cli_smb2_set_reparse_point_fnum_done,
4501 req);
4503 return req;
4506 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
4508 struct tevent_req *req = tevent_req_callback_data(
4509 subreq, struct tevent_req);
4510 struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
4511 req, struct cli_smb2_set_reparse_point_fnum_state);
4512 NTSTATUS status;
4514 status = smb2cli_ioctl_recv(subreq, state,
4515 NULL,
4516 NULL);
4517 TALLOC_FREE(subreq);
4518 if (tevent_req_nterror(req, status)) {
4519 return;
4521 tevent_req_done(req);
4524 NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
4526 return tevent_req_simple_recv_ntstatus(req);
4529 struct cli_smb2_get_reparse_point_fnum_state {
4530 struct cli_state *cli;
4531 uint16_t fnum;
4532 struct smb2_hnd *ph;
4533 DATA_BLOB output_buffer;
4536 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
4538 struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
4539 TALLOC_CTX *mem_ctx,
4540 struct tevent_context *ev,
4541 struct cli_state *cli,
4542 uint16_t fnum)
4544 struct tevent_req *req, *subreq;
4545 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
4546 NTSTATUS status;
4548 req = tevent_req_create(mem_ctx, &state,
4549 struct cli_smb2_get_reparse_point_fnum_state);
4550 if (req == NULL) {
4551 return NULL;
4554 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4555 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4556 return tevent_req_post(req, ev);
4559 state->cli = cli;
4560 state->fnum = fnum;
4562 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4563 if (tevent_req_nterror(req, status)) {
4564 return tevent_req_post(req, ev);
4567 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4568 state->cli->timeout,
4569 state->cli->smb2.session,
4570 state->cli->smb2.tcon,
4571 state->ph->fid_persistent, /* in_fid_persistent */
4572 state->ph->fid_volatile, /* in_fid_volatile */
4573 FSCTL_GET_REPARSE_POINT,
4574 0, /* in_max_input_length */
4575 NULL,
4576 64*1024,
4577 NULL,
4578 SMB2_IOCTL_FLAG_IS_FSCTL);
4580 if (tevent_req_nomem(subreq, req)) {
4581 return tevent_req_post(req, ev);
4583 tevent_req_set_callback(subreq,
4584 cli_smb2_get_reparse_point_fnum_done,
4585 req);
4587 return req;
4590 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
4592 struct tevent_req *req = tevent_req_callback_data(
4593 subreq, struct tevent_req);
4594 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
4595 req, struct cli_smb2_get_reparse_point_fnum_state);
4596 NTSTATUS status;
4598 status = smb2cli_ioctl_recv(subreq, state,
4599 NULL,
4600 &state->output_buffer);
4601 TALLOC_FREE(subreq);
4602 if (tevent_req_nterror(req, status)) {
4603 state->cli->raw_status = status;
4604 return;
4606 tevent_req_done(req);
4609 NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
4610 TALLOC_CTX *mem_ctx,
4611 DATA_BLOB *output)
4613 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
4614 req, struct cli_smb2_get_reparse_point_fnum_state);
4616 if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
4617 tevent_req_received(req);
4618 return state->cli->raw_status;
4620 *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
4621 if (output->data == NULL) {
4622 tevent_req_received(req);
4623 return NT_STATUS_NO_MEMORY;
4625 tevent_req_received(req);
4626 return NT_STATUS_OK;