libcli/smb: move {smb,trans2}_bytes_push_{str,bytes}() to common code
[Samba.git] / source3 / libsmb / cli_smb2_fnum.c
blob325ae7812d90585a9530303aa816eb683e8231e9
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"
45 struct smb2_hnd {
46 uint64_t fid_persistent;
47 uint64_t fid_volatile;
51 * Handle mapping code.
54 /***************************************************************
55 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
56 Ensures handle is owned by cli struct.
57 ***************************************************************/
59 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
60 const struct smb2_hnd *ph, /* In */
61 uint16_t *pfnum) /* Out */
63 int ret;
64 struct idr_context *idp = cli->smb2.open_handles;
65 struct smb2_hnd *owned_h = talloc_memdup(cli,
66 ph,
67 sizeof(struct smb2_hnd));
69 if (owned_h == NULL) {
70 return NT_STATUS_NO_MEMORY;
73 if (idp == NULL) {
74 /* Lazy init */
75 cli->smb2.open_handles = idr_init(cli);
76 if (cli->smb2.open_handles == NULL) {
77 TALLOC_FREE(owned_h);
78 return NT_STATUS_NO_MEMORY;
80 idp = cli->smb2.open_handles;
83 ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
84 if (ret == -1) {
85 TALLOC_FREE(owned_h);
86 return NT_STATUS_NO_MEMORY;
89 *pfnum = (uint16_t)ret;
90 return NT_STATUS_OK;
93 /***************************************************************
94 Return the smb2_hnd pointer associated with the given fnum.
95 ***************************************************************/
97 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
98 uint16_t fnum, /* In */
99 struct smb2_hnd **pph) /* Out */
101 struct idr_context *idp = cli->smb2.open_handles;
103 if (idp == NULL) {
104 return NT_STATUS_INVALID_PARAMETER;
106 *pph = (struct smb2_hnd *)idr_find(idp, fnum);
107 if (*pph == NULL) {
108 return NT_STATUS_INVALID_HANDLE;
110 return NT_STATUS_OK;
113 /***************************************************************
114 Delete the fnum to smb2_hnd mapping. Zeros out handle on
115 successful return.
116 ***************************************************************/
118 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
119 struct smb2_hnd **pph, /* In */
120 uint16_t fnum) /* In */
122 struct idr_context *idp = cli->smb2.open_handles;
123 struct smb2_hnd *ph;
125 if (idp == NULL) {
126 return NT_STATUS_INVALID_PARAMETER;
129 ph = (struct smb2_hnd *)idr_find(idp, fnum);
130 if (ph != *pph) {
131 return NT_STATUS_INVALID_PARAMETER;
133 idr_remove(idp, fnum);
134 TALLOC_FREE(*pph);
135 return NT_STATUS_OK;
138 /***************************************************************
139 Oplock mapping code.
140 ***************************************************************/
142 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
144 if (create_flags & REQUEST_BATCH_OPLOCK) {
145 return SMB2_OPLOCK_LEVEL_BATCH;
146 } else if (create_flags & REQUEST_OPLOCK) {
147 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
150 /* create_flags doesn't do a level2 request. */
151 return SMB2_OPLOCK_LEVEL_NONE;
154 /***************************************************************
155 Small wrapper that allows SMB2 create to return a uint16_t fnum.
156 ***************************************************************/
158 struct cli_smb2_create_fnum_state {
159 struct cli_state *cli;
160 struct smb_create_returns cr;
161 uint16_t fnum;
162 struct tevent_req *subreq;
165 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
166 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
168 struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
169 struct tevent_context *ev,
170 struct cli_state *cli,
171 const char *fname,
172 uint32_t create_flags,
173 uint32_t desired_access,
174 uint32_t file_attributes,
175 uint32_t share_access,
176 uint32_t create_disposition,
177 uint32_t create_options)
179 struct tevent_req *req, *subreq;
180 struct cli_smb2_create_fnum_state *state;
181 size_t fname_len = 0;
182 const char *startp = NULL;
183 const char *endp = NULL;
184 time_t tstamp = (time_t)0;
185 struct smb2_create_blobs *cblobs = NULL;
187 req = tevent_req_create(mem_ctx, &state,
188 struct cli_smb2_create_fnum_state);
189 if (req == NULL) {
190 return NULL;
192 state->cli = cli;
194 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
195 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
196 return tevent_req_post(req, ev);
199 if (cli->backup_intent) {
200 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
203 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
204 fname_len = strlen(fname);
205 if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
206 size_t len_before_gmt = startp - fname;
207 size_t len_after_gmt = fname + fname_len - endp;
208 DATA_BLOB twrp_blob;
209 NTTIME ntt;
210 NTSTATUS status;
212 char *new_fname = talloc_array(state, char,
213 len_before_gmt + len_after_gmt + 1);
215 if (tevent_req_nomem(new_fname, req)) {
216 return tevent_req_post(req, ev);
219 memcpy(new_fname, fname, len_before_gmt);
220 memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
221 fname = new_fname;
222 fname_len = len_before_gmt + len_after_gmt;
224 unix_to_nt_time(&ntt, tstamp);
225 twrp_blob = data_blob_const((const void *)&ntt, 8);
227 cblobs = talloc_zero(state, struct smb2_create_blobs);
228 if (tevent_req_nomem(cblobs, req)) {
229 return tevent_req_post(req, ev);
232 status = smb2_create_blob_add(state, cblobs,
233 SMB2_CREATE_TAG_TWRP, twrp_blob);
234 if (!NT_STATUS_IS_OK(status)) {
235 tevent_req_nterror(req, status);
236 return tevent_req_post(req, ev);
240 /* SMB2 is pickier about pathnames. Ensure it doesn't
241 start in a '\' */
242 if (*fname == '\\') {
243 fname++;
244 fname_len--;
247 /* Or end in a '\' */
248 if (fname_len > 0 && fname[fname_len-1] == '\\') {
249 char *new_fname = talloc_strdup(state, fname);
250 if (tevent_req_nomem(new_fname, req)) {
251 return tevent_req_post(req, ev);
253 new_fname[fname_len-1] = '\0';
254 fname = new_fname;
257 subreq = smb2cli_create_send(state, ev,
258 cli->conn,
259 cli->timeout,
260 cli->smb2.session,
261 cli->smb2.tcon,
262 fname,
263 flags_to_smb2_oplock(create_flags),
264 SMB2_IMPERSONATION_IMPERSONATION,
265 desired_access,
266 file_attributes,
267 share_access,
268 create_disposition,
269 create_options,
270 cblobs);
271 if (tevent_req_nomem(subreq, req)) {
272 return tevent_req_post(req, ev);
274 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
276 state->subreq = subreq;
277 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
279 return req;
282 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
284 struct tevent_req *req = tevent_req_callback_data(
285 subreq, struct tevent_req);
286 struct cli_smb2_create_fnum_state *state = tevent_req_data(
287 req, struct cli_smb2_create_fnum_state);
288 struct smb2_hnd h;
289 NTSTATUS status;
291 status = smb2cli_create_recv(subreq, &h.fid_persistent,
292 &h.fid_volatile, &state->cr, NULL, NULL);
293 TALLOC_FREE(subreq);
294 if (tevent_req_nterror(req, status)) {
295 return;
298 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
299 if (tevent_req_nterror(req, status)) {
300 return;
302 tevent_req_done(req);
305 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
307 struct cli_smb2_create_fnum_state *state = tevent_req_data(
308 req, struct cli_smb2_create_fnum_state);
309 return tevent_req_cancel(state->subreq);
312 NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum,
313 struct smb_create_returns *cr)
315 struct cli_smb2_create_fnum_state *state = tevent_req_data(
316 req, struct cli_smb2_create_fnum_state);
317 NTSTATUS status;
319 if (tevent_req_is_nterror(req, &status)) {
320 state->cli->raw_status = status;
321 return status;
323 if (pfnum != NULL) {
324 *pfnum = state->fnum;
326 if (cr != NULL) {
327 *cr = state->cr;
329 state->cli->raw_status = NT_STATUS_OK;
330 return NT_STATUS_OK;
333 NTSTATUS cli_smb2_create_fnum(struct cli_state *cli,
334 const char *fname,
335 uint32_t create_flags,
336 uint32_t desired_access,
337 uint32_t file_attributes,
338 uint32_t share_access,
339 uint32_t create_disposition,
340 uint32_t create_options,
341 uint16_t *pfid,
342 struct smb_create_returns *cr)
344 TALLOC_CTX *frame = talloc_stackframe();
345 struct tevent_context *ev;
346 struct tevent_req *req;
347 NTSTATUS status = NT_STATUS_NO_MEMORY;
349 if (smbXcli_conn_has_async_calls(cli->conn)) {
351 * Can't use sync call while an async call is in flight
353 status = NT_STATUS_INVALID_PARAMETER;
354 goto fail;
356 ev = samba_tevent_context_init(frame);
357 if (ev == NULL) {
358 goto fail;
360 req = cli_smb2_create_fnum_send(frame, ev, cli, fname, create_flags,
361 desired_access, file_attributes,
362 share_access, create_disposition,
363 create_options);
364 if (req == NULL) {
365 goto fail;
367 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
368 goto fail;
370 status = cli_smb2_create_fnum_recv(req, pfid, cr);
371 fail:
372 TALLOC_FREE(frame);
373 return status;
376 /***************************************************************
377 Small wrapper that allows SMB2 close to use a uint16_t fnum.
378 ***************************************************************/
380 struct cli_smb2_close_fnum_state {
381 struct cli_state *cli;
382 uint16_t fnum;
383 struct smb2_hnd *ph;
386 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
388 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
389 struct tevent_context *ev,
390 struct cli_state *cli,
391 uint16_t fnum)
393 struct tevent_req *req, *subreq;
394 struct cli_smb2_close_fnum_state *state;
395 NTSTATUS status;
397 req = tevent_req_create(mem_ctx, &state,
398 struct cli_smb2_close_fnum_state);
399 if (req == NULL) {
400 return NULL;
402 state->cli = cli;
403 state->fnum = fnum;
405 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
406 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
407 return tevent_req_post(req, ev);
410 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
411 if (tevent_req_nterror(req, status)) {
412 return tevent_req_post(req, ev);
415 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
416 cli->smb2.session, cli->smb2.tcon,
417 0, state->ph->fid_persistent,
418 state->ph->fid_volatile);
419 if (tevent_req_nomem(subreq, req)) {
420 return tevent_req_post(req, ev);
422 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
423 return req;
426 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
428 struct tevent_req *req = tevent_req_callback_data(
429 subreq, struct tevent_req);
430 struct cli_smb2_close_fnum_state *state = tevent_req_data(
431 req, struct cli_smb2_close_fnum_state);
432 NTSTATUS status;
434 status = smb2cli_close_recv(subreq);
435 if (tevent_req_nterror(req, status)) {
436 return;
439 /* Delete the fnum -> handle mapping. */
440 status = delete_smb2_handle_mapping(state->cli, &state->ph,
441 state->fnum);
442 if (tevent_req_nterror(req, status)) {
443 return;
445 tevent_req_done(req);
448 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
450 struct cli_smb2_close_fnum_state *state = tevent_req_data(
451 req, struct cli_smb2_close_fnum_state);
452 NTSTATUS status = tevent_req_simple_recv_ntstatus(req);
453 state->cli->raw_status = status;
454 return status;
457 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
459 TALLOC_CTX *frame = talloc_stackframe();
460 struct tevent_context *ev;
461 struct tevent_req *req;
462 NTSTATUS status = NT_STATUS_NO_MEMORY;
464 if (smbXcli_conn_has_async_calls(cli->conn)) {
466 * Can't use sync call while an async call is in flight
468 status = NT_STATUS_INVALID_PARAMETER;
469 goto fail;
471 ev = samba_tevent_context_init(frame);
472 if (ev == NULL) {
473 goto fail;
475 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
476 if (req == NULL) {
477 goto fail;
479 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
480 goto fail;
482 status = cli_smb2_close_fnum_recv(req);
483 fail:
484 TALLOC_FREE(frame);
485 return status;
488 /***************************************************************
489 Small wrapper that allows SMB2 to create a directory
490 Synchronous only.
491 ***************************************************************/
493 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
495 NTSTATUS status;
496 uint16_t fnum;
498 if (smbXcli_conn_has_async_calls(cli->conn)) {
500 * Can't use sync call while an async call is in flight
502 return NT_STATUS_INVALID_PARAMETER;
505 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
506 return NT_STATUS_INVALID_PARAMETER;
509 status = cli_smb2_create_fnum(cli,
510 dname,
511 0, /* create_flags */
512 FILE_READ_ATTRIBUTES, /* desired_access */
513 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
514 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
515 FILE_CREATE, /* create_disposition */
516 FILE_DIRECTORY_FILE, /* create_options */
517 &fnum,
518 NULL);
520 if (!NT_STATUS_IS_OK(status)) {
521 return status;
523 return cli_smb2_close_fnum(cli, fnum);
526 /***************************************************************
527 Small wrapper that allows SMB2 to delete a directory
528 Synchronous only.
529 ***************************************************************/
531 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
533 NTSTATUS status;
534 uint16_t fnum;
536 if (smbXcli_conn_has_async_calls(cli->conn)) {
538 * Can't use sync call while an async call is in flight
540 return NT_STATUS_INVALID_PARAMETER;
543 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
544 return NT_STATUS_INVALID_PARAMETER;
547 status = cli_smb2_create_fnum(cli,
548 dname,
549 0, /* create_flags */
550 DELETE_ACCESS, /* desired_access */
551 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
552 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
553 FILE_OPEN, /* create_disposition */
554 FILE_DIRECTORY_FILE|FILE_DELETE_ON_CLOSE, /* create_options */
555 &fnum,
556 NULL);
558 if (!NT_STATUS_IS_OK(status)) {
559 return status;
561 return cli_smb2_close_fnum(cli, fnum);
564 /***************************************************************
565 Small wrapper that allows SMB2 to unlink a pathname.
566 Synchronous only.
567 ***************************************************************/
569 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
571 NTSTATUS status;
572 uint16_t fnum;
574 if (smbXcli_conn_has_async_calls(cli->conn)) {
576 * Can't use sync call while an async call is in flight
578 return NT_STATUS_INVALID_PARAMETER;
581 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
582 return NT_STATUS_INVALID_PARAMETER;
585 status = cli_smb2_create_fnum(cli,
586 fname,
587 0, /* create_flags */
588 DELETE_ACCESS, /* desired_access */
589 FILE_ATTRIBUTE_NORMAL, /* file attributes */
590 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
591 FILE_OPEN, /* create_disposition */
592 FILE_DELETE_ON_CLOSE, /* create_options */
593 &fnum,
594 NULL);
596 if (!NT_STATUS_IS_OK(status)) {
597 return status;
599 return cli_smb2_close_fnum(cli, fnum);
602 /***************************************************************
603 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
604 ***************************************************************/
606 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
607 uint32_t dir_data_length,
608 struct file_info *finfo,
609 uint32_t *next_offset)
611 size_t namelen = 0;
612 size_t slen = 0;
613 size_t ret = 0;
615 if (dir_data_length < 4) {
616 return NT_STATUS_INFO_LENGTH_MISMATCH;
619 *next_offset = IVAL(dir_data, 0);
621 if (*next_offset > dir_data_length) {
622 return NT_STATUS_INFO_LENGTH_MISMATCH;
625 if (*next_offset != 0) {
626 /* Ensure we only read what in this record. */
627 dir_data_length = *next_offset;
630 if (dir_data_length < 105) {
631 return NT_STATUS_INFO_LENGTH_MISMATCH;
634 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
635 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
636 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
637 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
638 finfo->mode = CVAL(dir_data + 56, 0);
639 namelen = IVAL(dir_data + 60,0);
640 if (namelen > (dir_data_length - 104)) {
641 return NT_STATUS_INFO_LENGTH_MISMATCH;
643 slen = CVAL(dir_data + 68, 0);
644 if (slen > 24) {
645 return NT_STATUS_INFO_LENGTH_MISMATCH;
647 ret = pull_string_talloc(finfo,
648 dir_data,
649 FLAGS2_UNICODE_STRINGS,
650 &finfo->short_name,
651 dir_data + 70,
652 slen,
653 STR_UNICODE);
654 if (ret == (size_t)-1) {
655 /* Bad conversion. */
656 return NT_STATUS_INVALID_NETWORK_RESPONSE;
659 ret = pull_string_talloc(finfo,
660 dir_data,
661 FLAGS2_UNICODE_STRINGS,
662 &finfo->name,
663 dir_data + 104,
664 namelen,
665 STR_UNICODE);
666 if (ret == (size_t)-1) {
667 /* Bad conversion. */
668 return NT_STATUS_INVALID_NETWORK_RESPONSE;
670 return NT_STATUS_OK;
673 /*******************************************************************
674 Given a filename - get its directory name
675 ********************************************************************/
677 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
678 const char *dir,
679 char **parent,
680 const char **name)
682 char *p;
683 ptrdiff_t len;
685 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
687 if (p == NULL) {
688 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
689 return false;
691 if (name) {
692 *name = dir;
694 return true;
697 len = p-dir;
699 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
700 return false;
702 (*parent)[len] = '\0';
704 if (name) {
705 *name = p+1;
707 return true;
710 /***************************************************************
711 Wrapper that allows SMB2 to list a directory.
712 Synchronous only.
713 ***************************************************************/
715 NTSTATUS cli_smb2_list(struct cli_state *cli,
716 const char *pathname,
717 uint16_t attribute,
718 NTSTATUS (*fn)(const char *,
719 struct file_info *,
720 const char *,
721 void *),
722 void *state)
724 NTSTATUS status;
725 uint16_t fnum = 0xffff;
726 char *parent_dir = NULL;
727 const char *mask = NULL;
728 struct smb2_hnd *ph = NULL;
729 bool processed_file = false;
730 TALLOC_CTX *frame = talloc_stackframe();
731 TALLOC_CTX *subframe = NULL;
732 bool mask_has_wild;
734 if (smbXcli_conn_has_async_calls(cli->conn)) {
736 * Can't use sync call while an async call is in flight
738 status = NT_STATUS_INVALID_PARAMETER;
739 goto fail;
742 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
743 status = NT_STATUS_INVALID_PARAMETER;
744 goto fail;
747 /* Get the directory name. */
748 if (!windows_parent_dirname(frame,
749 pathname,
750 &parent_dir,
751 &mask)) {
752 status = NT_STATUS_NO_MEMORY;
753 goto fail;
756 mask_has_wild = ms_has_wild(mask);
758 status = cli_smb2_create_fnum(cli,
759 parent_dir,
760 0, /* create_flags */
761 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
762 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
763 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
764 FILE_OPEN, /* create_disposition */
765 FILE_DIRECTORY_FILE, /* create_options */
766 &fnum,
767 NULL);
769 if (!NT_STATUS_IS_OK(status)) {
770 goto fail;
773 status = map_fnum_to_smb2_handle(cli,
774 fnum,
775 &ph);
776 if (!NT_STATUS_IS_OK(status)) {
777 goto fail;
780 do {
781 uint8_t *dir_data = NULL;
782 uint32_t dir_data_length = 0;
783 uint32_t next_offset = 0;
784 subframe = talloc_stackframe();
786 status = smb2cli_query_directory(cli->conn,
787 cli->timeout,
788 cli->smb2.session,
789 cli->smb2.tcon,
790 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
791 0, /* flags */
792 0, /* file_index */
793 ph->fid_persistent,
794 ph->fid_volatile,
795 mask,
796 0xffff,
797 subframe,
798 &dir_data,
799 &dir_data_length);
801 if (!NT_STATUS_IS_OK(status)) {
802 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
803 break;
805 goto fail;
808 do {
809 struct file_info *finfo = talloc_zero(subframe,
810 struct file_info);
812 if (finfo == NULL) {
813 status = NT_STATUS_NO_MEMORY;
814 goto fail;
817 status = parse_finfo_id_both_directory_info(dir_data,
818 dir_data_length,
819 finfo,
820 &next_offset);
822 if (!NT_STATUS_IS_OK(status)) {
823 goto fail;
826 if (dir_check_ftype((uint32_t)finfo->mode,
827 (uint32_t)attribute)) {
829 * Only process if attributes match.
830 * On SMB1 server does this, so on
831 * SMB2 we need to emulate in the
832 * client.
834 * https://bugzilla.samba.org/show_bug.cgi?id=10260
836 processed_file = true;
838 status = fn(cli->dfs_mountpoint,
839 finfo,
840 pathname,
841 state);
843 if (!NT_STATUS_IS_OK(status)) {
844 break;
848 TALLOC_FREE(finfo);
850 /* Move to next entry. */
851 if (next_offset) {
852 dir_data += next_offset;
853 dir_data_length -= next_offset;
855 } while (next_offset != 0);
857 TALLOC_FREE(subframe);
859 if (!mask_has_wild) {
861 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
862 * when handed a non-wildcard path. Do it
863 * for the server (with a non-wildcard path
864 * there should only ever be one file returned.
866 status = STATUS_NO_MORE_FILES;
867 break;
870 } while (NT_STATUS_IS_OK(status));
872 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
873 status = NT_STATUS_OK;
876 if (NT_STATUS_IS_OK(status) && !processed_file) {
878 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
879 * if no files match. Emulate this in the client.
881 status = NT_STATUS_NO_SUCH_FILE;
884 fail:
886 if (fnum != 0xffff) {
887 cli_smb2_close_fnum(cli, fnum);
889 TALLOC_FREE(subframe);
890 TALLOC_FREE(frame);
891 return status;
894 /***************************************************************
895 Wrapper that allows SMB2 to query a path info (basic level).
896 Synchronous only.
897 ***************************************************************/
899 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
900 const char *name,
901 SMB_STRUCT_STAT *sbuf,
902 uint32_t *attributes)
904 NTSTATUS status;
905 struct smb_create_returns cr;
906 uint16_t fnum = 0xffff;
907 size_t namelen = strlen(name);
909 if (smbXcli_conn_has_async_calls(cli->conn)) {
911 * Can't use sync call while an async call is in flight
913 return NT_STATUS_INVALID_PARAMETER;
916 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
917 return NT_STATUS_INVALID_PARAMETER;
920 /* SMB2 is pickier about pathnames. Ensure it doesn't
921 end in a '\' */
922 if (namelen > 0 && name[namelen-1] == '\\') {
923 char *modname = talloc_strdup(talloc_tos(), name);
924 modname[namelen-1] = '\0';
925 name = modname;
928 /* This is commonly used as a 'cd'. Try qpathinfo on
929 a directory handle first. */
931 status = cli_smb2_create_fnum(cli,
932 name,
933 0, /* create_flags */
934 FILE_READ_ATTRIBUTES, /* desired_access */
935 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
936 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
937 FILE_OPEN, /* create_disposition */
938 FILE_DIRECTORY_FILE, /* create_options */
939 &fnum,
940 &cr);
942 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
943 /* Maybe a file ? */
944 status = cli_smb2_create_fnum(cli,
945 name,
946 0, /* create_flags */
947 FILE_READ_ATTRIBUTES, /* desired_access */
948 0, /* file attributes */
949 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
950 FILE_OPEN, /* create_disposition */
951 0, /* create_options */
952 &fnum,
953 &cr);
956 if (!NT_STATUS_IS_OK(status)) {
957 return status;
960 cli_smb2_close_fnum(cli, fnum);
962 ZERO_STRUCTP(sbuf);
964 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
965 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
966 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
967 sbuf->st_ex_size = cr.end_of_file;
968 *attributes = cr.file_attributes;
970 return NT_STATUS_OK;
973 /***************************************************************
974 Helper function for pathname operations.
975 ***************************************************************/
977 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
978 const char *name,
979 uint32_t desired_access,
980 uint16_t *pfnum)
982 NTSTATUS status;
983 size_t namelen = strlen(name);
984 TALLOC_CTX *frame = talloc_stackframe();
986 /* SMB2 is pickier about pathnames. Ensure it doesn't
987 end in a '\' */
988 if (namelen > 0 && name[namelen-1] == '\\') {
989 char *modname = talloc_strdup(frame, name);
990 if (modname == NULL) {
991 status = NT_STATUS_NO_MEMORY;
992 goto fail;
994 modname[namelen-1] = '\0';
995 name = modname;
998 /* Try to open a file handle first. */
999 status = cli_smb2_create_fnum(cli,
1000 name,
1001 0, /* create_flags */
1002 desired_access,
1003 0, /* file attributes */
1004 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1005 FILE_OPEN, /* create_disposition */
1006 0, /* create_options */
1007 pfnum,
1008 NULL);
1010 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1011 status = cli_smb2_create_fnum(cli,
1012 name,
1013 0, /* create_flags */
1014 desired_access,
1015 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1016 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1017 FILE_OPEN, /* create_disposition */
1018 FILE_DIRECTORY_FILE, /* create_options */
1019 pfnum,
1020 NULL);
1023 fail:
1025 TALLOC_FREE(frame);
1026 return status;
1029 /***************************************************************
1030 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1031 Synchronous only.
1032 ***************************************************************/
1034 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1035 const char *name,
1036 fstring alt_name)
1038 NTSTATUS status;
1039 DATA_BLOB outbuf = data_blob_null;
1040 uint16_t fnum = 0xffff;
1041 struct smb2_hnd *ph = NULL;
1042 uint32_t altnamelen = 0;
1043 TALLOC_CTX *frame = talloc_stackframe();
1045 if (smbXcli_conn_has_async_calls(cli->conn)) {
1047 * Can't use sync call while an async call is in flight
1049 status = NT_STATUS_INVALID_PARAMETER;
1050 goto fail;
1053 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1054 status = NT_STATUS_INVALID_PARAMETER;
1055 goto fail;
1058 status = get_fnum_from_path(cli,
1059 name,
1060 FILE_READ_ATTRIBUTES,
1061 &fnum);
1063 if (!NT_STATUS_IS_OK(status)) {
1064 goto fail;
1067 status = map_fnum_to_smb2_handle(cli,
1068 fnum,
1069 &ph);
1070 if (!NT_STATUS_IS_OK(status)) {
1071 goto fail;
1074 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1075 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1077 status = smb2cli_query_info(cli->conn,
1078 cli->timeout,
1079 cli->smb2.session,
1080 cli->smb2.tcon,
1081 1, /* in_info_type */
1082 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1083 0xFFFF, /* in_max_output_length */
1084 NULL, /* in_input_buffer */
1085 0, /* in_additional_info */
1086 0, /* in_flags */
1087 ph->fid_persistent,
1088 ph->fid_volatile,
1089 frame,
1090 &outbuf);
1092 if (!NT_STATUS_IS_OK(status)) {
1093 goto fail;
1096 /* Parse the reply. */
1097 if (outbuf.length < 4) {
1098 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1099 goto fail;
1102 altnamelen = IVAL(outbuf.data, 0);
1103 if (altnamelen > outbuf.length - 4) {
1104 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1105 goto fail;
1108 if (altnamelen > 0) {
1109 size_t ret = 0;
1110 char *short_name = NULL;
1111 ret = pull_string_talloc(frame,
1112 outbuf.data,
1113 FLAGS2_UNICODE_STRINGS,
1114 &short_name,
1115 outbuf.data + 4,
1116 altnamelen,
1117 STR_UNICODE);
1118 if (ret == (size_t)-1) {
1119 /* Bad conversion. */
1120 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1121 goto fail;
1124 fstrcpy(alt_name, short_name);
1125 } else {
1126 alt_name[0] = '\0';
1129 status = NT_STATUS_OK;
1131 fail:
1133 if (fnum != 0xffff) {
1134 cli_smb2_close_fnum(cli, fnum);
1136 TALLOC_FREE(frame);
1137 return status;
1141 /***************************************************************
1142 Wrapper that allows SMB2 to query a fnum info (basic level).
1143 Synchronous only.
1144 ***************************************************************/
1146 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1147 uint16_t fnum,
1148 uint16_t *mode,
1149 off_t *size,
1150 struct timespec *create_time,
1151 struct timespec *access_time,
1152 struct timespec *write_time,
1153 struct timespec *change_time,
1154 SMB_INO_T *ino)
1156 NTSTATUS status;
1157 DATA_BLOB outbuf = data_blob_null;
1158 struct smb2_hnd *ph = NULL;
1159 TALLOC_CTX *frame = talloc_stackframe();
1161 if (smbXcli_conn_has_async_calls(cli->conn)) {
1163 * Can't use sync call while an async call is in flight
1165 status = NT_STATUS_INVALID_PARAMETER;
1166 goto fail;
1169 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1170 status = NT_STATUS_INVALID_PARAMETER;
1171 goto fail;
1174 status = map_fnum_to_smb2_handle(cli,
1175 fnum,
1176 &ph);
1177 if (!NT_STATUS_IS_OK(status)) {
1178 goto fail;
1181 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1182 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1184 status = smb2cli_query_info(cli->conn,
1185 cli->timeout,
1186 cli->smb2.session,
1187 cli->smb2.tcon,
1188 1, /* in_info_type */
1189 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1190 0xFFFF, /* in_max_output_length */
1191 NULL, /* in_input_buffer */
1192 0, /* in_additional_info */
1193 0, /* in_flags */
1194 ph->fid_persistent,
1195 ph->fid_volatile,
1196 frame,
1197 &outbuf);
1198 if (!NT_STATUS_IS_OK(status)) {
1199 goto fail;
1202 /* Parse the reply. */
1203 if (outbuf.length < 0x60) {
1204 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1205 goto fail;
1208 if (create_time) {
1209 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1211 if (access_time) {
1212 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1214 if (write_time) {
1215 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1217 if (change_time) {
1218 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1220 if (mode) {
1221 uint32_t attr = IVAL(outbuf.data, 0x20);
1222 *mode = (uint16_t)attr;
1224 if (size) {
1225 uint64_t file_size = BVAL(outbuf.data, 0x30);
1226 *size = (off_t)file_size;
1228 if (ino) {
1229 uint64_t file_index = BVAL(outbuf.data, 0x40);
1230 *ino = (SMB_INO_T)file_index;
1233 fail:
1235 TALLOC_FREE(frame);
1236 return status;
1239 /***************************************************************
1240 Wrapper that allows SMB2 to query an fnum.
1241 Implement on top of cli_smb2_qfileinfo_basic().
1242 Synchronous only.
1243 ***************************************************************/
1245 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1246 uint16_t fnum,
1247 uint16_t *attr,
1248 off_t *size,
1249 time_t *change_time,
1250 time_t *access_time,
1251 time_t *write_time)
1253 struct timespec access_time_ts;
1254 struct timespec write_time_ts;
1255 struct timespec change_time_ts;
1256 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1257 fnum,
1258 attr,
1259 size,
1260 NULL,
1261 &access_time_ts,
1262 &write_time_ts,
1263 &change_time_ts,
1264 NULL);
1266 if (!NT_STATUS_IS_OK(status)) {
1267 return status;
1270 if (change_time) {
1271 *change_time = change_time_ts.tv_sec;
1273 if (access_time) {
1274 *access_time = access_time_ts.tv_sec;
1276 if (write_time) {
1277 *write_time = write_time_ts.tv_sec;
1279 return NT_STATUS_OK;
1282 /***************************************************************
1283 Wrapper that allows SMB2 to get pathname attributes.
1284 Synchronous only.
1285 ***************************************************************/
1287 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1288 const char *name,
1289 uint16_t *attr,
1290 off_t *size,
1291 time_t *write_time)
1293 NTSTATUS status;
1294 uint16_t fnum = 0xffff;
1295 struct smb2_hnd *ph = NULL;
1296 TALLOC_CTX *frame = talloc_stackframe();
1298 if (smbXcli_conn_has_async_calls(cli->conn)) {
1300 * Can't use sync call while an async call is in flight
1302 status = NT_STATUS_INVALID_PARAMETER;
1303 goto fail;
1306 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1307 status = NT_STATUS_INVALID_PARAMETER;
1308 goto fail;
1311 status = get_fnum_from_path(cli,
1312 name,
1313 FILE_READ_ATTRIBUTES,
1314 &fnum);
1316 if (!NT_STATUS_IS_OK(status)) {
1317 goto fail;
1320 status = map_fnum_to_smb2_handle(cli,
1321 fnum,
1322 &ph);
1323 if (!NT_STATUS_IS_OK(status)) {
1324 goto fail;
1326 status = cli_smb2_getattrE(cli,
1327 fnum,
1328 attr,
1329 size,
1330 NULL,
1331 NULL,
1332 write_time);
1333 if (!NT_STATUS_IS_OK(status)) {
1334 goto fail;
1337 fail:
1339 if (fnum != 0xffff) {
1340 cli_smb2_close_fnum(cli, fnum);
1343 TALLOC_FREE(frame);
1344 return status;
1347 /***************************************************************
1348 Wrapper that allows SMB2 to query a pathname info (basic level).
1349 Implement on top of cli_smb2_qfileinfo_basic().
1350 Synchronous only.
1351 ***************************************************************/
1353 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1354 const char *name,
1355 struct timespec *create_time,
1356 struct timespec *access_time,
1357 struct timespec *write_time,
1358 struct timespec *change_time,
1359 off_t *size,
1360 uint16_t *mode,
1361 SMB_INO_T *ino)
1363 NTSTATUS status;
1364 struct smb2_hnd *ph = NULL;
1365 uint16_t fnum = 0xffff;
1366 TALLOC_CTX *frame = talloc_stackframe();
1368 if (smbXcli_conn_has_async_calls(cli->conn)) {
1370 * Can't use sync call while an async call is in flight
1372 status = NT_STATUS_INVALID_PARAMETER;
1373 goto fail;
1376 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1377 status = NT_STATUS_INVALID_PARAMETER;
1378 goto fail;
1381 status = get_fnum_from_path(cli,
1382 name,
1383 FILE_READ_ATTRIBUTES,
1384 &fnum);
1386 if (!NT_STATUS_IS_OK(status)) {
1387 goto fail;
1390 status = map_fnum_to_smb2_handle(cli,
1391 fnum,
1392 &ph);
1393 if (!NT_STATUS_IS_OK(status)) {
1394 goto fail;
1397 status = cli_smb2_qfileinfo_basic(cli,
1398 fnum,
1399 mode,
1400 size,
1401 create_time,
1402 access_time,
1403 write_time,
1404 change_time,
1405 ino);
1407 fail:
1409 if (fnum != 0xffff) {
1410 cli_smb2_close_fnum(cli, fnum);
1413 TALLOC_FREE(frame);
1414 return status;
1417 /***************************************************************
1418 Wrapper that allows SMB2 to query pathname streams.
1419 Synchronous only.
1420 ***************************************************************/
1422 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1423 const char *name,
1424 TALLOC_CTX *mem_ctx,
1425 unsigned int *pnum_streams,
1426 struct stream_struct **pstreams)
1428 NTSTATUS status;
1429 struct smb2_hnd *ph = NULL;
1430 uint16_t fnum = 0xffff;
1431 DATA_BLOB outbuf = data_blob_null;
1432 TALLOC_CTX *frame = talloc_stackframe();
1434 if (smbXcli_conn_has_async_calls(cli->conn)) {
1436 * Can't use sync call while an async call is in flight
1438 status = NT_STATUS_INVALID_PARAMETER;
1439 goto fail;
1442 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1443 status = NT_STATUS_INVALID_PARAMETER;
1444 goto fail;
1447 status = get_fnum_from_path(cli,
1448 name,
1449 FILE_READ_ATTRIBUTES,
1450 &fnum);
1452 if (!NT_STATUS_IS_OK(status)) {
1453 goto fail;
1456 status = map_fnum_to_smb2_handle(cli,
1457 fnum,
1458 &ph);
1459 if (!NT_STATUS_IS_OK(status)) {
1460 goto fail;
1463 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1464 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1466 status = smb2cli_query_info(cli->conn,
1467 cli->timeout,
1468 cli->smb2.session,
1469 cli->smb2.tcon,
1470 1, /* in_info_type */
1471 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1472 0xFFFF, /* in_max_output_length */
1473 NULL, /* in_input_buffer */
1474 0, /* in_additional_info */
1475 0, /* in_flags */
1476 ph->fid_persistent,
1477 ph->fid_volatile,
1478 frame,
1479 &outbuf);
1481 if (!NT_STATUS_IS_OK(status)) {
1482 goto fail;
1485 /* Parse the reply. */
1486 if (!parse_streams_blob(mem_ctx,
1487 outbuf.data,
1488 outbuf.length,
1489 pnum_streams,
1490 pstreams)) {
1491 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1492 goto fail;
1495 fail:
1497 if (fnum != 0xffff) {
1498 cli_smb2_close_fnum(cli, fnum);
1501 TALLOC_FREE(frame);
1502 return status;
1505 /***************************************************************
1506 Wrapper that allows SMB2 to set pathname attributes.
1507 Synchronous only.
1508 ***************************************************************/
1510 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1511 const char *name,
1512 uint16_t attr,
1513 time_t mtime)
1515 NTSTATUS status;
1516 uint16_t fnum = 0xffff;
1517 struct smb2_hnd *ph = NULL;
1518 uint8_t inbuf_store[40];
1519 DATA_BLOB inbuf = data_blob_null;
1520 TALLOC_CTX *frame = talloc_stackframe();
1522 if (smbXcli_conn_has_async_calls(cli->conn)) {
1524 * Can't use sync call while an async call is in flight
1526 status = NT_STATUS_INVALID_PARAMETER;
1527 goto fail;
1530 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1531 status = NT_STATUS_INVALID_PARAMETER;
1532 goto fail;
1535 status = get_fnum_from_path(cli,
1536 name,
1537 FILE_WRITE_ATTRIBUTES,
1538 &fnum);
1540 if (!NT_STATUS_IS_OK(status)) {
1541 goto fail;
1544 status = map_fnum_to_smb2_handle(cli,
1545 fnum,
1546 &ph);
1547 if (!NT_STATUS_IS_OK(status)) {
1548 goto fail;
1551 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1552 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1554 inbuf.data = inbuf_store;
1555 inbuf.length = sizeof(inbuf_store);
1556 data_blob_clear(&inbuf);
1558 SSVAL(inbuf.data, 32, attr);
1559 if (mtime != 0) {
1560 put_long_date((char *)inbuf.data + 16,mtime);
1562 /* Set all the other times to -1. */
1563 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1564 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1565 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1567 status = smb2cli_set_info(cli->conn,
1568 cli->timeout,
1569 cli->smb2.session,
1570 cli->smb2.tcon,
1571 1, /* in_info_type */
1572 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1573 &inbuf, /* in_input_buffer */
1574 0, /* in_additional_info */
1575 ph->fid_persistent,
1576 ph->fid_volatile);
1577 fail:
1579 if (fnum != 0xffff) {
1580 cli_smb2_close_fnum(cli, fnum);
1583 TALLOC_FREE(frame);
1584 return status;
1587 /***************************************************************
1588 Wrapper that allows SMB2 to set file handle times.
1589 Synchronous only.
1590 ***************************************************************/
1592 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1593 uint16_t fnum,
1594 time_t change_time,
1595 time_t access_time,
1596 time_t write_time)
1598 NTSTATUS status;
1599 struct smb2_hnd *ph = NULL;
1600 uint8_t inbuf_store[40];
1601 DATA_BLOB inbuf = data_blob_null;
1603 if (smbXcli_conn_has_async_calls(cli->conn)) {
1605 * Can't use sync call while an async call is in flight
1607 return NT_STATUS_INVALID_PARAMETER;
1610 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1611 return NT_STATUS_INVALID_PARAMETER;
1614 status = map_fnum_to_smb2_handle(cli,
1615 fnum,
1616 &ph);
1617 if (!NT_STATUS_IS_OK(status)) {
1618 return status;
1621 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1622 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1624 inbuf.data = inbuf_store;
1625 inbuf.length = sizeof(inbuf_store);
1626 data_blob_clear(&inbuf);
1628 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1629 if (change_time != 0) {
1630 put_long_date((char *)inbuf.data + 24, change_time);
1632 if (access_time != 0) {
1633 put_long_date((char *)inbuf.data + 8, access_time);
1635 if (write_time != 0) {
1636 put_long_date((char *)inbuf.data + 16, write_time);
1639 return smb2cli_set_info(cli->conn,
1640 cli->timeout,
1641 cli->smb2.session,
1642 cli->smb2.tcon,
1643 1, /* in_info_type */
1644 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1645 &inbuf, /* in_input_buffer */
1646 0, /* in_additional_info */
1647 ph->fid_persistent,
1648 ph->fid_volatile);
1651 /***************************************************************
1652 Wrapper that allows SMB2 to query disk attributes (size).
1653 Synchronous only.
1654 ***************************************************************/
1656 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
1657 uint64_t *bsize, uint64_t *total, uint64_t *avail)
1659 NTSTATUS status;
1660 uint16_t fnum = 0xffff;
1661 DATA_BLOB outbuf = data_blob_null;
1662 struct smb2_hnd *ph = NULL;
1663 uint32_t sectors_per_unit = 0;
1664 uint32_t bytes_per_sector = 0;
1665 uint64_t total_size = 0;
1666 uint64_t size_free = 0;
1667 TALLOC_CTX *frame = talloc_stackframe();
1669 if (smbXcli_conn_has_async_calls(cli->conn)) {
1671 * Can't use sync call while an async call is in flight
1673 status = NT_STATUS_INVALID_PARAMETER;
1674 goto fail;
1677 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1678 status = NT_STATUS_INVALID_PARAMETER;
1679 goto fail;
1682 /* First open the top level directory. */
1683 status = cli_smb2_create_fnum(cli,
1684 path,
1685 0, /* create_flags */
1686 FILE_READ_ATTRIBUTES, /* desired_access */
1687 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1688 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1689 FILE_OPEN, /* create_disposition */
1690 FILE_DIRECTORY_FILE, /* create_options */
1691 &fnum,
1692 NULL);
1694 if (!NT_STATUS_IS_OK(status)) {
1695 goto fail;
1698 status = map_fnum_to_smb2_handle(cli,
1699 fnum,
1700 &ph);
1701 if (!NT_STATUS_IS_OK(status)) {
1702 goto fail;
1705 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1706 level 3 (SMB_FS_SIZE_INFORMATION). */
1708 status = smb2cli_query_info(cli->conn,
1709 cli->timeout,
1710 cli->smb2.session,
1711 cli->smb2.tcon,
1712 2, /* in_info_type */
1713 3, /* in_file_info_class */
1714 0xFFFF, /* in_max_output_length */
1715 NULL, /* in_input_buffer */
1716 0, /* in_additional_info */
1717 0, /* in_flags */
1718 ph->fid_persistent,
1719 ph->fid_volatile,
1720 frame,
1721 &outbuf);
1722 if (!NT_STATUS_IS_OK(status)) {
1723 goto fail;
1726 /* Parse the reply. */
1727 if (outbuf.length != 24) {
1728 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1729 goto fail;
1732 total_size = BVAL(outbuf.data, 0);
1733 size_free = BVAL(outbuf.data, 8);
1734 sectors_per_unit = IVAL(outbuf.data, 16);
1735 bytes_per_sector = IVAL(outbuf.data, 20);
1737 if (bsize) {
1738 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
1740 if (total) {
1741 *total = total_size;
1743 if (avail) {
1744 *avail = size_free;
1747 status = NT_STATUS_OK;
1749 fail:
1751 if (fnum != 0xffff) {
1752 cli_smb2_close_fnum(cli, fnum);
1755 TALLOC_FREE(frame);
1756 return status;
1759 /***************************************************************
1760 Wrapper that allows SMB2 to query file system attributes.
1761 Synchronous only.
1762 ***************************************************************/
1764 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
1766 NTSTATUS status;
1767 uint16_t fnum = 0xffff;
1768 DATA_BLOB outbuf = data_blob_null;
1769 struct smb2_hnd *ph = NULL;
1770 TALLOC_CTX *frame = talloc_stackframe();
1772 if (smbXcli_conn_has_async_calls(cli->conn)) {
1774 * Can't use sync call while an async call is in flight
1776 status = NT_STATUS_INVALID_PARAMETER;
1777 goto fail;
1780 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1781 status = NT_STATUS_INVALID_PARAMETER;
1782 goto fail;
1785 /* First open the top level directory. */
1786 status =
1787 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
1788 FILE_READ_ATTRIBUTES, /* desired_access */
1789 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1790 FILE_SHARE_READ | FILE_SHARE_WRITE |
1791 FILE_SHARE_DELETE, /* share_access */
1792 FILE_OPEN, /* create_disposition */
1793 FILE_DIRECTORY_FILE, /* create_options */
1794 &fnum,
1795 NULL);
1797 if (!NT_STATUS_IS_OK(status)) {
1798 goto fail;
1801 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1802 if (!NT_STATUS_IS_OK(status)) {
1803 goto fail;
1806 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
1807 cli->smb2.tcon, 2, /* in_info_type */
1808 5, /* in_file_info_class */
1809 0xFFFF, /* in_max_output_length */
1810 NULL, /* in_input_buffer */
1811 0, /* in_additional_info */
1812 0, /* in_flags */
1813 ph->fid_persistent, ph->fid_volatile, frame,
1814 &outbuf);
1815 if (!NT_STATUS_IS_OK(status)) {
1816 goto fail;
1819 if (outbuf.length < 12) {
1820 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1821 goto fail;
1824 *fs_attr = IVAL(outbuf.data, 0);
1826 fail:
1828 if (fnum != 0xffff) {
1829 cli_smb2_close_fnum(cli, fnum);
1832 TALLOC_FREE(frame);
1833 return status;
1836 /***************************************************************
1837 Wrapper that allows SMB2 to query a security descriptor.
1838 Synchronous only.
1839 ***************************************************************/
1841 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
1842 uint16_t fnum,
1843 uint32_t sec_info,
1844 TALLOC_CTX *mem_ctx,
1845 struct security_descriptor **ppsd)
1847 NTSTATUS status;
1848 DATA_BLOB outbuf = data_blob_null;
1849 struct smb2_hnd *ph = NULL;
1850 struct security_descriptor *lsd = NULL;
1851 TALLOC_CTX *frame = talloc_stackframe();
1853 if (smbXcli_conn_has_async_calls(cli->conn)) {
1855 * Can't use sync call while an async call is in flight
1857 status = NT_STATUS_INVALID_PARAMETER;
1858 goto fail;
1861 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1862 status = NT_STATUS_INVALID_PARAMETER;
1863 goto fail;
1866 status = map_fnum_to_smb2_handle(cli,
1867 fnum,
1868 &ph);
1869 if (!NT_STATUS_IS_OK(status)) {
1870 goto fail;
1873 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1875 status = smb2cli_query_info(cli->conn,
1876 cli->timeout,
1877 cli->smb2.session,
1878 cli->smb2.tcon,
1879 3, /* in_info_type */
1880 0, /* in_file_info_class */
1881 0xFFFF, /* in_max_output_length */
1882 NULL, /* in_input_buffer */
1883 sec_info, /* in_additional_info */
1884 0, /* in_flags */
1885 ph->fid_persistent,
1886 ph->fid_volatile,
1887 frame,
1888 &outbuf);
1890 if (!NT_STATUS_IS_OK(status)) {
1891 goto fail;
1894 /* Parse the reply. */
1895 status = unmarshall_sec_desc(mem_ctx,
1896 outbuf.data,
1897 outbuf.length,
1898 &lsd);
1900 if (!NT_STATUS_IS_OK(status)) {
1901 goto fail;
1904 if (ppsd != NULL) {
1905 *ppsd = lsd;
1906 } else {
1907 TALLOC_FREE(lsd);
1910 fail:
1912 TALLOC_FREE(frame);
1913 return status;
1916 /***************************************************************
1917 Wrapper that allows SMB2 to set a security descriptor.
1918 Synchronous only.
1919 ***************************************************************/
1921 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
1922 uint16_t fnum,
1923 uint32_t sec_info,
1924 const struct security_descriptor *sd)
1926 NTSTATUS status;
1927 DATA_BLOB inbuf = data_blob_null;
1928 struct smb2_hnd *ph = NULL;
1929 TALLOC_CTX *frame = talloc_stackframe();
1931 if (smbXcli_conn_has_async_calls(cli->conn)) {
1933 * Can't use sync call while an async call is in flight
1935 status = NT_STATUS_INVALID_PARAMETER;
1936 goto fail;
1939 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1940 status = NT_STATUS_INVALID_PARAMETER;
1941 goto fail;
1944 status = map_fnum_to_smb2_handle(cli,
1945 fnum,
1946 &ph);
1947 if (!NT_STATUS_IS_OK(status)) {
1948 goto fail;
1951 status = marshall_sec_desc(frame,
1953 &inbuf.data,
1954 &inbuf.length);
1956 if (!NT_STATUS_IS_OK(status)) {
1957 goto fail;
1960 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1962 status = smb2cli_set_info(cli->conn,
1963 cli->timeout,
1964 cli->smb2.session,
1965 cli->smb2.tcon,
1966 3, /* in_info_type */
1967 0, /* in_file_info_class */
1968 &inbuf, /* in_input_buffer */
1969 sec_info, /* in_additional_info */
1970 ph->fid_persistent,
1971 ph->fid_volatile);
1973 fail:
1975 TALLOC_FREE(frame);
1976 return status;
1979 /***************************************************************
1980 Wrapper that allows SMB2 to rename a file.
1981 Synchronous only.
1982 ***************************************************************/
1984 NTSTATUS cli_smb2_rename(struct cli_state *cli,
1985 const char *fname_src,
1986 const char *fname_dst)
1988 NTSTATUS status;
1989 DATA_BLOB inbuf = data_blob_null;
1990 uint16_t fnum = 0xffff;
1991 struct smb2_hnd *ph = NULL;
1992 smb_ucs2_t *converted_str = NULL;
1993 size_t converted_size_bytes = 0;
1994 size_t namelen = 0;
1995 TALLOC_CTX *frame = talloc_stackframe();
1997 if (smbXcli_conn_has_async_calls(cli->conn)) {
1999 * Can't use sync call while an async call is in flight
2001 status = NT_STATUS_INVALID_PARAMETER;
2002 goto fail;
2005 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2006 status = NT_STATUS_INVALID_PARAMETER;
2007 goto fail;
2010 status = get_fnum_from_path(cli,
2011 fname_src,
2012 DELETE_ACCESS,
2013 &fnum);
2015 if (!NT_STATUS_IS_OK(status)) {
2016 goto fail;
2019 status = map_fnum_to_smb2_handle(cli,
2020 fnum,
2021 &ph);
2022 if (!NT_STATUS_IS_OK(status)) {
2023 goto fail;
2026 /* SMB2 is pickier about pathnames. Ensure it doesn't
2027 start in a '\' */
2028 if (*fname_dst == '\\') {
2029 fname_dst++;
2032 /* SMB2 is pickier about pathnames. Ensure it doesn't
2033 end in a '\' */
2034 namelen = strlen(fname_dst);
2035 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2036 char *modname = talloc_strdup(frame, fname_dst);
2037 modname[namelen-1] = '\0';
2038 fname_dst = modname;
2041 if (!push_ucs2_talloc(frame,
2042 &converted_str,
2043 fname_dst,
2044 &converted_size_bytes)) {
2045 status = NT_STATUS_INVALID_PARAMETER;
2046 goto fail;
2049 /* W2K8 insists the dest name is not null
2050 terminated. Remove the last 2 zero bytes
2051 and reduce the name length. */
2053 if (converted_size_bytes < 2) {
2054 status = NT_STATUS_INVALID_PARAMETER;
2055 goto fail;
2057 converted_size_bytes -= 2;
2059 inbuf = data_blob_talloc_zero(frame,
2060 20 + converted_size_bytes);
2061 if (inbuf.data == NULL) {
2062 status = NT_STATUS_NO_MEMORY;
2063 goto fail;
2066 SIVAL(inbuf.data, 16, converted_size_bytes);
2067 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2069 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2070 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2072 status = smb2cli_set_info(cli->conn,
2073 cli->timeout,
2074 cli->smb2.session,
2075 cli->smb2.tcon,
2076 1, /* in_info_type */
2077 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2078 &inbuf, /* in_input_buffer */
2079 0, /* in_additional_info */
2080 ph->fid_persistent,
2081 ph->fid_volatile);
2083 fail:
2085 if (fnum != 0xffff) {
2086 cli_smb2_close_fnum(cli, fnum);
2089 TALLOC_FREE(frame);
2090 return status;
2093 /***************************************************************
2094 Wrapper that allows SMB2 to set an EA on a fnum.
2095 Synchronous only.
2096 ***************************************************************/
2098 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2099 uint16_t fnum,
2100 const char *ea_name,
2101 const char *ea_val,
2102 size_t ea_len)
2104 NTSTATUS status;
2105 DATA_BLOB inbuf = data_blob_null;
2106 size_t bloblen = 0;
2107 char *ea_name_ascii = NULL;
2108 size_t namelen = 0;
2109 struct smb2_hnd *ph = NULL;
2110 TALLOC_CTX *frame = talloc_stackframe();
2112 if (smbXcli_conn_has_async_calls(cli->conn)) {
2114 * Can't use sync call while an async call is in flight
2116 status = NT_STATUS_INVALID_PARAMETER;
2117 goto fail;
2120 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2121 status = NT_STATUS_INVALID_PARAMETER;
2122 goto fail;
2125 status = map_fnum_to_smb2_handle(cli,
2126 fnum,
2127 &ph);
2128 if (!NT_STATUS_IS_OK(status)) {
2129 goto fail;
2132 /* Marshall the SMB2 EA data. */
2133 if (ea_len > 0xFFFF) {
2134 status = NT_STATUS_INVALID_PARAMETER;
2135 goto fail;
2138 if (!push_ascii_talloc(frame,
2139 &ea_name_ascii,
2140 ea_name,
2141 &namelen)) {
2142 status = NT_STATUS_INVALID_PARAMETER;
2143 goto fail;
2146 if (namelen < 2 || namelen > 0xFF) {
2147 status = NT_STATUS_INVALID_PARAMETER;
2148 goto fail;
2151 bloblen = 8 + ea_len + namelen;
2152 /* Round up to a 4 byte boundary. */
2153 bloblen = ((bloblen + 3)&~3);
2155 inbuf = data_blob_talloc_zero(frame, bloblen);
2156 if (inbuf.data == NULL) {
2157 status = NT_STATUS_NO_MEMORY;
2158 goto fail;
2160 /* namelen doesn't include the NULL byte. */
2161 SCVAL(inbuf.data, 5, namelen - 1);
2162 SSVAL(inbuf.data, 6, ea_len);
2163 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2164 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2166 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2167 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2169 status = smb2cli_set_info(cli->conn,
2170 cli->timeout,
2171 cli->smb2.session,
2172 cli->smb2.tcon,
2173 1, /* in_info_type */
2174 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2175 &inbuf, /* in_input_buffer */
2176 0, /* in_additional_info */
2177 ph->fid_persistent,
2178 ph->fid_volatile);
2180 fail:
2182 TALLOC_FREE(frame);
2183 return status;
2186 /***************************************************************
2187 Wrapper that allows SMB2 to set an EA on a pathname.
2188 Synchronous only.
2189 ***************************************************************/
2191 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2192 const char *name,
2193 const char *ea_name,
2194 const char *ea_val,
2195 size_t ea_len)
2197 NTSTATUS status;
2198 uint16_t fnum = 0xffff;
2200 if (smbXcli_conn_has_async_calls(cli->conn)) {
2202 * Can't use sync call while an async call is in flight
2204 status = NT_STATUS_INVALID_PARAMETER;
2205 goto fail;
2208 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2209 status = NT_STATUS_INVALID_PARAMETER;
2210 goto fail;
2213 status = get_fnum_from_path(cli,
2214 name,
2215 FILE_WRITE_EA,
2216 &fnum);
2218 if (!NT_STATUS_IS_OK(status)) {
2219 goto fail;
2222 status = cli_set_ea_fnum(cli,
2223 fnum,
2224 ea_name,
2225 ea_val,
2226 ea_len);
2227 if (!NT_STATUS_IS_OK(status)) {
2228 goto fail;
2231 fail:
2233 if (fnum != 0xffff) {
2234 cli_smb2_close_fnum(cli, fnum);
2237 return status;
2240 /***************************************************************
2241 Wrapper that allows SMB2 to get an EA list on a pathname.
2242 Synchronous only.
2243 ***************************************************************/
2245 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2246 const char *name,
2247 TALLOC_CTX *ctx,
2248 size_t *pnum_eas,
2249 struct ea_struct **pea_array)
2251 NTSTATUS status;
2252 uint16_t fnum = 0xffff;
2253 DATA_BLOB outbuf = data_blob_null;
2254 struct smb2_hnd *ph = NULL;
2255 struct ea_list *ea_list = NULL;
2256 struct ea_list *eal = NULL;
2257 size_t ea_count = 0;
2258 TALLOC_CTX *frame = talloc_stackframe();
2260 *pnum_eas = 0;
2261 *pea_array = NULL;
2263 if (smbXcli_conn_has_async_calls(cli->conn)) {
2265 * Can't use sync call while an async call is in flight
2267 status = NT_STATUS_INVALID_PARAMETER;
2268 goto fail;
2271 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2272 status = NT_STATUS_INVALID_PARAMETER;
2273 goto fail;
2276 status = get_fnum_from_path(cli,
2277 name,
2278 FILE_READ_EA,
2279 &fnum);
2281 if (!NT_STATUS_IS_OK(status)) {
2282 goto fail;
2285 status = map_fnum_to_smb2_handle(cli,
2286 fnum,
2287 &ph);
2288 if (!NT_STATUS_IS_OK(status)) {
2289 goto fail;
2292 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2293 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2295 status = smb2cli_query_info(cli->conn,
2296 cli->timeout,
2297 cli->smb2.session,
2298 cli->smb2.tcon,
2299 1, /* in_info_type */
2300 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2301 0xFFFF, /* in_max_output_length */
2302 NULL, /* in_input_buffer */
2303 0, /* in_additional_info */
2304 0, /* in_flags */
2305 ph->fid_persistent,
2306 ph->fid_volatile,
2307 frame,
2308 &outbuf);
2310 if (!NT_STATUS_IS_OK(status)) {
2311 goto fail;
2314 /* Parse the reply. */
2315 ea_list = read_nttrans_ea_list(ctx,
2316 (const char *)outbuf.data,
2317 outbuf.length);
2318 if (ea_list == NULL) {
2319 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2320 goto fail;
2323 /* Convert to an array. */
2324 for (eal = ea_list; eal; eal = eal->next) {
2325 ea_count++;
2328 if (ea_count) {
2329 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2330 if (*pea_array == NULL) {
2331 status = NT_STATUS_NO_MEMORY;
2332 goto fail;
2334 ea_count = 0;
2335 for (eal = ea_list; eal; eal = eal->next) {
2336 (*pea_array)[ea_count++] = eal->ea;
2338 *pnum_eas = ea_count;
2341 fail:
2343 if (fnum != 0xffff) {
2344 cli_smb2_close_fnum(cli, fnum);
2347 TALLOC_FREE(frame);
2348 return status;
2351 /***************************************************************
2352 Wrapper that allows SMB2 to get user quota.
2353 Synchronous only.
2354 ***************************************************************/
2356 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
2357 int quota_fnum,
2358 SMB_NTQUOTA_STRUCT *pqt)
2360 NTSTATUS status;
2361 DATA_BLOB inbuf = data_blob_null;
2362 DATA_BLOB outbuf = data_blob_null;
2363 struct smb2_hnd *ph = NULL;
2364 TALLOC_CTX *frame = talloc_stackframe();
2365 unsigned sid_len;
2366 unsigned int offset;
2367 uint8_t *buf;
2369 if (smbXcli_conn_has_async_calls(cli->conn)) {
2371 * Can't use sync call while an async call is in flight
2373 status = NT_STATUS_INVALID_PARAMETER;
2374 goto fail;
2377 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2378 status = NT_STATUS_INVALID_PARAMETER;
2379 goto fail;
2382 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2383 if (!NT_STATUS_IS_OK(status)) {
2384 goto fail;
2387 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
2389 inbuf = data_blob_talloc_zero(frame, 24 + sid_len);
2390 if (inbuf.data == NULL) {
2391 status = NT_STATUS_NO_MEMORY;
2392 goto fail;
2395 buf = inbuf.data;
2397 SCVAL(buf, 0, 1); /* ReturnSingle */
2398 SCVAL(buf, 1, 0); /* RestartScan */
2399 SSVAL(buf, 2, 0); /* Reserved */
2400 if (8 + sid_len < 8) {
2401 status = NT_STATUS_INVALID_PARAMETER;
2402 goto fail;
2404 SIVAL(buf, 4, 8 + sid_len); /* SidListLength */
2405 SIVAL(buf, 8, 0); /* StartSidLength */
2406 SIVAL(buf, 12, 0); /* StartSidOffset */
2407 SIVAL(buf, 16, 0); /* NextEntryOffset */
2408 SIVAL(buf, 20, sid_len); /* SidLength */
2409 sid_linearize(buf + 24, sid_len, &pqt->sid);
2411 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2412 cli->smb2.tcon, 4, /* in_info_type */
2413 0, /* in_file_info_class */
2414 0xFFFF, /* in_max_output_length */
2415 &inbuf, /* in_input_buffer */
2416 0, /* in_additional_info */
2417 0, /* in_flags */
2418 ph->fid_persistent, ph->fid_volatile, frame,
2419 &outbuf);
2421 if (!NT_STATUS_IS_OK(status)) {
2422 goto fail;
2425 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
2426 pqt)) {
2427 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2428 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
2431 fail:
2432 TALLOC_FREE(frame);
2433 return status;
2436 /***************************************************************
2437 Wrapper that allows SMB2 to list user quota.
2438 Synchronous only.
2439 ***************************************************************/
2441 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
2442 TALLOC_CTX *mem_ctx,
2443 int quota_fnum,
2444 SMB_NTQUOTA_LIST **pqt_list,
2445 bool first)
2447 NTSTATUS status;
2448 DATA_BLOB inbuf = data_blob_null;
2449 DATA_BLOB outbuf = data_blob_null;
2450 struct smb2_hnd *ph = NULL;
2451 TALLOC_CTX *frame = talloc_stackframe();
2452 uint8_t *buf;
2454 if (smbXcli_conn_has_async_calls(cli->conn)) {
2456 * Can't use sync call while an async call is in flight
2458 status = NT_STATUS_INVALID_PARAMETER;
2459 goto cleanup;
2462 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2463 status = NT_STATUS_INVALID_PARAMETER;
2464 goto cleanup;
2467 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2468 if (!NT_STATUS_IS_OK(status)) {
2469 goto cleanup;
2472 inbuf = data_blob_talloc_zero(frame, 16);
2473 if (inbuf.data == NULL) {
2474 status = NT_STATUS_NO_MEMORY;
2475 goto cleanup;
2478 buf = inbuf.data;
2480 SCVAL(buf, 0, 0); /* ReturnSingle */
2481 SCVAL(buf, 1, first ? 1 : 0); /* RestartScan */
2482 SSVAL(buf, 2, 0); /* Reserved */
2483 SIVAL(buf, 4, 0); /* SidListLength */
2484 SIVAL(buf, 8, 0); /* StartSidLength */
2485 SIVAL(buf, 12, 0); /* StartSidOffset */
2487 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2488 cli->smb2.tcon, 4, /* in_info_type */
2489 0, /* in_file_info_class */
2490 0xFFFF, /* in_max_output_length */
2491 &inbuf, /* in_input_buffer */
2492 0, /* in_additional_info */
2493 0, /* in_flags */
2494 ph->fid_persistent, ph->fid_volatile, frame,
2495 &outbuf);
2497 if (!NT_STATUS_IS_OK(status)) {
2498 goto cleanup;
2501 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
2502 pqt_list);
2504 cleanup:
2505 TALLOC_FREE(frame);
2506 return status;
2509 /***************************************************************
2510 Wrapper that allows SMB2 to get file system quota.
2511 Synchronous only.
2512 ***************************************************************/
2514 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
2515 int quota_fnum,
2516 SMB_NTQUOTA_STRUCT *pqt)
2518 NTSTATUS status;
2519 DATA_BLOB outbuf = data_blob_null;
2520 struct smb2_hnd *ph = NULL;
2521 TALLOC_CTX *frame = talloc_stackframe();
2523 if (smbXcli_conn_has_async_calls(cli->conn)) {
2525 * Can't use sync call while an async call is in flight
2527 status = NT_STATUS_INVALID_PARAMETER;
2528 goto cleanup;
2531 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2532 status = NT_STATUS_INVALID_PARAMETER;
2533 goto cleanup;
2536 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2537 if (!NT_STATUS_IS_OK(status)) {
2538 goto cleanup;
2541 status = smb2cli_query_info(
2542 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
2543 2, /* in_info_type */
2544 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
2545 0xFFFF, /* in_max_output_length */
2546 NULL, /* in_input_buffer */
2547 0, /* in_additional_info */
2548 0, /* in_flags */
2549 ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
2551 if (!NT_STATUS_IS_OK(status)) {
2552 goto cleanup;
2555 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
2557 cleanup:
2558 TALLOC_FREE(frame);
2559 return status;
2562 /***************************************************************
2563 Wrapper that allows SMB2 to set user quota.
2564 Synchronous only.
2565 ***************************************************************/
2567 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
2568 int quota_fnum,
2569 SMB_NTQUOTA_LIST *qtl)
2571 NTSTATUS status;
2572 DATA_BLOB inbuf = data_blob_null;
2573 struct smb2_hnd *ph = NULL;
2574 TALLOC_CTX *frame = talloc_stackframe();
2576 if (smbXcli_conn_has_async_calls(cli->conn)) {
2578 * Can't use sync call while an async call is in flight
2580 status = NT_STATUS_INVALID_PARAMETER;
2581 goto cleanup;
2584 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2585 status = NT_STATUS_INVALID_PARAMETER;
2586 goto cleanup;
2589 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2590 if (!NT_STATUS_IS_OK(status)) {
2591 goto cleanup;
2594 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
2595 if (!NT_STATUS_IS_OK(status)) {
2596 goto cleanup;
2599 status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
2600 cli->smb2.tcon, 4, /* in_info_type */
2601 0, /* in_file_info_class */
2602 &inbuf, /* in_input_buffer */
2603 0, /* in_additional_info */
2604 ph->fid_persistent, ph->fid_volatile);
2605 cleanup:
2606 TALLOC_FREE(frame);
2608 return status;
2611 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
2612 int quota_fnum,
2613 SMB_NTQUOTA_STRUCT *pqt)
2615 NTSTATUS status;
2616 DATA_BLOB inbuf = data_blob_null;
2617 struct smb2_hnd *ph = NULL;
2618 TALLOC_CTX *frame = talloc_stackframe();
2620 if (smbXcli_conn_has_async_calls(cli->conn)) {
2622 * Can't use sync call while an async call is in flight
2624 status = NT_STATUS_INVALID_PARAMETER;
2625 goto cleanup;
2628 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2629 status = NT_STATUS_INVALID_PARAMETER;
2630 goto cleanup;
2633 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2634 if (!NT_STATUS_IS_OK(status)) {
2635 goto cleanup;
2638 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
2639 if (!NT_STATUS_IS_OK(status)) {
2640 return status;
2643 status = smb2cli_set_info(
2644 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
2645 2, /* in_info_type */
2646 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
2647 &inbuf, /* in_input_buffer */
2648 0, /* in_additional_info */
2649 ph->fid_persistent, ph->fid_volatile);
2650 cleanup:
2651 TALLOC_FREE(frame);
2652 return status;
2655 struct cli_smb2_read_state {
2656 struct tevent_context *ev;
2657 struct cli_state *cli;
2658 struct smb2_hnd *ph;
2659 uint64_t start_offset;
2660 uint32_t size;
2661 uint32_t received;
2662 uint8_t *buf;
2665 static void cli_smb2_read_done(struct tevent_req *subreq);
2667 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
2668 struct tevent_context *ev,
2669 struct cli_state *cli,
2670 uint16_t fnum,
2671 off_t offset,
2672 size_t size)
2674 NTSTATUS status;
2675 struct tevent_req *req, *subreq;
2676 struct cli_smb2_read_state *state;
2678 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
2679 if (req == NULL) {
2680 return NULL;
2682 state->ev = ev;
2683 state->cli = cli;
2684 state->start_offset = (uint64_t)offset;
2685 state->size = (uint32_t)size;
2686 state->received = 0;
2687 state->buf = NULL;
2689 status = map_fnum_to_smb2_handle(cli,
2690 fnum,
2691 &state->ph);
2692 if (tevent_req_nterror(req, status)) {
2693 return tevent_req_post(req, ev);
2696 subreq = smb2cli_read_send(state,
2697 state->ev,
2698 state->cli->conn,
2699 state->cli->timeout,
2700 state->cli->smb2.session,
2701 state->cli->smb2.tcon,
2702 state->size,
2703 state->start_offset,
2704 state->ph->fid_persistent,
2705 state->ph->fid_volatile,
2706 0, /* minimum_count */
2707 0); /* remaining_bytes */
2709 if (tevent_req_nomem(subreq, req)) {
2710 return tevent_req_post(req, ev);
2712 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
2713 return req;
2716 static void cli_smb2_read_done(struct tevent_req *subreq)
2718 struct tevent_req *req = tevent_req_callback_data(
2719 subreq, struct tevent_req);
2720 struct cli_smb2_read_state *state = tevent_req_data(
2721 req, struct cli_smb2_read_state);
2722 NTSTATUS status;
2724 status = smb2cli_read_recv(subreq, state,
2725 &state->buf, &state->received);
2726 if (tevent_req_nterror(req, status)) {
2727 return;
2730 if (state->received > state->size) {
2731 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2732 return;
2735 tevent_req_done(req);
2738 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
2739 ssize_t *received,
2740 uint8_t **rcvbuf)
2742 NTSTATUS status;
2743 struct cli_smb2_read_state *state = tevent_req_data(
2744 req, struct cli_smb2_read_state);
2746 if (tevent_req_is_nterror(req, &status)) {
2747 state->cli->raw_status = status;
2748 return status;
2751 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2752 * better make sure that you copy it away before you talloc_free(req).
2753 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2755 *received = (ssize_t)state->received;
2756 *rcvbuf = state->buf;
2757 state->cli->raw_status = NT_STATUS_OK;
2758 return NT_STATUS_OK;
2761 struct cli_smb2_write_state {
2762 struct tevent_context *ev;
2763 struct cli_state *cli;
2764 struct smb2_hnd *ph;
2765 uint32_t flags;
2766 const uint8_t *buf;
2767 uint64_t offset;
2768 uint32_t size;
2769 uint32_t written;
2772 static void cli_smb2_write_written(struct tevent_req *req);
2774 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
2775 struct tevent_context *ev,
2776 struct cli_state *cli,
2777 uint16_t fnum,
2778 uint16_t mode,
2779 const uint8_t *buf,
2780 off_t offset,
2781 size_t size)
2783 NTSTATUS status;
2784 struct tevent_req *req, *subreq = NULL;
2785 struct cli_smb2_write_state *state = NULL;
2787 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
2788 if (req == NULL) {
2789 return NULL;
2791 state->ev = ev;
2792 state->cli = cli;
2793 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2794 state->flags = (uint32_t)mode;
2795 state->buf = buf;
2796 state->offset = (uint64_t)offset;
2797 state->size = (uint32_t)size;
2798 state->written = 0;
2800 status = map_fnum_to_smb2_handle(cli,
2801 fnum,
2802 &state->ph);
2803 if (tevent_req_nterror(req, status)) {
2804 return tevent_req_post(req, ev);
2807 subreq = smb2cli_write_send(state,
2808 state->ev,
2809 state->cli->conn,
2810 state->cli->timeout,
2811 state->cli->smb2.session,
2812 state->cli->smb2.tcon,
2813 state->size,
2814 state->offset,
2815 state->ph->fid_persistent,
2816 state->ph->fid_volatile,
2817 0, /* remaining_bytes */
2818 state->flags, /* flags */
2819 state->buf);
2821 if (tevent_req_nomem(subreq, req)) {
2822 return tevent_req_post(req, ev);
2824 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
2825 return req;
2828 static void cli_smb2_write_written(struct tevent_req *subreq)
2830 struct tevent_req *req = tevent_req_callback_data(
2831 subreq, struct tevent_req);
2832 struct cli_smb2_write_state *state = tevent_req_data(
2833 req, struct cli_smb2_write_state);
2834 NTSTATUS status;
2835 uint32_t written;
2837 status = smb2cli_write_recv(subreq, &written);
2838 TALLOC_FREE(subreq);
2839 if (tevent_req_nterror(req, status)) {
2840 return;
2843 state->written = written;
2845 tevent_req_done(req);
2848 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
2849 size_t *pwritten)
2851 struct cli_smb2_write_state *state = tevent_req_data(
2852 req, struct cli_smb2_write_state);
2853 NTSTATUS status;
2855 if (tevent_req_is_nterror(req, &status)) {
2856 state->cli->raw_status = status;
2857 tevent_req_received(req);
2858 return status;
2861 if (pwritten != NULL) {
2862 *pwritten = (size_t)state->written;
2864 state->cli->raw_status = NT_STATUS_OK;
2865 tevent_req_received(req);
2866 return NT_STATUS_OK;
2869 /***************************************************************
2870 Wrapper that allows SMB2 async write using an fnum.
2871 This is mostly cut-and-paste from Volker's code inside
2872 source3/libsmb/clireadwrite.c, adapted for SMB2.
2874 Done this way so I can reuse all the logic inside cli_push()
2875 for free :-).
2876 ***************************************************************/
2878 struct cli_smb2_writeall_state {
2879 struct tevent_context *ev;
2880 struct cli_state *cli;
2881 struct smb2_hnd *ph;
2882 uint32_t flags;
2883 const uint8_t *buf;
2884 uint64_t offset;
2885 uint32_t size;
2886 uint32_t written;
2889 static void cli_smb2_writeall_written(struct tevent_req *req);
2891 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
2892 struct tevent_context *ev,
2893 struct cli_state *cli,
2894 uint16_t fnum,
2895 uint16_t mode,
2896 const uint8_t *buf,
2897 off_t offset,
2898 size_t size)
2900 NTSTATUS status;
2901 struct tevent_req *req, *subreq = NULL;
2902 struct cli_smb2_writeall_state *state = NULL;
2903 uint32_t to_write;
2904 uint32_t max_size;
2905 bool ok;
2907 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
2908 if (req == NULL) {
2909 return NULL;
2911 state->ev = ev;
2912 state->cli = cli;
2913 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2914 state->flags = (uint32_t)mode;
2915 state->buf = buf;
2916 state->offset = (uint64_t)offset;
2917 state->size = (uint32_t)size;
2918 state->written = 0;
2920 status = map_fnum_to_smb2_handle(cli,
2921 fnum,
2922 &state->ph);
2923 if (tevent_req_nterror(req, status)) {
2924 return tevent_req_post(req, ev);
2927 to_write = state->size;
2928 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2929 to_write = MIN(max_size, to_write);
2930 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2931 if (ok) {
2932 to_write = MIN(max_size, to_write);
2935 subreq = smb2cli_write_send(state,
2936 state->ev,
2937 state->cli->conn,
2938 state->cli->timeout,
2939 state->cli->smb2.session,
2940 state->cli->smb2.tcon,
2941 to_write,
2942 state->offset,
2943 state->ph->fid_persistent,
2944 state->ph->fid_volatile,
2945 0, /* remaining_bytes */
2946 state->flags, /* flags */
2947 state->buf + state->written);
2949 if (tevent_req_nomem(subreq, req)) {
2950 return tevent_req_post(req, ev);
2952 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2953 return req;
2956 static void cli_smb2_writeall_written(struct tevent_req *subreq)
2958 struct tevent_req *req = tevent_req_callback_data(
2959 subreq, struct tevent_req);
2960 struct cli_smb2_writeall_state *state = tevent_req_data(
2961 req, struct cli_smb2_writeall_state);
2962 NTSTATUS status;
2963 uint32_t written, to_write;
2964 uint32_t max_size;
2965 bool ok;
2967 status = smb2cli_write_recv(subreq, &written);
2968 TALLOC_FREE(subreq);
2969 if (tevent_req_nterror(req, status)) {
2970 return;
2973 state->written += written;
2975 if (state->written > state->size) {
2976 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2977 return;
2980 to_write = state->size - state->written;
2982 if (to_write == 0) {
2983 tevent_req_done(req);
2984 return;
2987 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2988 to_write = MIN(max_size, to_write);
2989 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2990 if (ok) {
2991 to_write = MIN(max_size, to_write);
2994 subreq = smb2cli_write_send(state,
2995 state->ev,
2996 state->cli->conn,
2997 state->cli->timeout,
2998 state->cli->smb2.session,
2999 state->cli->smb2.tcon,
3000 to_write,
3001 state->offset + state->written,
3002 state->ph->fid_persistent,
3003 state->ph->fid_volatile,
3004 0, /* remaining_bytes */
3005 state->flags, /* flags */
3006 state->buf + state->written);
3008 if (tevent_req_nomem(subreq, req)) {
3009 return;
3011 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3014 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
3015 size_t *pwritten)
3017 struct cli_smb2_writeall_state *state = tevent_req_data(
3018 req, struct cli_smb2_writeall_state);
3019 NTSTATUS status;
3021 if (tevent_req_is_nterror(req, &status)) {
3022 state->cli->raw_status = status;
3023 return status;
3025 if (pwritten != NULL) {
3026 *pwritten = (size_t)state->written;
3028 state->cli->raw_status = NT_STATUS_OK;
3029 return NT_STATUS_OK;
3032 struct cli_smb2_splice_state {
3033 struct tevent_context *ev;
3034 struct cli_state *cli;
3035 struct smb2_hnd *src_ph;
3036 struct smb2_hnd *dst_ph;
3037 int (*splice_cb)(off_t n, void *priv);
3038 void *priv;
3039 off_t written;
3040 off_t size;
3041 off_t src_offset;
3042 off_t dst_offset;
3043 bool resized;
3044 struct req_resume_key_rsp resume_rsp;
3045 struct srv_copychunk_copy cc_copy;
3048 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3049 struct tevent_req *req);
3051 static void cli_splice_copychunk_done(struct tevent_req *subreq)
3053 struct tevent_req *req = tevent_req_callback_data(
3054 subreq, struct tevent_req);
3055 struct cli_smb2_splice_state *state =
3056 tevent_req_data(req,
3057 struct cli_smb2_splice_state);
3058 struct smbXcli_conn *conn = state->cli->conn;
3059 DATA_BLOB out_input_buffer = data_blob_null;
3060 DATA_BLOB out_output_buffer = data_blob_null;
3061 struct srv_copychunk_rsp cc_copy_rsp;
3062 enum ndr_err_code ndr_ret;
3063 NTSTATUS status;
3065 status = smb2cli_ioctl_recv(subreq, state,
3066 &out_input_buffer,
3067 &out_output_buffer);
3068 TALLOC_FREE(subreq);
3069 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
3070 state->resized) && tevent_req_nterror(req, status)) {
3071 return;
3074 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
3075 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
3076 if (ndr_ret != NDR_ERR_SUCCESS) {
3077 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3078 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3079 return;
3082 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
3083 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
3084 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
3085 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
3086 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
3087 tevent_req_nterror(req, status)) {
3088 return;
3091 state->resized = true;
3092 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
3093 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
3094 } else {
3095 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3096 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3097 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
3098 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3099 return;
3101 state->src_offset += cc_copy_rsp.total_bytes_written;
3102 state->dst_offset += cc_copy_rsp.total_bytes_written;
3103 state->written += cc_copy_rsp.total_bytes_written;
3104 if (!state->splice_cb(state->written, state->priv)) {
3105 tevent_req_nterror(req, NT_STATUS_CANCELLED);
3106 return;
3110 cli_splice_copychunk_send(state, req);
3113 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3114 struct tevent_req *req)
3116 struct tevent_req *subreq;
3117 enum ndr_err_code ndr_ret;
3118 struct smbXcli_conn *conn = state->cli->conn;
3119 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
3120 off_t src_offset = state->src_offset;
3121 off_t dst_offset = state->dst_offset;
3122 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
3123 state->size - state->written);
3124 DATA_BLOB in_input_buffer = data_blob_null;
3125 DATA_BLOB in_output_buffer = data_blob_null;
3127 if (state->size - state->written == 0) {
3128 tevent_req_done(req);
3129 return;
3132 cc_copy->chunk_count = 0;
3133 while (req_len) {
3134 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
3135 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
3136 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
3137 smb2cli_conn_cc_chunk_len(conn));
3138 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
3139 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3140 return;
3142 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
3143 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
3144 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
3145 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3146 return;
3148 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3149 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3150 cc_copy->chunk_count++;
3153 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
3154 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
3155 if (ndr_ret != NDR_ERR_SUCCESS) {
3156 DEBUG(0, ("failed to marshall copy chunk req\n"));
3157 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3158 return;
3161 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
3162 state->cli->timeout,
3163 state->cli->smb2.session,
3164 state->cli->smb2.tcon,
3165 state->dst_ph->fid_persistent, /* in_fid_persistent */
3166 state->dst_ph->fid_volatile, /* in_fid_volatile */
3167 FSCTL_SRV_COPYCHUNK_WRITE,
3168 0, /* in_max_input_length */
3169 &in_input_buffer,
3170 12, /* in_max_output_length */
3171 &in_output_buffer,
3172 SMB2_IOCTL_FLAG_IS_FSCTL);
3173 if (tevent_req_nomem(subreq, req)) {
3174 return;
3176 tevent_req_set_callback(subreq,
3177 cli_splice_copychunk_done,
3178 req);
3181 static void cli_splice_key_done(struct tevent_req *subreq)
3183 struct tevent_req *req = tevent_req_callback_data(
3184 subreq, struct tevent_req);
3185 struct cli_smb2_splice_state *state =
3186 tevent_req_data(req,
3187 struct cli_smb2_splice_state);
3188 enum ndr_err_code ndr_ret;
3189 NTSTATUS status;
3191 DATA_BLOB out_input_buffer = data_blob_null;
3192 DATA_BLOB out_output_buffer = data_blob_null;
3194 status = smb2cli_ioctl_recv(subreq, state,
3195 &out_input_buffer,
3196 &out_output_buffer);
3197 TALLOC_FREE(subreq);
3198 if (tevent_req_nterror(req, status)) {
3199 return;
3202 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
3203 state, &state->resume_rsp,
3204 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
3205 if (ndr_ret != NDR_ERR_SUCCESS) {
3206 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3207 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3208 return;
3211 memcpy(&state->cc_copy.source_key,
3212 &state->resume_rsp.resume_key,
3213 sizeof state->resume_rsp.resume_key);
3215 cli_splice_copychunk_send(state, req);
3218 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
3219 struct tevent_context *ev,
3220 struct cli_state *cli,
3221 uint16_t src_fnum, uint16_t dst_fnum,
3222 off_t size, off_t src_offset, off_t dst_offset,
3223 int (*splice_cb)(off_t n, void *priv),
3224 void *priv)
3226 struct tevent_req *req;
3227 struct tevent_req *subreq;
3228 struct cli_smb2_splice_state *state;
3229 NTSTATUS status;
3230 DATA_BLOB in_input_buffer = data_blob_null;
3231 DATA_BLOB in_output_buffer = data_blob_null;
3233 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
3234 if (req == NULL) {
3235 return NULL;
3237 state->cli = cli;
3238 state->ev = ev;
3239 state->splice_cb = splice_cb;
3240 state->priv = priv;
3241 state->size = size;
3242 state->written = 0;
3243 state->src_offset = src_offset;
3244 state->dst_offset = dst_offset;
3245 state->cc_copy.chunks = talloc_array(state,
3246 struct srv_copychunk,
3247 smb2cli_conn_cc_max_chunks(cli->conn));
3248 if (state->cc_copy.chunks == NULL) {
3249 return NULL;
3252 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
3253 if (tevent_req_nterror(req, status))
3254 return tevent_req_post(req, ev);
3256 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
3257 if (tevent_req_nterror(req, status))
3258 return tevent_req_post(req, ev);
3260 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
3261 cli->timeout,
3262 cli->smb2.session,
3263 cli->smb2.tcon,
3264 state->src_ph->fid_persistent, /* in_fid_persistent */
3265 state->src_ph->fid_volatile, /* in_fid_volatile */
3266 FSCTL_SRV_REQUEST_RESUME_KEY,
3267 0, /* in_max_input_length */
3268 &in_input_buffer,
3269 32, /* in_max_output_length */
3270 &in_output_buffer,
3271 SMB2_IOCTL_FLAG_IS_FSCTL);
3272 if (tevent_req_nomem(subreq, req)) {
3273 return NULL;
3275 tevent_req_set_callback(subreq,
3276 cli_splice_key_done,
3277 req);
3279 return req;
3282 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
3284 struct cli_smb2_splice_state *state = tevent_req_data(
3285 req, struct cli_smb2_splice_state);
3286 NTSTATUS status;
3288 if (tevent_req_is_nterror(req, &status)) {
3289 state->cli->raw_status = status;
3290 tevent_req_received(req);
3291 return status;
3293 if (written != NULL) {
3294 *written = state->written;
3296 state->cli->raw_status = NT_STATUS_OK;
3297 tevent_req_received(req);
3298 return NT_STATUS_OK;
3301 /***************************************************************
3302 SMB2 enum shadow copy data.
3303 ***************************************************************/
3305 struct cli_smb2_shadow_copy_data_fnum_state {
3306 struct cli_state *cli;
3307 uint16_t fnum;
3308 struct smb2_hnd *ph;
3309 DATA_BLOB out_input_buffer;
3310 DATA_BLOB out_output_buffer;
3313 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
3315 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
3316 TALLOC_CTX *mem_ctx,
3317 struct tevent_context *ev,
3318 struct cli_state *cli,
3319 uint16_t fnum,
3320 bool get_names)
3322 struct tevent_req *req, *subreq;
3323 struct cli_smb2_shadow_copy_data_fnum_state *state;
3324 NTSTATUS status;
3326 req = tevent_req_create(mem_ctx, &state,
3327 struct cli_smb2_shadow_copy_data_fnum_state);
3328 if (req == NULL) {
3329 return NULL;
3332 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3333 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3334 return tevent_req_post(req, ev);
3337 state->cli = cli;
3338 state->fnum = fnum;
3340 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
3341 if (tevent_req_nterror(req, status)) {
3342 return tevent_req_post(req, ev);
3346 * TODO. Under SMB2 we should send a zero max_output_length
3347 * ioctl to get the required size, then send another ioctl
3348 * to get the data, but the current SMB1 implementation just
3349 * does one roundtrip with a 64K buffer size. Do the same
3350 * for now. JRA.
3353 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
3354 state->cli->timeout,
3355 state->cli->smb2.session,
3356 state->cli->smb2.tcon,
3357 state->ph->fid_persistent, /* in_fid_persistent */
3358 state->ph->fid_volatile, /* in_fid_volatile */
3359 FSCTL_GET_SHADOW_COPY_DATA,
3360 0, /* in_max_input_length */
3361 NULL, /* in_input_buffer */
3362 get_names ?
3363 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
3364 NULL, /* in_output_buffer */
3365 SMB2_IOCTL_FLAG_IS_FSCTL);
3367 if (tevent_req_nomem(subreq, req)) {
3368 return tevent_req_post(req, ev);
3370 tevent_req_set_callback(subreq,
3371 cli_smb2_shadow_copy_data_fnum_done,
3372 req);
3374 return req;
3377 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
3379 struct tevent_req *req = tevent_req_callback_data(
3380 subreq, struct tevent_req);
3381 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3382 req, struct cli_smb2_shadow_copy_data_fnum_state);
3383 NTSTATUS status;
3385 status = smb2cli_ioctl_recv(subreq, state,
3386 &state->out_input_buffer,
3387 &state->out_output_buffer);
3388 TALLOC_FREE(subreq);
3389 if (tevent_req_nterror(req, status)) {
3390 return;
3392 tevent_req_done(req);
3395 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
3396 TALLOC_CTX *mem_ctx,
3397 bool get_names,
3398 char ***pnames,
3399 int *pnum_names)
3401 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3402 req, struct cli_smb2_shadow_copy_data_fnum_state);
3403 char **names = NULL;
3404 uint32_t num_names = 0;
3405 uint32_t num_names_returned = 0;
3406 uint32_t dlength = 0;
3407 uint32_t i;
3408 uint8_t *endp = NULL;
3409 NTSTATUS status;
3411 if (tevent_req_is_nterror(req, &status)) {
3412 return status;
3415 if (state->out_output_buffer.length < 16) {
3416 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3419 num_names = IVAL(state->out_output_buffer.data, 0);
3420 num_names_returned = IVAL(state->out_output_buffer.data, 4);
3421 dlength = IVAL(state->out_output_buffer.data, 8);
3423 if (num_names > 0x7FFFFFFF) {
3424 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3427 if (get_names == false) {
3428 *pnum_names = (int)num_names;
3429 return NT_STATUS_OK;
3431 if (num_names != num_names_returned) {
3432 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3434 if (dlength + 12 < 12) {
3435 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3438 * NB. The below is an allowable return if there are
3439 * more snapshots than the buffer size we told the
3440 * server we can receive. We currently don't support
3441 * this.
3443 if (dlength + 12 > state->out_output_buffer.length) {
3444 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3446 if (state->out_output_buffer.length +
3447 (2 * sizeof(SHADOW_COPY_LABEL)) <
3448 state->out_output_buffer.length) {
3449 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3452 names = talloc_array(mem_ctx, char *, num_names_returned);
3453 if (names == NULL) {
3454 return NT_STATUS_NO_MEMORY;
3457 endp = state->out_output_buffer.data +
3458 state->out_output_buffer.length;
3460 for (i=0; i<num_names_returned; i++) {
3461 bool ret;
3462 uint8_t *src;
3463 size_t converted_size;
3465 src = state->out_output_buffer.data + 12 +
3466 (i * 2 * sizeof(SHADOW_COPY_LABEL));
3468 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
3469 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3471 ret = convert_string_talloc(
3472 names, CH_UTF16LE, CH_UNIX,
3473 src, 2 * sizeof(SHADOW_COPY_LABEL),
3474 &names[i], &converted_size);
3475 if (!ret) {
3476 TALLOC_FREE(names);
3477 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3480 *pnum_names = num_names;
3481 *pnames = names;
3482 return NT_STATUS_OK;
3485 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
3486 struct cli_state *cli,
3487 uint16_t fnum,
3488 bool get_names,
3489 char ***pnames,
3490 int *pnum_names)
3492 TALLOC_CTX *frame = talloc_stackframe();
3493 struct tevent_context *ev;
3494 struct tevent_req *req;
3495 NTSTATUS status = NT_STATUS_NO_MEMORY;
3497 if (smbXcli_conn_has_async_calls(cli->conn)) {
3499 * Can't use sync call while an async call is in flight
3501 status = NT_STATUS_INVALID_PARAMETER;
3502 goto fail;
3504 ev = samba_tevent_context_init(frame);
3505 if (ev == NULL) {
3506 goto fail;
3508 req = cli_smb2_shadow_copy_data_fnum_send(frame,
3510 cli,
3511 fnum,
3512 get_names);
3513 if (req == NULL) {
3514 goto fail;
3516 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3517 goto fail;
3519 status = cli_smb2_shadow_copy_data_fnum_recv(req,
3520 mem_ctx,
3521 get_names,
3522 pnames,
3523 pnum_names);
3524 fail:
3525 TALLOC_FREE(frame);
3526 return status;