s4:torture: FinderInfo conversion test with AppleDouble without xattr data
[Samba.git] / source3 / libsmb / cli_smb2_fnum.c
blob7192521e38a83cca8a41bb9c42e91b388b120633
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 desired_access,
175 uint32_t file_attributes,
176 uint32_t share_access,
177 uint32_t create_disposition,
178 uint32_t create_options)
180 struct tevent_req *req, *subreq;
181 struct cli_smb2_create_fnum_state *state;
182 size_t fname_len = 0;
183 const char *startp = NULL;
184 const char *endp = NULL;
185 time_t tstamp = (time_t)0;
186 struct smb2_create_blobs *cblobs = NULL;
188 req = tevent_req_create(mem_ctx, &state,
189 struct cli_smb2_create_fnum_state);
190 if (req == NULL) {
191 return NULL;
193 state->cli = cli;
195 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
196 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
197 return tevent_req_post(req, ev);
200 if (cli->backup_intent) {
201 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
204 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
205 fname_len = strlen(fname);
206 if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
207 size_t len_before_gmt = startp - fname;
208 size_t len_after_gmt = fname + fname_len - endp;
209 DATA_BLOB twrp_blob;
210 NTTIME ntt;
211 NTSTATUS status;
213 char *new_fname = talloc_array(state, char,
214 len_before_gmt + len_after_gmt + 1);
216 if (tevent_req_nomem(new_fname, req)) {
217 return tevent_req_post(req, ev);
220 memcpy(new_fname, fname, len_before_gmt);
221 memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
222 fname = new_fname;
223 fname_len = len_before_gmt + len_after_gmt;
225 unix_to_nt_time(&ntt, tstamp);
226 twrp_blob = data_blob_const((const void *)&ntt, 8);
228 cblobs = talloc_zero(state, struct smb2_create_blobs);
229 if (tevent_req_nomem(cblobs, req)) {
230 return tevent_req_post(req, ev);
233 status = smb2_create_blob_add(state, cblobs,
234 SMB2_CREATE_TAG_TWRP, twrp_blob);
235 if (!NT_STATUS_IS_OK(status)) {
236 tevent_req_nterror(req, status);
237 return tevent_req_post(req, ev);
241 /* SMB2 is pickier about pathnames. Ensure it doesn't
242 start in a '\' */
243 if (*fname == '\\') {
244 fname++;
245 fname_len--;
248 /* Or end in a '\' */
249 if (fname_len > 0 && fname[fname_len-1] == '\\') {
250 char *new_fname = talloc_strdup(state, fname);
251 if (tevent_req_nomem(new_fname, req)) {
252 return tevent_req_post(req, ev);
254 new_fname[fname_len-1] = '\0';
255 fname = new_fname;
258 subreq = smb2cli_create_send(state, ev,
259 cli->conn,
260 cli->timeout,
261 cli->smb2.session,
262 cli->smb2.tcon,
263 fname,
264 flags_to_smb2_oplock(create_flags),
265 SMB2_IMPERSONATION_IMPERSONATION,
266 desired_access,
267 file_attributes,
268 share_access,
269 create_disposition,
270 create_options,
271 cblobs);
272 if (tevent_req_nomem(subreq, req)) {
273 return tevent_req_post(req, ev);
275 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
277 state->subreq = subreq;
278 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
280 return req;
283 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
285 struct tevent_req *req = tevent_req_callback_data(
286 subreq, struct tevent_req);
287 struct cli_smb2_create_fnum_state *state = tevent_req_data(
288 req, struct cli_smb2_create_fnum_state);
289 struct smb2_hnd h;
290 NTSTATUS status;
292 status = smb2cli_create_recv(subreq, &h.fid_persistent,
293 &h.fid_volatile, &state->cr, NULL, NULL);
294 TALLOC_FREE(subreq);
295 if (tevent_req_nterror(req, status)) {
296 return;
299 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
300 if (tevent_req_nterror(req, status)) {
301 return;
303 tevent_req_done(req);
306 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
308 struct cli_smb2_create_fnum_state *state = tevent_req_data(
309 req, struct cli_smb2_create_fnum_state);
310 return tevent_req_cancel(state->subreq);
313 NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum,
314 struct smb_create_returns *cr)
316 struct cli_smb2_create_fnum_state *state = tevent_req_data(
317 req, struct cli_smb2_create_fnum_state);
318 NTSTATUS status;
320 if (tevent_req_is_nterror(req, &status)) {
321 state->cli->raw_status = status;
322 return status;
324 if (pfnum != NULL) {
325 *pfnum = state->fnum;
327 if (cr != NULL) {
328 *cr = state->cr;
330 state->cli->raw_status = NT_STATUS_OK;
331 return NT_STATUS_OK;
334 NTSTATUS cli_smb2_create_fnum(struct cli_state *cli,
335 const char *fname,
336 uint32_t create_flags,
337 uint32_t desired_access,
338 uint32_t file_attributes,
339 uint32_t share_access,
340 uint32_t create_disposition,
341 uint32_t create_options,
342 uint16_t *pfid,
343 struct smb_create_returns *cr)
345 TALLOC_CTX *frame = talloc_stackframe();
346 struct tevent_context *ev;
347 struct tevent_req *req;
348 NTSTATUS status = NT_STATUS_NO_MEMORY;
350 if (smbXcli_conn_has_async_calls(cli->conn)) {
352 * Can't use sync call while an async call is in flight
354 status = NT_STATUS_INVALID_PARAMETER;
355 goto fail;
357 ev = samba_tevent_context_init(frame);
358 if (ev == NULL) {
359 goto fail;
361 req = cli_smb2_create_fnum_send(frame, ev, cli, fname, create_flags,
362 desired_access, file_attributes,
363 share_access, create_disposition,
364 create_options);
365 if (req == NULL) {
366 goto fail;
368 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
369 goto fail;
371 status = cli_smb2_create_fnum_recv(req, pfid, cr);
372 fail:
373 TALLOC_FREE(frame);
374 return status;
377 /***************************************************************
378 Small wrapper that allows SMB2 close to use a uint16_t fnum.
379 ***************************************************************/
381 struct cli_smb2_close_fnum_state {
382 struct cli_state *cli;
383 uint16_t fnum;
384 struct smb2_hnd *ph;
387 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
389 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
390 struct tevent_context *ev,
391 struct cli_state *cli,
392 uint16_t fnum)
394 struct tevent_req *req, *subreq;
395 struct cli_smb2_close_fnum_state *state;
396 NTSTATUS status;
398 req = tevent_req_create(mem_ctx, &state,
399 struct cli_smb2_close_fnum_state);
400 if (req == NULL) {
401 return NULL;
403 state->cli = cli;
404 state->fnum = fnum;
406 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
407 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
408 return tevent_req_post(req, ev);
411 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
412 if (tevent_req_nterror(req, status)) {
413 return tevent_req_post(req, ev);
416 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
417 cli->smb2.session, cli->smb2.tcon,
418 0, state->ph->fid_persistent,
419 state->ph->fid_volatile);
420 if (tevent_req_nomem(subreq, req)) {
421 return tevent_req_post(req, ev);
423 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
424 return req;
427 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
429 struct tevent_req *req = tevent_req_callback_data(
430 subreq, struct tevent_req);
431 struct cli_smb2_close_fnum_state *state = tevent_req_data(
432 req, struct cli_smb2_close_fnum_state);
433 NTSTATUS status;
435 status = smb2cli_close_recv(subreq);
436 if (tevent_req_nterror(req, status)) {
437 return;
440 /* Delete the fnum -> handle mapping. */
441 status = delete_smb2_handle_mapping(state->cli, &state->ph,
442 state->fnum);
443 if (tevent_req_nterror(req, status)) {
444 return;
446 tevent_req_done(req);
449 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
451 struct cli_smb2_close_fnum_state *state = tevent_req_data(
452 req, struct cli_smb2_close_fnum_state);
453 NTSTATUS status = NT_STATUS_OK;
455 if (tevent_req_is_nterror(req, &status)) {
456 state->cli->raw_status = status;
458 tevent_req_received(req);
459 return status;
462 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
464 TALLOC_CTX *frame = talloc_stackframe();
465 struct tevent_context *ev;
466 struct tevent_req *req;
467 NTSTATUS status = NT_STATUS_NO_MEMORY;
469 if (smbXcli_conn_has_async_calls(cli->conn)) {
471 * Can't use sync call while an async call is in flight
473 status = NT_STATUS_INVALID_PARAMETER;
474 goto fail;
476 ev = samba_tevent_context_init(frame);
477 if (ev == NULL) {
478 goto fail;
480 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
481 if (req == NULL) {
482 goto fail;
484 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
485 goto fail;
487 status = cli_smb2_close_fnum_recv(req);
488 fail:
489 TALLOC_FREE(frame);
490 return status;
493 struct cli_smb2_delete_on_close_state {
494 struct cli_state *cli;
495 uint16_t fnum;
496 struct smb2_hnd *ph;
497 uint8_t data[1];
498 DATA_BLOB inbuf;
501 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
503 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
504 struct tevent_context *ev,
505 struct cli_state *cli,
506 uint16_t fnum,
507 bool flag)
509 struct tevent_req *req = NULL;
510 struct cli_smb2_delete_on_close_state *state = NULL;
511 struct tevent_req *subreq = NULL;
512 uint8_t in_info_type;
513 uint8_t in_file_info_class;
514 NTSTATUS status;
516 req = tevent_req_create(mem_ctx, &state,
517 struct cli_smb2_delete_on_close_state);
518 if (req == NULL) {
519 return NULL;
521 state->cli = cli;
522 state->fnum = fnum;
524 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
525 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
526 return tevent_req_post(req, ev);
529 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
530 if (tevent_req_nterror(req, status)) {
531 return tevent_req_post(req, ev);
535 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
536 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
538 in_info_type = 1;
539 in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
540 /* Setup data array. */
541 SCVAL(&state->data[0], 0, flag ? 1 : 0);
542 state->inbuf.data = &state->data[0];
543 state->inbuf.length = 1;
545 subreq = smb2cli_set_info_send(state, ev,
546 cli->conn,
547 cli->timeout,
548 cli->smb2.session,
549 cli->smb2.tcon,
550 in_info_type,
551 in_file_info_class,
552 &state->inbuf, /* in_input_buffer */
553 0, /* in_additional_info */
554 state->ph->fid_persistent,
555 state->ph->fid_volatile);
556 if (tevent_req_nomem(subreq, req)) {
557 return tevent_req_post(req, ev);
559 tevent_req_set_callback(subreq,
560 cli_smb2_delete_on_close_done,
561 req);
562 return req;
565 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
567 NTSTATUS status = smb2cli_set_info_recv(subreq);
568 tevent_req_simple_finish_ntstatus(subreq, status);
571 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
573 struct cli_smb2_delete_on_close_state *state =
574 tevent_req_data(req,
575 struct cli_smb2_delete_on_close_state);
576 NTSTATUS status;
578 if (tevent_req_is_nterror(req, &status)) {
579 state->cli->raw_status = status;
580 tevent_req_received(req);
581 return status;
584 state->cli->raw_status = NT_STATUS_OK;
585 tevent_req_received(req);
586 return NT_STATUS_OK;
589 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
591 TALLOC_CTX *frame = talloc_stackframe();
592 struct tevent_context *ev;
593 struct tevent_req *req;
594 NTSTATUS status = NT_STATUS_NO_MEMORY;
596 if (smbXcli_conn_has_async_calls(cli->conn)) {
598 * Can't use sync call while an async call is in flight
600 status = NT_STATUS_INVALID_PARAMETER;
601 goto fail;
603 ev = samba_tevent_context_init(frame);
604 if (ev == NULL) {
605 goto fail;
607 req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
608 if (req == NULL) {
609 goto fail;
611 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
612 goto fail;
614 status = cli_smb2_delete_on_close_recv(req);
615 fail:
616 TALLOC_FREE(frame);
617 return status;
620 /***************************************************************
621 Small wrapper that allows SMB2 to create a directory
622 Synchronous only.
623 ***************************************************************/
625 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
627 NTSTATUS status;
628 uint16_t fnum;
630 if (smbXcli_conn_has_async_calls(cli->conn)) {
632 * Can't use sync call while an async call is in flight
634 return NT_STATUS_INVALID_PARAMETER;
637 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
638 return NT_STATUS_INVALID_PARAMETER;
641 status = cli_smb2_create_fnum(cli,
642 dname,
643 0, /* create_flags */
644 FILE_READ_ATTRIBUTES, /* desired_access */
645 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
646 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
647 FILE_CREATE, /* create_disposition */
648 FILE_DIRECTORY_FILE, /* create_options */
649 &fnum,
650 NULL);
652 if (!NT_STATUS_IS_OK(status)) {
653 return status;
655 return cli_smb2_close_fnum(cli, fnum);
658 /***************************************************************
659 Small wrapper that allows SMB2 to delete a directory
660 Synchronous only.
661 ***************************************************************/
663 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
665 NTSTATUS status;
666 uint16_t fnum;
668 if (smbXcli_conn_has_async_calls(cli->conn)) {
670 * Can't use sync call while an async call is in flight
672 return NT_STATUS_INVALID_PARAMETER;
675 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
676 return NT_STATUS_INVALID_PARAMETER;
679 status = cli_smb2_create_fnum(cli,
680 dname,
681 0, /* create_flags */
682 DELETE_ACCESS, /* desired_access */
683 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
684 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
685 FILE_OPEN, /* create_disposition */
686 FILE_DIRECTORY_FILE, /* create_options */
687 &fnum,
688 NULL);
690 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
692 * Naive option to match our SMB1 code. Assume the
693 * symlink path that tripped us up was the last
694 * component and try again. Eventually we will have to
695 * deal with the returned path unprocessed component. JRA.
697 status = cli_smb2_create_fnum(cli,
698 dname,
699 0, /* create_flags */
700 DELETE_ACCESS, /* desired_access */
701 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
702 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
703 FILE_OPEN, /* create_disposition */
704 FILE_DIRECTORY_FILE|
705 FILE_DELETE_ON_CLOSE|
706 FILE_OPEN_REPARSE_POINT, /* create_options */
707 &fnum,
708 NULL);
711 if (!NT_STATUS_IS_OK(status)) {
712 return status;
715 status = cli_smb2_delete_on_close(cli, fnum, true);
716 if (!NT_STATUS_IS_OK(status)) {
717 cli_smb2_close_fnum(cli, fnum);
718 return status;
721 return cli_smb2_close_fnum(cli, fnum);
724 /***************************************************************
725 Small wrapper that allows SMB2 to unlink a pathname.
726 Synchronous only.
727 ***************************************************************/
729 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
731 NTSTATUS status;
732 uint16_t fnum;
734 if (smbXcli_conn_has_async_calls(cli->conn)) {
736 * Can't use sync call while an async call is in flight
738 return NT_STATUS_INVALID_PARAMETER;
741 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
742 return NT_STATUS_INVALID_PARAMETER;
745 status = cli_smb2_create_fnum(cli,
746 fname,
747 0, /* create_flags */
748 DELETE_ACCESS, /* desired_access */
749 FILE_ATTRIBUTE_NORMAL, /* file attributes */
750 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
751 FILE_OPEN, /* create_disposition */
752 FILE_DELETE_ON_CLOSE, /* create_options */
753 &fnum,
754 NULL);
756 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
758 * Naive option to match our SMB1 code. Assume the
759 * symlink path that tripped us up was the last
760 * component and try again. Eventually we will have to
761 * deal with the returned path unprocessed component. JRA.
763 status = cli_smb2_create_fnum(cli,
764 fname,
765 0, /* create_flags */
766 DELETE_ACCESS, /* desired_access */
767 FILE_ATTRIBUTE_NORMAL, /* file attributes */
768 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
769 FILE_OPEN, /* create_disposition */
770 FILE_DELETE_ON_CLOSE|
771 FILE_OPEN_REPARSE_POINT, /* create_options */
772 &fnum,
773 NULL);
776 if (!NT_STATUS_IS_OK(status)) {
777 return status;
779 return cli_smb2_close_fnum(cli, fnum);
782 /***************************************************************
783 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
784 ***************************************************************/
786 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
787 uint32_t dir_data_length,
788 struct file_info *finfo,
789 uint32_t *next_offset)
791 size_t namelen = 0;
792 size_t slen = 0;
793 size_t ret = 0;
795 if (dir_data_length < 4) {
796 return NT_STATUS_INFO_LENGTH_MISMATCH;
799 *next_offset = IVAL(dir_data, 0);
801 if (*next_offset > dir_data_length) {
802 return NT_STATUS_INFO_LENGTH_MISMATCH;
805 if (*next_offset != 0) {
806 /* Ensure we only read what in this record. */
807 dir_data_length = *next_offset;
810 if (dir_data_length < 105) {
811 return NT_STATUS_INFO_LENGTH_MISMATCH;
814 finfo->btime_ts = interpret_long_date((const char *)dir_data + 8);
815 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
816 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
817 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
818 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
819 finfo->mode = CVAL(dir_data + 56, 0);
820 namelen = IVAL(dir_data + 60,0);
821 if (namelen > (dir_data_length - 104)) {
822 return NT_STATUS_INFO_LENGTH_MISMATCH;
824 slen = CVAL(dir_data + 68, 0);
825 if (slen > 24) {
826 return NT_STATUS_INFO_LENGTH_MISMATCH;
828 ret = pull_string_talloc(finfo,
829 dir_data,
830 FLAGS2_UNICODE_STRINGS,
831 &finfo->short_name,
832 dir_data + 70,
833 slen,
834 STR_UNICODE);
835 if (ret == (size_t)-1) {
836 /* Bad conversion. */
837 return NT_STATUS_INVALID_NETWORK_RESPONSE;
840 ret = pull_string_talloc(finfo,
841 dir_data,
842 FLAGS2_UNICODE_STRINGS,
843 &finfo->name,
844 dir_data + 104,
845 namelen,
846 STR_UNICODE);
847 if (ret == (size_t)-1) {
848 /* Bad conversion. */
849 return NT_STATUS_INVALID_NETWORK_RESPONSE;
851 return NT_STATUS_OK;
854 /*******************************************************************
855 Given a filename - get its directory name
856 ********************************************************************/
858 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
859 const char *dir,
860 char **parent,
861 const char **name)
863 char *p;
864 ptrdiff_t len;
866 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
868 if (p == NULL) {
869 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
870 return false;
872 if (name) {
873 *name = dir;
875 return true;
878 len = p-dir;
880 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
881 return false;
883 (*parent)[len] = '\0';
885 if (name) {
886 *name = p+1;
888 return true;
891 /***************************************************************
892 Wrapper that allows SMB2 to list a directory.
893 Synchronous only.
894 ***************************************************************/
896 NTSTATUS cli_smb2_list(struct cli_state *cli,
897 const char *pathname,
898 uint16_t attribute,
899 NTSTATUS (*fn)(const char *,
900 struct file_info *,
901 const char *,
902 void *),
903 void *state)
905 NTSTATUS status;
906 uint16_t fnum = 0xffff;
907 char *parent_dir = NULL;
908 const char *mask = NULL;
909 struct smb2_hnd *ph = NULL;
910 bool processed_file = false;
911 TALLOC_CTX *frame = talloc_stackframe();
912 TALLOC_CTX *subframe = NULL;
913 bool mask_has_wild;
915 if (smbXcli_conn_has_async_calls(cli->conn)) {
917 * Can't use sync call while an async call is in flight
919 status = NT_STATUS_INVALID_PARAMETER;
920 goto fail;
923 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
924 status = NT_STATUS_INVALID_PARAMETER;
925 goto fail;
928 /* Get the directory name. */
929 if (!windows_parent_dirname(frame,
930 pathname,
931 &parent_dir,
932 &mask)) {
933 status = NT_STATUS_NO_MEMORY;
934 goto fail;
937 mask_has_wild = ms_has_wild(mask);
939 status = cli_smb2_create_fnum(cli,
940 parent_dir,
941 0, /* create_flags */
942 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
943 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
944 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
945 FILE_OPEN, /* create_disposition */
946 FILE_DIRECTORY_FILE, /* create_options */
947 &fnum,
948 NULL);
950 if (!NT_STATUS_IS_OK(status)) {
951 goto fail;
954 status = map_fnum_to_smb2_handle(cli,
955 fnum,
956 &ph);
957 if (!NT_STATUS_IS_OK(status)) {
958 goto fail;
961 do {
962 uint8_t *dir_data = NULL;
963 uint32_t dir_data_length = 0;
964 uint32_t next_offset = 0;
965 subframe = talloc_stackframe();
967 status = smb2cli_query_directory(cli->conn,
968 cli->timeout,
969 cli->smb2.session,
970 cli->smb2.tcon,
971 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
972 0, /* flags */
973 0, /* file_index */
974 ph->fid_persistent,
975 ph->fid_volatile,
976 mask,
977 0xffff,
978 subframe,
979 &dir_data,
980 &dir_data_length);
982 if (!NT_STATUS_IS_OK(status)) {
983 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
984 break;
986 goto fail;
989 do {
990 struct file_info *finfo = talloc_zero(subframe,
991 struct file_info);
993 if (finfo == NULL) {
994 status = NT_STATUS_NO_MEMORY;
995 goto fail;
998 status = parse_finfo_id_both_directory_info(dir_data,
999 dir_data_length,
1000 finfo,
1001 &next_offset);
1003 if (!NT_STATUS_IS_OK(status)) {
1004 goto fail;
1007 if (dir_check_ftype((uint32_t)finfo->mode,
1008 (uint32_t)attribute)) {
1010 * Only process if attributes match.
1011 * On SMB1 server does this, so on
1012 * SMB2 we need to emulate in the
1013 * client.
1015 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1017 processed_file = true;
1019 status = fn(cli->dfs_mountpoint,
1020 finfo,
1021 pathname,
1022 state);
1024 if (!NT_STATUS_IS_OK(status)) {
1025 break;
1029 TALLOC_FREE(finfo);
1031 /* Move to next entry. */
1032 if (next_offset) {
1033 dir_data += next_offset;
1034 dir_data_length -= next_offset;
1036 } while (next_offset != 0);
1038 TALLOC_FREE(subframe);
1040 if (!mask_has_wild) {
1042 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1043 * when handed a non-wildcard path. Do it
1044 * for the server (with a non-wildcard path
1045 * there should only ever be one file returned.
1047 status = STATUS_NO_MORE_FILES;
1048 break;
1051 } while (NT_STATUS_IS_OK(status));
1053 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1054 status = NT_STATUS_OK;
1057 if (NT_STATUS_IS_OK(status) && !processed_file) {
1059 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1060 * if no files match. Emulate this in the client.
1062 status = NT_STATUS_NO_SUCH_FILE;
1065 fail:
1067 if (fnum != 0xffff) {
1068 cli_smb2_close_fnum(cli, fnum);
1071 cli->raw_status = status;
1073 TALLOC_FREE(subframe);
1074 TALLOC_FREE(frame);
1075 return status;
1078 /***************************************************************
1079 Wrapper that allows SMB2 to query a path info (basic level).
1080 Synchronous only.
1081 ***************************************************************/
1083 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1084 const char *name,
1085 SMB_STRUCT_STAT *sbuf,
1086 uint32_t *attributes)
1088 NTSTATUS status;
1089 struct smb_create_returns cr;
1090 uint16_t fnum = 0xffff;
1091 size_t namelen = strlen(name);
1093 if (smbXcli_conn_has_async_calls(cli->conn)) {
1095 * Can't use sync call while an async call is in flight
1097 return NT_STATUS_INVALID_PARAMETER;
1100 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1101 return NT_STATUS_INVALID_PARAMETER;
1104 /* SMB2 is pickier about pathnames. Ensure it doesn't
1105 end in a '\' */
1106 if (namelen > 0 && name[namelen-1] == '\\') {
1107 char *modname = talloc_strdup(talloc_tos(), name);
1108 modname[namelen-1] = '\0';
1109 name = modname;
1112 /* This is commonly used as a 'cd'. Try qpathinfo on
1113 a directory handle first. */
1115 status = cli_smb2_create_fnum(cli,
1116 name,
1117 0, /* create_flags */
1118 FILE_READ_ATTRIBUTES, /* desired_access */
1119 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1120 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1121 FILE_OPEN, /* create_disposition */
1122 FILE_DIRECTORY_FILE, /* create_options */
1123 &fnum,
1124 &cr);
1126 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1127 /* Maybe a file ? */
1128 status = cli_smb2_create_fnum(cli,
1129 name,
1130 0, /* create_flags */
1131 FILE_READ_ATTRIBUTES, /* desired_access */
1132 0, /* file attributes */
1133 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1134 FILE_OPEN, /* create_disposition */
1135 0, /* create_options */
1136 &fnum,
1137 &cr);
1140 if (!NT_STATUS_IS_OK(status)) {
1141 return status;
1144 status = cli_smb2_close_fnum(cli, fnum);
1146 ZERO_STRUCTP(sbuf);
1148 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1149 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1150 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1151 sbuf->st_ex_size = cr.end_of_file;
1152 *attributes = cr.file_attributes;
1154 return status;
1157 /***************************************************************
1158 Wrapper that allows SMB2 to check if a path is a directory.
1159 Synchronous only.
1160 ***************************************************************/
1162 NTSTATUS cli_smb2_chkpath(struct cli_state *cli,
1163 const char *name)
1165 NTSTATUS status;
1166 uint16_t fnum = 0xffff;
1168 if (smbXcli_conn_has_async_calls(cli->conn)) {
1170 * Can't use sync call while an async call is in flight
1172 return NT_STATUS_INVALID_PARAMETER;
1175 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1176 return NT_STATUS_INVALID_PARAMETER;
1179 /* Ensure this is a directory. */
1180 status = cli_smb2_create_fnum(cli,
1181 name,
1182 0, /* create_flags */
1183 FILE_READ_ATTRIBUTES, /* desired_access */
1184 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1185 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1186 FILE_OPEN, /* create_disposition */
1187 FILE_DIRECTORY_FILE, /* create_options */
1188 &fnum,
1189 NULL);
1191 if (!NT_STATUS_IS_OK(status)) {
1192 return status;
1195 return cli_smb2_close_fnum(cli, fnum);
1198 /***************************************************************
1199 Helper function for pathname operations.
1200 ***************************************************************/
1202 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1203 const char *name,
1204 uint32_t desired_access,
1205 uint16_t *pfnum)
1207 NTSTATUS status;
1208 size_t namelen = strlen(name);
1209 TALLOC_CTX *frame = talloc_stackframe();
1210 uint32_t create_options = 0;
1212 /* SMB2 is pickier about pathnames. Ensure it doesn't
1213 end in a '\' */
1214 if (namelen > 0 && name[namelen-1] == '\\') {
1215 char *modname = talloc_strdup(frame, name);
1216 if (modname == NULL) {
1217 status = NT_STATUS_NO_MEMORY;
1218 goto fail;
1220 modname[namelen-1] = '\0';
1221 name = modname;
1224 /* Try to open a file handle first. */
1225 status = cli_smb2_create_fnum(cli,
1226 name,
1227 0, /* create_flags */
1228 desired_access,
1229 0, /* file attributes */
1230 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1231 FILE_OPEN, /* create_disposition */
1232 create_options,
1233 pfnum,
1234 NULL);
1236 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1238 * Naive option to match our SMB1 code. Assume the
1239 * symlink path that tripped us up was the last
1240 * component and try again. Eventually we will have to
1241 * deal with the returned path unprocessed component. JRA.
1243 create_options |= FILE_OPEN_REPARSE_POINT;
1244 status = cli_smb2_create_fnum(cli,
1245 name,
1246 0, /* create_flags */
1247 desired_access,
1248 0, /* file attributes */
1249 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1250 FILE_OPEN, /* create_disposition */
1251 create_options,
1252 pfnum,
1253 NULL);
1256 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1257 create_options |= FILE_DIRECTORY_FILE;
1258 status = cli_smb2_create_fnum(cli,
1259 name,
1260 0, /* create_flags */
1261 desired_access,
1262 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1263 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1264 FILE_OPEN, /* create_disposition */
1265 FILE_DIRECTORY_FILE, /* create_options */
1266 pfnum,
1267 NULL);
1270 fail:
1272 TALLOC_FREE(frame);
1273 return status;
1276 /***************************************************************
1277 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1278 Synchronous only.
1279 ***************************************************************/
1281 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1282 const char *name,
1283 fstring alt_name)
1285 NTSTATUS status;
1286 DATA_BLOB outbuf = data_blob_null;
1287 uint16_t fnum = 0xffff;
1288 struct smb2_hnd *ph = NULL;
1289 uint32_t altnamelen = 0;
1290 TALLOC_CTX *frame = talloc_stackframe();
1292 if (smbXcli_conn_has_async_calls(cli->conn)) {
1294 * Can't use sync call while an async call is in flight
1296 status = NT_STATUS_INVALID_PARAMETER;
1297 goto fail;
1300 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1301 status = NT_STATUS_INVALID_PARAMETER;
1302 goto fail;
1305 status = get_fnum_from_path(cli,
1306 name,
1307 FILE_READ_ATTRIBUTES,
1308 &fnum);
1310 if (!NT_STATUS_IS_OK(status)) {
1311 goto fail;
1314 status = map_fnum_to_smb2_handle(cli,
1315 fnum,
1316 &ph);
1317 if (!NT_STATUS_IS_OK(status)) {
1318 goto fail;
1321 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1322 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1324 status = smb2cli_query_info(cli->conn,
1325 cli->timeout,
1326 cli->smb2.session,
1327 cli->smb2.tcon,
1328 1, /* in_info_type */
1329 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1330 0xFFFF, /* in_max_output_length */
1331 NULL, /* in_input_buffer */
1332 0, /* in_additional_info */
1333 0, /* in_flags */
1334 ph->fid_persistent,
1335 ph->fid_volatile,
1336 frame,
1337 &outbuf);
1339 if (!NT_STATUS_IS_OK(status)) {
1340 goto fail;
1343 /* Parse the reply. */
1344 if (outbuf.length < 4) {
1345 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1346 goto fail;
1349 altnamelen = IVAL(outbuf.data, 0);
1350 if (altnamelen > outbuf.length - 4) {
1351 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1352 goto fail;
1355 if (altnamelen > 0) {
1356 size_t ret = 0;
1357 char *short_name = NULL;
1358 ret = pull_string_talloc(frame,
1359 outbuf.data,
1360 FLAGS2_UNICODE_STRINGS,
1361 &short_name,
1362 outbuf.data + 4,
1363 altnamelen,
1364 STR_UNICODE);
1365 if (ret == (size_t)-1) {
1366 /* Bad conversion. */
1367 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1368 goto fail;
1371 fstrcpy(alt_name, short_name);
1372 } else {
1373 alt_name[0] = '\0';
1376 status = NT_STATUS_OK;
1378 fail:
1380 if (fnum != 0xffff) {
1381 cli_smb2_close_fnum(cli, fnum);
1384 cli->raw_status = status;
1386 TALLOC_FREE(frame);
1387 return status;
1391 /***************************************************************
1392 Wrapper that allows SMB2 to query a fnum info (basic level).
1393 Synchronous only.
1394 ***************************************************************/
1396 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1397 uint16_t fnum,
1398 uint16_t *mode,
1399 off_t *size,
1400 struct timespec *create_time,
1401 struct timespec *access_time,
1402 struct timespec *write_time,
1403 struct timespec *change_time,
1404 SMB_INO_T *ino)
1406 NTSTATUS status;
1407 DATA_BLOB outbuf = data_blob_null;
1408 struct smb2_hnd *ph = NULL;
1409 TALLOC_CTX *frame = talloc_stackframe();
1411 if (smbXcli_conn_has_async_calls(cli->conn)) {
1413 * Can't use sync call while an async call is in flight
1415 status = NT_STATUS_INVALID_PARAMETER;
1416 goto fail;
1419 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1420 status = NT_STATUS_INVALID_PARAMETER;
1421 goto fail;
1424 status = map_fnum_to_smb2_handle(cli,
1425 fnum,
1426 &ph);
1427 if (!NT_STATUS_IS_OK(status)) {
1428 goto fail;
1431 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1432 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1434 status = smb2cli_query_info(cli->conn,
1435 cli->timeout,
1436 cli->smb2.session,
1437 cli->smb2.tcon,
1438 1, /* in_info_type */
1439 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1440 0xFFFF, /* in_max_output_length */
1441 NULL, /* in_input_buffer */
1442 0, /* in_additional_info */
1443 0, /* in_flags */
1444 ph->fid_persistent,
1445 ph->fid_volatile,
1446 frame,
1447 &outbuf);
1448 if (!NT_STATUS_IS_OK(status)) {
1449 goto fail;
1452 /* Parse the reply. */
1453 if (outbuf.length < 0x60) {
1454 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1455 goto fail;
1458 if (create_time) {
1459 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1461 if (access_time) {
1462 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1464 if (write_time) {
1465 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1467 if (change_time) {
1468 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1470 if (mode) {
1471 uint32_t attr = IVAL(outbuf.data, 0x20);
1472 *mode = (uint16_t)attr;
1474 if (size) {
1475 uint64_t file_size = BVAL(outbuf.data, 0x30);
1476 *size = (off_t)file_size;
1478 if (ino) {
1479 uint64_t file_index = BVAL(outbuf.data, 0x40);
1480 *ino = (SMB_INO_T)file_index;
1483 fail:
1485 cli->raw_status = status;
1487 TALLOC_FREE(frame);
1488 return status;
1491 /***************************************************************
1492 Wrapper that allows SMB2 to query an fnum.
1493 Implement on top of cli_smb2_qfileinfo_basic().
1494 Synchronous only.
1495 ***************************************************************/
1497 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1498 uint16_t fnum,
1499 uint16_t *attr,
1500 off_t *size,
1501 time_t *change_time,
1502 time_t *access_time,
1503 time_t *write_time)
1505 struct timespec access_time_ts;
1506 struct timespec write_time_ts;
1507 struct timespec change_time_ts;
1508 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1509 fnum,
1510 attr,
1511 size,
1512 NULL,
1513 &access_time_ts,
1514 &write_time_ts,
1515 &change_time_ts,
1516 NULL);
1518 cli->raw_status = status;
1520 if (!NT_STATUS_IS_OK(status)) {
1521 return status;
1524 if (change_time) {
1525 *change_time = change_time_ts.tv_sec;
1527 if (access_time) {
1528 *access_time = access_time_ts.tv_sec;
1530 if (write_time) {
1531 *write_time = write_time_ts.tv_sec;
1533 return NT_STATUS_OK;
1536 /***************************************************************
1537 Wrapper that allows SMB2 to get pathname attributes.
1538 Synchronous only.
1539 ***************************************************************/
1541 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1542 const char *name,
1543 uint16_t *attr,
1544 off_t *size,
1545 time_t *write_time)
1547 NTSTATUS status;
1548 uint16_t fnum = 0xffff;
1549 struct smb2_hnd *ph = NULL;
1550 TALLOC_CTX *frame = talloc_stackframe();
1552 if (smbXcli_conn_has_async_calls(cli->conn)) {
1554 * Can't use sync call while an async call is in flight
1556 status = NT_STATUS_INVALID_PARAMETER;
1557 goto fail;
1560 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1561 status = NT_STATUS_INVALID_PARAMETER;
1562 goto fail;
1565 status = get_fnum_from_path(cli,
1566 name,
1567 FILE_READ_ATTRIBUTES,
1568 &fnum);
1570 if (!NT_STATUS_IS_OK(status)) {
1571 goto fail;
1574 status = map_fnum_to_smb2_handle(cli,
1575 fnum,
1576 &ph);
1577 if (!NT_STATUS_IS_OK(status)) {
1578 goto fail;
1580 status = cli_smb2_getattrE(cli,
1581 fnum,
1582 attr,
1583 size,
1584 NULL,
1585 NULL,
1586 write_time);
1587 if (!NT_STATUS_IS_OK(status)) {
1588 goto fail;
1591 fail:
1593 if (fnum != 0xffff) {
1594 cli_smb2_close_fnum(cli, fnum);
1597 cli->raw_status = status;
1599 TALLOC_FREE(frame);
1600 return status;
1603 /***************************************************************
1604 Wrapper that allows SMB2 to query a pathname info (basic level).
1605 Implement on top of cli_smb2_qfileinfo_basic().
1606 Synchronous only.
1607 ***************************************************************/
1609 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1610 const char *name,
1611 struct timespec *create_time,
1612 struct timespec *access_time,
1613 struct timespec *write_time,
1614 struct timespec *change_time,
1615 off_t *size,
1616 uint16_t *mode,
1617 SMB_INO_T *ino)
1619 NTSTATUS status;
1620 struct smb2_hnd *ph = NULL;
1621 uint16_t fnum = 0xffff;
1622 TALLOC_CTX *frame = talloc_stackframe();
1624 if (smbXcli_conn_has_async_calls(cli->conn)) {
1626 * Can't use sync call while an async call is in flight
1628 status = NT_STATUS_INVALID_PARAMETER;
1629 goto fail;
1632 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1633 status = NT_STATUS_INVALID_PARAMETER;
1634 goto fail;
1637 status = get_fnum_from_path(cli,
1638 name,
1639 FILE_READ_ATTRIBUTES,
1640 &fnum);
1642 if (!NT_STATUS_IS_OK(status)) {
1643 goto fail;
1646 status = map_fnum_to_smb2_handle(cli,
1647 fnum,
1648 &ph);
1649 if (!NT_STATUS_IS_OK(status)) {
1650 goto fail;
1653 status = cli_smb2_qfileinfo_basic(cli,
1654 fnum,
1655 mode,
1656 size,
1657 create_time,
1658 access_time,
1659 write_time,
1660 change_time,
1661 ino);
1663 fail:
1665 if (fnum != 0xffff) {
1666 cli_smb2_close_fnum(cli, fnum);
1669 cli->raw_status = status;
1671 TALLOC_FREE(frame);
1672 return status;
1675 /***************************************************************
1676 Wrapper that allows SMB2 to query pathname streams.
1677 Synchronous only.
1678 ***************************************************************/
1680 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1681 const char *name,
1682 TALLOC_CTX *mem_ctx,
1683 unsigned int *pnum_streams,
1684 struct stream_struct **pstreams)
1686 NTSTATUS status;
1687 struct smb2_hnd *ph = NULL;
1688 uint16_t fnum = 0xffff;
1689 DATA_BLOB outbuf = data_blob_null;
1690 TALLOC_CTX *frame = talloc_stackframe();
1692 if (smbXcli_conn_has_async_calls(cli->conn)) {
1694 * Can't use sync call while an async call is in flight
1696 status = NT_STATUS_INVALID_PARAMETER;
1697 goto fail;
1700 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1701 status = NT_STATUS_INVALID_PARAMETER;
1702 goto fail;
1705 status = get_fnum_from_path(cli,
1706 name,
1707 FILE_READ_ATTRIBUTES,
1708 &fnum);
1710 if (!NT_STATUS_IS_OK(status)) {
1711 goto fail;
1714 status = map_fnum_to_smb2_handle(cli,
1715 fnum,
1716 &ph);
1717 if (!NT_STATUS_IS_OK(status)) {
1718 goto fail;
1721 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1722 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1724 status = smb2cli_query_info(cli->conn,
1725 cli->timeout,
1726 cli->smb2.session,
1727 cli->smb2.tcon,
1728 1, /* in_info_type */
1729 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1730 0xFFFF, /* in_max_output_length */
1731 NULL, /* in_input_buffer */
1732 0, /* in_additional_info */
1733 0, /* in_flags */
1734 ph->fid_persistent,
1735 ph->fid_volatile,
1736 frame,
1737 &outbuf);
1739 if (!NT_STATUS_IS_OK(status)) {
1740 goto fail;
1743 /* Parse the reply. */
1744 if (!parse_streams_blob(mem_ctx,
1745 outbuf.data,
1746 outbuf.length,
1747 pnum_streams,
1748 pstreams)) {
1749 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1750 goto fail;
1753 fail:
1755 if (fnum != 0xffff) {
1756 cli_smb2_close_fnum(cli, fnum);
1759 cli->raw_status = status;
1761 TALLOC_FREE(frame);
1762 return status;
1765 /***************************************************************
1766 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
1767 a pathname.
1768 Synchronous only.
1769 ***************************************************************/
1771 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
1772 const char *name,
1773 uint8_t in_info_type,
1774 uint8_t in_file_info_class,
1775 const DATA_BLOB *p_in_data)
1777 NTSTATUS status;
1778 uint16_t fnum = 0xffff;
1779 struct smb2_hnd *ph = NULL;
1780 TALLOC_CTX *frame = talloc_stackframe();
1782 if (smbXcli_conn_has_async_calls(cli->conn)) {
1784 * Can't use sync call while an async call is in flight
1786 status = NT_STATUS_INVALID_PARAMETER;
1787 goto fail;
1790 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1791 status = NT_STATUS_INVALID_PARAMETER;
1792 goto fail;
1795 status = get_fnum_from_path(cli,
1796 name,
1797 FILE_WRITE_ATTRIBUTES,
1798 &fnum);
1800 if (!NT_STATUS_IS_OK(status)) {
1801 goto fail;
1804 status = map_fnum_to_smb2_handle(cli,
1805 fnum,
1806 &ph);
1807 if (!NT_STATUS_IS_OK(status)) {
1808 goto fail;
1811 status = smb2cli_set_info(cli->conn,
1812 cli->timeout,
1813 cli->smb2.session,
1814 cli->smb2.tcon,
1815 in_info_type,
1816 in_file_info_class,
1817 p_in_data, /* in_input_buffer */
1818 0, /* in_additional_info */
1819 ph->fid_persistent,
1820 ph->fid_volatile);
1821 fail:
1823 if (fnum != 0xffff) {
1824 cli_smb2_close_fnum(cli, fnum);
1827 cli->raw_status = status;
1829 TALLOC_FREE(frame);
1830 return status;
1834 /***************************************************************
1835 Wrapper that allows SMB2 to set pathname attributes.
1836 Synchronous only.
1837 ***************************************************************/
1839 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1840 const char *name,
1841 uint16_t attr,
1842 time_t mtime)
1844 uint8_t inbuf_store[40];
1845 DATA_BLOB inbuf = data_blob_null;
1847 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1848 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1850 inbuf.data = inbuf_store;
1851 inbuf.length = sizeof(inbuf_store);
1852 data_blob_clear(&inbuf);
1855 * SMB1 uses attr == 0 to clear all attributes
1856 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
1857 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
1858 * request attribute change.
1860 * SMB2 uses exactly the reverse. Unfortunately as the
1861 * cli_setatr() ABI is exposed inside libsmbclient,
1862 * we must make the SMB2 cli_smb2_setatr() call
1863 * export the same ABI as the SMB1 cli_setatr()
1864 * which calls it. This means reversing the sense
1865 * of the requested attr argument if it's zero
1866 * or FILE_ATTRIBUTE_NORMAL.
1868 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
1871 if (attr == 0) {
1872 attr = FILE_ATTRIBUTE_NORMAL;
1873 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
1874 attr = 0;
1877 SSVAL(inbuf.data, 32, attr);
1878 if (mtime != 0) {
1879 put_long_date((char *)inbuf.data + 16,mtime);
1881 /* Set all the other times to -1. */
1882 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1883 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1884 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1886 return cli_smb2_setpathinfo(cli,
1887 name,
1888 1, /* in_info_type */
1889 /* in_file_info_class */
1890 SMB_FILE_BASIC_INFORMATION - 1000,
1891 &inbuf);
1895 /***************************************************************
1896 Wrapper that allows SMB2 to set file handle times.
1897 Synchronous only.
1898 ***************************************************************/
1900 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1901 uint16_t fnum,
1902 time_t change_time,
1903 time_t access_time,
1904 time_t write_time)
1906 NTSTATUS status;
1907 struct smb2_hnd *ph = NULL;
1908 uint8_t inbuf_store[40];
1909 DATA_BLOB inbuf = data_blob_null;
1911 if (smbXcli_conn_has_async_calls(cli->conn)) {
1913 * Can't use sync call while an async call is in flight
1915 return NT_STATUS_INVALID_PARAMETER;
1918 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1919 return NT_STATUS_INVALID_PARAMETER;
1922 status = map_fnum_to_smb2_handle(cli,
1923 fnum,
1924 &ph);
1925 if (!NT_STATUS_IS_OK(status)) {
1926 return status;
1929 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1930 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1932 inbuf.data = inbuf_store;
1933 inbuf.length = sizeof(inbuf_store);
1934 data_blob_clear(&inbuf);
1936 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1937 if (change_time != 0) {
1938 put_long_date((char *)inbuf.data + 24, change_time);
1940 if (access_time != 0) {
1941 put_long_date((char *)inbuf.data + 8, access_time);
1943 if (write_time != 0) {
1944 put_long_date((char *)inbuf.data + 16, write_time);
1947 cli->raw_status = smb2cli_set_info(cli->conn,
1948 cli->timeout,
1949 cli->smb2.session,
1950 cli->smb2.tcon,
1951 1, /* in_info_type */
1952 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1953 &inbuf, /* in_input_buffer */
1954 0, /* in_additional_info */
1955 ph->fid_persistent,
1956 ph->fid_volatile);
1958 return cli->raw_status;
1961 /***************************************************************
1962 Wrapper that allows SMB2 to query disk attributes (size).
1963 Synchronous only.
1964 ***************************************************************/
1966 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
1967 uint64_t *bsize, uint64_t *total, uint64_t *avail)
1969 NTSTATUS status;
1970 uint16_t fnum = 0xffff;
1971 DATA_BLOB outbuf = data_blob_null;
1972 struct smb2_hnd *ph = NULL;
1973 uint32_t sectors_per_unit = 0;
1974 uint32_t bytes_per_sector = 0;
1975 uint64_t total_size = 0;
1976 uint64_t size_free = 0;
1977 TALLOC_CTX *frame = talloc_stackframe();
1979 if (smbXcli_conn_has_async_calls(cli->conn)) {
1981 * Can't use sync call while an async call is in flight
1983 status = NT_STATUS_INVALID_PARAMETER;
1984 goto fail;
1987 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1988 status = NT_STATUS_INVALID_PARAMETER;
1989 goto fail;
1992 /* First open the top level directory. */
1993 status = cli_smb2_create_fnum(cli,
1994 path,
1995 0, /* create_flags */
1996 FILE_READ_ATTRIBUTES, /* desired_access */
1997 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1998 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1999 FILE_OPEN, /* create_disposition */
2000 FILE_DIRECTORY_FILE, /* create_options */
2001 &fnum,
2002 NULL);
2004 if (!NT_STATUS_IS_OK(status)) {
2005 goto fail;
2008 status = map_fnum_to_smb2_handle(cli,
2009 fnum,
2010 &ph);
2011 if (!NT_STATUS_IS_OK(status)) {
2012 goto fail;
2015 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2016 level 3 (SMB_FS_SIZE_INFORMATION). */
2018 status = smb2cli_query_info(cli->conn,
2019 cli->timeout,
2020 cli->smb2.session,
2021 cli->smb2.tcon,
2022 2, /* in_info_type */
2023 3, /* in_file_info_class */
2024 0xFFFF, /* in_max_output_length */
2025 NULL, /* in_input_buffer */
2026 0, /* in_additional_info */
2027 0, /* in_flags */
2028 ph->fid_persistent,
2029 ph->fid_volatile,
2030 frame,
2031 &outbuf);
2032 if (!NT_STATUS_IS_OK(status)) {
2033 goto fail;
2036 /* Parse the reply. */
2037 if (outbuf.length != 24) {
2038 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2039 goto fail;
2042 total_size = BVAL(outbuf.data, 0);
2043 size_free = BVAL(outbuf.data, 8);
2044 sectors_per_unit = IVAL(outbuf.data, 16);
2045 bytes_per_sector = IVAL(outbuf.data, 20);
2047 if (bsize) {
2048 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2050 if (total) {
2051 *total = total_size;
2053 if (avail) {
2054 *avail = size_free;
2057 status = NT_STATUS_OK;
2059 fail:
2061 if (fnum != 0xffff) {
2062 cli_smb2_close_fnum(cli, fnum);
2065 cli->raw_status = status;
2067 TALLOC_FREE(frame);
2068 return status;
2071 /***************************************************************
2072 Wrapper that allows SMB2 to query file system sizes.
2073 Synchronous only.
2074 ***************************************************************/
2076 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2077 uint64_t *total_allocation_units,
2078 uint64_t *caller_allocation_units,
2079 uint64_t *actual_allocation_units,
2080 uint64_t *sectors_per_allocation_unit,
2081 uint64_t *bytes_per_sector)
2083 NTSTATUS status;
2084 uint16_t fnum = 0xffff;
2085 DATA_BLOB outbuf = data_blob_null;
2086 struct smb2_hnd *ph = NULL;
2087 TALLOC_CTX *frame = talloc_stackframe();
2089 if (smbXcli_conn_has_async_calls(cli->conn)) {
2091 * Can't use sync call while an async call is in flight
2093 status = NT_STATUS_INVALID_PARAMETER;
2094 goto fail;
2097 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2098 status = NT_STATUS_INVALID_PARAMETER;
2099 goto fail;
2102 /* First open the top level directory. */
2103 status =
2104 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2105 FILE_READ_ATTRIBUTES, /* desired_access */
2106 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2107 FILE_SHARE_READ | FILE_SHARE_WRITE |
2108 FILE_SHARE_DELETE, /* share_access */
2109 FILE_OPEN, /* create_disposition */
2110 FILE_DIRECTORY_FILE, /* create_options */
2111 &fnum,
2112 NULL);
2114 if (!NT_STATUS_IS_OK(status)) {
2115 goto fail;
2118 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2119 if (!NT_STATUS_IS_OK(status)) {
2120 goto fail;
2123 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2124 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2126 status = smb2cli_query_info(cli->conn,
2127 cli->timeout,
2128 cli->smb2.session,
2129 cli->smb2.tcon,
2130 SMB2_GETINFO_FS, /* in_info_type */
2131 /* in_file_info_class */
2132 SMB_FS_FULL_SIZE_INFORMATION - 1000,
2133 0xFFFF, /* in_max_output_length */
2134 NULL, /* in_input_buffer */
2135 0, /* in_additional_info */
2136 0, /* in_flags */
2137 ph->fid_persistent,
2138 ph->fid_volatile,
2139 frame,
2140 &outbuf);
2141 if (!NT_STATUS_IS_OK(status)) {
2142 goto fail;
2145 if (outbuf.length < 32) {
2146 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2147 goto fail;
2150 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2151 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2152 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2153 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2154 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2156 fail:
2158 if (fnum != 0xffff) {
2159 cli_smb2_close_fnum(cli, fnum);
2162 cli->raw_status = status;
2164 TALLOC_FREE(frame);
2165 return status;
2168 /***************************************************************
2169 Wrapper that allows SMB2 to query file system attributes.
2170 Synchronous only.
2171 ***************************************************************/
2173 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2175 NTSTATUS status;
2176 uint16_t fnum = 0xffff;
2177 DATA_BLOB outbuf = data_blob_null;
2178 struct smb2_hnd *ph = NULL;
2179 TALLOC_CTX *frame = talloc_stackframe();
2181 if (smbXcli_conn_has_async_calls(cli->conn)) {
2183 * Can't use sync call while an async call is in flight
2185 status = NT_STATUS_INVALID_PARAMETER;
2186 goto fail;
2189 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2190 status = NT_STATUS_INVALID_PARAMETER;
2191 goto fail;
2194 /* First open the top level directory. */
2195 status =
2196 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2197 FILE_READ_ATTRIBUTES, /* desired_access */
2198 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2199 FILE_SHARE_READ | FILE_SHARE_WRITE |
2200 FILE_SHARE_DELETE, /* share_access */
2201 FILE_OPEN, /* create_disposition */
2202 FILE_DIRECTORY_FILE, /* create_options */
2203 &fnum,
2204 NULL);
2206 if (!NT_STATUS_IS_OK(status)) {
2207 goto fail;
2210 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2211 if (!NT_STATUS_IS_OK(status)) {
2212 goto fail;
2215 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2216 cli->smb2.tcon, 2, /* in_info_type */
2217 5, /* in_file_info_class */
2218 0xFFFF, /* in_max_output_length */
2219 NULL, /* in_input_buffer */
2220 0, /* in_additional_info */
2221 0, /* in_flags */
2222 ph->fid_persistent, ph->fid_volatile, frame,
2223 &outbuf);
2224 if (!NT_STATUS_IS_OK(status)) {
2225 goto fail;
2228 if (outbuf.length < 12) {
2229 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2230 goto fail;
2233 *fs_attr = IVAL(outbuf.data, 0);
2235 fail:
2237 if (fnum != 0xffff) {
2238 cli_smb2_close_fnum(cli, fnum);
2241 cli->raw_status = status;
2243 TALLOC_FREE(frame);
2244 return status;
2247 /***************************************************************
2248 Wrapper that allows SMB2 to query file system volume info.
2249 Synchronous only.
2250 ***************************************************************/
2252 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2253 TALLOC_CTX *mem_ctx,
2254 char **_volume_name,
2255 uint32_t *pserial_number,
2256 time_t *pdate)
2258 NTSTATUS status;
2259 uint16_t fnum = 0xffff;
2260 DATA_BLOB outbuf = data_blob_null;
2261 struct smb2_hnd *ph = NULL;
2262 uint32_t nlen;
2263 char *volume_name = NULL;
2264 TALLOC_CTX *frame = talloc_stackframe();
2266 if (smbXcli_conn_has_async_calls(cli->conn)) {
2268 * Can't use sync call while an async call is in flight
2270 status = NT_STATUS_INVALID_PARAMETER;
2271 goto fail;
2274 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2275 status = NT_STATUS_INVALID_PARAMETER;
2276 goto fail;
2279 /* First open the top level directory. */
2280 status =
2281 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2282 FILE_READ_ATTRIBUTES, /* desired_access */
2283 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2284 FILE_SHARE_READ | FILE_SHARE_WRITE |
2285 FILE_SHARE_DELETE, /* share_access */
2286 FILE_OPEN, /* create_disposition */
2287 FILE_DIRECTORY_FILE, /* create_options */
2288 &fnum,
2289 NULL);
2291 if (!NT_STATUS_IS_OK(status)) {
2292 goto fail;
2295 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2296 if (!NT_STATUS_IS_OK(status)) {
2297 goto fail;
2300 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2301 level 1 (SMB_FS_VOLUME_INFORMATION). */
2303 status = smb2cli_query_info(cli->conn,
2304 cli->timeout,
2305 cli->smb2.session,
2306 cli->smb2.tcon,
2307 SMB2_GETINFO_FS, /* in_info_type */
2308 /* in_file_info_class */
2309 SMB_FS_VOLUME_INFORMATION - 1000,
2310 0xFFFF, /* in_max_output_length */
2311 NULL, /* in_input_buffer */
2312 0, /* in_additional_info */
2313 0, /* in_flags */
2314 ph->fid_persistent,
2315 ph->fid_volatile,
2316 frame,
2317 &outbuf);
2318 if (!NT_STATUS_IS_OK(status)) {
2319 goto fail;
2322 if (outbuf.length < 24) {
2323 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2324 goto fail;
2327 if (pdate) {
2328 struct timespec ts;
2329 ts = interpret_long_date((char *)outbuf.data);
2330 *pdate = ts.tv_sec;
2332 if (pserial_number) {
2333 *pserial_number = IVAL(outbuf.data,8);
2335 nlen = IVAL(outbuf.data,12);
2336 if (nlen + 18 < 18) {
2337 /* Integer wrap. */
2338 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2339 goto fail;
2342 * The next check is safe as we know outbuf.length >= 24
2343 * from above.
2345 if (nlen > (outbuf.length - 18)) {
2346 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2347 goto fail;
2350 clistr_pull_talloc(mem_ctx,
2351 (const char *)outbuf.data,
2353 &volume_name,
2354 outbuf.data + 18,
2355 nlen,
2356 STR_UNICODE);
2357 if (volume_name == NULL) {
2358 status = map_nt_error_from_unix(errno);
2359 goto fail;
2362 *_volume_name = volume_name;
2364 fail:
2366 if (fnum != 0xffff) {
2367 cli_smb2_close_fnum(cli, fnum);
2370 cli->raw_status = status;
2372 TALLOC_FREE(frame);
2373 return status;
2377 /***************************************************************
2378 Wrapper that allows SMB2 to query a security descriptor.
2379 Synchronous only.
2380 ***************************************************************/
2382 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2383 uint16_t fnum,
2384 uint32_t sec_info,
2385 TALLOC_CTX *mem_ctx,
2386 struct security_descriptor **ppsd)
2388 NTSTATUS status;
2389 DATA_BLOB outbuf = data_blob_null;
2390 struct smb2_hnd *ph = NULL;
2391 struct security_descriptor *lsd = NULL;
2392 TALLOC_CTX *frame = talloc_stackframe();
2394 if (smbXcli_conn_has_async_calls(cli->conn)) {
2396 * Can't use sync call while an async call is in flight
2398 status = NT_STATUS_INVALID_PARAMETER;
2399 goto fail;
2402 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2403 status = NT_STATUS_INVALID_PARAMETER;
2404 goto fail;
2407 status = map_fnum_to_smb2_handle(cli,
2408 fnum,
2409 &ph);
2410 if (!NT_STATUS_IS_OK(status)) {
2411 goto fail;
2414 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2416 status = smb2cli_query_info(cli->conn,
2417 cli->timeout,
2418 cli->smb2.session,
2419 cli->smb2.tcon,
2420 3, /* in_info_type */
2421 0, /* in_file_info_class */
2422 0xFFFF, /* in_max_output_length */
2423 NULL, /* in_input_buffer */
2424 sec_info, /* in_additional_info */
2425 0, /* in_flags */
2426 ph->fid_persistent,
2427 ph->fid_volatile,
2428 frame,
2429 &outbuf);
2431 if (!NT_STATUS_IS_OK(status)) {
2432 goto fail;
2435 /* Parse the reply. */
2436 status = unmarshall_sec_desc(mem_ctx,
2437 outbuf.data,
2438 outbuf.length,
2439 &lsd);
2441 if (!NT_STATUS_IS_OK(status)) {
2442 goto fail;
2445 if (ppsd != NULL) {
2446 *ppsd = lsd;
2447 } else {
2448 TALLOC_FREE(lsd);
2451 fail:
2453 cli->raw_status = status;
2455 TALLOC_FREE(frame);
2456 return status;
2459 /***************************************************************
2460 Wrapper that allows SMB2 to set a security descriptor.
2461 Synchronous only.
2462 ***************************************************************/
2464 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
2465 uint16_t fnum,
2466 uint32_t sec_info,
2467 const struct security_descriptor *sd)
2469 NTSTATUS status;
2470 DATA_BLOB inbuf = data_blob_null;
2471 struct smb2_hnd *ph = NULL;
2472 TALLOC_CTX *frame = talloc_stackframe();
2474 if (smbXcli_conn_has_async_calls(cli->conn)) {
2476 * Can't use sync call while an async call is in flight
2478 status = NT_STATUS_INVALID_PARAMETER;
2479 goto fail;
2482 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2483 status = NT_STATUS_INVALID_PARAMETER;
2484 goto fail;
2487 status = map_fnum_to_smb2_handle(cli,
2488 fnum,
2489 &ph);
2490 if (!NT_STATUS_IS_OK(status)) {
2491 goto fail;
2494 status = marshall_sec_desc(frame,
2496 &inbuf.data,
2497 &inbuf.length);
2499 if (!NT_STATUS_IS_OK(status)) {
2500 goto fail;
2503 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2505 status = smb2cli_set_info(cli->conn,
2506 cli->timeout,
2507 cli->smb2.session,
2508 cli->smb2.tcon,
2509 3, /* in_info_type */
2510 0, /* in_file_info_class */
2511 &inbuf, /* in_input_buffer */
2512 sec_info, /* in_additional_info */
2513 ph->fid_persistent,
2514 ph->fid_volatile);
2516 fail:
2518 cli->raw_status = status;
2520 TALLOC_FREE(frame);
2521 return status;
2524 /***************************************************************
2525 Wrapper that allows SMB2 to rename a file.
2526 Synchronous only.
2527 ***************************************************************/
2529 NTSTATUS cli_smb2_rename(struct cli_state *cli,
2530 const char *fname_src,
2531 const char *fname_dst,
2532 bool replace)
2534 NTSTATUS status;
2535 DATA_BLOB inbuf = data_blob_null;
2536 uint16_t fnum = 0xffff;
2537 struct smb2_hnd *ph = NULL;
2538 smb_ucs2_t *converted_str = NULL;
2539 size_t converted_size_bytes = 0;
2540 size_t namelen = 0;
2541 TALLOC_CTX *frame = talloc_stackframe();
2543 if (smbXcli_conn_has_async_calls(cli->conn)) {
2545 * Can't use sync call while an async call is in flight
2547 status = NT_STATUS_INVALID_PARAMETER;
2548 goto fail;
2551 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2552 status = NT_STATUS_INVALID_PARAMETER;
2553 goto fail;
2556 status = get_fnum_from_path(cli,
2557 fname_src,
2558 DELETE_ACCESS,
2559 &fnum);
2561 if (!NT_STATUS_IS_OK(status)) {
2562 goto fail;
2565 status = map_fnum_to_smb2_handle(cli,
2566 fnum,
2567 &ph);
2568 if (!NT_STATUS_IS_OK(status)) {
2569 goto fail;
2572 /* SMB2 is pickier about pathnames. Ensure it doesn't
2573 start in a '\' */
2574 if (*fname_dst == '\\') {
2575 fname_dst++;
2578 /* SMB2 is pickier about pathnames. Ensure it doesn't
2579 end in a '\' */
2580 namelen = strlen(fname_dst);
2581 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2582 char *modname = talloc_strdup(frame, fname_dst);
2583 modname[namelen-1] = '\0';
2584 fname_dst = modname;
2587 if (!push_ucs2_talloc(frame,
2588 &converted_str,
2589 fname_dst,
2590 &converted_size_bytes)) {
2591 status = NT_STATUS_INVALID_PARAMETER;
2592 goto fail;
2595 /* W2K8 insists the dest name is not null
2596 terminated. Remove the last 2 zero bytes
2597 and reduce the name length. */
2599 if (converted_size_bytes < 2) {
2600 status = NT_STATUS_INVALID_PARAMETER;
2601 goto fail;
2603 converted_size_bytes -= 2;
2605 inbuf = data_blob_talloc_zero(frame,
2606 20 + converted_size_bytes);
2607 if (inbuf.data == NULL) {
2608 status = NT_STATUS_NO_MEMORY;
2609 goto fail;
2612 if (replace) {
2613 SCVAL(inbuf.data, 0, 1);
2616 SIVAL(inbuf.data, 16, converted_size_bytes);
2617 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2619 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2620 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2622 status = smb2cli_set_info(cli->conn,
2623 cli->timeout,
2624 cli->smb2.session,
2625 cli->smb2.tcon,
2626 1, /* in_info_type */
2627 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2628 &inbuf, /* in_input_buffer */
2629 0, /* in_additional_info */
2630 ph->fid_persistent,
2631 ph->fid_volatile);
2633 fail:
2635 if (fnum != 0xffff) {
2636 cli_smb2_close_fnum(cli, fnum);
2639 cli->raw_status = status;
2641 TALLOC_FREE(frame);
2642 return status;
2645 /***************************************************************
2646 Wrapper that allows SMB2 to set an EA on a fnum.
2647 Synchronous only.
2648 ***************************************************************/
2650 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2651 uint16_t fnum,
2652 const char *ea_name,
2653 const char *ea_val,
2654 size_t ea_len)
2656 NTSTATUS status;
2657 DATA_BLOB inbuf = data_blob_null;
2658 size_t bloblen = 0;
2659 char *ea_name_ascii = NULL;
2660 size_t namelen = 0;
2661 struct smb2_hnd *ph = NULL;
2662 TALLOC_CTX *frame = talloc_stackframe();
2664 if (smbXcli_conn_has_async_calls(cli->conn)) {
2666 * Can't use sync call while an async call is in flight
2668 status = NT_STATUS_INVALID_PARAMETER;
2669 goto fail;
2672 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2673 status = NT_STATUS_INVALID_PARAMETER;
2674 goto fail;
2677 status = map_fnum_to_smb2_handle(cli,
2678 fnum,
2679 &ph);
2680 if (!NT_STATUS_IS_OK(status)) {
2681 goto fail;
2684 /* Marshall the SMB2 EA data. */
2685 if (ea_len > 0xFFFF) {
2686 status = NT_STATUS_INVALID_PARAMETER;
2687 goto fail;
2690 if (!push_ascii_talloc(frame,
2691 &ea_name_ascii,
2692 ea_name,
2693 &namelen)) {
2694 status = NT_STATUS_INVALID_PARAMETER;
2695 goto fail;
2698 if (namelen < 2 || namelen > 0xFF) {
2699 status = NT_STATUS_INVALID_PARAMETER;
2700 goto fail;
2703 bloblen = 8 + ea_len + namelen;
2704 /* Round up to a 4 byte boundary. */
2705 bloblen = ((bloblen + 3)&~3);
2707 inbuf = data_blob_talloc_zero(frame, bloblen);
2708 if (inbuf.data == NULL) {
2709 status = NT_STATUS_NO_MEMORY;
2710 goto fail;
2712 /* namelen doesn't include the NULL byte. */
2713 SCVAL(inbuf.data, 5, namelen - 1);
2714 SSVAL(inbuf.data, 6, ea_len);
2715 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2716 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2718 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2719 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2721 status = smb2cli_set_info(cli->conn,
2722 cli->timeout,
2723 cli->smb2.session,
2724 cli->smb2.tcon,
2725 1, /* in_info_type */
2726 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2727 &inbuf, /* in_input_buffer */
2728 0, /* in_additional_info */
2729 ph->fid_persistent,
2730 ph->fid_volatile);
2732 fail:
2734 cli->raw_status = status;
2736 TALLOC_FREE(frame);
2737 return status;
2740 /***************************************************************
2741 Wrapper that allows SMB2 to set an EA on a pathname.
2742 Synchronous only.
2743 ***************************************************************/
2745 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2746 const char *name,
2747 const char *ea_name,
2748 const char *ea_val,
2749 size_t ea_len)
2751 NTSTATUS status;
2752 uint16_t fnum = 0xffff;
2754 if (smbXcli_conn_has_async_calls(cli->conn)) {
2756 * Can't use sync call while an async call is in flight
2758 status = NT_STATUS_INVALID_PARAMETER;
2759 goto fail;
2762 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2763 status = NT_STATUS_INVALID_PARAMETER;
2764 goto fail;
2767 status = get_fnum_from_path(cli,
2768 name,
2769 FILE_WRITE_EA,
2770 &fnum);
2772 if (!NT_STATUS_IS_OK(status)) {
2773 goto fail;
2776 status = cli_set_ea_fnum(cli,
2777 fnum,
2778 ea_name,
2779 ea_val,
2780 ea_len);
2781 if (!NT_STATUS_IS_OK(status)) {
2782 goto fail;
2785 fail:
2787 if (fnum != 0xffff) {
2788 cli_smb2_close_fnum(cli, fnum);
2791 cli->raw_status = status;
2793 return status;
2796 /***************************************************************
2797 Wrapper that allows SMB2 to get an EA list on a pathname.
2798 Synchronous only.
2799 ***************************************************************/
2801 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2802 const char *name,
2803 TALLOC_CTX *ctx,
2804 size_t *pnum_eas,
2805 struct ea_struct **pea_array)
2807 NTSTATUS status;
2808 uint16_t fnum = 0xffff;
2809 DATA_BLOB outbuf = data_blob_null;
2810 struct smb2_hnd *ph = NULL;
2811 struct ea_list *ea_list = NULL;
2812 struct ea_list *eal = NULL;
2813 size_t ea_count = 0;
2814 TALLOC_CTX *frame = talloc_stackframe();
2816 *pnum_eas = 0;
2817 *pea_array = NULL;
2819 if (smbXcli_conn_has_async_calls(cli->conn)) {
2821 * Can't use sync call while an async call is in flight
2823 status = NT_STATUS_INVALID_PARAMETER;
2824 goto fail;
2827 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2828 status = NT_STATUS_INVALID_PARAMETER;
2829 goto fail;
2832 status = get_fnum_from_path(cli,
2833 name,
2834 FILE_READ_EA,
2835 &fnum);
2837 if (!NT_STATUS_IS_OK(status)) {
2838 goto fail;
2841 status = map_fnum_to_smb2_handle(cli,
2842 fnum,
2843 &ph);
2844 if (!NT_STATUS_IS_OK(status)) {
2845 goto fail;
2848 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2849 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2851 status = smb2cli_query_info(cli->conn,
2852 cli->timeout,
2853 cli->smb2.session,
2854 cli->smb2.tcon,
2855 1, /* in_info_type */
2856 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2857 0xFFFF, /* in_max_output_length */
2858 NULL, /* in_input_buffer */
2859 0, /* in_additional_info */
2860 0, /* in_flags */
2861 ph->fid_persistent,
2862 ph->fid_volatile,
2863 frame,
2864 &outbuf);
2866 if (!NT_STATUS_IS_OK(status)) {
2867 goto fail;
2870 /* Parse the reply. */
2871 ea_list = read_nttrans_ea_list(ctx,
2872 (const char *)outbuf.data,
2873 outbuf.length);
2874 if (ea_list == NULL) {
2875 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2876 goto fail;
2879 /* Convert to an array. */
2880 for (eal = ea_list; eal; eal = eal->next) {
2881 ea_count++;
2884 if (ea_count) {
2885 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2886 if (*pea_array == NULL) {
2887 status = NT_STATUS_NO_MEMORY;
2888 goto fail;
2890 ea_count = 0;
2891 for (eal = ea_list; eal; eal = eal->next) {
2892 (*pea_array)[ea_count++] = eal->ea;
2894 *pnum_eas = ea_count;
2897 fail:
2899 if (fnum != 0xffff) {
2900 cli_smb2_close_fnum(cli, fnum);
2903 cli->raw_status = status;
2905 TALLOC_FREE(frame);
2906 return status;
2909 /***************************************************************
2910 Wrapper that allows SMB2 to get user quota.
2911 Synchronous only.
2912 ***************************************************************/
2914 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
2915 int quota_fnum,
2916 SMB_NTQUOTA_STRUCT *pqt)
2918 NTSTATUS status;
2919 DATA_BLOB inbuf = data_blob_null;
2920 DATA_BLOB info_blob = data_blob_null;
2921 DATA_BLOB outbuf = data_blob_null;
2922 struct smb2_hnd *ph = NULL;
2923 TALLOC_CTX *frame = talloc_stackframe();
2924 unsigned sid_len;
2925 unsigned int offset;
2926 struct smb2_query_quota_info query = {0};
2927 struct file_get_quota_info info = {0};
2928 enum ndr_err_code err;
2929 struct ndr_push *ndr_push = NULL;
2931 if (smbXcli_conn_has_async_calls(cli->conn)) {
2933 * Can't use sync call while an async call is in flight
2935 status = NT_STATUS_INVALID_PARAMETER;
2936 goto fail;
2939 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2940 status = NT_STATUS_INVALID_PARAMETER;
2941 goto fail;
2944 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2945 if (!NT_STATUS_IS_OK(status)) {
2946 goto fail;
2949 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
2951 query.return_single = 1;
2953 info.next_entry_offset = 0;
2954 info.sid_length = sid_len;
2955 info.sid = pqt->sid;
2957 err = ndr_push_struct_blob(
2958 &info_blob,
2959 frame,
2960 &info,
2961 (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
2963 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
2964 status = NT_STATUS_INTERNAL_ERROR;
2965 goto fail;
2968 query.sid_list_length = info_blob.length;
2969 ndr_push = ndr_push_init_ctx(frame);
2970 if (!ndr_push) {
2971 status = NT_STATUS_NO_MEMORY;
2972 goto fail;
2975 err = ndr_push_smb2_query_quota_info(ndr_push,
2976 NDR_SCALARS | NDR_BUFFERS,
2977 &query);
2979 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
2980 status = NT_STATUS_INTERNAL_ERROR;
2981 goto fail;
2984 err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
2985 info_blob.length);
2987 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
2988 status = NT_STATUS_INTERNAL_ERROR;
2989 goto fail;
2991 inbuf.data = ndr_push->data;
2992 inbuf.length = ndr_push->offset;
2994 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2995 cli->smb2.tcon, 4, /* in_info_type */
2996 0, /* in_file_info_class */
2997 0xFFFF, /* in_max_output_length */
2998 &inbuf, /* in_input_buffer */
2999 0, /* in_additional_info */
3000 0, /* in_flags */
3001 ph->fid_persistent, ph->fid_volatile, frame,
3002 &outbuf);
3004 if (!NT_STATUS_IS_OK(status)) {
3005 goto fail;
3008 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
3009 pqt)) {
3010 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
3011 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
3014 fail:
3015 cli->raw_status = status;
3017 TALLOC_FREE(frame);
3018 return status;
3021 /***************************************************************
3022 Wrapper that allows SMB2 to list user quota.
3023 Synchronous only.
3024 ***************************************************************/
3026 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
3027 TALLOC_CTX *mem_ctx,
3028 int quota_fnum,
3029 SMB_NTQUOTA_LIST **pqt_list,
3030 bool first)
3032 NTSTATUS status;
3033 DATA_BLOB inbuf = data_blob_null;
3034 DATA_BLOB outbuf = data_blob_null;
3035 struct smb2_hnd *ph = NULL;
3036 TALLOC_CTX *frame = talloc_stackframe();
3037 struct smb2_query_quota_info info = {0};
3038 enum ndr_err_code err;
3040 if (smbXcli_conn_has_async_calls(cli->conn)) {
3042 * Can't use sync call while an async call is in flight
3044 status = NT_STATUS_INVALID_PARAMETER;
3045 goto cleanup;
3048 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3049 status = NT_STATUS_INVALID_PARAMETER;
3050 goto cleanup;
3053 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3054 if (!NT_STATUS_IS_OK(status)) {
3055 goto cleanup;
3059 info.restart_scan = first ? 1 : 0;
3061 err = ndr_push_struct_blob(
3062 &inbuf,
3063 frame,
3064 &info,
3065 (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
3067 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
3068 status = NT_STATUS_INTERNAL_ERROR;
3069 goto cleanup;
3072 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
3073 cli->smb2.tcon, 4, /* in_info_type */
3074 0, /* in_file_info_class */
3075 0xFFFF, /* in_max_output_length */
3076 &inbuf, /* in_input_buffer */
3077 0, /* in_additional_info */
3078 0, /* in_flags */
3079 ph->fid_persistent, ph->fid_volatile, frame,
3080 &outbuf);
3083 * safeguard against panic from calling parse_user_quota_list with
3084 * NULL buffer
3086 if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
3087 status = NT_STATUS_NO_MORE_ENTRIES;
3090 if (!NT_STATUS_IS_OK(status)) {
3091 goto cleanup;
3094 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3095 pqt_list);
3097 cleanup:
3098 cli->raw_status = status;
3100 TALLOC_FREE(frame);
3101 return status;
3104 /***************************************************************
3105 Wrapper that allows SMB2 to get file system quota.
3106 Synchronous only.
3107 ***************************************************************/
3109 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3110 int quota_fnum,
3111 SMB_NTQUOTA_STRUCT *pqt)
3113 NTSTATUS status;
3114 DATA_BLOB outbuf = data_blob_null;
3115 struct smb2_hnd *ph = NULL;
3116 TALLOC_CTX *frame = talloc_stackframe();
3118 if (smbXcli_conn_has_async_calls(cli->conn)) {
3120 * Can't use sync call while an async call is in flight
3122 status = NT_STATUS_INVALID_PARAMETER;
3123 goto cleanup;
3126 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3127 status = NT_STATUS_INVALID_PARAMETER;
3128 goto cleanup;
3131 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3132 if (!NT_STATUS_IS_OK(status)) {
3133 goto cleanup;
3136 status = smb2cli_query_info(
3137 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3138 2, /* in_info_type */
3139 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3140 0xFFFF, /* in_max_output_length */
3141 NULL, /* in_input_buffer */
3142 0, /* in_additional_info */
3143 0, /* in_flags */
3144 ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
3146 if (!NT_STATUS_IS_OK(status)) {
3147 goto cleanup;
3150 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3152 cleanup:
3153 cli->raw_status = status;
3155 TALLOC_FREE(frame);
3156 return status;
3159 /***************************************************************
3160 Wrapper that allows SMB2 to set user quota.
3161 Synchronous only.
3162 ***************************************************************/
3164 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3165 int quota_fnum,
3166 SMB_NTQUOTA_LIST *qtl)
3168 NTSTATUS status;
3169 DATA_BLOB inbuf = data_blob_null;
3170 struct smb2_hnd *ph = NULL;
3171 TALLOC_CTX *frame = talloc_stackframe();
3173 if (smbXcli_conn_has_async_calls(cli->conn)) {
3175 * Can't use sync call while an async call is in flight
3177 status = NT_STATUS_INVALID_PARAMETER;
3178 goto cleanup;
3181 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3182 status = NT_STATUS_INVALID_PARAMETER;
3183 goto cleanup;
3186 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3187 if (!NT_STATUS_IS_OK(status)) {
3188 goto cleanup;
3191 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3192 if (!NT_STATUS_IS_OK(status)) {
3193 goto cleanup;
3196 status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
3197 cli->smb2.tcon, 4, /* in_info_type */
3198 0, /* in_file_info_class */
3199 &inbuf, /* in_input_buffer */
3200 0, /* in_additional_info */
3201 ph->fid_persistent, ph->fid_volatile);
3202 cleanup:
3204 cli->raw_status = status;
3206 TALLOC_FREE(frame);
3208 return status;
3211 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3212 int quota_fnum,
3213 SMB_NTQUOTA_STRUCT *pqt)
3215 NTSTATUS status;
3216 DATA_BLOB inbuf = data_blob_null;
3217 struct smb2_hnd *ph = NULL;
3218 TALLOC_CTX *frame = talloc_stackframe();
3220 if (smbXcli_conn_has_async_calls(cli->conn)) {
3222 * Can't use sync call while an async call is in flight
3224 status = NT_STATUS_INVALID_PARAMETER;
3225 goto cleanup;
3228 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3229 status = NT_STATUS_INVALID_PARAMETER;
3230 goto cleanup;
3233 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3234 if (!NT_STATUS_IS_OK(status)) {
3235 goto cleanup;
3238 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3239 if (!NT_STATUS_IS_OK(status)) {
3240 goto cleanup;
3243 status = smb2cli_set_info(
3244 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3245 2, /* in_info_type */
3246 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3247 &inbuf, /* in_input_buffer */
3248 0, /* in_additional_info */
3249 ph->fid_persistent, ph->fid_volatile);
3250 cleanup:
3251 cli->raw_status = status;
3253 TALLOC_FREE(frame);
3254 return status;
3257 struct cli_smb2_read_state {
3258 struct tevent_context *ev;
3259 struct cli_state *cli;
3260 struct smb2_hnd *ph;
3261 uint64_t start_offset;
3262 uint32_t size;
3263 uint32_t received;
3264 uint8_t *buf;
3267 static void cli_smb2_read_done(struct tevent_req *subreq);
3269 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3270 struct tevent_context *ev,
3271 struct cli_state *cli,
3272 uint16_t fnum,
3273 off_t offset,
3274 size_t size)
3276 NTSTATUS status;
3277 struct tevent_req *req, *subreq;
3278 struct cli_smb2_read_state *state;
3280 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3281 if (req == NULL) {
3282 return NULL;
3284 state->ev = ev;
3285 state->cli = cli;
3286 state->start_offset = (uint64_t)offset;
3287 state->size = (uint32_t)size;
3288 state->received = 0;
3289 state->buf = NULL;
3291 status = map_fnum_to_smb2_handle(cli,
3292 fnum,
3293 &state->ph);
3294 if (tevent_req_nterror(req, status)) {
3295 return tevent_req_post(req, ev);
3298 subreq = smb2cli_read_send(state,
3299 state->ev,
3300 state->cli->conn,
3301 state->cli->timeout,
3302 state->cli->smb2.session,
3303 state->cli->smb2.tcon,
3304 state->size,
3305 state->start_offset,
3306 state->ph->fid_persistent,
3307 state->ph->fid_volatile,
3308 0, /* minimum_count */
3309 0); /* remaining_bytes */
3311 if (tevent_req_nomem(subreq, req)) {
3312 return tevent_req_post(req, ev);
3314 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3315 return req;
3318 static void cli_smb2_read_done(struct tevent_req *subreq)
3320 struct tevent_req *req = tevent_req_callback_data(
3321 subreq, struct tevent_req);
3322 struct cli_smb2_read_state *state = tevent_req_data(
3323 req, struct cli_smb2_read_state);
3324 NTSTATUS status;
3326 status = smb2cli_read_recv(subreq, state,
3327 &state->buf, &state->received);
3328 if (tevent_req_nterror(req, status)) {
3329 return;
3332 if (state->received > state->size) {
3333 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3334 return;
3337 tevent_req_done(req);
3340 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
3341 ssize_t *received,
3342 uint8_t **rcvbuf)
3344 NTSTATUS status;
3345 struct cli_smb2_read_state *state = tevent_req_data(
3346 req, struct cli_smb2_read_state);
3348 if (tevent_req_is_nterror(req, &status)) {
3349 state->cli->raw_status = status;
3350 return status;
3353 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3354 * better make sure that you copy it away before you talloc_free(req).
3355 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3357 *received = (ssize_t)state->received;
3358 *rcvbuf = state->buf;
3359 state->cli->raw_status = NT_STATUS_OK;
3360 return NT_STATUS_OK;
3363 struct cli_smb2_write_state {
3364 struct tevent_context *ev;
3365 struct cli_state *cli;
3366 struct smb2_hnd *ph;
3367 uint32_t flags;
3368 const uint8_t *buf;
3369 uint64_t offset;
3370 uint32_t size;
3371 uint32_t written;
3374 static void cli_smb2_write_written(struct tevent_req *req);
3376 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
3377 struct tevent_context *ev,
3378 struct cli_state *cli,
3379 uint16_t fnum,
3380 uint16_t mode,
3381 const uint8_t *buf,
3382 off_t offset,
3383 size_t size)
3385 NTSTATUS status;
3386 struct tevent_req *req, *subreq = NULL;
3387 struct cli_smb2_write_state *state = NULL;
3389 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
3390 if (req == NULL) {
3391 return NULL;
3393 state->ev = ev;
3394 state->cli = cli;
3395 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3396 state->flags = (uint32_t)mode;
3397 state->buf = buf;
3398 state->offset = (uint64_t)offset;
3399 state->size = (uint32_t)size;
3400 state->written = 0;
3402 status = map_fnum_to_smb2_handle(cli,
3403 fnum,
3404 &state->ph);
3405 if (tevent_req_nterror(req, status)) {
3406 return tevent_req_post(req, ev);
3409 subreq = smb2cli_write_send(state,
3410 state->ev,
3411 state->cli->conn,
3412 state->cli->timeout,
3413 state->cli->smb2.session,
3414 state->cli->smb2.tcon,
3415 state->size,
3416 state->offset,
3417 state->ph->fid_persistent,
3418 state->ph->fid_volatile,
3419 0, /* remaining_bytes */
3420 state->flags, /* flags */
3421 state->buf);
3423 if (tevent_req_nomem(subreq, req)) {
3424 return tevent_req_post(req, ev);
3426 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
3427 return req;
3430 static void cli_smb2_write_written(struct tevent_req *subreq)
3432 struct tevent_req *req = tevent_req_callback_data(
3433 subreq, struct tevent_req);
3434 struct cli_smb2_write_state *state = tevent_req_data(
3435 req, struct cli_smb2_write_state);
3436 NTSTATUS status;
3437 uint32_t written;
3439 status = smb2cli_write_recv(subreq, &written);
3440 TALLOC_FREE(subreq);
3441 if (tevent_req_nterror(req, status)) {
3442 return;
3445 state->written = written;
3447 tevent_req_done(req);
3450 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
3451 size_t *pwritten)
3453 struct cli_smb2_write_state *state = tevent_req_data(
3454 req, struct cli_smb2_write_state);
3455 NTSTATUS status;
3457 if (tevent_req_is_nterror(req, &status)) {
3458 state->cli->raw_status = status;
3459 tevent_req_received(req);
3460 return status;
3463 if (pwritten != NULL) {
3464 *pwritten = (size_t)state->written;
3466 state->cli->raw_status = NT_STATUS_OK;
3467 tevent_req_received(req);
3468 return NT_STATUS_OK;
3471 /***************************************************************
3472 Wrapper that allows SMB2 async write using an fnum.
3473 This is mostly cut-and-paste from Volker's code inside
3474 source3/libsmb/clireadwrite.c, adapted for SMB2.
3476 Done this way so I can reuse all the logic inside cli_push()
3477 for free :-).
3478 ***************************************************************/
3480 struct cli_smb2_writeall_state {
3481 struct tevent_context *ev;
3482 struct cli_state *cli;
3483 struct smb2_hnd *ph;
3484 uint32_t flags;
3485 const uint8_t *buf;
3486 uint64_t offset;
3487 uint32_t size;
3488 uint32_t written;
3491 static void cli_smb2_writeall_written(struct tevent_req *req);
3493 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
3494 struct tevent_context *ev,
3495 struct cli_state *cli,
3496 uint16_t fnum,
3497 uint16_t mode,
3498 const uint8_t *buf,
3499 off_t offset,
3500 size_t size)
3502 NTSTATUS status;
3503 struct tevent_req *req, *subreq = NULL;
3504 struct cli_smb2_writeall_state *state = NULL;
3505 uint32_t to_write;
3506 uint32_t max_size;
3507 bool ok;
3509 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
3510 if (req == NULL) {
3511 return NULL;
3513 state->ev = ev;
3514 state->cli = cli;
3515 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3516 state->flags = (uint32_t)mode;
3517 state->buf = buf;
3518 state->offset = (uint64_t)offset;
3519 state->size = (uint32_t)size;
3520 state->written = 0;
3522 status = map_fnum_to_smb2_handle(cli,
3523 fnum,
3524 &state->ph);
3525 if (tevent_req_nterror(req, status)) {
3526 return tevent_req_post(req, ev);
3529 to_write = state->size;
3530 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3531 to_write = MIN(max_size, to_write);
3532 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3533 if (ok) {
3534 to_write = MIN(max_size, to_write);
3537 subreq = smb2cli_write_send(state,
3538 state->ev,
3539 state->cli->conn,
3540 state->cli->timeout,
3541 state->cli->smb2.session,
3542 state->cli->smb2.tcon,
3543 to_write,
3544 state->offset,
3545 state->ph->fid_persistent,
3546 state->ph->fid_volatile,
3547 0, /* remaining_bytes */
3548 state->flags, /* flags */
3549 state->buf + state->written);
3551 if (tevent_req_nomem(subreq, req)) {
3552 return tevent_req_post(req, ev);
3554 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3555 return req;
3558 static void cli_smb2_writeall_written(struct tevent_req *subreq)
3560 struct tevent_req *req = tevent_req_callback_data(
3561 subreq, struct tevent_req);
3562 struct cli_smb2_writeall_state *state = tevent_req_data(
3563 req, struct cli_smb2_writeall_state);
3564 NTSTATUS status;
3565 uint32_t written, to_write;
3566 uint32_t max_size;
3567 bool ok;
3569 status = smb2cli_write_recv(subreq, &written);
3570 TALLOC_FREE(subreq);
3571 if (tevent_req_nterror(req, status)) {
3572 return;
3575 state->written += written;
3577 if (state->written > state->size) {
3578 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3579 return;
3582 to_write = state->size - state->written;
3584 if (to_write == 0) {
3585 tevent_req_done(req);
3586 return;
3589 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3590 to_write = MIN(max_size, to_write);
3591 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3592 if (ok) {
3593 to_write = MIN(max_size, to_write);
3596 subreq = smb2cli_write_send(state,
3597 state->ev,
3598 state->cli->conn,
3599 state->cli->timeout,
3600 state->cli->smb2.session,
3601 state->cli->smb2.tcon,
3602 to_write,
3603 state->offset + state->written,
3604 state->ph->fid_persistent,
3605 state->ph->fid_volatile,
3606 0, /* remaining_bytes */
3607 state->flags, /* flags */
3608 state->buf + state->written);
3610 if (tevent_req_nomem(subreq, req)) {
3611 return;
3613 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3616 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
3617 size_t *pwritten)
3619 struct cli_smb2_writeall_state *state = tevent_req_data(
3620 req, struct cli_smb2_writeall_state);
3621 NTSTATUS status;
3623 if (tevent_req_is_nterror(req, &status)) {
3624 state->cli->raw_status = status;
3625 return status;
3627 if (pwritten != NULL) {
3628 *pwritten = (size_t)state->written;
3630 state->cli->raw_status = NT_STATUS_OK;
3631 return NT_STATUS_OK;
3634 struct cli_smb2_splice_state {
3635 struct tevent_context *ev;
3636 struct cli_state *cli;
3637 struct smb2_hnd *src_ph;
3638 struct smb2_hnd *dst_ph;
3639 int (*splice_cb)(off_t n, void *priv);
3640 void *priv;
3641 off_t written;
3642 off_t size;
3643 off_t src_offset;
3644 off_t dst_offset;
3645 bool resized;
3646 struct req_resume_key_rsp resume_rsp;
3647 struct srv_copychunk_copy cc_copy;
3650 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3651 struct tevent_req *req);
3653 static void cli_splice_copychunk_done(struct tevent_req *subreq)
3655 struct tevent_req *req = tevent_req_callback_data(
3656 subreq, struct tevent_req);
3657 struct cli_smb2_splice_state *state =
3658 tevent_req_data(req,
3659 struct cli_smb2_splice_state);
3660 struct smbXcli_conn *conn = state->cli->conn;
3661 DATA_BLOB out_input_buffer = data_blob_null;
3662 DATA_BLOB out_output_buffer = data_blob_null;
3663 struct srv_copychunk_rsp cc_copy_rsp;
3664 enum ndr_err_code ndr_ret;
3665 NTSTATUS status;
3667 status = smb2cli_ioctl_recv(subreq, state,
3668 &out_input_buffer,
3669 &out_output_buffer);
3670 TALLOC_FREE(subreq);
3671 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
3672 state->resized) && tevent_req_nterror(req, status)) {
3673 return;
3676 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
3677 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
3678 if (ndr_ret != NDR_ERR_SUCCESS) {
3679 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3680 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3681 return;
3684 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
3685 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
3686 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
3687 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
3688 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
3689 tevent_req_nterror(req, status)) {
3690 return;
3693 state->resized = true;
3694 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
3695 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
3696 } else {
3697 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3698 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3699 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
3700 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3701 return;
3703 state->src_offset += cc_copy_rsp.total_bytes_written;
3704 state->dst_offset += cc_copy_rsp.total_bytes_written;
3705 state->written += cc_copy_rsp.total_bytes_written;
3706 if (!state->splice_cb(state->written, state->priv)) {
3707 tevent_req_nterror(req, NT_STATUS_CANCELLED);
3708 return;
3712 cli_splice_copychunk_send(state, req);
3715 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3716 struct tevent_req *req)
3718 struct tevent_req *subreq;
3719 enum ndr_err_code ndr_ret;
3720 struct smbXcli_conn *conn = state->cli->conn;
3721 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
3722 off_t src_offset = state->src_offset;
3723 off_t dst_offset = state->dst_offset;
3724 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
3725 state->size - state->written);
3726 DATA_BLOB in_input_buffer = data_blob_null;
3727 DATA_BLOB in_output_buffer = data_blob_null;
3729 if (state->size - state->written == 0) {
3730 tevent_req_done(req);
3731 return;
3734 cc_copy->chunk_count = 0;
3735 while (req_len) {
3736 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
3737 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
3738 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
3739 smb2cli_conn_cc_chunk_len(conn));
3740 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
3741 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3742 return;
3744 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
3745 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
3746 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
3747 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3748 return;
3750 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3751 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3752 cc_copy->chunk_count++;
3755 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
3756 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
3757 if (ndr_ret != NDR_ERR_SUCCESS) {
3758 DEBUG(0, ("failed to marshall copy chunk req\n"));
3759 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3760 return;
3763 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
3764 state->cli->timeout,
3765 state->cli->smb2.session,
3766 state->cli->smb2.tcon,
3767 state->dst_ph->fid_persistent, /* in_fid_persistent */
3768 state->dst_ph->fid_volatile, /* in_fid_volatile */
3769 FSCTL_SRV_COPYCHUNK_WRITE,
3770 0, /* in_max_input_length */
3771 &in_input_buffer,
3772 12, /* in_max_output_length */
3773 &in_output_buffer,
3774 SMB2_IOCTL_FLAG_IS_FSCTL);
3775 if (tevent_req_nomem(subreq, req)) {
3776 return;
3778 tevent_req_set_callback(subreq,
3779 cli_splice_copychunk_done,
3780 req);
3783 static void cli_splice_key_done(struct tevent_req *subreq)
3785 struct tevent_req *req = tevent_req_callback_data(
3786 subreq, struct tevent_req);
3787 struct cli_smb2_splice_state *state =
3788 tevent_req_data(req,
3789 struct cli_smb2_splice_state);
3790 enum ndr_err_code ndr_ret;
3791 NTSTATUS status;
3793 DATA_BLOB out_input_buffer = data_blob_null;
3794 DATA_BLOB out_output_buffer = data_blob_null;
3796 status = smb2cli_ioctl_recv(subreq, state,
3797 &out_input_buffer,
3798 &out_output_buffer);
3799 TALLOC_FREE(subreq);
3800 if (tevent_req_nterror(req, status)) {
3801 return;
3804 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
3805 state, &state->resume_rsp,
3806 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
3807 if (ndr_ret != NDR_ERR_SUCCESS) {
3808 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3809 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3810 return;
3813 memcpy(&state->cc_copy.source_key,
3814 &state->resume_rsp.resume_key,
3815 sizeof state->resume_rsp.resume_key);
3817 cli_splice_copychunk_send(state, req);
3820 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
3821 struct tevent_context *ev,
3822 struct cli_state *cli,
3823 uint16_t src_fnum, uint16_t dst_fnum,
3824 off_t size, off_t src_offset, off_t dst_offset,
3825 int (*splice_cb)(off_t n, void *priv),
3826 void *priv)
3828 struct tevent_req *req;
3829 struct tevent_req *subreq;
3830 struct cli_smb2_splice_state *state;
3831 NTSTATUS status;
3832 DATA_BLOB in_input_buffer = data_blob_null;
3833 DATA_BLOB in_output_buffer = data_blob_null;
3835 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
3836 if (req == NULL) {
3837 return NULL;
3839 state->cli = cli;
3840 state->ev = ev;
3841 state->splice_cb = splice_cb;
3842 state->priv = priv;
3843 state->size = size;
3844 state->written = 0;
3845 state->src_offset = src_offset;
3846 state->dst_offset = dst_offset;
3847 state->cc_copy.chunks = talloc_array(state,
3848 struct srv_copychunk,
3849 smb2cli_conn_cc_max_chunks(cli->conn));
3850 if (state->cc_copy.chunks == NULL) {
3851 return NULL;
3854 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
3855 if (tevent_req_nterror(req, status))
3856 return tevent_req_post(req, ev);
3858 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
3859 if (tevent_req_nterror(req, status))
3860 return tevent_req_post(req, ev);
3862 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
3863 cli->timeout,
3864 cli->smb2.session,
3865 cli->smb2.tcon,
3866 state->src_ph->fid_persistent, /* in_fid_persistent */
3867 state->src_ph->fid_volatile, /* in_fid_volatile */
3868 FSCTL_SRV_REQUEST_RESUME_KEY,
3869 0, /* in_max_input_length */
3870 &in_input_buffer,
3871 32, /* in_max_output_length */
3872 &in_output_buffer,
3873 SMB2_IOCTL_FLAG_IS_FSCTL);
3874 if (tevent_req_nomem(subreq, req)) {
3875 return NULL;
3877 tevent_req_set_callback(subreq,
3878 cli_splice_key_done,
3879 req);
3881 return req;
3884 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
3886 struct cli_smb2_splice_state *state = tevent_req_data(
3887 req, struct cli_smb2_splice_state);
3888 NTSTATUS status;
3890 if (tevent_req_is_nterror(req, &status)) {
3891 state->cli->raw_status = status;
3892 tevent_req_received(req);
3893 return status;
3895 if (written != NULL) {
3896 *written = state->written;
3898 state->cli->raw_status = NT_STATUS_OK;
3899 tevent_req_received(req);
3900 return NT_STATUS_OK;
3903 /***************************************************************
3904 SMB2 enum shadow copy data.
3905 ***************************************************************/
3907 struct cli_smb2_shadow_copy_data_fnum_state {
3908 struct cli_state *cli;
3909 uint16_t fnum;
3910 struct smb2_hnd *ph;
3911 DATA_BLOB out_input_buffer;
3912 DATA_BLOB out_output_buffer;
3915 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
3917 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
3918 TALLOC_CTX *mem_ctx,
3919 struct tevent_context *ev,
3920 struct cli_state *cli,
3921 uint16_t fnum,
3922 bool get_names)
3924 struct tevent_req *req, *subreq;
3925 struct cli_smb2_shadow_copy_data_fnum_state *state;
3926 NTSTATUS status;
3928 req = tevent_req_create(mem_ctx, &state,
3929 struct cli_smb2_shadow_copy_data_fnum_state);
3930 if (req == NULL) {
3931 return NULL;
3934 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3935 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3936 return tevent_req_post(req, ev);
3939 state->cli = cli;
3940 state->fnum = fnum;
3942 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
3943 if (tevent_req_nterror(req, status)) {
3944 return tevent_req_post(req, ev);
3948 * TODO. Under SMB2 we should send a zero max_output_length
3949 * ioctl to get the required size, then send another ioctl
3950 * to get the data, but the current SMB1 implementation just
3951 * does one roundtrip with a 64K buffer size. Do the same
3952 * for now. JRA.
3955 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
3956 state->cli->timeout,
3957 state->cli->smb2.session,
3958 state->cli->smb2.tcon,
3959 state->ph->fid_persistent, /* in_fid_persistent */
3960 state->ph->fid_volatile, /* in_fid_volatile */
3961 FSCTL_GET_SHADOW_COPY_DATA,
3962 0, /* in_max_input_length */
3963 NULL, /* in_input_buffer */
3964 get_names ?
3965 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
3966 NULL, /* in_output_buffer */
3967 SMB2_IOCTL_FLAG_IS_FSCTL);
3969 if (tevent_req_nomem(subreq, req)) {
3970 return tevent_req_post(req, ev);
3972 tevent_req_set_callback(subreq,
3973 cli_smb2_shadow_copy_data_fnum_done,
3974 req);
3976 return req;
3979 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
3981 struct tevent_req *req = tevent_req_callback_data(
3982 subreq, struct tevent_req);
3983 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3984 req, struct cli_smb2_shadow_copy_data_fnum_state);
3985 NTSTATUS status;
3987 status = smb2cli_ioctl_recv(subreq, state,
3988 &state->out_input_buffer,
3989 &state->out_output_buffer);
3990 TALLOC_FREE(subreq);
3991 if (tevent_req_nterror(req, status)) {
3992 return;
3994 tevent_req_done(req);
3997 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
3998 TALLOC_CTX *mem_ctx,
3999 bool get_names,
4000 char ***pnames,
4001 int *pnum_names)
4003 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
4004 req, struct cli_smb2_shadow_copy_data_fnum_state);
4005 char **names = NULL;
4006 uint32_t num_names = 0;
4007 uint32_t num_names_returned = 0;
4008 uint32_t dlength = 0;
4009 uint32_t i;
4010 uint8_t *endp = NULL;
4011 NTSTATUS status;
4013 if (tevent_req_is_nterror(req, &status)) {
4014 return status;
4017 if (state->out_output_buffer.length < 16) {
4018 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4021 num_names = IVAL(state->out_output_buffer.data, 0);
4022 num_names_returned = IVAL(state->out_output_buffer.data, 4);
4023 dlength = IVAL(state->out_output_buffer.data, 8);
4025 if (num_names > 0x7FFFFFFF) {
4026 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4029 if (get_names == false) {
4030 *pnum_names = (int)num_names;
4031 return NT_STATUS_OK;
4033 if (num_names != num_names_returned) {
4034 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4036 if (dlength + 12 < 12) {
4037 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4040 * NB. The below is an allowable return if there are
4041 * more snapshots than the buffer size we told the
4042 * server we can receive. We currently don't support
4043 * this.
4045 if (dlength + 12 > state->out_output_buffer.length) {
4046 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4048 if (state->out_output_buffer.length +
4049 (2 * sizeof(SHADOW_COPY_LABEL)) <
4050 state->out_output_buffer.length) {
4051 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4054 names = talloc_array(mem_ctx, char *, num_names_returned);
4055 if (names == NULL) {
4056 return NT_STATUS_NO_MEMORY;
4059 endp = state->out_output_buffer.data +
4060 state->out_output_buffer.length;
4062 for (i=0; i<num_names_returned; i++) {
4063 bool ret;
4064 uint8_t *src;
4065 size_t converted_size;
4067 src = state->out_output_buffer.data + 12 +
4068 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4070 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4071 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4073 ret = convert_string_talloc(
4074 names, CH_UTF16LE, CH_UNIX,
4075 src, 2 * sizeof(SHADOW_COPY_LABEL),
4076 &names[i], &converted_size);
4077 if (!ret) {
4078 TALLOC_FREE(names);
4079 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4082 *pnum_names = num_names;
4083 *pnames = names;
4084 return NT_STATUS_OK;
4087 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4088 struct cli_state *cli,
4089 uint16_t fnum,
4090 bool get_names,
4091 char ***pnames,
4092 int *pnum_names)
4094 TALLOC_CTX *frame = talloc_stackframe();
4095 struct tevent_context *ev;
4096 struct tevent_req *req;
4097 NTSTATUS status = NT_STATUS_NO_MEMORY;
4099 if (smbXcli_conn_has_async_calls(cli->conn)) {
4101 * Can't use sync call while an async call is in flight
4103 status = NT_STATUS_INVALID_PARAMETER;
4104 goto fail;
4106 ev = samba_tevent_context_init(frame);
4107 if (ev == NULL) {
4108 goto fail;
4110 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4112 cli,
4113 fnum,
4114 get_names);
4115 if (req == NULL) {
4116 goto fail;
4118 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4119 goto fail;
4121 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4122 mem_ctx,
4123 get_names,
4124 pnames,
4125 pnum_names);
4126 fail:
4127 cli->raw_status = status;
4129 TALLOC_FREE(frame);
4130 return status;
4133 /***************************************************************
4134 Wrapper that allows SMB2 to truncate a file.
4135 Synchronous only.
4136 ***************************************************************/
4138 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4139 uint16_t fnum,
4140 uint64_t newsize)
4142 NTSTATUS status;
4143 DATA_BLOB inbuf = data_blob_null;
4144 struct smb2_hnd *ph = NULL;
4145 TALLOC_CTX *frame = talloc_stackframe();
4147 if (smbXcli_conn_has_async_calls(cli->conn)) {
4149 * Can't use sync call while an async call is in flight
4151 status = NT_STATUS_INVALID_PARAMETER;
4152 goto fail;
4155 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4156 status = NT_STATUS_INVALID_PARAMETER;
4157 goto fail;
4160 status = map_fnum_to_smb2_handle(cli,
4161 fnum,
4162 &ph);
4163 if (!NT_STATUS_IS_OK(status)) {
4164 goto fail;
4167 inbuf = data_blob_talloc_zero(frame, 8);
4168 if (inbuf.data == NULL) {
4169 status = NT_STATUS_NO_MEMORY;
4170 goto fail;
4173 SBVAL(inbuf.data, 0, newsize);
4175 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4176 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4178 status = smb2cli_set_info(cli->conn,
4179 cli->timeout,
4180 cli->smb2.session,
4181 cli->smb2.tcon,
4182 1, /* in_info_type */
4183 /* in_file_info_class */
4184 SMB_FILE_END_OF_FILE_INFORMATION - 1000,
4185 &inbuf, /* in_input_buffer */
4186 0, /* in_additional_info */
4187 ph->fid_persistent,
4188 ph->fid_volatile);
4190 fail:
4192 cli->raw_status = status;
4194 TALLOC_FREE(frame);
4195 return status;
4198 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
4199 uint32_t buffer_size, uint32_t completion_filter,
4200 bool recursive, TALLOC_CTX *mem_ctx,
4201 struct notify_change **pchanges,
4202 uint32_t *pnum_changes)
4204 NTSTATUS status;
4205 struct smb2_hnd *ph = NULL;
4206 TALLOC_CTX *frame = talloc_stackframe();
4207 uint8_t *base;
4208 uint32_t len, ofs;
4209 struct notify_change *changes = NULL;
4210 size_t num_changes = 0;
4212 if (smbXcli_conn_has_async_calls(cli->conn)) {
4214 * Can't use sync call while an async call is in flight
4216 status = NT_STATUS_INVALID_PARAMETER;
4217 goto fail;
4220 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4221 status = NT_STATUS_INVALID_PARAMETER;
4222 goto fail;
4225 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4226 if (!NT_STATUS_IS_OK(status)) {
4227 goto fail;
4230 status = smb2cli_notify(cli->conn, cli->timeout,
4231 cli->smb2.session, cli->smb2.tcon,
4232 buffer_size,
4233 ph->fid_persistent, ph->fid_volatile,
4234 completion_filter, recursive,
4235 frame, &base, &len);
4237 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4238 len = 0;
4239 status = NT_STATUS_OK;
4242 if (!NT_STATUS_IS_OK(status)) {
4243 goto fail;
4246 ofs = 0;
4248 while (len - ofs >= 12) {
4249 struct notify_change *tmp;
4250 struct notify_change *c;
4251 uint32_t next_ofs = IVAL(base, ofs);
4252 uint32_t file_name_length = IVAL(base, ofs+8);
4253 size_t namelen;
4254 bool ok;
4256 tmp = talloc_realloc(frame, changes, struct notify_change,
4257 num_changes + 1);
4258 if (tmp == NULL) {
4259 status = NT_STATUS_NO_MEMORY;
4260 goto fail;
4262 changes = tmp;
4263 c = &changes[num_changes];
4264 num_changes += 1;
4266 if (smb_buffer_oob(len, ofs, next_ofs) ||
4267 smb_buffer_oob(len, ofs+12, file_name_length)) {
4268 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
4269 goto fail;
4272 c->action = IVAL(base, ofs+4);
4274 ok = convert_string_talloc(changes, CH_UTF16LE, CH_UNIX,
4275 base + ofs + 12, file_name_length,
4276 &c->name, &namelen);
4277 if (!ok) {
4278 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
4279 goto fail;
4282 if (next_ofs == 0) {
4283 break;
4285 ofs += next_ofs;
4288 *pchanges = talloc_move(mem_ctx, &changes);
4289 *pnum_changes = num_changes;
4290 status = NT_STATUS_OK;
4292 fail:
4293 cli->raw_status = status;
4295 TALLOC_FREE(frame);
4296 return status;
4299 struct cli_smb2_set_reparse_point_fnum_state {
4300 struct cli_state *cli;
4301 uint16_t fnum;
4302 struct smb2_hnd *ph;
4303 DATA_BLOB input_buffer;
4306 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
4308 struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
4309 TALLOC_CTX *mem_ctx,
4310 struct tevent_context *ev,
4311 struct cli_state *cli,
4312 uint16_t fnum,
4313 DATA_BLOB in_buf)
4315 struct tevent_req *req, *subreq;
4316 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
4317 NTSTATUS status;
4319 req = tevent_req_create(mem_ctx, &state,
4320 struct cli_smb2_set_reparse_point_fnum_state);
4321 if (req == NULL) {
4322 return NULL;
4325 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4326 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4327 return tevent_req_post(req, ev);
4330 state->cli = cli;
4331 state->fnum = fnum;
4333 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4334 if (tevent_req_nterror(req, status)) {
4335 return tevent_req_post(req, ev);
4338 state->input_buffer = data_blob_talloc(state,
4339 in_buf.data,
4340 in_buf.length);
4341 if (state->input_buffer.data == NULL) {
4342 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4343 return tevent_req_post(req, ev);
4346 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4347 state->cli->timeout,
4348 state->cli->smb2.session,
4349 state->cli->smb2.tcon,
4350 state->ph->fid_persistent, /* in_fid_persistent */
4351 state->ph->fid_volatile, /* in_fid_volatile */
4352 FSCTL_SET_REPARSE_POINT,
4353 0, /* in_max_input_length */
4354 &state->input_buffer ,
4356 NULL,
4357 SMB2_IOCTL_FLAG_IS_FSCTL);
4359 if (tevent_req_nomem(subreq, req)) {
4360 return tevent_req_post(req, ev);
4362 tevent_req_set_callback(subreq,
4363 cli_smb2_set_reparse_point_fnum_done,
4364 req);
4366 return req;
4369 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
4371 struct tevent_req *req = tevent_req_callback_data(
4372 subreq, struct tevent_req);
4373 struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
4374 req, struct cli_smb2_set_reparse_point_fnum_state);
4375 NTSTATUS status;
4377 status = smb2cli_ioctl_recv(subreq, state,
4378 NULL,
4379 NULL);
4380 TALLOC_FREE(subreq);
4381 if (tevent_req_nterror(req, status)) {
4382 return;
4384 tevent_req_done(req);
4387 NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
4389 return tevent_req_simple_recv_ntstatus(req);
4392 struct cli_smb2_get_reparse_point_fnum_state {
4393 struct cli_state *cli;
4394 uint16_t fnum;
4395 struct smb2_hnd *ph;
4396 DATA_BLOB output_buffer;
4399 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
4401 struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
4402 TALLOC_CTX *mem_ctx,
4403 struct tevent_context *ev,
4404 struct cli_state *cli,
4405 uint16_t fnum)
4407 struct tevent_req *req, *subreq;
4408 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
4409 NTSTATUS status;
4411 req = tevent_req_create(mem_ctx, &state,
4412 struct cli_smb2_get_reparse_point_fnum_state);
4413 if (req == NULL) {
4414 return NULL;
4417 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4418 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4419 return tevent_req_post(req, ev);
4422 state->cli = cli;
4423 state->fnum = fnum;
4425 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4426 if (tevent_req_nterror(req, status)) {
4427 return tevent_req_post(req, ev);
4430 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4431 state->cli->timeout,
4432 state->cli->smb2.session,
4433 state->cli->smb2.tcon,
4434 state->ph->fid_persistent, /* in_fid_persistent */
4435 state->ph->fid_volatile, /* in_fid_volatile */
4436 FSCTL_GET_REPARSE_POINT,
4437 0, /* in_max_input_length */
4438 NULL,
4439 64*1024,
4440 NULL,
4441 SMB2_IOCTL_FLAG_IS_FSCTL);
4443 if (tevent_req_nomem(subreq, req)) {
4444 return tevent_req_post(req, ev);
4446 tevent_req_set_callback(subreq,
4447 cli_smb2_get_reparse_point_fnum_done,
4448 req);
4450 return req;
4453 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
4455 struct tevent_req *req = tevent_req_callback_data(
4456 subreq, struct tevent_req);
4457 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
4458 req, struct cli_smb2_get_reparse_point_fnum_state);
4459 NTSTATUS status;
4461 status = smb2cli_ioctl_recv(subreq, state,
4462 NULL,
4463 &state->output_buffer);
4464 TALLOC_FREE(subreq);
4465 if (tevent_req_nterror(req, status)) {
4466 state->cli->raw_status = status;
4467 return;
4469 tevent_req_done(req);
4472 NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
4473 TALLOC_CTX *mem_ctx,
4474 DATA_BLOB *output)
4476 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
4477 req, struct cli_smb2_get_reparse_point_fnum_state);
4479 if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
4480 tevent_req_received(req);
4481 return state->cli->raw_status;
4483 *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
4484 if (output->data == NULL) {
4485 tevent_req_received(req);
4486 return NT_STATUS_NO_MEMORY;
4488 tevent_req_received(req);
4489 return NT_STATUS_OK;