smbXcli: Add "force_channel_sequence"
[Samba.git] / source3 / libsmb / cli_smb2_fnum.c
blob237e6bb2b540593aef6e4796c1482767069d7704
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 = NT_STATUS_OK;
454 if (tevent_req_is_nterror(req, &status)) {
455 state->cli->raw_status = status;
457 tevent_req_received(req);
458 return status;
461 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
463 TALLOC_CTX *frame = talloc_stackframe();
464 struct tevent_context *ev;
465 struct tevent_req *req;
466 NTSTATUS status = NT_STATUS_NO_MEMORY;
468 if (smbXcli_conn_has_async_calls(cli->conn)) {
470 * Can't use sync call while an async call is in flight
472 status = NT_STATUS_INVALID_PARAMETER;
473 goto fail;
475 ev = samba_tevent_context_init(frame);
476 if (ev == NULL) {
477 goto fail;
479 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
480 if (req == NULL) {
481 goto fail;
483 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
484 goto fail;
486 status = cli_smb2_close_fnum_recv(req);
487 fail:
488 TALLOC_FREE(frame);
489 return status;
492 struct cli_smb2_delete_on_close_state {
493 struct cli_state *cli;
494 uint16_t fnum;
495 struct smb2_hnd *ph;
496 uint8_t data[1];
497 DATA_BLOB inbuf;
500 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
502 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
503 struct tevent_context *ev,
504 struct cli_state *cli,
505 uint16_t fnum,
506 bool flag)
508 struct tevent_req *req = NULL;
509 struct cli_smb2_delete_on_close_state *state = NULL;
510 struct tevent_req *subreq = NULL;
511 uint8_t in_info_type;
512 uint8_t in_file_info_class;
513 NTSTATUS status;
515 req = tevent_req_create(mem_ctx, &state,
516 struct cli_smb2_delete_on_close_state);
517 if (req == NULL) {
518 return NULL;
520 state->cli = cli;
521 state->fnum = fnum;
523 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
524 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
525 return tevent_req_post(req, ev);
528 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
529 if (tevent_req_nterror(req, status)) {
530 return tevent_req_post(req, ev);
534 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
535 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
537 in_info_type = 1;
538 in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
539 /* Setup data array. */
540 SCVAL(&state->data[0], 0, flag ? 1 : 0);
541 state->inbuf.data = &state->data[0];
542 state->inbuf.length = 1;
544 subreq = smb2cli_set_info_send(state, ev,
545 cli->conn,
546 cli->timeout,
547 cli->smb2.session,
548 cli->smb2.tcon,
549 in_info_type,
550 in_file_info_class,
551 &state->inbuf, /* in_input_buffer */
552 0, /* in_additional_info */
553 state->ph->fid_persistent,
554 state->ph->fid_volatile);
555 if (tevent_req_nomem(subreq, req)) {
556 return tevent_req_post(req, ev);
558 tevent_req_set_callback(subreq,
559 cli_smb2_delete_on_close_done,
560 req);
561 return req;
564 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
566 NTSTATUS status = smb2cli_set_info_recv(subreq);
567 tevent_req_simple_finish_ntstatus(subreq, status);
570 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
572 struct cli_smb2_delete_on_close_state *state =
573 tevent_req_data(req,
574 struct cli_smb2_delete_on_close_state);
575 NTSTATUS status;
577 if (tevent_req_is_nterror(req, &status)) {
578 state->cli->raw_status = status;
579 tevent_req_received(req);
580 return status;
583 state->cli->raw_status = NT_STATUS_OK;
584 tevent_req_received(req);
585 return NT_STATUS_OK;
588 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
590 TALLOC_CTX *frame = talloc_stackframe();
591 struct tevent_context *ev;
592 struct tevent_req *req;
593 NTSTATUS status = NT_STATUS_NO_MEMORY;
595 if (smbXcli_conn_has_async_calls(cli->conn)) {
597 * Can't use sync call while an async call is in flight
599 status = NT_STATUS_INVALID_PARAMETER;
600 goto fail;
602 ev = samba_tevent_context_init(frame);
603 if (ev == NULL) {
604 goto fail;
606 req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
607 if (req == NULL) {
608 goto fail;
610 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
611 goto fail;
613 status = cli_smb2_delete_on_close_recv(req);
614 fail:
615 TALLOC_FREE(frame);
616 return status;
619 /***************************************************************
620 Small wrapper that allows SMB2 to create a directory
621 Synchronous only.
622 ***************************************************************/
624 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
626 NTSTATUS status;
627 uint16_t fnum;
629 if (smbXcli_conn_has_async_calls(cli->conn)) {
631 * Can't use sync call while an async call is in flight
633 return NT_STATUS_INVALID_PARAMETER;
636 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
637 return NT_STATUS_INVALID_PARAMETER;
640 status = cli_smb2_create_fnum(cli,
641 dname,
642 0, /* create_flags */
643 FILE_READ_ATTRIBUTES, /* desired_access */
644 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
645 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
646 FILE_CREATE, /* create_disposition */
647 FILE_DIRECTORY_FILE, /* create_options */
648 &fnum,
649 NULL);
651 if (!NT_STATUS_IS_OK(status)) {
652 return status;
654 return cli_smb2_close_fnum(cli, fnum);
657 /***************************************************************
658 Small wrapper that allows SMB2 to delete a directory
659 Synchronous only.
660 ***************************************************************/
662 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
664 NTSTATUS status;
665 uint16_t fnum;
667 if (smbXcli_conn_has_async_calls(cli->conn)) {
669 * Can't use sync call while an async call is in flight
671 return NT_STATUS_INVALID_PARAMETER;
674 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
675 return NT_STATUS_INVALID_PARAMETER;
678 status = cli_smb2_create_fnum(cli,
679 dname,
680 0, /* create_flags */
681 DELETE_ACCESS, /* desired_access */
682 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
683 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
684 FILE_OPEN, /* create_disposition */
685 FILE_DIRECTORY_FILE|FILE_DELETE_ON_CLOSE, /* create_options */
686 &fnum,
687 NULL);
689 if (!NT_STATUS_IS_OK(status)) {
690 return status;
692 return cli_smb2_close_fnum(cli, fnum);
695 /***************************************************************
696 Small wrapper that allows SMB2 to unlink a pathname.
697 Synchronous only.
698 ***************************************************************/
700 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
702 NTSTATUS status;
703 uint16_t fnum;
705 if (smbXcli_conn_has_async_calls(cli->conn)) {
707 * Can't use sync call while an async call is in flight
709 return NT_STATUS_INVALID_PARAMETER;
712 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
713 return NT_STATUS_INVALID_PARAMETER;
716 status = cli_smb2_create_fnum(cli,
717 fname,
718 0, /* create_flags */
719 DELETE_ACCESS, /* desired_access */
720 FILE_ATTRIBUTE_NORMAL, /* file attributes */
721 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
722 FILE_OPEN, /* create_disposition */
723 FILE_DELETE_ON_CLOSE, /* create_options */
724 &fnum,
725 NULL);
727 if (!NT_STATUS_IS_OK(status)) {
728 return status;
730 return cli_smb2_close_fnum(cli, fnum);
733 /***************************************************************
734 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
735 ***************************************************************/
737 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
738 uint32_t dir_data_length,
739 struct file_info *finfo,
740 uint32_t *next_offset)
742 size_t namelen = 0;
743 size_t slen = 0;
744 size_t ret = 0;
746 if (dir_data_length < 4) {
747 return NT_STATUS_INFO_LENGTH_MISMATCH;
750 *next_offset = IVAL(dir_data, 0);
752 if (*next_offset > dir_data_length) {
753 return NT_STATUS_INFO_LENGTH_MISMATCH;
756 if (*next_offset != 0) {
757 /* Ensure we only read what in this record. */
758 dir_data_length = *next_offset;
761 if (dir_data_length < 105) {
762 return NT_STATUS_INFO_LENGTH_MISMATCH;
765 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
766 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
767 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
768 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
769 finfo->mode = CVAL(dir_data + 56, 0);
770 namelen = IVAL(dir_data + 60,0);
771 if (namelen > (dir_data_length - 104)) {
772 return NT_STATUS_INFO_LENGTH_MISMATCH;
774 slen = CVAL(dir_data + 68, 0);
775 if (slen > 24) {
776 return NT_STATUS_INFO_LENGTH_MISMATCH;
778 ret = pull_string_talloc(finfo,
779 dir_data,
780 FLAGS2_UNICODE_STRINGS,
781 &finfo->short_name,
782 dir_data + 70,
783 slen,
784 STR_UNICODE);
785 if (ret == (size_t)-1) {
786 /* Bad conversion. */
787 return NT_STATUS_INVALID_NETWORK_RESPONSE;
790 ret = pull_string_talloc(finfo,
791 dir_data,
792 FLAGS2_UNICODE_STRINGS,
793 &finfo->name,
794 dir_data + 104,
795 namelen,
796 STR_UNICODE);
797 if (ret == (size_t)-1) {
798 /* Bad conversion. */
799 return NT_STATUS_INVALID_NETWORK_RESPONSE;
801 return NT_STATUS_OK;
804 /*******************************************************************
805 Given a filename - get its directory name
806 ********************************************************************/
808 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
809 const char *dir,
810 char **parent,
811 const char **name)
813 char *p;
814 ptrdiff_t len;
816 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
818 if (p == NULL) {
819 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
820 return false;
822 if (name) {
823 *name = dir;
825 return true;
828 len = p-dir;
830 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
831 return false;
833 (*parent)[len] = '\0';
835 if (name) {
836 *name = p+1;
838 return true;
841 /***************************************************************
842 Wrapper that allows SMB2 to list a directory.
843 Synchronous only.
844 ***************************************************************/
846 NTSTATUS cli_smb2_list(struct cli_state *cli,
847 const char *pathname,
848 uint16_t attribute,
849 NTSTATUS (*fn)(const char *,
850 struct file_info *,
851 const char *,
852 void *),
853 void *state)
855 NTSTATUS status;
856 uint16_t fnum = 0xffff;
857 char *parent_dir = NULL;
858 const char *mask = NULL;
859 struct smb2_hnd *ph = NULL;
860 bool processed_file = false;
861 TALLOC_CTX *frame = talloc_stackframe();
862 TALLOC_CTX *subframe = NULL;
863 bool mask_has_wild;
865 if (smbXcli_conn_has_async_calls(cli->conn)) {
867 * Can't use sync call while an async call is in flight
869 status = NT_STATUS_INVALID_PARAMETER;
870 goto fail;
873 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
874 status = NT_STATUS_INVALID_PARAMETER;
875 goto fail;
878 /* Get the directory name. */
879 if (!windows_parent_dirname(frame,
880 pathname,
881 &parent_dir,
882 &mask)) {
883 status = NT_STATUS_NO_MEMORY;
884 goto fail;
887 mask_has_wild = ms_has_wild(mask);
889 status = cli_smb2_create_fnum(cli,
890 parent_dir,
891 0, /* create_flags */
892 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
893 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
894 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
895 FILE_OPEN, /* create_disposition */
896 FILE_DIRECTORY_FILE, /* create_options */
897 &fnum,
898 NULL);
900 if (!NT_STATUS_IS_OK(status)) {
901 goto fail;
904 status = map_fnum_to_smb2_handle(cli,
905 fnum,
906 &ph);
907 if (!NT_STATUS_IS_OK(status)) {
908 goto fail;
911 do {
912 uint8_t *dir_data = NULL;
913 uint32_t dir_data_length = 0;
914 uint32_t next_offset = 0;
915 subframe = talloc_stackframe();
917 status = smb2cli_query_directory(cli->conn,
918 cli->timeout,
919 cli->smb2.session,
920 cli->smb2.tcon,
921 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
922 0, /* flags */
923 0, /* file_index */
924 ph->fid_persistent,
925 ph->fid_volatile,
926 mask,
927 0xffff,
928 subframe,
929 &dir_data,
930 &dir_data_length);
932 if (!NT_STATUS_IS_OK(status)) {
933 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
934 break;
936 goto fail;
939 do {
940 struct file_info *finfo = talloc_zero(subframe,
941 struct file_info);
943 if (finfo == NULL) {
944 status = NT_STATUS_NO_MEMORY;
945 goto fail;
948 status = parse_finfo_id_both_directory_info(dir_data,
949 dir_data_length,
950 finfo,
951 &next_offset);
953 if (!NT_STATUS_IS_OK(status)) {
954 goto fail;
957 if (dir_check_ftype((uint32_t)finfo->mode,
958 (uint32_t)attribute)) {
960 * Only process if attributes match.
961 * On SMB1 server does this, so on
962 * SMB2 we need to emulate in the
963 * client.
965 * https://bugzilla.samba.org/show_bug.cgi?id=10260
967 processed_file = true;
969 status = fn(cli->dfs_mountpoint,
970 finfo,
971 pathname,
972 state);
974 if (!NT_STATUS_IS_OK(status)) {
975 break;
979 TALLOC_FREE(finfo);
981 /* Move to next entry. */
982 if (next_offset) {
983 dir_data += next_offset;
984 dir_data_length -= next_offset;
986 } while (next_offset != 0);
988 TALLOC_FREE(subframe);
990 if (!mask_has_wild) {
992 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
993 * when handed a non-wildcard path. Do it
994 * for the server (with a non-wildcard path
995 * there should only ever be one file returned.
997 status = STATUS_NO_MORE_FILES;
998 break;
1001 } while (NT_STATUS_IS_OK(status));
1003 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1004 status = NT_STATUS_OK;
1007 if (NT_STATUS_IS_OK(status) && !processed_file) {
1009 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1010 * if no files match. Emulate this in the client.
1012 status = NT_STATUS_NO_SUCH_FILE;
1015 fail:
1017 if (fnum != 0xffff) {
1018 cli_smb2_close_fnum(cli, fnum);
1021 cli->raw_status = status;
1023 TALLOC_FREE(subframe);
1024 TALLOC_FREE(frame);
1025 return status;
1028 /***************************************************************
1029 Wrapper that allows SMB2 to query a path info (basic level).
1030 Synchronous only.
1031 ***************************************************************/
1033 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1034 const char *name,
1035 SMB_STRUCT_STAT *sbuf,
1036 uint32_t *attributes)
1038 NTSTATUS status;
1039 struct smb_create_returns cr;
1040 uint16_t fnum = 0xffff;
1041 size_t namelen = strlen(name);
1043 if (smbXcli_conn_has_async_calls(cli->conn)) {
1045 * Can't use sync call while an async call is in flight
1047 return NT_STATUS_INVALID_PARAMETER;
1050 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1051 return NT_STATUS_INVALID_PARAMETER;
1054 /* SMB2 is pickier about pathnames. Ensure it doesn't
1055 end in a '\' */
1056 if (namelen > 0 && name[namelen-1] == '\\') {
1057 char *modname = talloc_strdup(talloc_tos(), name);
1058 modname[namelen-1] = '\0';
1059 name = modname;
1062 /* This is commonly used as a 'cd'. Try qpathinfo on
1063 a directory handle first. */
1065 status = cli_smb2_create_fnum(cli,
1066 name,
1067 0, /* create_flags */
1068 FILE_READ_ATTRIBUTES, /* desired_access */
1069 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1070 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1071 FILE_OPEN, /* create_disposition */
1072 FILE_DIRECTORY_FILE, /* create_options */
1073 &fnum,
1074 &cr);
1076 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1077 /* Maybe a file ? */
1078 status = cli_smb2_create_fnum(cli,
1079 name,
1080 0, /* create_flags */
1081 FILE_READ_ATTRIBUTES, /* desired_access */
1082 0, /* file attributes */
1083 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1084 FILE_OPEN, /* create_disposition */
1085 0, /* create_options */
1086 &fnum,
1087 &cr);
1090 if (!NT_STATUS_IS_OK(status)) {
1091 return status;
1094 status = cli_smb2_close_fnum(cli, fnum);
1096 ZERO_STRUCTP(sbuf);
1098 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1099 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1100 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1101 sbuf->st_ex_size = cr.end_of_file;
1102 *attributes = cr.file_attributes;
1104 return status;
1107 /***************************************************************
1108 Wrapper that allows SMB2 to check if a path is a directory.
1109 Synchronous only.
1110 ***************************************************************/
1112 NTSTATUS cli_smb2_chkpath(struct cli_state *cli,
1113 const char *name)
1115 NTSTATUS status;
1116 uint16_t fnum = 0xffff;
1118 if (smbXcli_conn_has_async_calls(cli->conn)) {
1120 * Can't use sync call while an async call is in flight
1122 return NT_STATUS_INVALID_PARAMETER;
1125 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1126 return NT_STATUS_INVALID_PARAMETER;
1129 /* Ensure this is a directory. */
1130 status = cli_smb2_create_fnum(cli,
1131 name,
1132 0, /* create_flags */
1133 FILE_READ_ATTRIBUTES, /* desired_access */
1134 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1135 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1136 FILE_OPEN, /* create_disposition */
1137 FILE_DIRECTORY_FILE, /* create_options */
1138 &fnum,
1139 NULL);
1141 if (!NT_STATUS_IS_OK(status)) {
1142 return status;
1145 return cli_smb2_close_fnum(cli, fnum);
1148 /***************************************************************
1149 Helper function for pathname operations.
1150 ***************************************************************/
1152 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1153 const char *name,
1154 uint32_t desired_access,
1155 uint16_t *pfnum)
1157 NTSTATUS status;
1158 size_t namelen = strlen(name);
1159 TALLOC_CTX *frame = talloc_stackframe();
1161 /* SMB2 is pickier about pathnames. Ensure it doesn't
1162 end in a '\' */
1163 if (namelen > 0 && name[namelen-1] == '\\') {
1164 char *modname = talloc_strdup(frame, name);
1165 if (modname == NULL) {
1166 status = NT_STATUS_NO_MEMORY;
1167 goto fail;
1169 modname[namelen-1] = '\0';
1170 name = modname;
1173 /* Try to open a file handle first. */
1174 status = cli_smb2_create_fnum(cli,
1175 name,
1176 0, /* create_flags */
1177 desired_access,
1178 0, /* file attributes */
1179 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1180 FILE_OPEN, /* create_disposition */
1181 0, /* create_options */
1182 pfnum,
1183 NULL);
1185 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1186 status = cli_smb2_create_fnum(cli,
1187 name,
1188 0, /* create_flags */
1189 desired_access,
1190 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1191 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1192 FILE_OPEN, /* create_disposition */
1193 FILE_DIRECTORY_FILE, /* create_options */
1194 pfnum,
1195 NULL);
1198 fail:
1200 TALLOC_FREE(frame);
1201 return status;
1204 /***************************************************************
1205 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1206 Synchronous only.
1207 ***************************************************************/
1209 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1210 const char *name,
1211 fstring alt_name)
1213 NTSTATUS status;
1214 DATA_BLOB outbuf = data_blob_null;
1215 uint16_t fnum = 0xffff;
1216 struct smb2_hnd *ph = NULL;
1217 uint32_t altnamelen = 0;
1218 TALLOC_CTX *frame = talloc_stackframe();
1220 if (smbXcli_conn_has_async_calls(cli->conn)) {
1222 * Can't use sync call while an async call is in flight
1224 status = NT_STATUS_INVALID_PARAMETER;
1225 goto fail;
1228 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1229 status = NT_STATUS_INVALID_PARAMETER;
1230 goto fail;
1233 status = get_fnum_from_path(cli,
1234 name,
1235 FILE_READ_ATTRIBUTES,
1236 &fnum);
1238 if (!NT_STATUS_IS_OK(status)) {
1239 goto fail;
1242 status = map_fnum_to_smb2_handle(cli,
1243 fnum,
1244 &ph);
1245 if (!NT_STATUS_IS_OK(status)) {
1246 goto fail;
1249 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1250 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1252 status = smb2cli_query_info(cli->conn,
1253 cli->timeout,
1254 cli->smb2.session,
1255 cli->smb2.tcon,
1256 1, /* in_info_type */
1257 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1258 0xFFFF, /* in_max_output_length */
1259 NULL, /* in_input_buffer */
1260 0, /* in_additional_info */
1261 0, /* in_flags */
1262 ph->fid_persistent,
1263 ph->fid_volatile,
1264 frame,
1265 &outbuf);
1267 if (!NT_STATUS_IS_OK(status)) {
1268 goto fail;
1271 /* Parse the reply. */
1272 if (outbuf.length < 4) {
1273 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1274 goto fail;
1277 altnamelen = IVAL(outbuf.data, 0);
1278 if (altnamelen > outbuf.length - 4) {
1279 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1280 goto fail;
1283 if (altnamelen > 0) {
1284 size_t ret = 0;
1285 char *short_name = NULL;
1286 ret = pull_string_talloc(frame,
1287 outbuf.data,
1288 FLAGS2_UNICODE_STRINGS,
1289 &short_name,
1290 outbuf.data + 4,
1291 altnamelen,
1292 STR_UNICODE);
1293 if (ret == (size_t)-1) {
1294 /* Bad conversion. */
1295 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1296 goto fail;
1299 fstrcpy(alt_name, short_name);
1300 } else {
1301 alt_name[0] = '\0';
1304 status = NT_STATUS_OK;
1306 fail:
1308 if (fnum != 0xffff) {
1309 cli_smb2_close_fnum(cli, fnum);
1312 cli->raw_status = status;
1314 TALLOC_FREE(frame);
1315 return status;
1319 /***************************************************************
1320 Wrapper that allows SMB2 to query a fnum info (basic level).
1321 Synchronous only.
1322 ***************************************************************/
1324 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1325 uint16_t fnum,
1326 uint16_t *mode,
1327 off_t *size,
1328 struct timespec *create_time,
1329 struct timespec *access_time,
1330 struct timespec *write_time,
1331 struct timespec *change_time,
1332 SMB_INO_T *ino)
1334 NTSTATUS status;
1335 DATA_BLOB outbuf = data_blob_null;
1336 struct smb2_hnd *ph = NULL;
1337 TALLOC_CTX *frame = talloc_stackframe();
1339 if (smbXcli_conn_has_async_calls(cli->conn)) {
1341 * Can't use sync call while an async call is in flight
1343 status = NT_STATUS_INVALID_PARAMETER;
1344 goto fail;
1347 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1348 status = NT_STATUS_INVALID_PARAMETER;
1349 goto fail;
1352 status = map_fnum_to_smb2_handle(cli,
1353 fnum,
1354 &ph);
1355 if (!NT_STATUS_IS_OK(status)) {
1356 goto fail;
1359 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1360 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1362 status = smb2cli_query_info(cli->conn,
1363 cli->timeout,
1364 cli->smb2.session,
1365 cli->smb2.tcon,
1366 1, /* in_info_type */
1367 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1368 0xFFFF, /* in_max_output_length */
1369 NULL, /* in_input_buffer */
1370 0, /* in_additional_info */
1371 0, /* in_flags */
1372 ph->fid_persistent,
1373 ph->fid_volatile,
1374 frame,
1375 &outbuf);
1376 if (!NT_STATUS_IS_OK(status)) {
1377 goto fail;
1380 /* Parse the reply. */
1381 if (outbuf.length < 0x60) {
1382 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1383 goto fail;
1386 if (create_time) {
1387 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1389 if (access_time) {
1390 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1392 if (write_time) {
1393 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1395 if (change_time) {
1396 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1398 if (mode) {
1399 uint32_t attr = IVAL(outbuf.data, 0x20);
1400 *mode = (uint16_t)attr;
1402 if (size) {
1403 uint64_t file_size = BVAL(outbuf.data, 0x30);
1404 *size = (off_t)file_size;
1406 if (ino) {
1407 uint64_t file_index = BVAL(outbuf.data, 0x40);
1408 *ino = (SMB_INO_T)file_index;
1411 fail:
1413 cli->raw_status = status;
1415 TALLOC_FREE(frame);
1416 return status;
1419 /***************************************************************
1420 Wrapper that allows SMB2 to query an fnum.
1421 Implement on top of cli_smb2_qfileinfo_basic().
1422 Synchronous only.
1423 ***************************************************************/
1425 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1426 uint16_t fnum,
1427 uint16_t *attr,
1428 off_t *size,
1429 time_t *change_time,
1430 time_t *access_time,
1431 time_t *write_time)
1433 struct timespec access_time_ts;
1434 struct timespec write_time_ts;
1435 struct timespec change_time_ts;
1436 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1437 fnum,
1438 attr,
1439 size,
1440 NULL,
1441 &access_time_ts,
1442 &write_time_ts,
1443 &change_time_ts,
1444 NULL);
1446 cli->raw_status = status;
1448 if (!NT_STATUS_IS_OK(status)) {
1449 return status;
1452 if (change_time) {
1453 *change_time = change_time_ts.tv_sec;
1455 if (access_time) {
1456 *access_time = access_time_ts.tv_sec;
1458 if (write_time) {
1459 *write_time = write_time_ts.tv_sec;
1461 return NT_STATUS_OK;
1464 /***************************************************************
1465 Wrapper that allows SMB2 to get pathname attributes.
1466 Synchronous only.
1467 ***************************************************************/
1469 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1470 const char *name,
1471 uint16_t *attr,
1472 off_t *size,
1473 time_t *write_time)
1475 NTSTATUS status;
1476 uint16_t fnum = 0xffff;
1477 struct smb2_hnd *ph = NULL;
1478 TALLOC_CTX *frame = talloc_stackframe();
1480 if (smbXcli_conn_has_async_calls(cli->conn)) {
1482 * Can't use sync call while an async call is in flight
1484 status = NT_STATUS_INVALID_PARAMETER;
1485 goto fail;
1488 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1489 status = NT_STATUS_INVALID_PARAMETER;
1490 goto fail;
1493 status = get_fnum_from_path(cli,
1494 name,
1495 FILE_READ_ATTRIBUTES,
1496 &fnum);
1498 if (!NT_STATUS_IS_OK(status)) {
1499 goto fail;
1502 status = map_fnum_to_smb2_handle(cli,
1503 fnum,
1504 &ph);
1505 if (!NT_STATUS_IS_OK(status)) {
1506 goto fail;
1508 status = cli_smb2_getattrE(cli,
1509 fnum,
1510 attr,
1511 size,
1512 NULL,
1513 NULL,
1514 write_time);
1515 if (!NT_STATUS_IS_OK(status)) {
1516 goto fail;
1519 fail:
1521 if (fnum != 0xffff) {
1522 cli_smb2_close_fnum(cli, fnum);
1525 cli->raw_status = status;
1527 TALLOC_FREE(frame);
1528 return status;
1531 /***************************************************************
1532 Wrapper that allows SMB2 to query a pathname info (basic level).
1533 Implement on top of cli_smb2_qfileinfo_basic().
1534 Synchronous only.
1535 ***************************************************************/
1537 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1538 const char *name,
1539 struct timespec *create_time,
1540 struct timespec *access_time,
1541 struct timespec *write_time,
1542 struct timespec *change_time,
1543 off_t *size,
1544 uint16_t *mode,
1545 SMB_INO_T *ino)
1547 NTSTATUS status;
1548 struct smb2_hnd *ph = NULL;
1549 uint16_t fnum = 0xffff;
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;
1581 status = cli_smb2_qfileinfo_basic(cli,
1582 fnum,
1583 mode,
1584 size,
1585 create_time,
1586 access_time,
1587 write_time,
1588 change_time,
1589 ino);
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 pathname streams.
1605 Synchronous only.
1606 ***************************************************************/
1608 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1609 const char *name,
1610 TALLOC_CTX *mem_ctx,
1611 unsigned int *pnum_streams,
1612 struct stream_struct **pstreams)
1614 NTSTATUS status;
1615 struct smb2_hnd *ph = NULL;
1616 uint16_t fnum = 0xffff;
1617 DATA_BLOB outbuf = data_blob_null;
1618 TALLOC_CTX *frame = talloc_stackframe();
1620 if (smbXcli_conn_has_async_calls(cli->conn)) {
1622 * Can't use sync call while an async call is in flight
1624 status = NT_STATUS_INVALID_PARAMETER;
1625 goto fail;
1628 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1629 status = NT_STATUS_INVALID_PARAMETER;
1630 goto fail;
1633 status = get_fnum_from_path(cli,
1634 name,
1635 FILE_READ_ATTRIBUTES,
1636 &fnum);
1638 if (!NT_STATUS_IS_OK(status)) {
1639 goto fail;
1642 status = map_fnum_to_smb2_handle(cli,
1643 fnum,
1644 &ph);
1645 if (!NT_STATUS_IS_OK(status)) {
1646 goto fail;
1649 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1650 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1652 status = smb2cli_query_info(cli->conn,
1653 cli->timeout,
1654 cli->smb2.session,
1655 cli->smb2.tcon,
1656 1, /* in_info_type */
1657 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1658 0xFFFF, /* in_max_output_length */
1659 NULL, /* in_input_buffer */
1660 0, /* in_additional_info */
1661 0, /* in_flags */
1662 ph->fid_persistent,
1663 ph->fid_volatile,
1664 frame,
1665 &outbuf);
1667 if (!NT_STATUS_IS_OK(status)) {
1668 goto fail;
1671 /* Parse the reply. */
1672 if (!parse_streams_blob(mem_ctx,
1673 outbuf.data,
1674 outbuf.length,
1675 pnum_streams,
1676 pstreams)) {
1677 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1678 goto fail;
1681 fail:
1683 if (fnum != 0xffff) {
1684 cli_smb2_close_fnum(cli, fnum);
1687 cli->raw_status = status;
1689 TALLOC_FREE(frame);
1690 return status;
1693 /***************************************************************
1694 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
1695 a pathname.
1696 Synchronous only.
1697 ***************************************************************/
1699 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
1700 const char *name,
1701 uint8_t in_info_type,
1702 uint8_t in_file_info_class,
1703 const DATA_BLOB *p_in_data)
1705 NTSTATUS status;
1706 uint16_t fnum = 0xffff;
1707 struct smb2_hnd *ph = NULL;
1708 TALLOC_CTX *frame = talloc_stackframe();
1710 if (smbXcli_conn_has_async_calls(cli->conn)) {
1712 * Can't use sync call while an async call is in flight
1714 status = NT_STATUS_INVALID_PARAMETER;
1715 goto fail;
1718 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1719 status = NT_STATUS_INVALID_PARAMETER;
1720 goto fail;
1723 status = get_fnum_from_path(cli,
1724 name,
1725 FILE_WRITE_ATTRIBUTES,
1726 &fnum);
1728 if (!NT_STATUS_IS_OK(status)) {
1729 goto fail;
1732 status = map_fnum_to_smb2_handle(cli,
1733 fnum,
1734 &ph);
1735 if (!NT_STATUS_IS_OK(status)) {
1736 goto fail;
1739 status = smb2cli_set_info(cli->conn,
1740 cli->timeout,
1741 cli->smb2.session,
1742 cli->smb2.tcon,
1743 in_info_type,
1744 in_file_info_class,
1745 p_in_data, /* in_input_buffer */
1746 0, /* in_additional_info */
1747 ph->fid_persistent,
1748 ph->fid_volatile);
1749 fail:
1751 if (fnum != 0xffff) {
1752 cli_smb2_close_fnum(cli, fnum);
1755 cli->raw_status = status;
1757 TALLOC_FREE(frame);
1758 return status;
1762 /***************************************************************
1763 Wrapper that allows SMB2 to set pathname attributes.
1764 Synchronous only.
1765 ***************************************************************/
1767 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1768 const char *name,
1769 uint16_t attr,
1770 time_t mtime)
1772 uint8_t inbuf_store[40];
1773 DATA_BLOB inbuf = data_blob_null;
1775 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1776 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1778 inbuf.data = inbuf_store;
1779 inbuf.length = sizeof(inbuf_store);
1780 data_blob_clear(&inbuf);
1783 * SMB1 uses attr == 0 to clear all attributes
1784 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
1785 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
1786 * request attribute change.
1788 * SMB2 uses exactly the reverse. Unfortunately as the
1789 * cli_setatr() ABI is exposed inside libsmbclient,
1790 * we must make the SMB2 cli_smb2_setatr() call
1791 * export the same ABI as the SMB1 cli_setatr()
1792 * which calls it. This means reversing the sense
1793 * of the requested attr argument if it's zero
1794 * or FILE_ATTRIBUTE_NORMAL.
1796 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
1799 if (attr == 0) {
1800 attr = FILE_ATTRIBUTE_NORMAL;
1801 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
1802 attr = 0;
1805 SSVAL(inbuf.data, 32, attr);
1806 if (mtime != 0) {
1807 put_long_date((char *)inbuf.data + 16,mtime);
1809 /* Set all the other times to -1. */
1810 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1811 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1812 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1814 return cli_smb2_setpathinfo(cli,
1815 name,
1816 1, /* in_info_type */
1817 /* in_file_info_class */
1818 SMB_FILE_BASIC_INFORMATION - 1000,
1819 &inbuf);
1823 /***************************************************************
1824 Wrapper that allows SMB2 to set file handle times.
1825 Synchronous only.
1826 ***************************************************************/
1828 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1829 uint16_t fnum,
1830 time_t change_time,
1831 time_t access_time,
1832 time_t write_time)
1834 NTSTATUS status;
1835 struct smb2_hnd *ph = NULL;
1836 uint8_t inbuf_store[40];
1837 DATA_BLOB inbuf = data_blob_null;
1839 if (smbXcli_conn_has_async_calls(cli->conn)) {
1841 * Can't use sync call while an async call is in flight
1843 return NT_STATUS_INVALID_PARAMETER;
1846 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1847 return NT_STATUS_INVALID_PARAMETER;
1850 status = map_fnum_to_smb2_handle(cli,
1851 fnum,
1852 &ph);
1853 if (!NT_STATUS_IS_OK(status)) {
1854 return status;
1857 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1858 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1860 inbuf.data = inbuf_store;
1861 inbuf.length = sizeof(inbuf_store);
1862 data_blob_clear(&inbuf);
1864 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1865 if (change_time != 0) {
1866 put_long_date((char *)inbuf.data + 24, change_time);
1868 if (access_time != 0) {
1869 put_long_date((char *)inbuf.data + 8, access_time);
1871 if (write_time != 0) {
1872 put_long_date((char *)inbuf.data + 16, write_time);
1875 cli->raw_status = smb2cli_set_info(cli->conn,
1876 cli->timeout,
1877 cli->smb2.session,
1878 cli->smb2.tcon,
1879 1, /* in_info_type */
1880 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1881 &inbuf, /* in_input_buffer */
1882 0, /* in_additional_info */
1883 ph->fid_persistent,
1884 ph->fid_volatile);
1886 return cli->raw_status;
1889 /***************************************************************
1890 Wrapper that allows SMB2 to query disk attributes (size).
1891 Synchronous only.
1892 ***************************************************************/
1894 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
1895 uint64_t *bsize, uint64_t *total, uint64_t *avail)
1897 NTSTATUS status;
1898 uint16_t fnum = 0xffff;
1899 DATA_BLOB outbuf = data_blob_null;
1900 struct smb2_hnd *ph = NULL;
1901 uint32_t sectors_per_unit = 0;
1902 uint32_t bytes_per_sector = 0;
1903 uint64_t total_size = 0;
1904 uint64_t size_free = 0;
1905 TALLOC_CTX *frame = talloc_stackframe();
1907 if (smbXcli_conn_has_async_calls(cli->conn)) {
1909 * Can't use sync call while an async call is in flight
1911 status = NT_STATUS_INVALID_PARAMETER;
1912 goto fail;
1915 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1916 status = NT_STATUS_INVALID_PARAMETER;
1917 goto fail;
1920 /* First open the top level directory. */
1921 status = cli_smb2_create_fnum(cli,
1922 path,
1923 0, /* create_flags */
1924 FILE_READ_ATTRIBUTES, /* desired_access */
1925 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1926 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1927 FILE_OPEN, /* create_disposition */
1928 FILE_DIRECTORY_FILE, /* create_options */
1929 &fnum,
1930 NULL);
1932 if (!NT_STATUS_IS_OK(status)) {
1933 goto fail;
1936 status = map_fnum_to_smb2_handle(cli,
1937 fnum,
1938 &ph);
1939 if (!NT_STATUS_IS_OK(status)) {
1940 goto fail;
1943 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1944 level 3 (SMB_FS_SIZE_INFORMATION). */
1946 status = smb2cli_query_info(cli->conn,
1947 cli->timeout,
1948 cli->smb2.session,
1949 cli->smb2.tcon,
1950 2, /* in_info_type */
1951 3, /* in_file_info_class */
1952 0xFFFF, /* in_max_output_length */
1953 NULL, /* in_input_buffer */
1954 0, /* in_additional_info */
1955 0, /* in_flags */
1956 ph->fid_persistent,
1957 ph->fid_volatile,
1958 frame,
1959 &outbuf);
1960 if (!NT_STATUS_IS_OK(status)) {
1961 goto fail;
1964 /* Parse the reply. */
1965 if (outbuf.length != 24) {
1966 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1967 goto fail;
1970 total_size = BVAL(outbuf.data, 0);
1971 size_free = BVAL(outbuf.data, 8);
1972 sectors_per_unit = IVAL(outbuf.data, 16);
1973 bytes_per_sector = IVAL(outbuf.data, 20);
1975 if (bsize) {
1976 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
1978 if (total) {
1979 *total = total_size;
1981 if (avail) {
1982 *avail = size_free;
1985 status = NT_STATUS_OK;
1987 fail:
1989 if (fnum != 0xffff) {
1990 cli_smb2_close_fnum(cli, fnum);
1993 cli->raw_status = status;
1995 TALLOC_FREE(frame);
1996 return status;
1999 /***************************************************************
2000 Wrapper that allows SMB2 to query file system sizes.
2001 Synchronous only.
2002 ***************************************************************/
2004 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2005 uint64_t *total_allocation_units,
2006 uint64_t *caller_allocation_units,
2007 uint64_t *actual_allocation_units,
2008 uint64_t *sectors_per_allocation_unit,
2009 uint64_t *bytes_per_sector)
2011 NTSTATUS status;
2012 uint16_t fnum = 0xffff;
2013 DATA_BLOB outbuf = data_blob_null;
2014 struct smb2_hnd *ph = NULL;
2015 TALLOC_CTX *frame = talloc_stackframe();
2017 if (smbXcli_conn_has_async_calls(cli->conn)) {
2019 * Can't use sync call while an async call is in flight
2021 status = NT_STATUS_INVALID_PARAMETER;
2022 goto fail;
2025 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2026 status = NT_STATUS_INVALID_PARAMETER;
2027 goto fail;
2030 /* First open the top level directory. */
2031 status =
2032 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2033 FILE_READ_ATTRIBUTES, /* desired_access */
2034 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2035 FILE_SHARE_READ | FILE_SHARE_WRITE |
2036 FILE_SHARE_DELETE, /* share_access */
2037 FILE_OPEN, /* create_disposition */
2038 FILE_DIRECTORY_FILE, /* create_options */
2039 &fnum,
2040 NULL);
2042 if (!NT_STATUS_IS_OK(status)) {
2043 goto fail;
2046 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2047 if (!NT_STATUS_IS_OK(status)) {
2048 goto fail;
2051 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2052 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2054 status = smb2cli_query_info(cli->conn,
2055 cli->timeout,
2056 cli->smb2.session,
2057 cli->smb2.tcon,
2058 SMB2_GETINFO_FS, /* in_info_type */
2059 /* in_file_info_class */
2060 SMB_FS_FULL_SIZE_INFORMATION - 1000,
2061 0xFFFF, /* in_max_output_length */
2062 NULL, /* in_input_buffer */
2063 0, /* in_additional_info */
2064 0, /* in_flags */
2065 ph->fid_persistent,
2066 ph->fid_volatile,
2067 frame,
2068 &outbuf);
2069 if (!NT_STATUS_IS_OK(status)) {
2070 goto fail;
2073 if (outbuf.length < 32) {
2074 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2075 goto fail;
2078 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2079 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2080 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2081 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2082 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2084 fail:
2086 if (fnum != 0xffff) {
2087 cli_smb2_close_fnum(cli, fnum);
2090 cli->raw_status = status;
2092 TALLOC_FREE(frame);
2093 return status;
2096 /***************************************************************
2097 Wrapper that allows SMB2 to query file system attributes.
2098 Synchronous only.
2099 ***************************************************************/
2101 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2103 NTSTATUS status;
2104 uint16_t fnum = 0xffff;
2105 DATA_BLOB outbuf = data_blob_null;
2106 struct smb2_hnd *ph = NULL;
2107 TALLOC_CTX *frame = talloc_stackframe();
2109 if (smbXcli_conn_has_async_calls(cli->conn)) {
2111 * Can't use sync call while an async call is in flight
2113 status = NT_STATUS_INVALID_PARAMETER;
2114 goto fail;
2117 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2118 status = NT_STATUS_INVALID_PARAMETER;
2119 goto fail;
2122 /* First open the top level directory. */
2123 status =
2124 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2125 FILE_READ_ATTRIBUTES, /* desired_access */
2126 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2127 FILE_SHARE_READ | FILE_SHARE_WRITE |
2128 FILE_SHARE_DELETE, /* share_access */
2129 FILE_OPEN, /* create_disposition */
2130 FILE_DIRECTORY_FILE, /* create_options */
2131 &fnum,
2132 NULL);
2134 if (!NT_STATUS_IS_OK(status)) {
2135 goto fail;
2138 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2139 if (!NT_STATUS_IS_OK(status)) {
2140 goto fail;
2143 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2144 cli->smb2.tcon, 2, /* in_info_type */
2145 5, /* in_file_info_class */
2146 0xFFFF, /* in_max_output_length */
2147 NULL, /* in_input_buffer */
2148 0, /* in_additional_info */
2149 0, /* in_flags */
2150 ph->fid_persistent, ph->fid_volatile, frame,
2151 &outbuf);
2152 if (!NT_STATUS_IS_OK(status)) {
2153 goto fail;
2156 if (outbuf.length < 12) {
2157 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2158 goto fail;
2161 *fs_attr = IVAL(outbuf.data, 0);
2163 fail:
2165 if (fnum != 0xffff) {
2166 cli_smb2_close_fnum(cli, fnum);
2169 cli->raw_status = status;
2171 TALLOC_FREE(frame);
2172 return status;
2175 /***************************************************************
2176 Wrapper that allows SMB2 to query file system volume info.
2177 Synchronous only.
2178 ***************************************************************/
2180 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2181 TALLOC_CTX *mem_ctx,
2182 char **_volume_name,
2183 uint32_t *pserial_number,
2184 time_t *pdate)
2186 NTSTATUS status;
2187 uint16_t fnum = 0xffff;
2188 DATA_BLOB outbuf = data_blob_null;
2189 struct smb2_hnd *ph = NULL;
2190 uint32_t nlen;
2191 char *volume_name = NULL;
2192 TALLOC_CTX *frame = talloc_stackframe();
2194 if (smbXcli_conn_has_async_calls(cli->conn)) {
2196 * Can't use sync call while an async call is in flight
2198 status = NT_STATUS_INVALID_PARAMETER;
2199 goto fail;
2202 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2203 status = NT_STATUS_INVALID_PARAMETER;
2204 goto fail;
2207 /* First open the top level directory. */
2208 status =
2209 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2210 FILE_READ_ATTRIBUTES, /* desired_access */
2211 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2212 FILE_SHARE_READ | FILE_SHARE_WRITE |
2213 FILE_SHARE_DELETE, /* share_access */
2214 FILE_OPEN, /* create_disposition */
2215 FILE_DIRECTORY_FILE, /* create_options */
2216 &fnum,
2217 NULL);
2219 if (!NT_STATUS_IS_OK(status)) {
2220 goto fail;
2223 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2224 if (!NT_STATUS_IS_OK(status)) {
2225 goto fail;
2228 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2229 level 1 (SMB_FS_VOLUME_INFORMATION). */
2231 status = smb2cli_query_info(cli->conn,
2232 cli->timeout,
2233 cli->smb2.session,
2234 cli->smb2.tcon,
2235 SMB2_GETINFO_FS, /* in_info_type */
2236 /* in_file_info_class */
2237 SMB_FS_VOLUME_INFORMATION - 1000,
2238 0xFFFF, /* in_max_output_length */
2239 NULL, /* in_input_buffer */
2240 0, /* in_additional_info */
2241 0, /* in_flags */
2242 ph->fid_persistent,
2243 ph->fid_volatile,
2244 frame,
2245 &outbuf);
2246 if (!NT_STATUS_IS_OK(status)) {
2247 goto fail;
2250 if (outbuf.length < 24) {
2251 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2252 goto fail;
2255 if (pdate) {
2256 struct timespec ts;
2257 ts = interpret_long_date((char *)outbuf.data);
2258 *pdate = ts.tv_sec;
2260 if (pserial_number) {
2261 *pserial_number = IVAL(outbuf.data,8);
2263 nlen = IVAL(outbuf.data,12);
2264 if (nlen + 18 < 18) {
2265 /* Integer wrap. */
2266 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2267 goto fail;
2270 * The next check is safe as we know outbuf.length >= 24
2271 * from above.
2273 if (nlen > (outbuf.length - 18)) {
2274 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2275 goto fail;
2278 clistr_pull_talloc(mem_ctx,
2279 (const char *)outbuf.data,
2281 &volume_name,
2282 outbuf.data + 18,
2283 nlen,
2284 STR_UNICODE);
2285 if (volume_name == NULL) {
2286 status = map_nt_error_from_unix(errno);
2287 goto fail;
2290 *_volume_name = volume_name;
2292 fail:
2294 if (fnum != 0xffff) {
2295 cli_smb2_close_fnum(cli, fnum);
2298 cli->raw_status = status;
2300 TALLOC_FREE(frame);
2301 return status;
2305 /***************************************************************
2306 Wrapper that allows SMB2 to query a security descriptor.
2307 Synchronous only.
2308 ***************************************************************/
2310 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2311 uint16_t fnum,
2312 uint32_t sec_info,
2313 TALLOC_CTX *mem_ctx,
2314 struct security_descriptor **ppsd)
2316 NTSTATUS status;
2317 DATA_BLOB outbuf = data_blob_null;
2318 struct smb2_hnd *ph = NULL;
2319 struct security_descriptor *lsd = NULL;
2320 TALLOC_CTX *frame = talloc_stackframe();
2322 if (smbXcli_conn_has_async_calls(cli->conn)) {
2324 * Can't use sync call while an async call is in flight
2326 status = NT_STATUS_INVALID_PARAMETER;
2327 goto fail;
2330 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2331 status = NT_STATUS_INVALID_PARAMETER;
2332 goto fail;
2335 status = map_fnum_to_smb2_handle(cli,
2336 fnum,
2337 &ph);
2338 if (!NT_STATUS_IS_OK(status)) {
2339 goto fail;
2342 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2344 status = smb2cli_query_info(cli->conn,
2345 cli->timeout,
2346 cli->smb2.session,
2347 cli->smb2.tcon,
2348 3, /* in_info_type */
2349 0, /* in_file_info_class */
2350 0xFFFF, /* in_max_output_length */
2351 NULL, /* in_input_buffer */
2352 sec_info, /* in_additional_info */
2353 0, /* in_flags */
2354 ph->fid_persistent,
2355 ph->fid_volatile,
2356 frame,
2357 &outbuf);
2359 if (!NT_STATUS_IS_OK(status)) {
2360 goto fail;
2363 /* Parse the reply. */
2364 status = unmarshall_sec_desc(mem_ctx,
2365 outbuf.data,
2366 outbuf.length,
2367 &lsd);
2369 if (!NT_STATUS_IS_OK(status)) {
2370 goto fail;
2373 if (ppsd != NULL) {
2374 *ppsd = lsd;
2375 } else {
2376 TALLOC_FREE(lsd);
2379 fail:
2381 cli->raw_status = status;
2383 TALLOC_FREE(frame);
2384 return status;
2387 /***************************************************************
2388 Wrapper that allows SMB2 to set a security descriptor.
2389 Synchronous only.
2390 ***************************************************************/
2392 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
2393 uint16_t fnum,
2394 uint32_t sec_info,
2395 const struct security_descriptor *sd)
2397 NTSTATUS status;
2398 DATA_BLOB inbuf = data_blob_null;
2399 struct smb2_hnd *ph = NULL;
2400 TALLOC_CTX *frame = talloc_stackframe();
2402 if (smbXcli_conn_has_async_calls(cli->conn)) {
2404 * Can't use sync call while an async call is in flight
2406 status = NT_STATUS_INVALID_PARAMETER;
2407 goto fail;
2410 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2411 status = NT_STATUS_INVALID_PARAMETER;
2412 goto fail;
2415 status = map_fnum_to_smb2_handle(cli,
2416 fnum,
2417 &ph);
2418 if (!NT_STATUS_IS_OK(status)) {
2419 goto fail;
2422 status = marshall_sec_desc(frame,
2424 &inbuf.data,
2425 &inbuf.length);
2427 if (!NT_STATUS_IS_OK(status)) {
2428 goto fail;
2431 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2433 status = smb2cli_set_info(cli->conn,
2434 cli->timeout,
2435 cli->smb2.session,
2436 cli->smb2.tcon,
2437 3, /* in_info_type */
2438 0, /* in_file_info_class */
2439 &inbuf, /* in_input_buffer */
2440 sec_info, /* in_additional_info */
2441 ph->fid_persistent,
2442 ph->fid_volatile);
2444 fail:
2446 cli->raw_status = status;
2448 TALLOC_FREE(frame);
2449 return status;
2452 /***************************************************************
2453 Wrapper that allows SMB2 to rename a file.
2454 Synchronous only.
2455 ***************************************************************/
2457 NTSTATUS cli_smb2_rename(struct cli_state *cli,
2458 const char *fname_src,
2459 const char *fname_dst,
2460 bool replace)
2462 NTSTATUS status;
2463 DATA_BLOB inbuf = data_blob_null;
2464 uint16_t fnum = 0xffff;
2465 struct smb2_hnd *ph = NULL;
2466 smb_ucs2_t *converted_str = NULL;
2467 size_t converted_size_bytes = 0;
2468 size_t namelen = 0;
2469 TALLOC_CTX *frame = talloc_stackframe();
2471 if (smbXcli_conn_has_async_calls(cli->conn)) {
2473 * Can't use sync call while an async call is in flight
2475 status = NT_STATUS_INVALID_PARAMETER;
2476 goto fail;
2479 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2480 status = NT_STATUS_INVALID_PARAMETER;
2481 goto fail;
2484 status = get_fnum_from_path(cli,
2485 fname_src,
2486 DELETE_ACCESS,
2487 &fnum);
2489 if (!NT_STATUS_IS_OK(status)) {
2490 goto fail;
2493 status = map_fnum_to_smb2_handle(cli,
2494 fnum,
2495 &ph);
2496 if (!NT_STATUS_IS_OK(status)) {
2497 goto fail;
2500 /* SMB2 is pickier about pathnames. Ensure it doesn't
2501 start in a '\' */
2502 if (*fname_dst == '\\') {
2503 fname_dst++;
2506 /* SMB2 is pickier about pathnames. Ensure it doesn't
2507 end in a '\' */
2508 namelen = strlen(fname_dst);
2509 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2510 char *modname = talloc_strdup(frame, fname_dst);
2511 modname[namelen-1] = '\0';
2512 fname_dst = modname;
2515 if (!push_ucs2_talloc(frame,
2516 &converted_str,
2517 fname_dst,
2518 &converted_size_bytes)) {
2519 status = NT_STATUS_INVALID_PARAMETER;
2520 goto fail;
2523 /* W2K8 insists the dest name is not null
2524 terminated. Remove the last 2 zero bytes
2525 and reduce the name length. */
2527 if (converted_size_bytes < 2) {
2528 status = NT_STATUS_INVALID_PARAMETER;
2529 goto fail;
2531 converted_size_bytes -= 2;
2533 inbuf = data_blob_talloc_zero(frame,
2534 20 + converted_size_bytes);
2535 if (inbuf.data == NULL) {
2536 status = NT_STATUS_NO_MEMORY;
2537 goto fail;
2540 if (replace) {
2541 SCVAL(inbuf.data, 0, 1);
2544 SIVAL(inbuf.data, 16, converted_size_bytes);
2545 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2547 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2548 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2550 status = smb2cli_set_info(cli->conn,
2551 cli->timeout,
2552 cli->smb2.session,
2553 cli->smb2.tcon,
2554 1, /* in_info_type */
2555 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2556 &inbuf, /* in_input_buffer */
2557 0, /* in_additional_info */
2558 ph->fid_persistent,
2559 ph->fid_volatile);
2561 fail:
2563 if (fnum != 0xffff) {
2564 cli_smb2_close_fnum(cli, fnum);
2567 cli->raw_status = status;
2569 TALLOC_FREE(frame);
2570 return status;
2573 /***************************************************************
2574 Wrapper that allows SMB2 to set an EA on a fnum.
2575 Synchronous only.
2576 ***************************************************************/
2578 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2579 uint16_t fnum,
2580 const char *ea_name,
2581 const char *ea_val,
2582 size_t ea_len)
2584 NTSTATUS status;
2585 DATA_BLOB inbuf = data_blob_null;
2586 size_t bloblen = 0;
2587 char *ea_name_ascii = NULL;
2588 size_t namelen = 0;
2589 struct smb2_hnd *ph = NULL;
2590 TALLOC_CTX *frame = talloc_stackframe();
2592 if (smbXcli_conn_has_async_calls(cli->conn)) {
2594 * Can't use sync call while an async call is in flight
2596 status = NT_STATUS_INVALID_PARAMETER;
2597 goto fail;
2600 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2601 status = NT_STATUS_INVALID_PARAMETER;
2602 goto fail;
2605 status = map_fnum_to_smb2_handle(cli,
2606 fnum,
2607 &ph);
2608 if (!NT_STATUS_IS_OK(status)) {
2609 goto fail;
2612 /* Marshall the SMB2 EA data. */
2613 if (ea_len > 0xFFFF) {
2614 status = NT_STATUS_INVALID_PARAMETER;
2615 goto fail;
2618 if (!push_ascii_talloc(frame,
2619 &ea_name_ascii,
2620 ea_name,
2621 &namelen)) {
2622 status = NT_STATUS_INVALID_PARAMETER;
2623 goto fail;
2626 if (namelen < 2 || namelen > 0xFF) {
2627 status = NT_STATUS_INVALID_PARAMETER;
2628 goto fail;
2631 bloblen = 8 + ea_len + namelen;
2632 /* Round up to a 4 byte boundary. */
2633 bloblen = ((bloblen + 3)&~3);
2635 inbuf = data_blob_talloc_zero(frame, bloblen);
2636 if (inbuf.data == NULL) {
2637 status = NT_STATUS_NO_MEMORY;
2638 goto fail;
2640 /* namelen doesn't include the NULL byte. */
2641 SCVAL(inbuf.data, 5, namelen - 1);
2642 SSVAL(inbuf.data, 6, ea_len);
2643 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2644 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2646 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2647 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2649 status = smb2cli_set_info(cli->conn,
2650 cli->timeout,
2651 cli->smb2.session,
2652 cli->smb2.tcon,
2653 1, /* in_info_type */
2654 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2655 &inbuf, /* in_input_buffer */
2656 0, /* in_additional_info */
2657 ph->fid_persistent,
2658 ph->fid_volatile);
2660 fail:
2662 cli->raw_status = status;
2664 TALLOC_FREE(frame);
2665 return status;
2668 /***************************************************************
2669 Wrapper that allows SMB2 to set an EA on a pathname.
2670 Synchronous only.
2671 ***************************************************************/
2673 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2674 const char *name,
2675 const char *ea_name,
2676 const char *ea_val,
2677 size_t ea_len)
2679 NTSTATUS status;
2680 uint16_t fnum = 0xffff;
2682 if (smbXcli_conn_has_async_calls(cli->conn)) {
2684 * Can't use sync call while an async call is in flight
2686 status = NT_STATUS_INVALID_PARAMETER;
2687 goto fail;
2690 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2691 status = NT_STATUS_INVALID_PARAMETER;
2692 goto fail;
2695 status = get_fnum_from_path(cli,
2696 name,
2697 FILE_WRITE_EA,
2698 &fnum);
2700 if (!NT_STATUS_IS_OK(status)) {
2701 goto fail;
2704 status = cli_set_ea_fnum(cli,
2705 fnum,
2706 ea_name,
2707 ea_val,
2708 ea_len);
2709 if (!NT_STATUS_IS_OK(status)) {
2710 goto fail;
2713 fail:
2715 if (fnum != 0xffff) {
2716 cli_smb2_close_fnum(cli, fnum);
2719 cli->raw_status = status;
2721 return status;
2724 /***************************************************************
2725 Wrapper that allows SMB2 to get an EA list on a pathname.
2726 Synchronous only.
2727 ***************************************************************/
2729 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2730 const char *name,
2731 TALLOC_CTX *ctx,
2732 size_t *pnum_eas,
2733 struct ea_struct **pea_array)
2735 NTSTATUS status;
2736 uint16_t fnum = 0xffff;
2737 DATA_BLOB outbuf = data_blob_null;
2738 struct smb2_hnd *ph = NULL;
2739 struct ea_list *ea_list = NULL;
2740 struct ea_list *eal = NULL;
2741 size_t ea_count = 0;
2742 TALLOC_CTX *frame = talloc_stackframe();
2744 *pnum_eas = 0;
2745 *pea_array = NULL;
2747 if (smbXcli_conn_has_async_calls(cli->conn)) {
2749 * Can't use sync call while an async call is in flight
2751 status = NT_STATUS_INVALID_PARAMETER;
2752 goto fail;
2755 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2756 status = NT_STATUS_INVALID_PARAMETER;
2757 goto fail;
2760 status = get_fnum_from_path(cli,
2761 name,
2762 FILE_READ_EA,
2763 &fnum);
2765 if (!NT_STATUS_IS_OK(status)) {
2766 goto fail;
2769 status = map_fnum_to_smb2_handle(cli,
2770 fnum,
2771 &ph);
2772 if (!NT_STATUS_IS_OK(status)) {
2773 goto fail;
2776 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2777 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2779 status = smb2cli_query_info(cli->conn,
2780 cli->timeout,
2781 cli->smb2.session,
2782 cli->smb2.tcon,
2783 1, /* in_info_type */
2784 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2785 0xFFFF, /* in_max_output_length */
2786 NULL, /* in_input_buffer */
2787 0, /* in_additional_info */
2788 0, /* in_flags */
2789 ph->fid_persistent,
2790 ph->fid_volatile,
2791 frame,
2792 &outbuf);
2794 if (!NT_STATUS_IS_OK(status)) {
2795 goto fail;
2798 /* Parse the reply. */
2799 ea_list = read_nttrans_ea_list(ctx,
2800 (const char *)outbuf.data,
2801 outbuf.length);
2802 if (ea_list == NULL) {
2803 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2804 goto fail;
2807 /* Convert to an array. */
2808 for (eal = ea_list; eal; eal = eal->next) {
2809 ea_count++;
2812 if (ea_count) {
2813 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2814 if (*pea_array == NULL) {
2815 status = NT_STATUS_NO_MEMORY;
2816 goto fail;
2818 ea_count = 0;
2819 for (eal = ea_list; eal; eal = eal->next) {
2820 (*pea_array)[ea_count++] = eal->ea;
2822 *pnum_eas = ea_count;
2825 fail:
2827 if (fnum != 0xffff) {
2828 cli_smb2_close_fnum(cli, fnum);
2831 cli->raw_status = status;
2833 TALLOC_FREE(frame);
2834 return status;
2837 /***************************************************************
2838 Wrapper that allows SMB2 to get user quota.
2839 Synchronous only.
2840 ***************************************************************/
2842 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
2843 int quota_fnum,
2844 SMB_NTQUOTA_STRUCT *pqt)
2846 NTSTATUS status;
2847 DATA_BLOB inbuf = data_blob_null;
2848 DATA_BLOB outbuf = data_blob_null;
2849 struct smb2_hnd *ph = NULL;
2850 TALLOC_CTX *frame = talloc_stackframe();
2851 unsigned sid_len;
2852 unsigned int offset;
2853 uint8_t *buf;
2855 if (smbXcli_conn_has_async_calls(cli->conn)) {
2857 * Can't use sync call while an async call is in flight
2859 status = NT_STATUS_INVALID_PARAMETER;
2860 goto fail;
2863 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2864 status = NT_STATUS_INVALID_PARAMETER;
2865 goto fail;
2868 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2869 if (!NT_STATUS_IS_OK(status)) {
2870 goto fail;
2873 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
2875 inbuf = data_blob_talloc_zero(frame, 24 + sid_len);
2876 if (inbuf.data == NULL) {
2877 status = NT_STATUS_NO_MEMORY;
2878 goto fail;
2881 buf = inbuf.data;
2883 SCVAL(buf, 0, 1); /* ReturnSingle */
2884 SCVAL(buf, 1, 0); /* RestartScan */
2885 SSVAL(buf, 2, 0); /* Reserved */
2886 if (8 + sid_len < 8) {
2887 status = NT_STATUS_INVALID_PARAMETER;
2888 goto fail;
2890 SIVAL(buf, 4, 8 + sid_len); /* SidListLength */
2891 SIVAL(buf, 8, 0); /* StartSidLength */
2892 SIVAL(buf, 12, 0); /* StartSidOffset */
2893 SIVAL(buf, 16, 0); /* NextEntryOffset */
2894 SIVAL(buf, 20, sid_len); /* SidLength */
2895 sid_linearize(buf + 24, sid_len, &pqt->sid);
2897 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2898 cli->smb2.tcon, 4, /* in_info_type */
2899 0, /* in_file_info_class */
2900 0xFFFF, /* in_max_output_length */
2901 &inbuf, /* in_input_buffer */
2902 0, /* in_additional_info */
2903 0, /* in_flags */
2904 ph->fid_persistent, ph->fid_volatile, frame,
2905 &outbuf);
2907 if (!NT_STATUS_IS_OK(status)) {
2908 goto fail;
2911 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
2912 pqt)) {
2913 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2914 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
2917 fail:
2918 cli->raw_status = status;
2920 TALLOC_FREE(frame);
2921 return status;
2924 /***************************************************************
2925 Wrapper that allows SMB2 to list user quota.
2926 Synchronous only.
2927 ***************************************************************/
2929 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
2930 TALLOC_CTX *mem_ctx,
2931 int quota_fnum,
2932 SMB_NTQUOTA_LIST **pqt_list,
2933 bool first)
2935 NTSTATUS status;
2936 DATA_BLOB inbuf = data_blob_null;
2937 DATA_BLOB outbuf = data_blob_null;
2938 struct smb2_hnd *ph = NULL;
2939 TALLOC_CTX *frame = talloc_stackframe();
2940 uint8_t *buf;
2942 if (smbXcli_conn_has_async_calls(cli->conn)) {
2944 * Can't use sync call while an async call is in flight
2946 status = NT_STATUS_INVALID_PARAMETER;
2947 goto cleanup;
2950 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2951 status = NT_STATUS_INVALID_PARAMETER;
2952 goto cleanup;
2955 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2956 if (!NT_STATUS_IS_OK(status)) {
2957 goto cleanup;
2960 inbuf = data_blob_talloc_zero(frame, 16);
2961 if (inbuf.data == NULL) {
2962 status = NT_STATUS_NO_MEMORY;
2963 goto cleanup;
2966 buf = inbuf.data;
2968 SCVAL(buf, 0, 0); /* ReturnSingle */
2969 SCVAL(buf, 1, first ? 1 : 0); /* RestartScan */
2970 SSVAL(buf, 2, 0); /* Reserved */
2971 SIVAL(buf, 4, 0); /* SidListLength */
2972 SIVAL(buf, 8, 0); /* StartSidLength */
2973 SIVAL(buf, 12, 0); /* StartSidOffset */
2975 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2976 cli->smb2.tcon, 4, /* in_info_type */
2977 0, /* in_file_info_class */
2978 0xFFFF, /* in_max_output_length */
2979 &inbuf, /* in_input_buffer */
2980 0, /* in_additional_info */
2981 0, /* in_flags */
2982 ph->fid_persistent, ph->fid_volatile, frame,
2983 &outbuf);
2985 if (!NT_STATUS_IS_OK(status)) {
2986 goto cleanup;
2989 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
2990 pqt_list);
2992 cleanup:
2993 cli->raw_status = status;
2995 TALLOC_FREE(frame);
2996 return status;
2999 /***************************************************************
3000 Wrapper that allows SMB2 to get file system quota.
3001 Synchronous only.
3002 ***************************************************************/
3004 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3005 int quota_fnum,
3006 SMB_NTQUOTA_STRUCT *pqt)
3008 NTSTATUS status;
3009 DATA_BLOB outbuf = data_blob_null;
3010 struct smb2_hnd *ph = NULL;
3011 TALLOC_CTX *frame = talloc_stackframe();
3013 if (smbXcli_conn_has_async_calls(cli->conn)) {
3015 * Can't use sync call while an async call is in flight
3017 status = NT_STATUS_INVALID_PARAMETER;
3018 goto cleanup;
3021 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3022 status = NT_STATUS_INVALID_PARAMETER;
3023 goto cleanup;
3026 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3027 if (!NT_STATUS_IS_OK(status)) {
3028 goto cleanup;
3031 status = smb2cli_query_info(
3032 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3033 2, /* in_info_type */
3034 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3035 0xFFFF, /* in_max_output_length */
3036 NULL, /* in_input_buffer */
3037 0, /* in_additional_info */
3038 0, /* in_flags */
3039 ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
3041 if (!NT_STATUS_IS_OK(status)) {
3042 goto cleanup;
3045 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3047 cleanup:
3048 cli->raw_status = status;
3050 TALLOC_FREE(frame);
3051 return status;
3054 /***************************************************************
3055 Wrapper that allows SMB2 to set user quota.
3056 Synchronous only.
3057 ***************************************************************/
3059 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3060 int quota_fnum,
3061 SMB_NTQUOTA_LIST *qtl)
3063 NTSTATUS status;
3064 DATA_BLOB inbuf = data_blob_null;
3065 struct smb2_hnd *ph = NULL;
3066 TALLOC_CTX *frame = talloc_stackframe();
3068 if (smbXcli_conn_has_async_calls(cli->conn)) {
3070 * Can't use sync call while an async call is in flight
3072 status = NT_STATUS_INVALID_PARAMETER;
3073 goto cleanup;
3076 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3077 status = NT_STATUS_INVALID_PARAMETER;
3078 goto cleanup;
3081 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3082 if (!NT_STATUS_IS_OK(status)) {
3083 goto cleanup;
3086 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3087 if (!NT_STATUS_IS_OK(status)) {
3088 goto cleanup;
3091 status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
3092 cli->smb2.tcon, 4, /* in_info_type */
3093 0, /* in_file_info_class */
3094 &inbuf, /* in_input_buffer */
3095 0, /* in_additional_info */
3096 ph->fid_persistent, ph->fid_volatile);
3097 cleanup:
3099 cli->raw_status = status;
3101 TALLOC_FREE(frame);
3103 return status;
3106 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3107 int quota_fnum,
3108 SMB_NTQUOTA_STRUCT *pqt)
3110 NTSTATUS status;
3111 DATA_BLOB inbuf = data_blob_null;
3112 struct smb2_hnd *ph = NULL;
3113 TALLOC_CTX *frame = talloc_stackframe();
3115 if (smbXcli_conn_has_async_calls(cli->conn)) {
3117 * Can't use sync call while an async call is in flight
3119 status = NT_STATUS_INVALID_PARAMETER;
3120 goto cleanup;
3123 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3124 status = NT_STATUS_INVALID_PARAMETER;
3125 goto cleanup;
3128 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3129 if (!NT_STATUS_IS_OK(status)) {
3130 goto cleanup;
3133 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3134 if (!NT_STATUS_IS_OK(status)) {
3135 goto cleanup;
3138 status = smb2cli_set_info(
3139 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3140 2, /* in_info_type */
3141 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3142 &inbuf, /* in_input_buffer */
3143 0, /* in_additional_info */
3144 ph->fid_persistent, ph->fid_volatile);
3145 cleanup:
3146 cli->raw_status = status;
3148 TALLOC_FREE(frame);
3149 return status;
3152 struct cli_smb2_read_state {
3153 struct tevent_context *ev;
3154 struct cli_state *cli;
3155 struct smb2_hnd *ph;
3156 uint64_t start_offset;
3157 uint32_t size;
3158 uint32_t received;
3159 uint8_t *buf;
3162 static void cli_smb2_read_done(struct tevent_req *subreq);
3164 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3165 struct tevent_context *ev,
3166 struct cli_state *cli,
3167 uint16_t fnum,
3168 off_t offset,
3169 size_t size)
3171 NTSTATUS status;
3172 struct tevent_req *req, *subreq;
3173 struct cli_smb2_read_state *state;
3175 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3176 if (req == NULL) {
3177 return NULL;
3179 state->ev = ev;
3180 state->cli = cli;
3181 state->start_offset = (uint64_t)offset;
3182 state->size = (uint32_t)size;
3183 state->received = 0;
3184 state->buf = NULL;
3186 status = map_fnum_to_smb2_handle(cli,
3187 fnum,
3188 &state->ph);
3189 if (tevent_req_nterror(req, status)) {
3190 return tevent_req_post(req, ev);
3193 subreq = smb2cli_read_send(state,
3194 state->ev,
3195 state->cli->conn,
3196 state->cli->timeout,
3197 state->cli->smb2.session,
3198 state->cli->smb2.tcon,
3199 state->size,
3200 state->start_offset,
3201 state->ph->fid_persistent,
3202 state->ph->fid_volatile,
3203 0, /* minimum_count */
3204 0); /* remaining_bytes */
3206 if (tevent_req_nomem(subreq, req)) {
3207 return tevent_req_post(req, ev);
3209 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3210 return req;
3213 static void cli_smb2_read_done(struct tevent_req *subreq)
3215 struct tevent_req *req = tevent_req_callback_data(
3216 subreq, struct tevent_req);
3217 struct cli_smb2_read_state *state = tevent_req_data(
3218 req, struct cli_smb2_read_state);
3219 NTSTATUS status;
3221 status = smb2cli_read_recv(subreq, state,
3222 &state->buf, &state->received);
3223 if (tevent_req_nterror(req, status)) {
3224 return;
3227 if (state->received > state->size) {
3228 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3229 return;
3232 tevent_req_done(req);
3235 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
3236 ssize_t *received,
3237 uint8_t **rcvbuf)
3239 NTSTATUS status;
3240 struct cli_smb2_read_state *state = tevent_req_data(
3241 req, struct cli_smb2_read_state);
3243 if (tevent_req_is_nterror(req, &status)) {
3244 state->cli->raw_status = status;
3245 return status;
3248 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3249 * better make sure that you copy it away before you talloc_free(req).
3250 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3252 *received = (ssize_t)state->received;
3253 *rcvbuf = state->buf;
3254 state->cli->raw_status = NT_STATUS_OK;
3255 return NT_STATUS_OK;
3258 struct cli_smb2_write_state {
3259 struct tevent_context *ev;
3260 struct cli_state *cli;
3261 struct smb2_hnd *ph;
3262 uint32_t flags;
3263 const uint8_t *buf;
3264 uint64_t offset;
3265 uint32_t size;
3266 uint32_t written;
3269 static void cli_smb2_write_written(struct tevent_req *req);
3271 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
3272 struct tevent_context *ev,
3273 struct cli_state *cli,
3274 uint16_t fnum,
3275 uint16_t mode,
3276 const uint8_t *buf,
3277 off_t offset,
3278 size_t size)
3280 NTSTATUS status;
3281 struct tevent_req *req, *subreq = NULL;
3282 struct cli_smb2_write_state *state = NULL;
3284 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
3285 if (req == NULL) {
3286 return NULL;
3288 state->ev = ev;
3289 state->cli = cli;
3290 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3291 state->flags = (uint32_t)mode;
3292 state->buf = buf;
3293 state->offset = (uint64_t)offset;
3294 state->size = (uint32_t)size;
3295 state->written = 0;
3297 status = map_fnum_to_smb2_handle(cli,
3298 fnum,
3299 &state->ph);
3300 if (tevent_req_nterror(req, status)) {
3301 return tevent_req_post(req, ev);
3304 subreq = smb2cli_write_send(state,
3305 state->ev,
3306 state->cli->conn,
3307 state->cli->timeout,
3308 state->cli->smb2.session,
3309 state->cli->smb2.tcon,
3310 state->size,
3311 state->offset,
3312 state->ph->fid_persistent,
3313 state->ph->fid_volatile,
3314 0, /* remaining_bytes */
3315 state->flags, /* flags */
3316 state->buf);
3318 if (tevent_req_nomem(subreq, req)) {
3319 return tevent_req_post(req, ev);
3321 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
3322 return req;
3325 static void cli_smb2_write_written(struct tevent_req *subreq)
3327 struct tevent_req *req = tevent_req_callback_data(
3328 subreq, struct tevent_req);
3329 struct cli_smb2_write_state *state = tevent_req_data(
3330 req, struct cli_smb2_write_state);
3331 NTSTATUS status;
3332 uint32_t written;
3334 status = smb2cli_write_recv(subreq, &written);
3335 TALLOC_FREE(subreq);
3336 if (tevent_req_nterror(req, status)) {
3337 return;
3340 state->written = written;
3342 tevent_req_done(req);
3345 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
3346 size_t *pwritten)
3348 struct cli_smb2_write_state *state = tevent_req_data(
3349 req, struct cli_smb2_write_state);
3350 NTSTATUS status;
3352 if (tevent_req_is_nterror(req, &status)) {
3353 state->cli->raw_status = status;
3354 tevent_req_received(req);
3355 return status;
3358 if (pwritten != NULL) {
3359 *pwritten = (size_t)state->written;
3361 state->cli->raw_status = NT_STATUS_OK;
3362 tevent_req_received(req);
3363 return NT_STATUS_OK;
3366 /***************************************************************
3367 Wrapper that allows SMB2 async write using an fnum.
3368 This is mostly cut-and-paste from Volker's code inside
3369 source3/libsmb/clireadwrite.c, adapted for SMB2.
3371 Done this way so I can reuse all the logic inside cli_push()
3372 for free :-).
3373 ***************************************************************/
3375 struct cli_smb2_writeall_state {
3376 struct tevent_context *ev;
3377 struct cli_state *cli;
3378 struct smb2_hnd *ph;
3379 uint32_t flags;
3380 const uint8_t *buf;
3381 uint64_t offset;
3382 uint32_t size;
3383 uint32_t written;
3386 static void cli_smb2_writeall_written(struct tevent_req *req);
3388 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
3389 struct tevent_context *ev,
3390 struct cli_state *cli,
3391 uint16_t fnum,
3392 uint16_t mode,
3393 const uint8_t *buf,
3394 off_t offset,
3395 size_t size)
3397 NTSTATUS status;
3398 struct tevent_req *req, *subreq = NULL;
3399 struct cli_smb2_writeall_state *state = NULL;
3400 uint32_t to_write;
3401 uint32_t max_size;
3402 bool ok;
3404 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
3405 if (req == NULL) {
3406 return NULL;
3408 state->ev = ev;
3409 state->cli = cli;
3410 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3411 state->flags = (uint32_t)mode;
3412 state->buf = buf;
3413 state->offset = (uint64_t)offset;
3414 state->size = (uint32_t)size;
3415 state->written = 0;
3417 status = map_fnum_to_smb2_handle(cli,
3418 fnum,
3419 &state->ph);
3420 if (tevent_req_nterror(req, status)) {
3421 return tevent_req_post(req, ev);
3424 to_write = state->size;
3425 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3426 to_write = MIN(max_size, to_write);
3427 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3428 if (ok) {
3429 to_write = MIN(max_size, to_write);
3432 subreq = smb2cli_write_send(state,
3433 state->ev,
3434 state->cli->conn,
3435 state->cli->timeout,
3436 state->cli->smb2.session,
3437 state->cli->smb2.tcon,
3438 to_write,
3439 state->offset,
3440 state->ph->fid_persistent,
3441 state->ph->fid_volatile,
3442 0, /* remaining_bytes */
3443 state->flags, /* flags */
3444 state->buf + state->written);
3446 if (tevent_req_nomem(subreq, req)) {
3447 return tevent_req_post(req, ev);
3449 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3450 return req;
3453 static void cli_smb2_writeall_written(struct tevent_req *subreq)
3455 struct tevent_req *req = tevent_req_callback_data(
3456 subreq, struct tevent_req);
3457 struct cli_smb2_writeall_state *state = tevent_req_data(
3458 req, struct cli_smb2_writeall_state);
3459 NTSTATUS status;
3460 uint32_t written, to_write;
3461 uint32_t max_size;
3462 bool ok;
3464 status = smb2cli_write_recv(subreq, &written);
3465 TALLOC_FREE(subreq);
3466 if (tevent_req_nterror(req, status)) {
3467 return;
3470 state->written += written;
3472 if (state->written > state->size) {
3473 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3474 return;
3477 to_write = state->size - state->written;
3479 if (to_write == 0) {
3480 tevent_req_done(req);
3481 return;
3484 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3485 to_write = MIN(max_size, to_write);
3486 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3487 if (ok) {
3488 to_write = MIN(max_size, to_write);
3491 subreq = smb2cli_write_send(state,
3492 state->ev,
3493 state->cli->conn,
3494 state->cli->timeout,
3495 state->cli->smb2.session,
3496 state->cli->smb2.tcon,
3497 to_write,
3498 state->offset + state->written,
3499 state->ph->fid_persistent,
3500 state->ph->fid_volatile,
3501 0, /* remaining_bytes */
3502 state->flags, /* flags */
3503 state->buf + state->written);
3505 if (tevent_req_nomem(subreq, req)) {
3506 return;
3508 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3511 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
3512 size_t *pwritten)
3514 struct cli_smb2_writeall_state *state = tevent_req_data(
3515 req, struct cli_smb2_writeall_state);
3516 NTSTATUS status;
3518 if (tevent_req_is_nterror(req, &status)) {
3519 state->cli->raw_status = status;
3520 return status;
3522 if (pwritten != NULL) {
3523 *pwritten = (size_t)state->written;
3525 state->cli->raw_status = NT_STATUS_OK;
3526 return NT_STATUS_OK;
3529 struct cli_smb2_splice_state {
3530 struct tevent_context *ev;
3531 struct cli_state *cli;
3532 struct smb2_hnd *src_ph;
3533 struct smb2_hnd *dst_ph;
3534 int (*splice_cb)(off_t n, void *priv);
3535 void *priv;
3536 off_t written;
3537 off_t size;
3538 off_t src_offset;
3539 off_t dst_offset;
3540 bool resized;
3541 struct req_resume_key_rsp resume_rsp;
3542 struct srv_copychunk_copy cc_copy;
3545 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3546 struct tevent_req *req);
3548 static void cli_splice_copychunk_done(struct tevent_req *subreq)
3550 struct tevent_req *req = tevent_req_callback_data(
3551 subreq, struct tevent_req);
3552 struct cli_smb2_splice_state *state =
3553 tevent_req_data(req,
3554 struct cli_smb2_splice_state);
3555 struct smbXcli_conn *conn = state->cli->conn;
3556 DATA_BLOB out_input_buffer = data_blob_null;
3557 DATA_BLOB out_output_buffer = data_blob_null;
3558 struct srv_copychunk_rsp cc_copy_rsp;
3559 enum ndr_err_code ndr_ret;
3560 NTSTATUS status;
3562 status = smb2cli_ioctl_recv(subreq, state,
3563 &out_input_buffer,
3564 &out_output_buffer);
3565 TALLOC_FREE(subreq);
3566 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
3567 state->resized) && tevent_req_nterror(req, status)) {
3568 return;
3571 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
3572 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
3573 if (ndr_ret != NDR_ERR_SUCCESS) {
3574 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3575 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3576 return;
3579 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
3580 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
3581 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
3582 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
3583 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
3584 tevent_req_nterror(req, status)) {
3585 return;
3588 state->resized = true;
3589 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
3590 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
3591 } else {
3592 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3593 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3594 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
3595 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3596 return;
3598 state->src_offset += cc_copy_rsp.total_bytes_written;
3599 state->dst_offset += cc_copy_rsp.total_bytes_written;
3600 state->written += cc_copy_rsp.total_bytes_written;
3601 if (!state->splice_cb(state->written, state->priv)) {
3602 tevent_req_nterror(req, NT_STATUS_CANCELLED);
3603 return;
3607 cli_splice_copychunk_send(state, req);
3610 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3611 struct tevent_req *req)
3613 struct tevent_req *subreq;
3614 enum ndr_err_code ndr_ret;
3615 struct smbXcli_conn *conn = state->cli->conn;
3616 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
3617 off_t src_offset = state->src_offset;
3618 off_t dst_offset = state->dst_offset;
3619 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
3620 state->size - state->written);
3621 DATA_BLOB in_input_buffer = data_blob_null;
3622 DATA_BLOB in_output_buffer = data_blob_null;
3624 if (state->size - state->written == 0) {
3625 tevent_req_done(req);
3626 return;
3629 cc_copy->chunk_count = 0;
3630 while (req_len) {
3631 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
3632 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
3633 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
3634 smb2cli_conn_cc_chunk_len(conn));
3635 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
3636 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3637 return;
3639 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
3640 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
3641 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
3642 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3643 return;
3645 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3646 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3647 cc_copy->chunk_count++;
3650 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
3651 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
3652 if (ndr_ret != NDR_ERR_SUCCESS) {
3653 DEBUG(0, ("failed to marshall copy chunk req\n"));
3654 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3655 return;
3658 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
3659 state->cli->timeout,
3660 state->cli->smb2.session,
3661 state->cli->smb2.tcon,
3662 state->dst_ph->fid_persistent, /* in_fid_persistent */
3663 state->dst_ph->fid_volatile, /* in_fid_volatile */
3664 FSCTL_SRV_COPYCHUNK_WRITE,
3665 0, /* in_max_input_length */
3666 &in_input_buffer,
3667 12, /* in_max_output_length */
3668 &in_output_buffer,
3669 SMB2_IOCTL_FLAG_IS_FSCTL);
3670 if (tevent_req_nomem(subreq, req)) {
3671 return;
3673 tevent_req_set_callback(subreq,
3674 cli_splice_copychunk_done,
3675 req);
3678 static void cli_splice_key_done(struct tevent_req *subreq)
3680 struct tevent_req *req = tevent_req_callback_data(
3681 subreq, struct tevent_req);
3682 struct cli_smb2_splice_state *state =
3683 tevent_req_data(req,
3684 struct cli_smb2_splice_state);
3685 enum ndr_err_code ndr_ret;
3686 NTSTATUS status;
3688 DATA_BLOB out_input_buffer = data_blob_null;
3689 DATA_BLOB out_output_buffer = data_blob_null;
3691 status = smb2cli_ioctl_recv(subreq, state,
3692 &out_input_buffer,
3693 &out_output_buffer);
3694 TALLOC_FREE(subreq);
3695 if (tevent_req_nterror(req, status)) {
3696 return;
3699 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
3700 state, &state->resume_rsp,
3701 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
3702 if (ndr_ret != NDR_ERR_SUCCESS) {
3703 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3704 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3705 return;
3708 memcpy(&state->cc_copy.source_key,
3709 &state->resume_rsp.resume_key,
3710 sizeof state->resume_rsp.resume_key);
3712 cli_splice_copychunk_send(state, req);
3715 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
3716 struct tevent_context *ev,
3717 struct cli_state *cli,
3718 uint16_t src_fnum, uint16_t dst_fnum,
3719 off_t size, off_t src_offset, off_t dst_offset,
3720 int (*splice_cb)(off_t n, void *priv),
3721 void *priv)
3723 struct tevent_req *req;
3724 struct tevent_req *subreq;
3725 struct cli_smb2_splice_state *state;
3726 NTSTATUS status;
3727 DATA_BLOB in_input_buffer = data_blob_null;
3728 DATA_BLOB in_output_buffer = data_blob_null;
3730 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
3731 if (req == NULL) {
3732 return NULL;
3734 state->cli = cli;
3735 state->ev = ev;
3736 state->splice_cb = splice_cb;
3737 state->priv = priv;
3738 state->size = size;
3739 state->written = 0;
3740 state->src_offset = src_offset;
3741 state->dst_offset = dst_offset;
3742 state->cc_copy.chunks = talloc_array(state,
3743 struct srv_copychunk,
3744 smb2cli_conn_cc_max_chunks(cli->conn));
3745 if (state->cc_copy.chunks == NULL) {
3746 return NULL;
3749 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
3750 if (tevent_req_nterror(req, status))
3751 return tevent_req_post(req, ev);
3753 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
3754 if (tevent_req_nterror(req, status))
3755 return tevent_req_post(req, ev);
3757 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
3758 cli->timeout,
3759 cli->smb2.session,
3760 cli->smb2.tcon,
3761 state->src_ph->fid_persistent, /* in_fid_persistent */
3762 state->src_ph->fid_volatile, /* in_fid_volatile */
3763 FSCTL_SRV_REQUEST_RESUME_KEY,
3764 0, /* in_max_input_length */
3765 &in_input_buffer,
3766 32, /* in_max_output_length */
3767 &in_output_buffer,
3768 SMB2_IOCTL_FLAG_IS_FSCTL);
3769 if (tevent_req_nomem(subreq, req)) {
3770 return NULL;
3772 tevent_req_set_callback(subreq,
3773 cli_splice_key_done,
3774 req);
3776 return req;
3779 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
3781 struct cli_smb2_splice_state *state = tevent_req_data(
3782 req, struct cli_smb2_splice_state);
3783 NTSTATUS status;
3785 if (tevent_req_is_nterror(req, &status)) {
3786 state->cli->raw_status = status;
3787 tevent_req_received(req);
3788 return status;
3790 if (written != NULL) {
3791 *written = state->written;
3793 state->cli->raw_status = NT_STATUS_OK;
3794 tevent_req_received(req);
3795 return NT_STATUS_OK;
3798 /***************************************************************
3799 SMB2 enum shadow copy data.
3800 ***************************************************************/
3802 struct cli_smb2_shadow_copy_data_fnum_state {
3803 struct cli_state *cli;
3804 uint16_t fnum;
3805 struct smb2_hnd *ph;
3806 DATA_BLOB out_input_buffer;
3807 DATA_BLOB out_output_buffer;
3810 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
3812 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
3813 TALLOC_CTX *mem_ctx,
3814 struct tevent_context *ev,
3815 struct cli_state *cli,
3816 uint16_t fnum,
3817 bool get_names)
3819 struct tevent_req *req, *subreq;
3820 struct cli_smb2_shadow_copy_data_fnum_state *state;
3821 NTSTATUS status;
3823 req = tevent_req_create(mem_ctx, &state,
3824 struct cli_smb2_shadow_copy_data_fnum_state);
3825 if (req == NULL) {
3826 return NULL;
3829 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3830 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3831 return tevent_req_post(req, ev);
3834 state->cli = cli;
3835 state->fnum = fnum;
3837 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
3838 if (tevent_req_nterror(req, status)) {
3839 return tevent_req_post(req, ev);
3843 * TODO. Under SMB2 we should send a zero max_output_length
3844 * ioctl to get the required size, then send another ioctl
3845 * to get the data, but the current SMB1 implementation just
3846 * does one roundtrip with a 64K buffer size. Do the same
3847 * for now. JRA.
3850 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
3851 state->cli->timeout,
3852 state->cli->smb2.session,
3853 state->cli->smb2.tcon,
3854 state->ph->fid_persistent, /* in_fid_persistent */
3855 state->ph->fid_volatile, /* in_fid_volatile */
3856 FSCTL_GET_SHADOW_COPY_DATA,
3857 0, /* in_max_input_length */
3858 NULL, /* in_input_buffer */
3859 get_names ?
3860 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
3861 NULL, /* in_output_buffer */
3862 SMB2_IOCTL_FLAG_IS_FSCTL);
3864 if (tevent_req_nomem(subreq, req)) {
3865 return tevent_req_post(req, ev);
3867 tevent_req_set_callback(subreq,
3868 cli_smb2_shadow_copy_data_fnum_done,
3869 req);
3871 return req;
3874 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
3876 struct tevent_req *req = tevent_req_callback_data(
3877 subreq, struct tevent_req);
3878 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3879 req, struct cli_smb2_shadow_copy_data_fnum_state);
3880 NTSTATUS status;
3882 status = smb2cli_ioctl_recv(subreq, state,
3883 &state->out_input_buffer,
3884 &state->out_output_buffer);
3885 TALLOC_FREE(subreq);
3886 if (tevent_req_nterror(req, status)) {
3887 return;
3889 tevent_req_done(req);
3892 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
3893 TALLOC_CTX *mem_ctx,
3894 bool get_names,
3895 char ***pnames,
3896 int *pnum_names)
3898 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3899 req, struct cli_smb2_shadow_copy_data_fnum_state);
3900 char **names = NULL;
3901 uint32_t num_names = 0;
3902 uint32_t num_names_returned = 0;
3903 uint32_t dlength = 0;
3904 uint32_t i;
3905 uint8_t *endp = NULL;
3906 NTSTATUS status;
3908 if (tevent_req_is_nterror(req, &status)) {
3909 return status;
3912 if (state->out_output_buffer.length < 16) {
3913 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3916 num_names = IVAL(state->out_output_buffer.data, 0);
3917 num_names_returned = IVAL(state->out_output_buffer.data, 4);
3918 dlength = IVAL(state->out_output_buffer.data, 8);
3920 if (num_names > 0x7FFFFFFF) {
3921 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3924 if (get_names == false) {
3925 *pnum_names = (int)num_names;
3926 return NT_STATUS_OK;
3928 if (num_names != num_names_returned) {
3929 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3931 if (dlength + 12 < 12) {
3932 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3935 * NB. The below is an allowable return if there are
3936 * more snapshots than the buffer size we told the
3937 * server we can receive. We currently don't support
3938 * this.
3940 if (dlength + 12 > state->out_output_buffer.length) {
3941 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3943 if (state->out_output_buffer.length +
3944 (2 * sizeof(SHADOW_COPY_LABEL)) <
3945 state->out_output_buffer.length) {
3946 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3949 names = talloc_array(mem_ctx, char *, num_names_returned);
3950 if (names == NULL) {
3951 return NT_STATUS_NO_MEMORY;
3954 endp = state->out_output_buffer.data +
3955 state->out_output_buffer.length;
3957 for (i=0; i<num_names_returned; i++) {
3958 bool ret;
3959 uint8_t *src;
3960 size_t converted_size;
3962 src = state->out_output_buffer.data + 12 +
3963 (i * 2 * sizeof(SHADOW_COPY_LABEL));
3965 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
3966 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3968 ret = convert_string_talloc(
3969 names, CH_UTF16LE, CH_UNIX,
3970 src, 2 * sizeof(SHADOW_COPY_LABEL),
3971 &names[i], &converted_size);
3972 if (!ret) {
3973 TALLOC_FREE(names);
3974 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3977 *pnum_names = num_names;
3978 *pnames = names;
3979 return NT_STATUS_OK;
3982 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
3983 struct cli_state *cli,
3984 uint16_t fnum,
3985 bool get_names,
3986 char ***pnames,
3987 int *pnum_names)
3989 TALLOC_CTX *frame = talloc_stackframe();
3990 struct tevent_context *ev;
3991 struct tevent_req *req;
3992 NTSTATUS status = NT_STATUS_NO_MEMORY;
3994 if (smbXcli_conn_has_async_calls(cli->conn)) {
3996 * Can't use sync call while an async call is in flight
3998 status = NT_STATUS_INVALID_PARAMETER;
3999 goto fail;
4001 ev = samba_tevent_context_init(frame);
4002 if (ev == NULL) {
4003 goto fail;
4005 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4007 cli,
4008 fnum,
4009 get_names);
4010 if (req == NULL) {
4011 goto fail;
4013 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4014 goto fail;
4016 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4017 mem_ctx,
4018 get_names,
4019 pnames,
4020 pnum_names);
4021 fail:
4022 cli->raw_status = status;
4024 TALLOC_FREE(frame);
4025 return status;
4028 /***************************************************************
4029 Wrapper that allows SMB2 to truncate a file.
4030 Synchronous only.
4031 ***************************************************************/
4033 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4034 uint16_t fnum,
4035 uint64_t newsize)
4037 NTSTATUS status;
4038 DATA_BLOB inbuf = data_blob_null;
4039 struct smb2_hnd *ph = NULL;
4040 TALLOC_CTX *frame = talloc_stackframe();
4042 if (smbXcli_conn_has_async_calls(cli->conn)) {
4044 * Can't use sync call while an async call is in flight
4046 status = NT_STATUS_INVALID_PARAMETER;
4047 goto fail;
4050 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4051 status = NT_STATUS_INVALID_PARAMETER;
4052 goto fail;
4055 status = map_fnum_to_smb2_handle(cli,
4056 fnum,
4057 &ph);
4058 if (!NT_STATUS_IS_OK(status)) {
4059 goto fail;
4062 inbuf = data_blob_talloc_zero(frame, 8);
4063 if (inbuf.data == NULL) {
4064 status = NT_STATUS_NO_MEMORY;
4065 goto fail;
4068 SBVAL(inbuf.data, 0, newsize);
4070 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4071 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4073 status = smb2cli_set_info(cli->conn,
4074 cli->timeout,
4075 cli->smb2.session,
4076 cli->smb2.tcon,
4077 1, /* in_info_type */
4078 /* in_file_info_class */
4079 SMB_FILE_END_OF_FILE_INFORMATION - 1000,
4080 &inbuf, /* in_input_buffer */
4081 0, /* in_additional_info */
4082 ph->fid_persistent,
4083 ph->fid_volatile);
4085 fail:
4087 cli->raw_status = status;
4089 TALLOC_FREE(frame);
4090 return status;