s4:selftest: explicitly set NSS/RESOLV_WAPPER_* in wait_for_start
[Samba.git] / source3 / libsmb / cli_smb2_fnum.c
blob2d87b58d730ff1355f0d8edc82e8da16a5fd780b
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_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
691 * Naive option to match our SMB1 code. Assume the
692 * symlink path that tripped us up was the last
693 * component and try again. Eventually we will have to
694 * deal with the returned path unprocessed component. JRA.
696 status = cli_smb2_create_fnum(cli,
697 dname,
698 0, /* create_flags */
699 DELETE_ACCESS, /* desired_access */
700 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
701 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
702 FILE_OPEN, /* create_disposition */
703 FILE_DIRECTORY_FILE|
704 FILE_DELETE_ON_CLOSE|
705 FILE_OPEN_REPARSE_POINT, /* create_options */
706 &fnum,
707 NULL);
710 if (!NT_STATUS_IS_OK(status)) {
711 return status;
713 return cli_smb2_close_fnum(cli, fnum);
716 /***************************************************************
717 Small wrapper that allows SMB2 to unlink a pathname.
718 Synchronous only.
719 ***************************************************************/
721 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
723 NTSTATUS status;
724 uint16_t fnum;
726 if (smbXcli_conn_has_async_calls(cli->conn)) {
728 * Can't use sync call while an async call is in flight
730 return NT_STATUS_INVALID_PARAMETER;
733 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
734 return NT_STATUS_INVALID_PARAMETER;
737 status = cli_smb2_create_fnum(cli,
738 fname,
739 0, /* create_flags */
740 DELETE_ACCESS, /* desired_access */
741 FILE_ATTRIBUTE_NORMAL, /* file attributes */
742 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
743 FILE_OPEN, /* create_disposition */
744 FILE_DELETE_ON_CLOSE, /* create_options */
745 &fnum,
746 NULL);
748 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
750 * Naive option to match our SMB1 code. Assume the
751 * symlink path that tripped us up was the last
752 * component and try again. Eventually we will have to
753 * deal with the returned path unprocessed component. JRA.
755 status = cli_smb2_create_fnum(cli,
756 fname,
757 0, /* create_flags */
758 DELETE_ACCESS, /* desired_access */
759 FILE_ATTRIBUTE_NORMAL, /* file attributes */
760 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
761 FILE_OPEN, /* create_disposition */
762 FILE_DELETE_ON_CLOSE|
763 FILE_OPEN_REPARSE_POINT, /* create_options */
764 &fnum,
765 NULL);
768 if (!NT_STATUS_IS_OK(status)) {
769 return status;
771 return cli_smb2_close_fnum(cli, fnum);
774 /***************************************************************
775 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
776 ***************************************************************/
778 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
779 uint32_t dir_data_length,
780 struct file_info *finfo,
781 uint32_t *next_offset)
783 size_t namelen = 0;
784 size_t slen = 0;
785 size_t ret = 0;
787 if (dir_data_length < 4) {
788 return NT_STATUS_INFO_LENGTH_MISMATCH;
791 *next_offset = IVAL(dir_data, 0);
793 if (*next_offset > dir_data_length) {
794 return NT_STATUS_INFO_LENGTH_MISMATCH;
797 if (*next_offset != 0) {
798 /* Ensure we only read what in this record. */
799 dir_data_length = *next_offset;
802 if (dir_data_length < 105) {
803 return NT_STATUS_INFO_LENGTH_MISMATCH;
806 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
807 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
808 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
809 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
810 finfo->mode = CVAL(dir_data + 56, 0);
811 namelen = IVAL(dir_data + 60,0);
812 if (namelen > (dir_data_length - 104)) {
813 return NT_STATUS_INFO_LENGTH_MISMATCH;
815 slen = CVAL(dir_data + 68, 0);
816 if (slen > 24) {
817 return NT_STATUS_INFO_LENGTH_MISMATCH;
819 ret = pull_string_talloc(finfo,
820 dir_data,
821 FLAGS2_UNICODE_STRINGS,
822 &finfo->short_name,
823 dir_data + 70,
824 slen,
825 STR_UNICODE);
826 if (ret == (size_t)-1) {
827 /* Bad conversion. */
828 return NT_STATUS_INVALID_NETWORK_RESPONSE;
831 ret = pull_string_talloc(finfo,
832 dir_data,
833 FLAGS2_UNICODE_STRINGS,
834 &finfo->name,
835 dir_data + 104,
836 namelen,
837 STR_UNICODE);
838 if (ret == (size_t)-1) {
839 /* Bad conversion. */
840 return NT_STATUS_INVALID_NETWORK_RESPONSE;
842 return NT_STATUS_OK;
845 /*******************************************************************
846 Given a filename - get its directory name
847 ********************************************************************/
849 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
850 const char *dir,
851 char **parent,
852 const char **name)
854 char *p;
855 ptrdiff_t len;
857 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
859 if (p == NULL) {
860 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
861 return false;
863 if (name) {
864 *name = dir;
866 return true;
869 len = p-dir;
871 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
872 return false;
874 (*parent)[len] = '\0';
876 if (name) {
877 *name = p+1;
879 return true;
882 /***************************************************************
883 Wrapper that allows SMB2 to list a directory.
884 Synchronous only.
885 ***************************************************************/
887 NTSTATUS cli_smb2_list(struct cli_state *cli,
888 const char *pathname,
889 uint16_t attribute,
890 NTSTATUS (*fn)(const char *,
891 struct file_info *,
892 const char *,
893 void *),
894 void *state)
896 NTSTATUS status;
897 uint16_t fnum = 0xffff;
898 char *parent_dir = NULL;
899 const char *mask = NULL;
900 struct smb2_hnd *ph = NULL;
901 bool processed_file = false;
902 TALLOC_CTX *frame = talloc_stackframe();
903 TALLOC_CTX *subframe = NULL;
904 bool mask_has_wild;
906 if (smbXcli_conn_has_async_calls(cli->conn)) {
908 * Can't use sync call while an async call is in flight
910 status = NT_STATUS_INVALID_PARAMETER;
911 goto fail;
914 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
915 status = NT_STATUS_INVALID_PARAMETER;
916 goto fail;
919 /* Get the directory name. */
920 if (!windows_parent_dirname(frame,
921 pathname,
922 &parent_dir,
923 &mask)) {
924 status = NT_STATUS_NO_MEMORY;
925 goto fail;
928 mask_has_wild = ms_has_wild(mask);
930 status = cli_smb2_create_fnum(cli,
931 parent_dir,
932 0, /* create_flags */
933 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
934 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
935 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
936 FILE_OPEN, /* create_disposition */
937 FILE_DIRECTORY_FILE, /* create_options */
938 &fnum,
939 NULL);
941 if (!NT_STATUS_IS_OK(status)) {
942 goto fail;
945 status = map_fnum_to_smb2_handle(cli,
946 fnum,
947 &ph);
948 if (!NT_STATUS_IS_OK(status)) {
949 goto fail;
952 do {
953 uint8_t *dir_data = NULL;
954 uint32_t dir_data_length = 0;
955 uint32_t next_offset = 0;
956 subframe = talloc_stackframe();
958 status = smb2cli_query_directory(cli->conn,
959 cli->timeout,
960 cli->smb2.session,
961 cli->smb2.tcon,
962 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
963 0, /* flags */
964 0, /* file_index */
965 ph->fid_persistent,
966 ph->fid_volatile,
967 mask,
968 0xffff,
969 subframe,
970 &dir_data,
971 &dir_data_length);
973 if (!NT_STATUS_IS_OK(status)) {
974 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
975 break;
977 goto fail;
980 do {
981 struct file_info *finfo = talloc_zero(subframe,
982 struct file_info);
984 if (finfo == NULL) {
985 status = NT_STATUS_NO_MEMORY;
986 goto fail;
989 status = parse_finfo_id_both_directory_info(dir_data,
990 dir_data_length,
991 finfo,
992 &next_offset);
994 if (!NT_STATUS_IS_OK(status)) {
995 goto fail;
998 if (dir_check_ftype((uint32_t)finfo->mode,
999 (uint32_t)attribute)) {
1001 * Only process if attributes match.
1002 * On SMB1 server does this, so on
1003 * SMB2 we need to emulate in the
1004 * client.
1006 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1008 processed_file = true;
1010 status = fn(cli->dfs_mountpoint,
1011 finfo,
1012 pathname,
1013 state);
1015 if (!NT_STATUS_IS_OK(status)) {
1016 break;
1020 TALLOC_FREE(finfo);
1022 /* Move to next entry. */
1023 if (next_offset) {
1024 dir_data += next_offset;
1025 dir_data_length -= next_offset;
1027 } while (next_offset != 0);
1029 TALLOC_FREE(subframe);
1031 if (!mask_has_wild) {
1033 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
1034 * when handed a non-wildcard path. Do it
1035 * for the server (with a non-wildcard path
1036 * there should only ever be one file returned.
1038 status = STATUS_NO_MORE_FILES;
1039 break;
1042 } while (NT_STATUS_IS_OK(status));
1044 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1045 status = NT_STATUS_OK;
1048 if (NT_STATUS_IS_OK(status) && !processed_file) {
1050 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1051 * if no files match. Emulate this in the client.
1053 status = NT_STATUS_NO_SUCH_FILE;
1056 fail:
1058 if (fnum != 0xffff) {
1059 cli_smb2_close_fnum(cli, fnum);
1062 cli->raw_status = status;
1064 TALLOC_FREE(subframe);
1065 TALLOC_FREE(frame);
1066 return status;
1069 /***************************************************************
1070 Wrapper that allows SMB2 to query a path info (basic level).
1071 Synchronous only.
1072 ***************************************************************/
1074 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1075 const char *name,
1076 SMB_STRUCT_STAT *sbuf,
1077 uint32_t *attributes)
1079 NTSTATUS status;
1080 struct smb_create_returns cr;
1081 uint16_t fnum = 0xffff;
1082 size_t namelen = strlen(name);
1084 if (smbXcli_conn_has_async_calls(cli->conn)) {
1086 * Can't use sync call while an async call is in flight
1088 return NT_STATUS_INVALID_PARAMETER;
1091 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1092 return NT_STATUS_INVALID_PARAMETER;
1095 /* SMB2 is pickier about pathnames. Ensure it doesn't
1096 end in a '\' */
1097 if (namelen > 0 && name[namelen-1] == '\\') {
1098 char *modname = talloc_strdup(talloc_tos(), name);
1099 modname[namelen-1] = '\0';
1100 name = modname;
1103 /* This is commonly used as a 'cd'. Try qpathinfo on
1104 a directory handle first. */
1106 status = cli_smb2_create_fnum(cli,
1107 name,
1108 0, /* create_flags */
1109 FILE_READ_ATTRIBUTES, /* desired_access */
1110 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1111 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1112 FILE_OPEN, /* create_disposition */
1113 FILE_DIRECTORY_FILE, /* create_options */
1114 &fnum,
1115 &cr);
1117 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1118 /* Maybe a file ? */
1119 status = cli_smb2_create_fnum(cli,
1120 name,
1121 0, /* create_flags */
1122 FILE_READ_ATTRIBUTES, /* desired_access */
1123 0, /* file attributes */
1124 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1125 FILE_OPEN, /* create_disposition */
1126 0, /* create_options */
1127 &fnum,
1128 &cr);
1131 if (!NT_STATUS_IS_OK(status)) {
1132 return status;
1135 status = cli_smb2_close_fnum(cli, fnum);
1137 ZERO_STRUCTP(sbuf);
1139 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1140 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1141 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1142 sbuf->st_ex_size = cr.end_of_file;
1143 *attributes = cr.file_attributes;
1145 return status;
1148 /***************************************************************
1149 Wrapper that allows SMB2 to check if a path is a directory.
1150 Synchronous only.
1151 ***************************************************************/
1153 NTSTATUS cli_smb2_chkpath(struct cli_state *cli,
1154 const char *name)
1156 NTSTATUS status;
1157 uint16_t fnum = 0xffff;
1159 if (smbXcli_conn_has_async_calls(cli->conn)) {
1161 * Can't use sync call while an async call is in flight
1163 return NT_STATUS_INVALID_PARAMETER;
1166 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1167 return NT_STATUS_INVALID_PARAMETER;
1170 /* Ensure this is a directory. */
1171 status = cli_smb2_create_fnum(cli,
1172 name,
1173 0, /* create_flags */
1174 FILE_READ_ATTRIBUTES, /* desired_access */
1175 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1176 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1177 FILE_OPEN, /* create_disposition */
1178 FILE_DIRECTORY_FILE, /* create_options */
1179 &fnum,
1180 NULL);
1182 if (!NT_STATUS_IS_OK(status)) {
1183 return status;
1186 return cli_smb2_close_fnum(cli, fnum);
1189 /***************************************************************
1190 Helper function for pathname operations.
1191 ***************************************************************/
1193 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1194 const char *name,
1195 uint32_t desired_access,
1196 uint16_t *pfnum)
1198 NTSTATUS status;
1199 size_t namelen = strlen(name);
1200 TALLOC_CTX *frame = talloc_stackframe();
1201 uint32_t create_options = 0;
1203 /* SMB2 is pickier about pathnames. Ensure it doesn't
1204 end in a '\' */
1205 if (namelen > 0 && name[namelen-1] == '\\') {
1206 char *modname = talloc_strdup(frame, name);
1207 if (modname == NULL) {
1208 status = NT_STATUS_NO_MEMORY;
1209 goto fail;
1211 modname[namelen-1] = '\0';
1212 name = modname;
1215 /* Try to open a file handle first. */
1216 status = cli_smb2_create_fnum(cli,
1217 name,
1218 0, /* create_flags */
1219 desired_access,
1220 0, /* file attributes */
1221 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1222 FILE_OPEN, /* create_disposition */
1223 create_options,
1224 pfnum,
1225 NULL);
1227 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1229 * Naive option to match our SMB1 code. Assume the
1230 * symlink path that tripped us up was the last
1231 * component and try again. Eventually we will have to
1232 * deal with the returned path unprocessed component. JRA.
1234 create_options |= FILE_OPEN_REPARSE_POINT;
1235 status = cli_smb2_create_fnum(cli,
1236 name,
1237 0, /* create_flags */
1238 desired_access,
1239 0, /* file attributes */
1240 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1241 FILE_OPEN, /* create_disposition */
1242 create_options,
1243 pfnum,
1244 NULL);
1247 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1248 create_options |= FILE_DIRECTORY_FILE;
1249 status = cli_smb2_create_fnum(cli,
1250 name,
1251 0, /* create_flags */
1252 desired_access,
1253 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1254 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1255 FILE_OPEN, /* create_disposition */
1256 FILE_DIRECTORY_FILE, /* create_options */
1257 pfnum,
1258 NULL);
1261 fail:
1263 TALLOC_FREE(frame);
1264 return status;
1267 /***************************************************************
1268 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1269 Synchronous only.
1270 ***************************************************************/
1272 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1273 const char *name,
1274 fstring alt_name)
1276 NTSTATUS status;
1277 DATA_BLOB outbuf = data_blob_null;
1278 uint16_t fnum = 0xffff;
1279 struct smb2_hnd *ph = NULL;
1280 uint32_t altnamelen = 0;
1281 TALLOC_CTX *frame = talloc_stackframe();
1283 if (smbXcli_conn_has_async_calls(cli->conn)) {
1285 * Can't use sync call while an async call is in flight
1287 status = NT_STATUS_INVALID_PARAMETER;
1288 goto fail;
1291 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1292 status = NT_STATUS_INVALID_PARAMETER;
1293 goto fail;
1296 status = get_fnum_from_path(cli,
1297 name,
1298 FILE_READ_ATTRIBUTES,
1299 &fnum);
1301 if (!NT_STATUS_IS_OK(status)) {
1302 goto fail;
1305 status = map_fnum_to_smb2_handle(cli,
1306 fnum,
1307 &ph);
1308 if (!NT_STATUS_IS_OK(status)) {
1309 goto fail;
1312 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1313 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1315 status = smb2cli_query_info(cli->conn,
1316 cli->timeout,
1317 cli->smb2.session,
1318 cli->smb2.tcon,
1319 1, /* in_info_type */
1320 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1321 0xFFFF, /* in_max_output_length */
1322 NULL, /* in_input_buffer */
1323 0, /* in_additional_info */
1324 0, /* in_flags */
1325 ph->fid_persistent,
1326 ph->fid_volatile,
1327 frame,
1328 &outbuf);
1330 if (!NT_STATUS_IS_OK(status)) {
1331 goto fail;
1334 /* Parse the reply. */
1335 if (outbuf.length < 4) {
1336 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1337 goto fail;
1340 altnamelen = IVAL(outbuf.data, 0);
1341 if (altnamelen > outbuf.length - 4) {
1342 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1343 goto fail;
1346 if (altnamelen > 0) {
1347 size_t ret = 0;
1348 char *short_name = NULL;
1349 ret = pull_string_talloc(frame,
1350 outbuf.data,
1351 FLAGS2_UNICODE_STRINGS,
1352 &short_name,
1353 outbuf.data + 4,
1354 altnamelen,
1355 STR_UNICODE);
1356 if (ret == (size_t)-1) {
1357 /* Bad conversion. */
1358 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1359 goto fail;
1362 fstrcpy(alt_name, short_name);
1363 } else {
1364 alt_name[0] = '\0';
1367 status = NT_STATUS_OK;
1369 fail:
1371 if (fnum != 0xffff) {
1372 cli_smb2_close_fnum(cli, fnum);
1375 cli->raw_status = status;
1377 TALLOC_FREE(frame);
1378 return status;
1382 /***************************************************************
1383 Wrapper that allows SMB2 to query a fnum info (basic level).
1384 Synchronous only.
1385 ***************************************************************/
1387 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1388 uint16_t fnum,
1389 uint16_t *mode,
1390 off_t *size,
1391 struct timespec *create_time,
1392 struct timespec *access_time,
1393 struct timespec *write_time,
1394 struct timespec *change_time,
1395 SMB_INO_T *ino)
1397 NTSTATUS status;
1398 DATA_BLOB outbuf = data_blob_null;
1399 struct smb2_hnd *ph = NULL;
1400 TALLOC_CTX *frame = talloc_stackframe();
1402 if (smbXcli_conn_has_async_calls(cli->conn)) {
1404 * Can't use sync call while an async call is in flight
1406 status = NT_STATUS_INVALID_PARAMETER;
1407 goto fail;
1410 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1411 status = NT_STATUS_INVALID_PARAMETER;
1412 goto fail;
1415 status = map_fnum_to_smb2_handle(cli,
1416 fnum,
1417 &ph);
1418 if (!NT_STATUS_IS_OK(status)) {
1419 goto fail;
1422 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1423 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1425 status = smb2cli_query_info(cli->conn,
1426 cli->timeout,
1427 cli->smb2.session,
1428 cli->smb2.tcon,
1429 1, /* in_info_type */
1430 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1431 0xFFFF, /* in_max_output_length */
1432 NULL, /* in_input_buffer */
1433 0, /* in_additional_info */
1434 0, /* in_flags */
1435 ph->fid_persistent,
1436 ph->fid_volatile,
1437 frame,
1438 &outbuf);
1439 if (!NT_STATUS_IS_OK(status)) {
1440 goto fail;
1443 /* Parse the reply. */
1444 if (outbuf.length < 0x60) {
1445 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1446 goto fail;
1449 if (create_time) {
1450 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1452 if (access_time) {
1453 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1455 if (write_time) {
1456 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1458 if (change_time) {
1459 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1461 if (mode) {
1462 uint32_t attr = IVAL(outbuf.data, 0x20);
1463 *mode = (uint16_t)attr;
1465 if (size) {
1466 uint64_t file_size = BVAL(outbuf.data, 0x30);
1467 *size = (off_t)file_size;
1469 if (ino) {
1470 uint64_t file_index = BVAL(outbuf.data, 0x40);
1471 *ino = (SMB_INO_T)file_index;
1474 fail:
1476 cli->raw_status = status;
1478 TALLOC_FREE(frame);
1479 return status;
1482 /***************************************************************
1483 Wrapper that allows SMB2 to query an fnum.
1484 Implement on top of cli_smb2_qfileinfo_basic().
1485 Synchronous only.
1486 ***************************************************************/
1488 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1489 uint16_t fnum,
1490 uint16_t *attr,
1491 off_t *size,
1492 time_t *change_time,
1493 time_t *access_time,
1494 time_t *write_time)
1496 struct timespec access_time_ts;
1497 struct timespec write_time_ts;
1498 struct timespec change_time_ts;
1499 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1500 fnum,
1501 attr,
1502 size,
1503 NULL,
1504 &access_time_ts,
1505 &write_time_ts,
1506 &change_time_ts,
1507 NULL);
1509 cli->raw_status = status;
1511 if (!NT_STATUS_IS_OK(status)) {
1512 return status;
1515 if (change_time) {
1516 *change_time = change_time_ts.tv_sec;
1518 if (access_time) {
1519 *access_time = access_time_ts.tv_sec;
1521 if (write_time) {
1522 *write_time = write_time_ts.tv_sec;
1524 return NT_STATUS_OK;
1527 /***************************************************************
1528 Wrapper that allows SMB2 to get pathname attributes.
1529 Synchronous only.
1530 ***************************************************************/
1532 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1533 const char *name,
1534 uint16_t *attr,
1535 off_t *size,
1536 time_t *write_time)
1538 NTSTATUS status;
1539 uint16_t fnum = 0xffff;
1540 struct smb2_hnd *ph = NULL;
1541 TALLOC_CTX *frame = talloc_stackframe();
1543 if (smbXcli_conn_has_async_calls(cli->conn)) {
1545 * Can't use sync call while an async call is in flight
1547 status = NT_STATUS_INVALID_PARAMETER;
1548 goto fail;
1551 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1552 status = NT_STATUS_INVALID_PARAMETER;
1553 goto fail;
1556 status = get_fnum_from_path(cli,
1557 name,
1558 FILE_READ_ATTRIBUTES,
1559 &fnum);
1561 if (!NT_STATUS_IS_OK(status)) {
1562 goto fail;
1565 status = map_fnum_to_smb2_handle(cli,
1566 fnum,
1567 &ph);
1568 if (!NT_STATUS_IS_OK(status)) {
1569 goto fail;
1571 status = cli_smb2_getattrE(cli,
1572 fnum,
1573 attr,
1574 size,
1575 NULL,
1576 NULL,
1577 write_time);
1578 if (!NT_STATUS_IS_OK(status)) {
1579 goto fail;
1582 fail:
1584 if (fnum != 0xffff) {
1585 cli_smb2_close_fnum(cli, fnum);
1588 cli->raw_status = status;
1590 TALLOC_FREE(frame);
1591 return status;
1594 /***************************************************************
1595 Wrapper that allows SMB2 to query a pathname info (basic level).
1596 Implement on top of cli_smb2_qfileinfo_basic().
1597 Synchronous only.
1598 ***************************************************************/
1600 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1601 const char *name,
1602 struct timespec *create_time,
1603 struct timespec *access_time,
1604 struct timespec *write_time,
1605 struct timespec *change_time,
1606 off_t *size,
1607 uint16_t *mode,
1608 SMB_INO_T *ino)
1610 NTSTATUS status;
1611 struct smb2_hnd *ph = NULL;
1612 uint16_t fnum = 0xffff;
1613 TALLOC_CTX *frame = talloc_stackframe();
1615 if (smbXcli_conn_has_async_calls(cli->conn)) {
1617 * Can't use sync call while an async call is in flight
1619 status = NT_STATUS_INVALID_PARAMETER;
1620 goto fail;
1623 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1624 status = NT_STATUS_INVALID_PARAMETER;
1625 goto fail;
1628 status = get_fnum_from_path(cli,
1629 name,
1630 FILE_READ_ATTRIBUTES,
1631 &fnum);
1633 if (!NT_STATUS_IS_OK(status)) {
1634 goto fail;
1637 status = map_fnum_to_smb2_handle(cli,
1638 fnum,
1639 &ph);
1640 if (!NT_STATUS_IS_OK(status)) {
1641 goto fail;
1644 status = cli_smb2_qfileinfo_basic(cli,
1645 fnum,
1646 mode,
1647 size,
1648 create_time,
1649 access_time,
1650 write_time,
1651 change_time,
1652 ino);
1654 fail:
1656 if (fnum != 0xffff) {
1657 cli_smb2_close_fnum(cli, fnum);
1660 cli->raw_status = status;
1662 TALLOC_FREE(frame);
1663 return status;
1666 /***************************************************************
1667 Wrapper that allows SMB2 to query pathname streams.
1668 Synchronous only.
1669 ***************************************************************/
1671 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1672 const char *name,
1673 TALLOC_CTX *mem_ctx,
1674 unsigned int *pnum_streams,
1675 struct stream_struct **pstreams)
1677 NTSTATUS status;
1678 struct smb2_hnd *ph = NULL;
1679 uint16_t fnum = 0xffff;
1680 DATA_BLOB outbuf = data_blob_null;
1681 TALLOC_CTX *frame = talloc_stackframe();
1683 if (smbXcli_conn_has_async_calls(cli->conn)) {
1685 * Can't use sync call while an async call is in flight
1687 status = NT_STATUS_INVALID_PARAMETER;
1688 goto fail;
1691 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1692 status = NT_STATUS_INVALID_PARAMETER;
1693 goto fail;
1696 status = get_fnum_from_path(cli,
1697 name,
1698 FILE_READ_ATTRIBUTES,
1699 &fnum);
1701 if (!NT_STATUS_IS_OK(status)) {
1702 goto fail;
1705 status = map_fnum_to_smb2_handle(cli,
1706 fnum,
1707 &ph);
1708 if (!NT_STATUS_IS_OK(status)) {
1709 goto fail;
1712 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1713 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1715 status = smb2cli_query_info(cli->conn,
1716 cli->timeout,
1717 cli->smb2.session,
1718 cli->smb2.tcon,
1719 1, /* in_info_type */
1720 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1721 0xFFFF, /* in_max_output_length */
1722 NULL, /* in_input_buffer */
1723 0, /* in_additional_info */
1724 0, /* in_flags */
1725 ph->fid_persistent,
1726 ph->fid_volatile,
1727 frame,
1728 &outbuf);
1730 if (!NT_STATUS_IS_OK(status)) {
1731 goto fail;
1734 /* Parse the reply. */
1735 if (!parse_streams_blob(mem_ctx,
1736 outbuf.data,
1737 outbuf.length,
1738 pnum_streams,
1739 pstreams)) {
1740 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1741 goto fail;
1744 fail:
1746 if (fnum != 0xffff) {
1747 cli_smb2_close_fnum(cli, fnum);
1750 cli->raw_status = status;
1752 TALLOC_FREE(frame);
1753 return status;
1756 /***************************************************************
1757 Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
1758 a pathname.
1759 Synchronous only.
1760 ***************************************************************/
1762 NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
1763 const char *name,
1764 uint8_t in_info_type,
1765 uint8_t in_file_info_class,
1766 const DATA_BLOB *p_in_data)
1768 NTSTATUS status;
1769 uint16_t fnum = 0xffff;
1770 struct smb2_hnd *ph = NULL;
1771 TALLOC_CTX *frame = talloc_stackframe();
1773 if (smbXcli_conn_has_async_calls(cli->conn)) {
1775 * Can't use sync call while an async call is in flight
1777 status = NT_STATUS_INVALID_PARAMETER;
1778 goto fail;
1781 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1782 status = NT_STATUS_INVALID_PARAMETER;
1783 goto fail;
1786 status = get_fnum_from_path(cli,
1787 name,
1788 FILE_WRITE_ATTRIBUTES,
1789 &fnum);
1791 if (!NT_STATUS_IS_OK(status)) {
1792 goto fail;
1795 status = map_fnum_to_smb2_handle(cli,
1796 fnum,
1797 &ph);
1798 if (!NT_STATUS_IS_OK(status)) {
1799 goto fail;
1802 status = smb2cli_set_info(cli->conn,
1803 cli->timeout,
1804 cli->smb2.session,
1805 cli->smb2.tcon,
1806 in_info_type,
1807 in_file_info_class,
1808 p_in_data, /* in_input_buffer */
1809 0, /* in_additional_info */
1810 ph->fid_persistent,
1811 ph->fid_volatile);
1812 fail:
1814 if (fnum != 0xffff) {
1815 cli_smb2_close_fnum(cli, fnum);
1818 cli->raw_status = status;
1820 TALLOC_FREE(frame);
1821 return status;
1825 /***************************************************************
1826 Wrapper that allows SMB2 to set pathname attributes.
1827 Synchronous only.
1828 ***************************************************************/
1830 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1831 const char *name,
1832 uint16_t attr,
1833 time_t mtime)
1835 uint8_t inbuf_store[40];
1836 DATA_BLOB inbuf = data_blob_null;
1838 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1839 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1841 inbuf.data = inbuf_store;
1842 inbuf.length = sizeof(inbuf_store);
1843 data_blob_clear(&inbuf);
1846 * SMB1 uses attr == 0 to clear all attributes
1847 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
1848 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
1849 * request attribute change.
1851 * SMB2 uses exactly the reverse. Unfortunately as the
1852 * cli_setatr() ABI is exposed inside libsmbclient,
1853 * we must make the SMB2 cli_smb2_setatr() call
1854 * export the same ABI as the SMB1 cli_setatr()
1855 * which calls it. This means reversing the sense
1856 * of the requested attr argument if it's zero
1857 * or FILE_ATTRIBUTE_NORMAL.
1859 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
1862 if (attr == 0) {
1863 attr = FILE_ATTRIBUTE_NORMAL;
1864 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
1865 attr = 0;
1868 SSVAL(inbuf.data, 32, attr);
1869 if (mtime != 0) {
1870 put_long_date((char *)inbuf.data + 16,mtime);
1872 /* Set all the other times to -1. */
1873 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1874 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1875 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1877 return cli_smb2_setpathinfo(cli,
1878 name,
1879 1, /* in_info_type */
1880 /* in_file_info_class */
1881 SMB_FILE_BASIC_INFORMATION - 1000,
1882 &inbuf);
1886 /***************************************************************
1887 Wrapper that allows SMB2 to set file handle times.
1888 Synchronous only.
1889 ***************************************************************/
1891 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1892 uint16_t fnum,
1893 time_t change_time,
1894 time_t access_time,
1895 time_t write_time)
1897 NTSTATUS status;
1898 struct smb2_hnd *ph = NULL;
1899 uint8_t inbuf_store[40];
1900 DATA_BLOB inbuf = data_blob_null;
1902 if (smbXcli_conn_has_async_calls(cli->conn)) {
1904 * Can't use sync call while an async call is in flight
1906 return NT_STATUS_INVALID_PARAMETER;
1909 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1910 return NT_STATUS_INVALID_PARAMETER;
1913 status = map_fnum_to_smb2_handle(cli,
1914 fnum,
1915 &ph);
1916 if (!NT_STATUS_IS_OK(status)) {
1917 return status;
1920 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1921 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1923 inbuf.data = inbuf_store;
1924 inbuf.length = sizeof(inbuf_store);
1925 data_blob_clear(&inbuf);
1927 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1928 if (change_time != 0) {
1929 put_long_date((char *)inbuf.data + 24, change_time);
1931 if (access_time != 0) {
1932 put_long_date((char *)inbuf.data + 8, access_time);
1934 if (write_time != 0) {
1935 put_long_date((char *)inbuf.data + 16, write_time);
1938 cli->raw_status = smb2cli_set_info(cli->conn,
1939 cli->timeout,
1940 cli->smb2.session,
1941 cli->smb2.tcon,
1942 1, /* in_info_type */
1943 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1944 &inbuf, /* in_input_buffer */
1945 0, /* in_additional_info */
1946 ph->fid_persistent,
1947 ph->fid_volatile);
1949 return cli->raw_status;
1952 /***************************************************************
1953 Wrapper that allows SMB2 to query disk attributes (size).
1954 Synchronous only.
1955 ***************************************************************/
1957 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
1958 uint64_t *bsize, uint64_t *total, uint64_t *avail)
1960 NTSTATUS status;
1961 uint16_t fnum = 0xffff;
1962 DATA_BLOB outbuf = data_blob_null;
1963 struct smb2_hnd *ph = NULL;
1964 uint32_t sectors_per_unit = 0;
1965 uint32_t bytes_per_sector = 0;
1966 uint64_t total_size = 0;
1967 uint64_t size_free = 0;
1968 TALLOC_CTX *frame = talloc_stackframe();
1970 if (smbXcli_conn_has_async_calls(cli->conn)) {
1972 * Can't use sync call while an async call is in flight
1974 status = NT_STATUS_INVALID_PARAMETER;
1975 goto fail;
1978 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1979 status = NT_STATUS_INVALID_PARAMETER;
1980 goto fail;
1983 /* First open the top level directory. */
1984 status = cli_smb2_create_fnum(cli,
1985 path,
1986 0, /* create_flags */
1987 FILE_READ_ATTRIBUTES, /* desired_access */
1988 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1989 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1990 FILE_OPEN, /* create_disposition */
1991 FILE_DIRECTORY_FILE, /* create_options */
1992 &fnum,
1993 NULL);
1995 if (!NT_STATUS_IS_OK(status)) {
1996 goto fail;
1999 status = map_fnum_to_smb2_handle(cli,
2000 fnum,
2001 &ph);
2002 if (!NT_STATUS_IS_OK(status)) {
2003 goto fail;
2006 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2007 level 3 (SMB_FS_SIZE_INFORMATION). */
2009 status = smb2cli_query_info(cli->conn,
2010 cli->timeout,
2011 cli->smb2.session,
2012 cli->smb2.tcon,
2013 2, /* in_info_type */
2014 3, /* in_file_info_class */
2015 0xFFFF, /* in_max_output_length */
2016 NULL, /* in_input_buffer */
2017 0, /* in_additional_info */
2018 0, /* in_flags */
2019 ph->fid_persistent,
2020 ph->fid_volatile,
2021 frame,
2022 &outbuf);
2023 if (!NT_STATUS_IS_OK(status)) {
2024 goto fail;
2027 /* Parse the reply. */
2028 if (outbuf.length != 24) {
2029 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2030 goto fail;
2033 total_size = BVAL(outbuf.data, 0);
2034 size_free = BVAL(outbuf.data, 8);
2035 sectors_per_unit = IVAL(outbuf.data, 16);
2036 bytes_per_sector = IVAL(outbuf.data, 20);
2038 if (bsize) {
2039 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
2041 if (total) {
2042 *total = total_size;
2044 if (avail) {
2045 *avail = size_free;
2048 status = NT_STATUS_OK;
2050 fail:
2052 if (fnum != 0xffff) {
2053 cli_smb2_close_fnum(cli, fnum);
2056 cli->raw_status = status;
2058 TALLOC_FREE(frame);
2059 return status;
2062 /***************************************************************
2063 Wrapper that allows SMB2 to query file system sizes.
2064 Synchronous only.
2065 ***************************************************************/
2067 NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
2068 uint64_t *total_allocation_units,
2069 uint64_t *caller_allocation_units,
2070 uint64_t *actual_allocation_units,
2071 uint64_t *sectors_per_allocation_unit,
2072 uint64_t *bytes_per_sector)
2074 NTSTATUS status;
2075 uint16_t fnum = 0xffff;
2076 DATA_BLOB outbuf = data_blob_null;
2077 struct smb2_hnd *ph = NULL;
2078 TALLOC_CTX *frame = talloc_stackframe();
2080 if (smbXcli_conn_has_async_calls(cli->conn)) {
2082 * Can't use sync call while an async call is in flight
2084 status = NT_STATUS_INVALID_PARAMETER;
2085 goto fail;
2088 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2089 status = NT_STATUS_INVALID_PARAMETER;
2090 goto fail;
2093 /* First open the top level directory. */
2094 status =
2095 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2096 FILE_READ_ATTRIBUTES, /* desired_access */
2097 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2098 FILE_SHARE_READ | FILE_SHARE_WRITE |
2099 FILE_SHARE_DELETE, /* share_access */
2100 FILE_OPEN, /* create_disposition */
2101 FILE_DIRECTORY_FILE, /* create_options */
2102 &fnum,
2103 NULL);
2105 if (!NT_STATUS_IS_OK(status)) {
2106 goto fail;
2109 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2110 if (!NT_STATUS_IS_OK(status)) {
2111 goto fail;
2114 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2115 level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
2117 status = smb2cli_query_info(cli->conn,
2118 cli->timeout,
2119 cli->smb2.session,
2120 cli->smb2.tcon,
2121 SMB2_GETINFO_FS, /* in_info_type */
2122 /* in_file_info_class */
2123 SMB_FS_FULL_SIZE_INFORMATION - 1000,
2124 0xFFFF, /* in_max_output_length */
2125 NULL, /* in_input_buffer */
2126 0, /* in_additional_info */
2127 0, /* in_flags */
2128 ph->fid_persistent,
2129 ph->fid_volatile,
2130 frame,
2131 &outbuf);
2132 if (!NT_STATUS_IS_OK(status)) {
2133 goto fail;
2136 if (outbuf.length < 32) {
2137 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2138 goto fail;
2141 *total_allocation_units = BIG_UINT(outbuf.data, 0);
2142 *caller_allocation_units = BIG_UINT(outbuf.data, 8);
2143 *actual_allocation_units = BIG_UINT(outbuf.data, 16);
2144 *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
2145 *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
2147 fail:
2149 if (fnum != 0xffff) {
2150 cli_smb2_close_fnum(cli, fnum);
2153 cli->raw_status = status;
2155 TALLOC_FREE(frame);
2156 return status;
2159 /***************************************************************
2160 Wrapper that allows SMB2 to query file system attributes.
2161 Synchronous only.
2162 ***************************************************************/
2164 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
2166 NTSTATUS status;
2167 uint16_t fnum = 0xffff;
2168 DATA_BLOB outbuf = data_blob_null;
2169 struct smb2_hnd *ph = NULL;
2170 TALLOC_CTX *frame = talloc_stackframe();
2172 if (smbXcli_conn_has_async_calls(cli->conn)) {
2174 * Can't use sync call while an async call is in flight
2176 status = NT_STATUS_INVALID_PARAMETER;
2177 goto fail;
2180 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2181 status = NT_STATUS_INVALID_PARAMETER;
2182 goto fail;
2185 /* First open the top level directory. */
2186 status =
2187 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2188 FILE_READ_ATTRIBUTES, /* desired_access */
2189 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2190 FILE_SHARE_READ | FILE_SHARE_WRITE |
2191 FILE_SHARE_DELETE, /* share_access */
2192 FILE_OPEN, /* create_disposition */
2193 FILE_DIRECTORY_FILE, /* create_options */
2194 &fnum,
2195 NULL);
2197 if (!NT_STATUS_IS_OK(status)) {
2198 goto fail;
2201 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2202 if (!NT_STATUS_IS_OK(status)) {
2203 goto fail;
2206 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2207 cli->smb2.tcon, 2, /* in_info_type */
2208 5, /* in_file_info_class */
2209 0xFFFF, /* in_max_output_length */
2210 NULL, /* in_input_buffer */
2211 0, /* in_additional_info */
2212 0, /* in_flags */
2213 ph->fid_persistent, ph->fid_volatile, frame,
2214 &outbuf);
2215 if (!NT_STATUS_IS_OK(status)) {
2216 goto fail;
2219 if (outbuf.length < 12) {
2220 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2221 goto fail;
2224 *fs_attr = IVAL(outbuf.data, 0);
2226 fail:
2228 if (fnum != 0xffff) {
2229 cli_smb2_close_fnum(cli, fnum);
2232 cli->raw_status = status;
2234 TALLOC_FREE(frame);
2235 return status;
2238 /***************************************************************
2239 Wrapper that allows SMB2 to query file system volume info.
2240 Synchronous only.
2241 ***************************************************************/
2243 NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
2244 TALLOC_CTX *mem_ctx,
2245 char **_volume_name,
2246 uint32_t *pserial_number,
2247 time_t *pdate)
2249 NTSTATUS status;
2250 uint16_t fnum = 0xffff;
2251 DATA_BLOB outbuf = data_blob_null;
2252 struct smb2_hnd *ph = NULL;
2253 uint32_t nlen;
2254 char *volume_name = NULL;
2255 TALLOC_CTX *frame = talloc_stackframe();
2257 if (smbXcli_conn_has_async_calls(cli->conn)) {
2259 * Can't use sync call while an async call is in flight
2261 status = NT_STATUS_INVALID_PARAMETER;
2262 goto fail;
2265 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2266 status = NT_STATUS_INVALID_PARAMETER;
2267 goto fail;
2270 /* First open the top level directory. */
2271 status =
2272 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
2273 FILE_READ_ATTRIBUTES, /* desired_access */
2274 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
2275 FILE_SHARE_READ | FILE_SHARE_WRITE |
2276 FILE_SHARE_DELETE, /* share_access */
2277 FILE_OPEN, /* create_disposition */
2278 FILE_DIRECTORY_FILE, /* create_options */
2279 &fnum,
2280 NULL);
2282 if (!NT_STATUS_IS_OK(status)) {
2283 goto fail;
2286 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
2287 if (!NT_STATUS_IS_OK(status)) {
2288 goto fail;
2291 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
2292 level 1 (SMB_FS_VOLUME_INFORMATION). */
2294 status = smb2cli_query_info(cli->conn,
2295 cli->timeout,
2296 cli->smb2.session,
2297 cli->smb2.tcon,
2298 SMB2_GETINFO_FS, /* in_info_type */
2299 /* in_file_info_class */
2300 SMB_FS_VOLUME_INFORMATION - 1000,
2301 0xFFFF, /* in_max_output_length */
2302 NULL, /* in_input_buffer */
2303 0, /* in_additional_info */
2304 0, /* in_flags */
2305 ph->fid_persistent,
2306 ph->fid_volatile,
2307 frame,
2308 &outbuf);
2309 if (!NT_STATUS_IS_OK(status)) {
2310 goto fail;
2313 if (outbuf.length < 24) {
2314 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2315 goto fail;
2318 if (pdate) {
2319 struct timespec ts;
2320 ts = interpret_long_date((char *)outbuf.data);
2321 *pdate = ts.tv_sec;
2323 if (pserial_number) {
2324 *pserial_number = IVAL(outbuf.data,8);
2326 nlen = IVAL(outbuf.data,12);
2327 if (nlen + 18 < 18) {
2328 /* Integer wrap. */
2329 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2330 goto fail;
2333 * The next check is safe as we know outbuf.length >= 24
2334 * from above.
2336 if (nlen > (outbuf.length - 18)) {
2337 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2338 goto fail;
2341 clistr_pull_talloc(mem_ctx,
2342 (const char *)outbuf.data,
2344 &volume_name,
2345 outbuf.data + 18,
2346 nlen,
2347 STR_UNICODE);
2348 if (volume_name == NULL) {
2349 status = map_nt_error_from_unix(errno);
2350 goto fail;
2353 *_volume_name = volume_name;
2355 fail:
2357 if (fnum != 0xffff) {
2358 cli_smb2_close_fnum(cli, fnum);
2361 cli->raw_status = status;
2363 TALLOC_FREE(frame);
2364 return status;
2368 /***************************************************************
2369 Wrapper that allows SMB2 to query a security descriptor.
2370 Synchronous only.
2371 ***************************************************************/
2373 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2374 uint16_t fnum,
2375 uint32_t sec_info,
2376 TALLOC_CTX *mem_ctx,
2377 struct security_descriptor **ppsd)
2379 NTSTATUS status;
2380 DATA_BLOB outbuf = data_blob_null;
2381 struct smb2_hnd *ph = NULL;
2382 struct security_descriptor *lsd = NULL;
2383 TALLOC_CTX *frame = talloc_stackframe();
2385 if (smbXcli_conn_has_async_calls(cli->conn)) {
2387 * Can't use sync call while an async call is in flight
2389 status = NT_STATUS_INVALID_PARAMETER;
2390 goto fail;
2393 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2394 status = NT_STATUS_INVALID_PARAMETER;
2395 goto fail;
2398 status = map_fnum_to_smb2_handle(cli,
2399 fnum,
2400 &ph);
2401 if (!NT_STATUS_IS_OK(status)) {
2402 goto fail;
2405 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2407 status = smb2cli_query_info(cli->conn,
2408 cli->timeout,
2409 cli->smb2.session,
2410 cli->smb2.tcon,
2411 3, /* in_info_type */
2412 0, /* in_file_info_class */
2413 0xFFFF, /* in_max_output_length */
2414 NULL, /* in_input_buffer */
2415 sec_info, /* in_additional_info */
2416 0, /* in_flags */
2417 ph->fid_persistent,
2418 ph->fid_volatile,
2419 frame,
2420 &outbuf);
2422 if (!NT_STATUS_IS_OK(status)) {
2423 goto fail;
2426 /* Parse the reply. */
2427 status = unmarshall_sec_desc(mem_ctx,
2428 outbuf.data,
2429 outbuf.length,
2430 &lsd);
2432 if (!NT_STATUS_IS_OK(status)) {
2433 goto fail;
2436 if (ppsd != NULL) {
2437 *ppsd = lsd;
2438 } else {
2439 TALLOC_FREE(lsd);
2442 fail:
2444 cli->raw_status = status;
2446 TALLOC_FREE(frame);
2447 return status;
2450 /***************************************************************
2451 Wrapper that allows SMB2 to set a security descriptor.
2452 Synchronous only.
2453 ***************************************************************/
2455 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
2456 uint16_t fnum,
2457 uint32_t sec_info,
2458 const struct security_descriptor *sd)
2460 NTSTATUS status;
2461 DATA_BLOB inbuf = data_blob_null;
2462 struct smb2_hnd *ph = NULL;
2463 TALLOC_CTX *frame = talloc_stackframe();
2465 if (smbXcli_conn_has_async_calls(cli->conn)) {
2467 * Can't use sync call while an async call is in flight
2469 status = NT_STATUS_INVALID_PARAMETER;
2470 goto fail;
2473 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2474 status = NT_STATUS_INVALID_PARAMETER;
2475 goto fail;
2478 status = map_fnum_to_smb2_handle(cli,
2479 fnum,
2480 &ph);
2481 if (!NT_STATUS_IS_OK(status)) {
2482 goto fail;
2485 status = marshall_sec_desc(frame,
2487 &inbuf.data,
2488 &inbuf.length);
2490 if (!NT_STATUS_IS_OK(status)) {
2491 goto fail;
2494 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2496 status = smb2cli_set_info(cli->conn,
2497 cli->timeout,
2498 cli->smb2.session,
2499 cli->smb2.tcon,
2500 3, /* in_info_type */
2501 0, /* in_file_info_class */
2502 &inbuf, /* in_input_buffer */
2503 sec_info, /* in_additional_info */
2504 ph->fid_persistent,
2505 ph->fid_volatile);
2507 fail:
2509 cli->raw_status = status;
2511 TALLOC_FREE(frame);
2512 return status;
2515 /***************************************************************
2516 Wrapper that allows SMB2 to rename a file.
2517 Synchronous only.
2518 ***************************************************************/
2520 NTSTATUS cli_smb2_rename(struct cli_state *cli,
2521 const char *fname_src,
2522 const char *fname_dst,
2523 bool replace)
2525 NTSTATUS status;
2526 DATA_BLOB inbuf = data_blob_null;
2527 uint16_t fnum = 0xffff;
2528 struct smb2_hnd *ph = NULL;
2529 smb_ucs2_t *converted_str = NULL;
2530 size_t converted_size_bytes = 0;
2531 size_t namelen = 0;
2532 TALLOC_CTX *frame = talloc_stackframe();
2534 if (smbXcli_conn_has_async_calls(cli->conn)) {
2536 * Can't use sync call while an async call is in flight
2538 status = NT_STATUS_INVALID_PARAMETER;
2539 goto fail;
2542 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2543 status = NT_STATUS_INVALID_PARAMETER;
2544 goto fail;
2547 status = get_fnum_from_path(cli,
2548 fname_src,
2549 DELETE_ACCESS,
2550 &fnum);
2552 if (!NT_STATUS_IS_OK(status)) {
2553 goto fail;
2556 status = map_fnum_to_smb2_handle(cli,
2557 fnum,
2558 &ph);
2559 if (!NT_STATUS_IS_OK(status)) {
2560 goto fail;
2563 /* SMB2 is pickier about pathnames. Ensure it doesn't
2564 start in a '\' */
2565 if (*fname_dst == '\\') {
2566 fname_dst++;
2569 /* SMB2 is pickier about pathnames. Ensure it doesn't
2570 end in a '\' */
2571 namelen = strlen(fname_dst);
2572 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2573 char *modname = talloc_strdup(frame, fname_dst);
2574 modname[namelen-1] = '\0';
2575 fname_dst = modname;
2578 if (!push_ucs2_talloc(frame,
2579 &converted_str,
2580 fname_dst,
2581 &converted_size_bytes)) {
2582 status = NT_STATUS_INVALID_PARAMETER;
2583 goto fail;
2586 /* W2K8 insists the dest name is not null
2587 terminated. Remove the last 2 zero bytes
2588 and reduce the name length. */
2590 if (converted_size_bytes < 2) {
2591 status = NT_STATUS_INVALID_PARAMETER;
2592 goto fail;
2594 converted_size_bytes -= 2;
2596 inbuf = data_blob_talloc_zero(frame,
2597 20 + converted_size_bytes);
2598 if (inbuf.data == NULL) {
2599 status = NT_STATUS_NO_MEMORY;
2600 goto fail;
2603 if (replace) {
2604 SCVAL(inbuf.data, 0, 1);
2607 SIVAL(inbuf.data, 16, converted_size_bytes);
2608 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2610 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2611 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2613 status = smb2cli_set_info(cli->conn,
2614 cli->timeout,
2615 cli->smb2.session,
2616 cli->smb2.tcon,
2617 1, /* in_info_type */
2618 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2619 &inbuf, /* in_input_buffer */
2620 0, /* in_additional_info */
2621 ph->fid_persistent,
2622 ph->fid_volatile);
2624 fail:
2626 if (fnum != 0xffff) {
2627 cli_smb2_close_fnum(cli, fnum);
2630 cli->raw_status = status;
2632 TALLOC_FREE(frame);
2633 return status;
2636 /***************************************************************
2637 Wrapper that allows SMB2 to set an EA on a fnum.
2638 Synchronous only.
2639 ***************************************************************/
2641 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2642 uint16_t fnum,
2643 const char *ea_name,
2644 const char *ea_val,
2645 size_t ea_len)
2647 NTSTATUS status;
2648 DATA_BLOB inbuf = data_blob_null;
2649 size_t bloblen = 0;
2650 char *ea_name_ascii = NULL;
2651 size_t namelen = 0;
2652 struct smb2_hnd *ph = NULL;
2653 TALLOC_CTX *frame = talloc_stackframe();
2655 if (smbXcli_conn_has_async_calls(cli->conn)) {
2657 * Can't use sync call while an async call is in flight
2659 status = NT_STATUS_INVALID_PARAMETER;
2660 goto fail;
2663 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2664 status = NT_STATUS_INVALID_PARAMETER;
2665 goto fail;
2668 status = map_fnum_to_smb2_handle(cli,
2669 fnum,
2670 &ph);
2671 if (!NT_STATUS_IS_OK(status)) {
2672 goto fail;
2675 /* Marshall the SMB2 EA data. */
2676 if (ea_len > 0xFFFF) {
2677 status = NT_STATUS_INVALID_PARAMETER;
2678 goto fail;
2681 if (!push_ascii_talloc(frame,
2682 &ea_name_ascii,
2683 ea_name,
2684 &namelen)) {
2685 status = NT_STATUS_INVALID_PARAMETER;
2686 goto fail;
2689 if (namelen < 2 || namelen > 0xFF) {
2690 status = NT_STATUS_INVALID_PARAMETER;
2691 goto fail;
2694 bloblen = 8 + ea_len + namelen;
2695 /* Round up to a 4 byte boundary. */
2696 bloblen = ((bloblen + 3)&~3);
2698 inbuf = data_blob_talloc_zero(frame, bloblen);
2699 if (inbuf.data == NULL) {
2700 status = NT_STATUS_NO_MEMORY;
2701 goto fail;
2703 /* namelen doesn't include the NULL byte. */
2704 SCVAL(inbuf.data, 5, namelen - 1);
2705 SSVAL(inbuf.data, 6, ea_len);
2706 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2707 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2709 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2710 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2712 status = smb2cli_set_info(cli->conn,
2713 cli->timeout,
2714 cli->smb2.session,
2715 cli->smb2.tcon,
2716 1, /* in_info_type */
2717 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2718 &inbuf, /* in_input_buffer */
2719 0, /* in_additional_info */
2720 ph->fid_persistent,
2721 ph->fid_volatile);
2723 fail:
2725 cli->raw_status = status;
2727 TALLOC_FREE(frame);
2728 return status;
2731 /***************************************************************
2732 Wrapper that allows SMB2 to set an EA on a pathname.
2733 Synchronous only.
2734 ***************************************************************/
2736 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2737 const char *name,
2738 const char *ea_name,
2739 const char *ea_val,
2740 size_t ea_len)
2742 NTSTATUS status;
2743 uint16_t fnum = 0xffff;
2745 if (smbXcli_conn_has_async_calls(cli->conn)) {
2747 * Can't use sync call while an async call is in flight
2749 status = NT_STATUS_INVALID_PARAMETER;
2750 goto fail;
2753 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2754 status = NT_STATUS_INVALID_PARAMETER;
2755 goto fail;
2758 status = get_fnum_from_path(cli,
2759 name,
2760 FILE_WRITE_EA,
2761 &fnum);
2763 if (!NT_STATUS_IS_OK(status)) {
2764 goto fail;
2767 status = cli_set_ea_fnum(cli,
2768 fnum,
2769 ea_name,
2770 ea_val,
2771 ea_len);
2772 if (!NT_STATUS_IS_OK(status)) {
2773 goto fail;
2776 fail:
2778 if (fnum != 0xffff) {
2779 cli_smb2_close_fnum(cli, fnum);
2782 cli->raw_status = status;
2784 return status;
2787 /***************************************************************
2788 Wrapper that allows SMB2 to get an EA list on a pathname.
2789 Synchronous only.
2790 ***************************************************************/
2792 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2793 const char *name,
2794 TALLOC_CTX *ctx,
2795 size_t *pnum_eas,
2796 struct ea_struct **pea_array)
2798 NTSTATUS status;
2799 uint16_t fnum = 0xffff;
2800 DATA_BLOB outbuf = data_blob_null;
2801 struct smb2_hnd *ph = NULL;
2802 struct ea_list *ea_list = NULL;
2803 struct ea_list *eal = NULL;
2804 size_t ea_count = 0;
2805 TALLOC_CTX *frame = talloc_stackframe();
2807 *pnum_eas = 0;
2808 *pea_array = NULL;
2810 if (smbXcli_conn_has_async_calls(cli->conn)) {
2812 * Can't use sync call while an async call is in flight
2814 status = NT_STATUS_INVALID_PARAMETER;
2815 goto fail;
2818 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2819 status = NT_STATUS_INVALID_PARAMETER;
2820 goto fail;
2823 status = get_fnum_from_path(cli,
2824 name,
2825 FILE_READ_EA,
2826 &fnum);
2828 if (!NT_STATUS_IS_OK(status)) {
2829 goto fail;
2832 status = map_fnum_to_smb2_handle(cli,
2833 fnum,
2834 &ph);
2835 if (!NT_STATUS_IS_OK(status)) {
2836 goto fail;
2839 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2840 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2842 status = smb2cli_query_info(cli->conn,
2843 cli->timeout,
2844 cli->smb2.session,
2845 cli->smb2.tcon,
2846 1, /* in_info_type */
2847 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2848 0xFFFF, /* in_max_output_length */
2849 NULL, /* in_input_buffer */
2850 0, /* in_additional_info */
2851 0, /* in_flags */
2852 ph->fid_persistent,
2853 ph->fid_volatile,
2854 frame,
2855 &outbuf);
2857 if (!NT_STATUS_IS_OK(status)) {
2858 goto fail;
2861 /* Parse the reply. */
2862 ea_list = read_nttrans_ea_list(ctx,
2863 (const char *)outbuf.data,
2864 outbuf.length);
2865 if (ea_list == NULL) {
2866 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2867 goto fail;
2870 /* Convert to an array. */
2871 for (eal = ea_list; eal; eal = eal->next) {
2872 ea_count++;
2875 if (ea_count) {
2876 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2877 if (*pea_array == NULL) {
2878 status = NT_STATUS_NO_MEMORY;
2879 goto fail;
2881 ea_count = 0;
2882 for (eal = ea_list; eal; eal = eal->next) {
2883 (*pea_array)[ea_count++] = eal->ea;
2885 *pnum_eas = ea_count;
2888 fail:
2890 if (fnum != 0xffff) {
2891 cli_smb2_close_fnum(cli, fnum);
2894 cli->raw_status = status;
2896 TALLOC_FREE(frame);
2897 return status;
2900 /***************************************************************
2901 Wrapper that allows SMB2 to get user quota.
2902 Synchronous only.
2903 ***************************************************************/
2905 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
2906 int quota_fnum,
2907 SMB_NTQUOTA_STRUCT *pqt)
2909 NTSTATUS status;
2910 DATA_BLOB inbuf = data_blob_null;
2911 DATA_BLOB outbuf = data_blob_null;
2912 struct smb2_hnd *ph = NULL;
2913 TALLOC_CTX *frame = talloc_stackframe();
2914 unsigned sid_len;
2915 unsigned int offset;
2916 uint8_t *buf;
2918 if (smbXcli_conn_has_async_calls(cli->conn)) {
2920 * Can't use sync call while an async call is in flight
2922 status = NT_STATUS_INVALID_PARAMETER;
2923 goto fail;
2926 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2927 status = NT_STATUS_INVALID_PARAMETER;
2928 goto fail;
2931 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2932 if (!NT_STATUS_IS_OK(status)) {
2933 goto fail;
2936 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
2938 inbuf = data_blob_talloc_zero(frame, 24 + sid_len);
2939 if (inbuf.data == NULL) {
2940 status = NT_STATUS_NO_MEMORY;
2941 goto fail;
2944 buf = inbuf.data;
2946 SCVAL(buf, 0, 1); /* ReturnSingle */
2947 SCVAL(buf, 1, 0); /* RestartScan */
2948 SSVAL(buf, 2, 0); /* Reserved */
2949 if (8 + sid_len < 8) {
2950 status = NT_STATUS_INVALID_PARAMETER;
2951 goto fail;
2953 SIVAL(buf, 4, 8 + sid_len); /* SidListLength */
2954 SIVAL(buf, 8, 0); /* StartSidLength */
2955 SIVAL(buf, 12, 0); /* StartSidOffset */
2956 SIVAL(buf, 16, 0); /* NextEntryOffset */
2957 SIVAL(buf, 20, sid_len); /* SidLength */
2958 sid_linearize(buf + 24, sid_len, &pqt->sid);
2960 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2961 cli->smb2.tcon, 4, /* in_info_type */
2962 0, /* in_file_info_class */
2963 0xFFFF, /* in_max_output_length */
2964 &inbuf, /* in_input_buffer */
2965 0, /* in_additional_info */
2966 0, /* in_flags */
2967 ph->fid_persistent, ph->fid_volatile, frame,
2968 &outbuf);
2970 if (!NT_STATUS_IS_OK(status)) {
2971 goto fail;
2974 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
2975 pqt)) {
2976 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2977 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
2980 fail:
2981 cli->raw_status = status;
2983 TALLOC_FREE(frame);
2984 return status;
2987 /***************************************************************
2988 Wrapper that allows SMB2 to list user quota.
2989 Synchronous only.
2990 ***************************************************************/
2992 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
2993 TALLOC_CTX *mem_ctx,
2994 int quota_fnum,
2995 SMB_NTQUOTA_LIST **pqt_list,
2996 bool first)
2998 NTSTATUS status;
2999 DATA_BLOB inbuf = data_blob_null;
3000 DATA_BLOB outbuf = data_blob_null;
3001 struct smb2_hnd *ph = NULL;
3002 TALLOC_CTX *frame = talloc_stackframe();
3003 uint8_t *buf;
3005 if (smbXcli_conn_has_async_calls(cli->conn)) {
3007 * Can't use sync call while an async call is in flight
3009 status = NT_STATUS_INVALID_PARAMETER;
3010 goto cleanup;
3013 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3014 status = NT_STATUS_INVALID_PARAMETER;
3015 goto cleanup;
3018 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3019 if (!NT_STATUS_IS_OK(status)) {
3020 goto cleanup;
3023 inbuf = data_blob_talloc_zero(frame, 16);
3024 if (inbuf.data == NULL) {
3025 status = NT_STATUS_NO_MEMORY;
3026 goto cleanup;
3029 buf = inbuf.data;
3031 SCVAL(buf, 0, 0); /* ReturnSingle */
3032 SCVAL(buf, 1, first ? 1 : 0); /* RestartScan */
3033 SSVAL(buf, 2, 0); /* Reserved */
3034 SIVAL(buf, 4, 0); /* SidListLength */
3035 SIVAL(buf, 8, 0); /* StartSidLength */
3036 SIVAL(buf, 12, 0); /* StartSidOffset */
3038 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
3039 cli->smb2.tcon, 4, /* in_info_type */
3040 0, /* in_file_info_class */
3041 0xFFFF, /* in_max_output_length */
3042 &inbuf, /* in_input_buffer */
3043 0, /* in_additional_info */
3044 0, /* in_flags */
3045 ph->fid_persistent, ph->fid_volatile, frame,
3046 &outbuf);
3048 if (!NT_STATUS_IS_OK(status)) {
3049 goto cleanup;
3052 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
3053 pqt_list);
3055 cleanup:
3056 cli->raw_status = status;
3058 TALLOC_FREE(frame);
3059 return status;
3062 /***************************************************************
3063 Wrapper that allows SMB2 to get file system quota.
3064 Synchronous only.
3065 ***************************************************************/
3067 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
3068 int quota_fnum,
3069 SMB_NTQUOTA_STRUCT *pqt)
3071 NTSTATUS status;
3072 DATA_BLOB outbuf = data_blob_null;
3073 struct smb2_hnd *ph = NULL;
3074 TALLOC_CTX *frame = talloc_stackframe();
3076 if (smbXcli_conn_has_async_calls(cli->conn)) {
3078 * Can't use sync call while an async call is in flight
3080 status = NT_STATUS_INVALID_PARAMETER;
3081 goto cleanup;
3084 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3085 status = NT_STATUS_INVALID_PARAMETER;
3086 goto cleanup;
3089 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3090 if (!NT_STATUS_IS_OK(status)) {
3091 goto cleanup;
3094 status = smb2cli_query_info(
3095 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3096 2, /* in_info_type */
3097 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3098 0xFFFF, /* in_max_output_length */
3099 NULL, /* in_input_buffer */
3100 0, /* in_additional_info */
3101 0, /* in_flags */
3102 ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
3104 if (!NT_STATUS_IS_OK(status)) {
3105 goto cleanup;
3108 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
3110 cleanup:
3111 cli->raw_status = status;
3113 TALLOC_FREE(frame);
3114 return status;
3117 /***************************************************************
3118 Wrapper that allows SMB2 to set user quota.
3119 Synchronous only.
3120 ***************************************************************/
3122 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
3123 int quota_fnum,
3124 SMB_NTQUOTA_LIST *qtl)
3126 NTSTATUS status;
3127 DATA_BLOB inbuf = data_blob_null;
3128 struct smb2_hnd *ph = NULL;
3129 TALLOC_CTX *frame = talloc_stackframe();
3131 if (smbXcli_conn_has_async_calls(cli->conn)) {
3133 * Can't use sync call while an async call is in flight
3135 status = NT_STATUS_INVALID_PARAMETER;
3136 goto cleanup;
3139 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3140 status = NT_STATUS_INVALID_PARAMETER;
3141 goto cleanup;
3144 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3145 if (!NT_STATUS_IS_OK(status)) {
3146 goto cleanup;
3149 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
3150 if (!NT_STATUS_IS_OK(status)) {
3151 goto cleanup;
3154 status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
3155 cli->smb2.tcon, 4, /* in_info_type */
3156 0, /* in_file_info_class */
3157 &inbuf, /* in_input_buffer */
3158 0, /* in_additional_info */
3159 ph->fid_persistent, ph->fid_volatile);
3160 cleanup:
3162 cli->raw_status = status;
3164 TALLOC_FREE(frame);
3166 return status;
3169 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
3170 int quota_fnum,
3171 SMB_NTQUOTA_STRUCT *pqt)
3173 NTSTATUS status;
3174 DATA_BLOB inbuf = data_blob_null;
3175 struct smb2_hnd *ph = NULL;
3176 TALLOC_CTX *frame = talloc_stackframe();
3178 if (smbXcli_conn_has_async_calls(cli->conn)) {
3180 * Can't use sync call while an async call is in flight
3182 status = NT_STATUS_INVALID_PARAMETER;
3183 goto cleanup;
3186 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3187 status = NT_STATUS_INVALID_PARAMETER;
3188 goto cleanup;
3191 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
3192 if (!NT_STATUS_IS_OK(status)) {
3193 goto cleanup;
3196 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
3197 if (!NT_STATUS_IS_OK(status)) {
3198 goto cleanup;
3201 status = smb2cli_set_info(
3202 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
3203 2, /* in_info_type */
3204 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
3205 &inbuf, /* in_input_buffer */
3206 0, /* in_additional_info */
3207 ph->fid_persistent, ph->fid_volatile);
3208 cleanup:
3209 cli->raw_status = status;
3211 TALLOC_FREE(frame);
3212 return status;
3215 struct cli_smb2_read_state {
3216 struct tevent_context *ev;
3217 struct cli_state *cli;
3218 struct smb2_hnd *ph;
3219 uint64_t start_offset;
3220 uint32_t size;
3221 uint32_t received;
3222 uint8_t *buf;
3225 static void cli_smb2_read_done(struct tevent_req *subreq);
3227 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
3228 struct tevent_context *ev,
3229 struct cli_state *cli,
3230 uint16_t fnum,
3231 off_t offset,
3232 size_t size)
3234 NTSTATUS status;
3235 struct tevent_req *req, *subreq;
3236 struct cli_smb2_read_state *state;
3238 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
3239 if (req == NULL) {
3240 return NULL;
3242 state->ev = ev;
3243 state->cli = cli;
3244 state->start_offset = (uint64_t)offset;
3245 state->size = (uint32_t)size;
3246 state->received = 0;
3247 state->buf = NULL;
3249 status = map_fnum_to_smb2_handle(cli,
3250 fnum,
3251 &state->ph);
3252 if (tevent_req_nterror(req, status)) {
3253 return tevent_req_post(req, ev);
3256 subreq = smb2cli_read_send(state,
3257 state->ev,
3258 state->cli->conn,
3259 state->cli->timeout,
3260 state->cli->smb2.session,
3261 state->cli->smb2.tcon,
3262 state->size,
3263 state->start_offset,
3264 state->ph->fid_persistent,
3265 state->ph->fid_volatile,
3266 0, /* minimum_count */
3267 0); /* remaining_bytes */
3269 if (tevent_req_nomem(subreq, req)) {
3270 return tevent_req_post(req, ev);
3272 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
3273 return req;
3276 static void cli_smb2_read_done(struct tevent_req *subreq)
3278 struct tevent_req *req = tevent_req_callback_data(
3279 subreq, struct tevent_req);
3280 struct cli_smb2_read_state *state = tevent_req_data(
3281 req, struct cli_smb2_read_state);
3282 NTSTATUS status;
3284 status = smb2cli_read_recv(subreq, state,
3285 &state->buf, &state->received);
3286 if (tevent_req_nterror(req, status)) {
3287 return;
3290 if (state->received > state->size) {
3291 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3292 return;
3295 tevent_req_done(req);
3298 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
3299 ssize_t *received,
3300 uint8_t **rcvbuf)
3302 NTSTATUS status;
3303 struct cli_smb2_read_state *state = tevent_req_data(
3304 req, struct cli_smb2_read_state);
3306 if (tevent_req_is_nterror(req, &status)) {
3307 state->cli->raw_status = status;
3308 return status;
3311 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
3312 * better make sure that you copy it away before you talloc_free(req).
3313 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
3315 *received = (ssize_t)state->received;
3316 *rcvbuf = state->buf;
3317 state->cli->raw_status = NT_STATUS_OK;
3318 return NT_STATUS_OK;
3321 struct cli_smb2_write_state {
3322 struct tevent_context *ev;
3323 struct cli_state *cli;
3324 struct smb2_hnd *ph;
3325 uint32_t flags;
3326 const uint8_t *buf;
3327 uint64_t offset;
3328 uint32_t size;
3329 uint32_t written;
3332 static void cli_smb2_write_written(struct tevent_req *req);
3334 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
3335 struct tevent_context *ev,
3336 struct cli_state *cli,
3337 uint16_t fnum,
3338 uint16_t mode,
3339 const uint8_t *buf,
3340 off_t offset,
3341 size_t size)
3343 NTSTATUS status;
3344 struct tevent_req *req, *subreq = NULL;
3345 struct cli_smb2_write_state *state = NULL;
3347 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
3348 if (req == NULL) {
3349 return NULL;
3351 state->ev = ev;
3352 state->cli = cli;
3353 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3354 state->flags = (uint32_t)mode;
3355 state->buf = buf;
3356 state->offset = (uint64_t)offset;
3357 state->size = (uint32_t)size;
3358 state->written = 0;
3360 status = map_fnum_to_smb2_handle(cli,
3361 fnum,
3362 &state->ph);
3363 if (tevent_req_nterror(req, status)) {
3364 return tevent_req_post(req, ev);
3367 subreq = smb2cli_write_send(state,
3368 state->ev,
3369 state->cli->conn,
3370 state->cli->timeout,
3371 state->cli->smb2.session,
3372 state->cli->smb2.tcon,
3373 state->size,
3374 state->offset,
3375 state->ph->fid_persistent,
3376 state->ph->fid_volatile,
3377 0, /* remaining_bytes */
3378 state->flags, /* flags */
3379 state->buf);
3381 if (tevent_req_nomem(subreq, req)) {
3382 return tevent_req_post(req, ev);
3384 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
3385 return req;
3388 static void cli_smb2_write_written(struct tevent_req *subreq)
3390 struct tevent_req *req = tevent_req_callback_data(
3391 subreq, struct tevent_req);
3392 struct cli_smb2_write_state *state = tevent_req_data(
3393 req, struct cli_smb2_write_state);
3394 NTSTATUS status;
3395 uint32_t written;
3397 status = smb2cli_write_recv(subreq, &written);
3398 TALLOC_FREE(subreq);
3399 if (tevent_req_nterror(req, status)) {
3400 return;
3403 state->written = written;
3405 tevent_req_done(req);
3408 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
3409 size_t *pwritten)
3411 struct cli_smb2_write_state *state = tevent_req_data(
3412 req, struct cli_smb2_write_state);
3413 NTSTATUS status;
3415 if (tevent_req_is_nterror(req, &status)) {
3416 state->cli->raw_status = status;
3417 tevent_req_received(req);
3418 return status;
3421 if (pwritten != NULL) {
3422 *pwritten = (size_t)state->written;
3424 state->cli->raw_status = NT_STATUS_OK;
3425 tevent_req_received(req);
3426 return NT_STATUS_OK;
3429 /***************************************************************
3430 Wrapper that allows SMB2 async write using an fnum.
3431 This is mostly cut-and-paste from Volker's code inside
3432 source3/libsmb/clireadwrite.c, adapted for SMB2.
3434 Done this way so I can reuse all the logic inside cli_push()
3435 for free :-).
3436 ***************************************************************/
3438 struct cli_smb2_writeall_state {
3439 struct tevent_context *ev;
3440 struct cli_state *cli;
3441 struct smb2_hnd *ph;
3442 uint32_t flags;
3443 const uint8_t *buf;
3444 uint64_t offset;
3445 uint32_t size;
3446 uint32_t written;
3449 static void cli_smb2_writeall_written(struct tevent_req *req);
3451 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
3452 struct tevent_context *ev,
3453 struct cli_state *cli,
3454 uint16_t fnum,
3455 uint16_t mode,
3456 const uint8_t *buf,
3457 off_t offset,
3458 size_t size)
3460 NTSTATUS status;
3461 struct tevent_req *req, *subreq = NULL;
3462 struct cli_smb2_writeall_state *state = NULL;
3463 uint32_t to_write;
3464 uint32_t max_size;
3465 bool ok;
3467 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
3468 if (req == NULL) {
3469 return NULL;
3471 state->ev = ev;
3472 state->cli = cli;
3473 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3474 state->flags = (uint32_t)mode;
3475 state->buf = buf;
3476 state->offset = (uint64_t)offset;
3477 state->size = (uint32_t)size;
3478 state->written = 0;
3480 status = map_fnum_to_smb2_handle(cli,
3481 fnum,
3482 &state->ph);
3483 if (tevent_req_nterror(req, status)) {
3484 return tevent_req_post(req, ev);
3487 to_write = state->size;
3488 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3489 to_write = MIN(max_size, to_write);
3490 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3491 if (ok) {
3492 to_write = MIN(max_size, to_write);
3495 subreq = smb2cli_write_send(state,
3496 state->ev,
3497 state->cli->conn,
3498 state->cli->timeout,
3499 state->cli->smb2.session,
3500 state->cli->smb2.tcon,
3501 to_write,
3502 state->offset,
3503 state->ph->fid_persistent,
3504 state->ph->fid_volatile,
3505 0, /* remaining_bytes */
3506 state->flags, /* flags */
3507 state->buf + state->written);
3509 if (tevent_req_nomem(subreq, req)) {
3510 return tevent_req_post(req, ev);
3512 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3513 return req;
3516 static void cli_smb2_writeall_written(struct tevent_req *subreq)
3518 struct tevent_req *req = tevent_req_callback_data(
3519 subreq, struct tevent_req);
3520 struct cli_smb2_writeall_state *state = tevent_req_data(
3521 req, struct cli_smb2_writeall_state);
3522 NTSTATUS status;
3523 uint32_t written, to_write;
3524 uint32_t max_size;
3525 bool ok;
3527 status = smb2cli_write_recv(subreq, &written);
3528 TALLOC_FREE(subreq);
3529 if (tevent_req_nterror(req, status)) {
3530 return;
3533 state->written += written;
3535 if (state->written > state->size) {
3536 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3537 return;
3540 to_write = state->size - state->written;
3542 if (to_write == 0) {
3543 tevent_req_done(req);
3544 return;
3547 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3548 to_write = MIN(max_size, to_write);
3549 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3550 if (ok) {
3551 to_write = MIN(max_size, to_write);
3554 subreq = smb2cli_write_send(state,
3555 state->ev,
3556 state->cli->conn,
3557 state->cli->timeout,
3558 state->cli->smb2.session,
3559 state->cli->smb2.tcon,
3560 to_write,
3561 state->offset + state->written,
3562 state->ph->fid_persistent,
3563 state->ph->fid_volatile,
3564 0, /* remaining_bytes */
3565 state->flags, /* flags */
3566 state->buf + state->written);
3568 if (tevent_req_nomem(subreq, req)) {
3569 return;
3571 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3574 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
3575 size_t *pwritten)
3577 struct cli_smb2_writeall_state *state = tevent_req_data(
3578 req, struct cli_smb2_writeall_state);
3579 NTSTATUS status;
3581 if (tevent_req_is_nterror(req, &status)) {
3582 state->cli->raw_status = status;
3583 return status;
3585 if (pwritten != NULL) {
3586 *pwritten = (size_t)state->written;
3588 state->cli->raw_status = NT_STATUS_OK;
3589 return NT_STATUS_OK;
3592 struct cli_smb2_splice_state {
3593 struct tevent_context *ev;
3594 struct cli_state *cli;
3595 struct smb2_hnd *src_ph;
3596 struct smb2_hnd *dst_ph;
3597 int (*splice_cb)(off_t n, void *priv);
3598 void *priv;
3599 off_t written;
3600 off_t size;
3601 off_t src_offset;
3602 off_t dst_offset;
3603 bool resized;
3604 struct req_resume_key_rsp resume_rsp;
3605 struct srv_copychunk_copy cc_copy;
3608 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3609 struct tevent_req *req);
3611 static void cli_splice_copychunk_done(struct tevent_req *subreq)
3613 struct tevent_req *req = tevent_req_callback_data(
3614 subreq, struct tevent_req);
3615 struct cli_smb2_splice_state *state =
3616 tevent_req_data(req,
3617 struct cli_smb2_splice_state);
3618 struct smbXcli_conn *conn = state->cli->conn;
3619 DATA_BLOB out_input_buffer = data_blob_null;
3620 DATA_BLOB out_output_buffer = data_blob_null;
3621 struct srv_copychunk_rsp cc_copy_rsp;
3622 enum ndr_err_code ndr_ret;
3623 NTSTATUS status;
3625 status = smb2cli_ioctl_recv(subreq, state,
3626 &out_input_buffer,
3627 &out_output_buffer);
3628 TALLOC_FREE(subreq);
3629 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
3630 state->resized) && tevent_req_nterror(req, status)) {
3631 return;
3634 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
3635 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
3636 if (ndr_ret != NDR_ERR_SUCCESS) {
3637 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3638 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3639 return;
3642 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
3643 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
3644 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
3645 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
3646 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
3647 tevent_req_nterror(req, status)) {
3648 return;
3651 state->resized = true;
3652 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
3653 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
3654 } else {
3655 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3656 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3657 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
3658 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3659 return;
3661 state->src_offset += cc_copy_rsp.total_bytes_written;
3662 state->dst_offset += cc_copy_rsp.total_bytes_written;
3663 state->written += cc_copy_rsp.total_bytes_written;
3664 if (!state->splice_cb(state->written, state->priv)) {
3665 tevent_req_nterror(req, NT_STATUS_CANCELLED);
3666 return;
3670 cli_splice_copychunk_send(state, req);
3673 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3674 struct tevent_req *req)
3676 struct tevent_req *subreq;
3677 enum ndr_err_code ndr_ret;
3678 struct smbXcli_conn *conn = state->cli->conn;
3679 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
3680 off_t src_offset = state->src_offset;
3681 off_t dst_offset = state->dst_offset;
3682 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
3683 state->size - state->written);
3684 DATA_BLOB in_input_buffer = data_blob_null;
3685 DATA_BLOB in_output_buffer = data_blob_null;
3687 if (state->size - state->written == 0) {
3688 tevent_req_done(req);
3689 return;
3692 cc_copy->chunk_count = 0;
3693 while (req_len) {
3694 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
3695 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
3696 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
3697 smb2cli_conn_cc_chunk_len(conn));
3698 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
3699 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3700 return;
3702 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
3703 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
3704 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
3705 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3706 return;
3708 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3709 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3710 cc_copy->chunk_count++;
3713 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
3714 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
3715 if (ndr_ret != NDR_ERR_SUCCESS) {
3716 DEBUG(0, ("failed to marshall copy chunk req\n"));
3717 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3718 return;
3721 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
3722 state->cli->timeout,
3723 state->cli->smb2.session,
3724 state->cli->smb2.tcon,
3725 state->dst_ph->fid_persistent, /* in_fid_persistent */
3726 state->dst_ph->fid_volatile, /* in_fid_volatile */
3727 FSCTL_SRV_COPYCHUNK_WRITE,
3728 0, /* in_max_input_length */
3729 &in_input_buffer,
3730 12, /* in_max_output_length */
3731 &in_output_buffer,
3732 SMB2_IOCTL_FLAG_IS_FSCTL);
3733 if (tevent_req_nomem(subreq, req)) {
3734 return;
3736 tevent_req_set_callback(subreq,
3737 cli_splice_copychunk_done,
3738 req);
3741 static void cli_splice_key_done(struct tevent_req *subreq)
3743 struct tevent_req *req = tevent_req_callback_data(
3744 subreq, struct tevent_req);
3745 struct cli_smb2_splice_state *state =
3746 tevent_req_data(req,
3747 struct cli_smb2_splice_state);
3748 enum ndr_err_code ndr_ret;
3749 NTSTATUS status;
3751 DATA_BLOB out_input_buffer = data_blob_null;
3752 DATA_BLOB out_output_buffer = data_blob_null;
3754 status = smb2cli_ioctl_recv(subreq, state,
3755 &out_input_buffer,
3756 &out_output_buffer);
3757 TALLOC_FREE(subreq);
3758 if (tevent_req_nterror(req, status)) {
3759 return;
3762 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
3763 state, &state->resume_rsp,
3764 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
3765 if (ndr_ret != NDR_ERR_SUCCESS) {
3766 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3767 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3768 return;
3771 memcpy(&state->cc_copy.source_key,
3772 &state->resume_rsp.resume_key,
3773 sizeof state->resume_rsp.resume_key);
3775 cli_splice_copychunk_send(state, req);
3778 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
3779 struct tevent_context *ev,
3780 struct cli_state *cli,
3781 uint16_t src_fnum, uint16_t dst_fnum,
3782 off_t size, off_t src_offset, off_t dst_offset,
3783 int (*splice_cb)(off_t n, void *priv),
3784 void *priv)
3786 struct tevent_req *req;
3787 struct tevent_req *subreq;
3788 struct cli_smb2_splice_state *state;
3789 NTSTATUS status;
3790 DATA_BLOB in_input_buffer = data_blob_null;
3791 DATA_BLOB in_output_buffer = data_blob_null;
3793 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
3794 if (req == NULL) {
3795 return NULL;
3797 state->cli = cli;
3798 state->ev = ev;
3799 state->splice_cb = splice_cb;
3800 state->priv = priv;
3801 state->size = size;
3802 state->written = 0;
3803 state->src_offset = src_offset;
3804 state->dst_offset = dst_offset;
3805 state->cc_copy.chunks = talloc_array(state,
3806 struct srv_copychunk,
3807 smb2cli_conn_cc_max_chunks(cli->conn));
3808 if (state->cc_copy.chunks == NULL) {
3809 return NULL;
3812 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
3813 if (tevent_req_nterror(req, status))
3814 return tevent_req_post(req, ev);
3816 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
3817 if (tevent_req_nterror(req, status))
3818 return tevent_req_post(req, ev);
3820 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
3821 cli->timeout,
3822 cli->smb2.session,
3823 cli->smb2.tcon,
3824 state->src_ph->fid_persistent, /* in_fid_persistent */
3825 state->src_ph->fid_volatile, /* in_fid_volatile */
3826 FSCTL_SRV_REQUEST_RESUME_KEY,
3827 0, /* in_max_input_length */
3828 &in_input_buffer,
3829 32, /* in_max_output_length */
3830 &in_output_buffer,
3831 SMB2_IOCTL_FLAG_IS_FSCTL);
3832 if (tevent_req_nomem(subreq, req)) {
3833 return NULL;
3835 tevent_req_set_callback(subreq,
3836 cli_splice_key_done,
3837 req);
3839 return req;
3842 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
3844 struct cli_smb2_splice_state *state = tevent_req_data(
3845 req, struct cli_smb2_splice_state);
3846 NTSTATUS status;
3848 if (tevent_req_is_nterror(req, &status)) {
3849 state->cli->raw_status = status;
3850 tevent_req_received(req);
3851 return status;
3853 if (written != NULL) {
3854 *written = state->written;
3856 state->cli->raw_status = NT_STATUS_OK;
3857 tevent_req_received(req);
3858 return NT_STATUS_OK;
3861 /***************************************************************
3862 SMB2 enum shadow copy data.
3863 ***************************************************************/
3865 struct cli_smb2_shadow_copy_data_fnum_state {
3866 struct cli_state *cli;
3867 uint16_t fnum;
3868 struct smb2_hnd *ph;
3869 DATA_BLOB out_input_buffer;
3870 DATA_BLOB out_output_buffer;
3873 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
3875 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
3876 TALLOC_CTX *mem_ctx,
3877 struct tevent_context *ev,
3878 struct cli_state *cli,
3879 uint16_t fnum,
3880 bool get_names)
3882 struct tevent_req *req, *subreq;
3883 struct cli_smb2_shadow_copy_data_fnum_state *state;
3884 NTSTATUS status;
3886 req = tevent_req_create(mem_ctx, &state,
3887 struct cli_smb2_shadow_copy_data_fnum_state);
3888 if (req == NULL) {
3889 return NULL;
3892 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3893 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3894 return tevent_req_post(req, ev);
3897 state->cli = cli;
3898 state->fnum = fnum;
3900 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
3901 if (tevent_req_nterror(req, status)) {
3902 return tevent_req_post(req, ev);
3906 * TODO. Under SMB2 we should send a zero max_output_length
3907 * ioctl to get the required size, then send another ioctl
3908 * to get the data, but the current SMB1 implementation just
3909 * does one roundtrip with a 64K buffer size. Do the same
3910 * for now. JRA.
3913 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
3914 state->cli->timeout,
3915 state->cli->smb2.session,
3916 state->cli->smb2.tcon,
3917 state->ph->fid_persistent, /* in_fid_persistent */
3918 state->ph->fid_volatile, /* in_fid_volatile */
3919 FSCTL_GET_SHADOW_COPY_DATA,
3920 0, /* in_max_input_length */
3921 NULL, /* in_input_buffer */
3922 get_names ?
3923 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
3924 NULL, /* in_output_buffer */
3925 SMB2_IOCTL_FLAG_IS_FSCTL);
3927 if (tevent_req_nomem(subreq, req)) {
3928 return tevent_req_post(req, ev);
3930 tevent_req_set_callback(subreq,
3931 cli_smb2_shadow_copy_data_fnum_done,
3932 req);
3934 return req;
3937 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
3939 struct tevent_req *req = tevent_req_callback_data(
3940 subreq, struct tevent_req);
3941 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3942 req, struct cli_smb2_shadow_copy_data_fnum_state);
3943 NTSTATUS status;
3945 status = smb2cli_ioctl_recv(subreq, state,
3946 &state->out_input_buffer,
3947 &state->out_output_buffer);
3948 TALLOC_FREE(subreq);
3949 if (tevent_req_nterror(req, status)) {
3950 return;
3952 tevent_req_done(req);
3955 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
3956 TALLOC_CTX *mem_ctx,
3957 bool get_names,
3958 char ***pnames,
3959 int *pnum_names)
3961 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3962 req, struct cli_smb2_shadow_copy_data_fnum_state);
3963 char **names = NULL;
3964 uint32_t num_names = 0;
3965 uint32_t num_names_returned = 0;
3966 uint32_t dlength = 0;
3967 uint32_t i;
3968 uint8_t *endp = NULL;
3969 NTSTATUS status;
3971 if (tevent_req_is_nterror(req, &status)) {
3972 return status;
3975 if (state->out_output_buffer.length < 16) {
3976 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3979 num_names = IVAL(state->out_output_buffer.data, 0);
3980 num_names_returned = IVAL(state->out_output_buffer.data, 4);
3981 dlength = IVAL(state->out_output_buffer.data, 8);
3983 if (num_names > 0x7FFFFFFF) {
3984 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3987 if (get_names == false) {
3988 *pnum_names = (int)num_names;
3989 return NT_STATUS_OK;
3991 if (num_names != num_names_returned) {
3992 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3994 if (dlength + 12 < 12) {
3995 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3998 * NB. The below is an allowable return if there are
3999 * more snapshots than the buffer size we told the
4000 * server we can receive. We currently don't support
4001 * this.
4003 if (dlength + 12 > state->out_output_buffer.length) {
4004 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4006 if (state->out_output_buffer.length +
4007 (2 * sizeof(SHADOW_COPY_LABEL)) <
4008 state->out_output_buffer.length) {
4009 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4012 names = talloc_array(mem_ctx, char *, num_names_returned);
4013 if (names == NULL) {
4014 return NT_STATUS_NO_MEMORY;
4017 endp = state->out_output_buffer.data +
4018 state->out_output_buffer.length;
4020 for (i=0; i<num_names_returned; i++) {
4021 bool ret;
4022 uint8_t *src;
4023 size_t converted_size;
4025 src = state->out_output_buffer.data + 12 +
4026 (i * 2 * sizeof(SHADOW_COPY_LABEL));
4028 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
4029 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4031 ret = convert_string_talloc(
4032 names, CH_UTF16LE, CH_UNIX,
4033 src, 2 * sizeof(SHADOW_COPY_LABEL),
4034 &names[i], &converted_size);
4035 if (!ret) {
4036 TALLOC_FREE(names);
4037 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4040 *pnum_names = num_names;
4041 *pnames = names;
4042 return NT_STATUS_OK;
4045 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
4046 struct cli_state *cli,
4047 uint16_t fnum,
4048 bool get_names,
4049 char ***pnames,
4050 int *pnum_names)
4052 TALLOC_CTX *frame = talloc_stackframe();
4053 struct tevent_context *ev;
4054 struct tevent_req *req;
4055 NTSTATUS status = NT_STATUS_NO_MEMORY;
4057 if (smbXcli_conn_has_async_calls(cli->conn)) {
4059 * Can't use sync call while an async call is in flight
4061 status = NT_STATUS_INVALID_PARAMETER;
4062 goto fail;
4064 ev = samba_tevent_context_init(frame);
4065 if (ev == NULL) {
4066 goto fail;
4068 req = cli_smb2_shadow_copy_data_fnum_send(frame,
4070 cli,
4071 fnum,
4072 get_names);
4073 if (req == NULL) {
4074 goto fail;
4076 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4077 goto fail;
4079 status = cli_smb2_shadow_copy_data_fnum_recv(req,
4080 mem_ctx,
4081 get_names,
4082 pnames,
4083 pnum_names);
4084 fail:
4085 cli->raw_status = status;
4087 TALLOC_FREE(frame);
4088 return status;
4091 /***************************************************************
4092 Wrapper that allows SMB2 to truncate a file.
4093 Synchronous only.
4094 ***************************************************************/
4096 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
4097 uint16_t fnum,
4098 uint64_t newsize)
4100 NTSTATUS status;
4101 DATA_BLOB inbuf = data_blob_null;
4102 struct smb2_hnd *ph = NULL;
4103 TALLOC_CTX *frame = talloc_stackframe();
4105 if (smbXcli_conn_has_async_calls(cli->conn)) {
4107 * Can't use sync call while an async call is in flight
4109 status = NT_STATUS_INVALID_PARAMETER;
4110 goto fail;
4113 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4114 status = NT_STATUS_INVALID_PARAMETER;
4115 goto fail;
4118 status = map_fnum_to_smb2_handle(cli,
4119 fnum,
4120 &ph);
4121 if (!NT_STATUS_IS_OK(status)) {
4122 goto fail;
4125 inbuf = data_blob_talloc_zero(frame, 8);
4126 if (inbuf.data == NULL) {
4127 status = NT_STATUS_NO_MEMORY;
4128 goto fail;
4131 SBVAL(inbuf.data, 0, newsize);
4133 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
4134 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
4136 status = smb2cli_set_info(cli->conn,
4137 cli->timeout,
4138 cli->smb2.session,
4139 cli->smb2.tcon,
4140 1, /* in_info_type */
4141 /* in_file_info_class */
4142 SMB_FILE_END_OF_FILE_INFORMATION - 1000,
4143 &inbuf, /* in_input_buffer */
4144 0, /* in_additional_info */
4145 ph->fid_persistent,
4146 ph->fid_volatile);
4148 fail:
4150 cli->raw_status = status;
4152 TALLOC_FREE(frame);
4153 return status;
4156 NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
4157 uint32_t buffer_size, uint32_t completion_filter,
4158 bool recursive, TALLOC_CTX *mem_ctx,
4159 struct notify_change **pchanges,
4160 uint32_t *pnum_changes)
4162 NTSTATUS status;
4163 struct smb2_hnd *ph = NULL;
4164 TALLOC_CTX *frame = talloc_stackframe();
4165 uint8_t *base;
4166 uint32_t len, ofs;
4167 struct notify_change *changes = NULL;
4168 size_t num_changes = 0;
4170 if (smbXcli_conn_has_async_calls(cli->conn)) {
4172 * Can't use sync call while an async call is in flight
4174 status = NT_STATUS_INVALID_PARAMETER;
4175 goto fail;
4178 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4179 status = NT_STATUS_INVALID_PARAMETER;
4180 goto fail;
4183 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
4184 if (!NT_STATUS_IS_OK(status)) {
4185 goto fail;
4188 status = smb2cli_notify(cli->conn, cli->timeout,
4189 cli->smb2.session, cli->smb2.tcon,
4190 buffer_size,
4191 ph->fid_persistent, ph->fid_volatile,
4192 completion_filter, recursive,
4193 frame, &base, &len);
4195 ofs = 0;
4197 while (len - ofs >= 12) {
4198 struct notify_change *tmp;
4199 struct notify_change *c;
4200 uint32_t next_ofs = IVAL(base, ofs);
4201 uint32_t file_name_length = IVAL(base, ofs+8);
4202 size_t namelen;
4203 bool ok;
4205 tmp = talloc_realloc(frame, changes, struct notify_change,
4206 num_changes + 1);
4207 if (tmp == NULL) {
4208 status = NT_STATUS_NO_MEMORY;
4209 goto fail;
4211 changes = tmp;
4212 c = &changes[num_changes];
4213 num_changes += 1;
4215 if (smb_buffer_oob(len, ofs, next_ofs) ||
4216 smb_buffer_oob(len, ofs+12, file_name_length)) {
4217 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
4218 goto fail;
4221 c->action = IVAL(base, ofs+4);
4223 ok = convert_string_talloc(changes, CH_UTF16LE, CH_UNIX,
4224 base + ofs + 12, file_name_length,
4225 &c->name, &namelen);
4226 if (!ok) {
4227 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
4228 goto fail;
4231 if (next_ofs == 0) {
4232 break;
4234 ofs += next_ofs;
4237 *pchanges = talloc_move(mem_ctx, &changes);
4238 *pnum_changes = num_changes;
4239 status = NT_STATUS_OK;
4241 fail:
4242 cli->raw_status = status;
4244 TALLOC_FREE(frame);
4245 return status;
4248 struct cli_smb2_set_reparse_point_fnum_state {
4249 struct cli_state *cli;
4250 uint16_t fnum;
4251 struct smb2_hnd *ph;
4252 DATA_BLOB input_buffer;
4255 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
4257 struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
4258 TALLOC_CTX *mem_ctx,
4259 struct tevent_context *ev,
4260 struct cli_state *cli,
4261 uint16_t fnum,
4262 DATA_BLOB in_buf)
4264 struct tevent_req *req, *subreq;
4265 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
4266 NTSTATUS status;
4268 req = tevent_req_create(mem_ctx, &state,
4269 struct cli_smb2_set_reparse_point_fnum_state);
4270 if (req == NULL) {
4271 return NULL;
4274 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4275 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4276 return tevent_req_post(req, ev);
4279 state->cli = cli;
4280 state->fnum = fnum;
4282 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4283 if (tevent_req_nterror(req, status)) {
4284 return tevent_req_post(req, ev);
4287 state->input_buffer = data_blob_talloc(state,
4288 in_buf.data,
4289 in_buf.length);
4290 if (state->input_buffer.data == NULL) {
4291 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4292 return tevent_req_post(req, ev);
4295 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4296 state->cli->timeout,
4297 state->cli->smb2.session,
4298 state->cli->smb2.tcon,
4299 state->ph->fid_persistent, /* in_fid_persistent */
4300 state->ph->fid_volatile, /* in_fid_volatile */
4301 FSCTL_SET_REPARSE_POINT,
4302 0, /* in_max_input_length */
4303 &state->input_buffer ,
4305 NULL,
4306 SMB2_IOCTL_FLAG_IS_FSCTL);
4308 if (tevent_req_nomem(subreq, req)) {
4309 return tevent_req_post(req, ev);
4311 tevent_req_set_callback(subreq,
4312 cli_smb2_set_reparse_point_fnum_done,
4313 req);
4315 return req;
4318 static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
4320 struct tevent_req *req = tevent_req_callback_data(
4321 subreq, struct tevent_req);
4322 struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
4323 req, struct cli_smb2_set_reparse_point_fnum_state);
4324 NTSTATUS status;
4326 status = smb2cli_ioctl_recv(subreq, state,
4327 NULL,
4328 NULL);
4329 TALLOC_FREE(subreq);
4330 if (tevent_req_nterror(req, status)) {
4331 return;
4333 tevent_req_done(req);
4336 NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
4338 return tevent_req_simple_recv_ntstatus(req);
4341 struct cli_smb2_get_reparse_point_fnum_state {
4342 struct cli_state *cli;
4343 uint16_t fnum;
4344 struct smb2_hnd *ph;
4345 DATA_BLOB output_buffer;
4348 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
4350 struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
4351 TALLOC_CTX *mem_ctx,
4352 struct tevent_context *ev,
4353 struct cli_state *cli,
4354 uint16_t fnum)
4356 struct tevent_req *req, *subreq;
4357 struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
4358 NTSTATUS status;
4360 req = tevent_req_create(mem_ctx, &state,
4361 struct cli_smb2_get_reparse_point_fnum_state);
4362 if (req == NULL) {
4363 return NULL;
4366 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
4367 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
4368 return tevent_req_post(req, ev);
4371 state->cli = cli;
4372 state->fnum = fnum;
4374 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
4375 if (tevent_req_nterror(req, status)) {
4376 return tevent_req_post(req, ev);
4379 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
4380 state->cli->timeout,
4381 state->cli->smb2.session,
4382 state->cli->smb2.tcon,
4383 state->ph->fid_persistent, /* in_fid_persistent */
4384 state->ph->fid_volatile, /* in_fid_volatile */
4385 FSCTL_GET_REPARSE_POINT,
4386 0, /* in_max_input_length */
4387 NULL,
4388 64*1024,
4389 NULL,
4390 SMB2_IOCTL_FLAG_IS_FSCTL);
4392 if (tevent_req_nomem(subreq, req)) {
4393 return tevent_req_post(req, ev);
4395 tevent_req_set_callback(subreq,
4396 cli_smb2_get_reparse_point_fnum_done,
4397 req);
4399 return req;
4402 static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
4404 struct tevent_req *req = tevent_req_callback_data(
4405 subreq, struct tevent_req);
4406 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
4407 req, struct cli_smb2_get_reparse_point_fnum_state);
4408 NTSTATUS status;
4410 status = smb2cli_ioctl_recv(subreq, state,
4411 NULL,
4412 &state->output_buffer);
4413 TALLOC_FREE(subreq);
4414 if (tevent_req_nterror(req, status)) {
4415 state->cli->raw_status = status;
4416 return;
4418 tevent_req_done(req);
4421 NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
4422 TALLOC_CTX *mem_ctx,
4423 DATA_BLOB *output)
4425 struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
4426 req, struct cli_smb2_get_reparse_point_fnum_state);
4428 if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
4429 tevent_req_received(req);
4430 return state->cli->raw_status;
4432 *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
4433 if (output->data == NULL) {
4434 tevent_req_received(req);
4435 return NT_STATUS_NO_MEMORY;
4437 tevent_req_received(req);
4438 return NT_STATUS_OK;