s3: libsmb: Reverse sense of 'clear all attributes', ignore attribute change in SMB2...
[Samba.git] / source3 / libsmb / cli_smb2_fnum.c
blob6967555797aea8b5022a0d97f9294833d87a0160
1 /*
2 Unix SMB/CIFS implementation.
3 smb2 lib
4 Copyright (C) Jeremy Allison 2013
5 Copyright (C) Volker Lendecke 2013
6 Copyright (C) Stefan Metzmacher 2013
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This code is a thin wrapper around the existing
24 cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c,
25 but allows the handles to be mapped to uint16_t fnums,
26 which are easier for smbclient to use.
29 #include "includes.h"
30 #include "client.h"
31 #include "async_smb.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "cli_smb2_fnum.h"
34 #include "trans2.h"
35 #include "clirap.h"
36 #include "../libcli/smb/smb2_create_blob.h"
37 #include "libsmb/proto.h"
38 #include "lib/util/tevent_ntstatus.h"
39 #include "../libcli/security/security.h"
40 #include "../librpc/gen_ndr/ndr_security.h"
41 #include "lib/util_ea.h"
42 #include "librpc/gen_ndr/ndr_ioctl.h"
43 #include "ntioctl.h"
45 struct smb2_hnd {
46 uint64_t fid_persistent;
47 uint64_t fid_volatile;
51 * Handle mapping code.
54 /***************************************************************
55 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
56 Ensures handle is owned by cli struct.
57 ***************************************************************/
59 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
60 const struct smb2_hnd *ph, /* In */
61 uint16_t *pfnum) /* Out */
63 int ret;
64 struct idr_context *idp = cli->smb2.open_handles;
65 struct smb2_hnd *owned_h = talloc_memdup(cli,
66 ph,
67 sizeof(struct smb2_hnd));
69 if (owned_h == NULL) {
70 return NT_STATUS_NO_MEMORY;
73 if (idp == NULL) {
74 /* Lazy init */
75 cli->smb2.open_handles = idr_init(cli);
76 if (cli->smb2.open_handles == NULL) {
77 TALLOC_FREE(owned_h);
78 return NT_STATUS_NO_MEMORY;
80 idp = cli->smb2.open_handles;
83 ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
84 if (ret == -1) {
85 TALLOC_FREE(owned_h);
86 return NT_STATUS_NO_MEMORY;
89 *pfnum = (uint16_t)ret;
90 return NT_STATUS_OK;
93 /***************************************************************
94 Return the smb2_hnd pointer associated with the given fnum.
95 ***************************************************************/
97 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
98 uint16_t fnum, /* In */
99 struct smb2_hnd **pph) /* Out */
101 struct idr_context *idp = cli->smb2.open_handles;
103 if (idp == NULL) {
104 return NT_STATUS_INVALID_PARAMETER;
106 *pph = (struct smb2_hnd *)idr_find(idp, fnum);
107 if (*pph == NULL) {
108 return NT_STATUS_INVALID_HANDLE;
110 return NT_STATUS_OK;
113 /***************************************************************
114 Delete the fnum to smb2_hnd mapping. Zeros out handle on
115 successful return.
116 ***************************************************************/
118 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
119 struct smb2_hnd **pph, /* In */
120 uint16_t fnum) /* In */
122 struct idr_context *idp = cli->smb2.open_handles;
123 struct smb2_hnd *ph;
125 if (idp == NULL) {
126 return NT_STATUS_INVALID_PARAMETER;
129 ph = (struct smb2_hnd *)idr_find(idp, fnum);
130 if (ph != *pph) {
131 return NT_STATUS_INVALID_PARAMETER;
133 idr_remove(idp, fnum);
134 TALLOC_FREE(*pph);
135 return NT_STATUS_OK;
138 /***************************************************************
139 Oplock mapping code.
140 ***************************************************************/
142 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
144 if (create_flags & REQUEST_BATCH_OPLOCK) {
145 return SMB2_OPLOCK_LEVEL_BATCH;
146 } else if (create_flags & REQUEST_OPLOCK) {
147 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
150 /* create_flags doesn't do a level2 request. */
151 return SMB2_OPLOCK_LEVEL_NONE;
154 /***************************************************************
155 Small wrapper that allows SMB2 create to return a uint16_t fnum.
156 ***************************************************************/
158 struct cli_smb2_create_fnum_state {
159 struct cli_state *cli;
160 struct smb_create_returns cr;
161 uint16_t fnum;
162 struct tevent_req *subreq;
165 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
166 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
168 struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
169 struct tevent_context *ev,
170 struct cli_state *cli,
171 const char *fname,
172 uint32_t create_flags,
173 uint32_t desired_access,
174 uint32_t file_attributes,
175 uint32_t share_access,
176 uint32_t create_disposition,
177 uint32_t create_options)
179 struct tevent_req *req, *subreq;
180 struct cli_smb2_create_fnum_state *state;
181 size_t fname_len = 0;
182 const char *startp = NULL;
183 const char *endp = NULL;
184 time_t tstamp = (time_t)0;
185 struct smb2_create_blobs *cblobs = NULL;
187 req = tevent_req_create(mem_ctx, &state,
188 struct cli_smb2_create_fnum_state);
189 if (req == NULL) {
190 return NULL;
192 state->cli = cli;
194 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
195 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
196 return tevent_req_post(req, ev);
199 if (cli->backup_intent) {
200 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
203 /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
204 fname_len = strlen(fname);
205 if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
206 size_t len_before_gmt = startp - fname;
207 size_t len_after_gmt = fname + fname_len - endp;
208 DATA_BLOB twrp_blob;
209 NTTIME ntt;
210 NTSTATUS status;
212 char *new_fname = talloc_array(state, char,
213 len_before_gmt + len_after_gmt + 1);
215 if (tevent_req_nomem(new_fname, req)) {
216 return tevent_req_post(req, ev);
219 memcpy(new_fname, fname, len_before_gmt);
220 memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
221 fname = new_fname;
222 fname_len = len_before_gmt + len_after_gmt;
224 unix_to_nt_time(&ntt, tstamp);
225 twrp_blob = data_blob_const((const void *)&ntt, 8);
227 cblobs = talloc_zero(state, struct smb2_create_blobs);
228 if (tevent_req_nomem(cblobs, req)) {
229 return tevent_req_post(req, ev);
232 status = smb2_create_blob_add(state, cblobs,
233 SMB2_CREATE_TAG_TWRP, twrp_blob);
234 if (!NT_STATUS_IS_OK(status)) {
235 tevent_req_nterror(req, status);
236 return tevent_req_post(req, ev);
240 /* SMB2 is pickier about pathnames. Ensure it doesn't
241 start in a '\' */
242 if (*fname == '\\') {
243 fname++;
244 fname_len--;
247 /* Or end in a '\' */
248 if (fname_len > 0 && fname[fname_len-1] == '\\') {
249 char *new_fname = talloc_strdup(state, fname);
250 if (tevent_req_nomem(new_fname, req)) {
251 return tevent_req_post(req, ev);
253 new_fname[fname_len-1] = '\0';
254 fname = new_fname;
257 subreq = smb2cli_create_send(state, ev,
258 cli->conn,
259 cli->timeout,
260 cli->smb2.session,
261 cli->smb2.tcon,
262 fname,
263 flags_to_smb2_oplock(create_flags),
264 SMB2_IMPERSONATION_IMPERSONATION,
265 desired_access,
266 file_attributes,
267 share_access,
268 create_disposition,
269 create_options,
270 cblobs);
271 if (tevent_req_nomem(subreq, req)) {
272 return tevent_req_post(req, ev);
274 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
276 state->subreq = subreq;
277 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
279 return req;
282 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
284 struct tevent_req *req = tevent_req_callback_data(
285 subreq, struct tevent_req);
286 struct cli_smb2_create_fnum_state *state = tevent_req_data(
287 req, struct cli_smb2_create_fnum_state);
288 struct smb2_hnd h;
289 NTSTATUS status;
291 status = smb2cli_create_recv(subreq, &h.fid_persistent,
292 &h.fid_volatile, &state->cr, NULL, NULL);
293 TALLOC_FREE(subreq);
294 if (tevent_req_nterror(req, status)) {
295 return;
298 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
299 if (tevent_req_nterror(req, status)) {
300 return;
302 tevent_req_done(req);
305 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
307 struct cli_smb2_create_fnum_state *state = tevent_req_data(
308 req, struct cli_smb2_create_fnum_state);
309 return tevent_req_cancel(state->subreq);
312 NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum,
313 struct smb_create_returns *cr)
315 struct cli_smb2_create_fnum_state *state = tevent_req_data(
316 req, struct cli_smb2_create_fnum_state);
317 NTSTATUS status;
319 if (tevent_req_is_nterror(req, &status)) {
320 state->cli->raw_status = status;
321 return status;
323 if (pfnum != NULL) {
324 *pfnum = state->fnum;
326 if (cr != NULL) {
327 *cr = state->cr;
329 state->cli->raw_status = NT_STATUS_OK;
330 return NT_STATUS_OK;
333 NTSTATUS cli_smb2_create_fnum(struct cli_state *cli,
334 const char *fname,
335 uint32_t create_flags,
336 uint32_t desired_access,
337 uint32_t file_attributes,
338 uint32_t share_access,
339 uint32_t create_disposition,
340 uint32_t create_options,
341 uint16_t *pfid,
342 struct smb_create_returns *cr)
344 TALLOC_CTX *frame = talloc_stackframe();
345 struct tevent_context *ev;
346 struct tevent_req *req;
347 NTSTATUS status = NT_STATUS_NO_MEMORY;
349 if (smbXcli_conn_has_async_calls(cli->conn)) {
351 * Can't use sync call while an async call is in flight
353 status = NT_STATUS_INVALID_PARAMETER;
354 goto fail;
356 ev = samba_tevent_context_init(frame);
357 if (ev == NULL) {
358 goto fail;
360 req = cli_smb2_create_fnum_send(frame, ev, cli, fname, create_flags,
361 desired_access, file_attributes,
362 share_access, create_disposition,
363 create_options);
364 if (req == NULL) {
365 goto fail;
367 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
368 goto fail;
370 status = cli_smb2_create_fnum_recv(req, pfid, cr);
371 fail:
372 TALLOC_FREE(frame);
373 return status;
376 /***************************************************************
377 Small wrapper that allows SMB2 close to use a uint16_t fnum.
378 ***************************************************************/
380 struct cli_smb2_close_fnum_state {
381 struct cli_state *cli;
382 uint16_t fnum;
383 struct smb2_hnd *ph;
386 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
388 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
389 struct tevent_context *ev,
390 struct cli_state *cli,
391 uint16_t fnum)
393 struct tevent_req *req, *subreq;
394 struct cli_smb2_close_fnum_state *state;
395 NTSTATUS status;
397 req = tevent_req_create(mem_ctx, &state,
398 struct cli_smb2_close_fnum_state);
399 if (req == NULL) {
400 return NULL;
402 state->cli = cli;
403 state->fnum = fnum;
405 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
406 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
407 return tevent_req_post(req, ev);
410 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
411 if (tevent_req_nterror(req, status)) {
412 return tevent_req_post(req, ev);
415 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
416 cli->smb2.session, cli->smb2.tcon,
417 0, state->ph->fid_persistent,
418 state->ph->fid_volatile);
419 if (tevent_req_nomem(subreq, req)) {
420 return tevent_req_post(req, ev);
422 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
423 return req;
426 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
428 struct tevent_req *req = tevent_req_callback_data(
429 subreq, struct tevent_req);
430 struct cli_smb2_close_fnum_state *state = tevent_req_data(
431 req, struct cli_smb2_close_fnum_state);
432 NTSTATUS status;
434 status = smb2cli_close_recv(subreq);
435 if (tevent_req_nterror(req, status)) {
436 return;
439 /* Delete the fnum -> handle mapping. */
440 status = delete_smb2_handle_mapping(state->cli, &state->ph,
441 state->fnum);
442 if (tevent_req_nterror(req, status)) {
443 return;
445 tevent_req_done(req);
448 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
450 struct cli_smb2_close_fnum_state *state = tevent_req_data(
451 req, struct cli_smb2_close_fnum_state);
452 NTSTATUS status = tevent_req_simple_recv_ntstatus(req);
453 state->cli->raw_status = status;
454 return status;
457 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
459 TALLOC_CTX *frame = talloc_stackframe();
460 struct tevent_context *ev;
461 struct tevent_req *req;
462 NTSTATUS status = NT_STATUS_NO_MEMORY;
464 if (smbXcli_conn_has_async_calls(cli->conn)) {
466 * Can't use sync call while an async call is in flight
468 status = NT_STATUS_INVALID_PARAMETER;
469 goto fail;
471 ev = samba_tevent_context_init(frame);
472 if (ev == NULL) {
473 goto fail;
475 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
476 if (req == NULL) {
477 goto fail;
479 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
480 goto fail;
482 status = cli_smb2_close_fnum_recv(req);
483 fail:
484 TALLOC_FREE(frame);
485 return status;
488 struct cli_smb2_delete_on_close_state {
489 struct cli_state *cli;
490 uint16_t fnum;
491 struct smb2_hnd *ph;
492 uint8_t data[1];
493 DATA_BLOB inbuf;
496 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
498 struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
499 struct tevent_context *ev,
500 struct cli_state *cli,
501 uint16_t fnum,
502 bool flag)
504 struct tevent_req *req = NULL;
505 struct cli_smb2_delete_on_close_state *state = NULL;
506 struct tevent_req *subreq = NULL;
507 uint8_t in_info_type;
508 uint8_t in_file_info_class;
509 NTSTATUS status;
511 req = tevent_req_create(mem_ctx, &state,
512 struct cli_smb2_delete_on_close_state);
513 if (req == NULL) {
514 return NULL;
516 state->cli = cli;
517 state->fnum = fnum;
519 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
520 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
521 return tevent_req_post(req, ev);
524 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
525 if (tevent_req_nterror(req, status)) {
526 return tevent_req_post(req, ev);
530 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
531 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
533 in_info_type = 1;
534 in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
535 /* Setup data array. */
536 SCVAL(&state->data[0], 0, flag ? 1 : 0);
537 state->inbuf.data = &state->data[0];
538 state->inbuf.length = 1;
540 subreq = smb2cli_set_info_send(state, ev,
541 cli->conn,
542 cli->timeout,
543 cli->smb2.session,
544 cli->smb2.tcon,
545 in_info_type,
546 in_file_info_class,
547 &state->inbuf, /* in_input_buffer */
548 0, /* in_additional_info */
549 state->ph->fid_persistent,
550 state->ph->fid_volatile);
551 if (tevent_req_nomem(subreq, req)) {
552 return tevent_req_post(req, ev);
554 tevent_req_set_callback(subreq,
555 cli_smb2_delete_on_close_done,
556 req);
557 return req;
560 static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
562 NTSTATUS status = smb2cli_set_info_recv(subreq);
563 tevent_req_simple_finish_ntstatus(subreq, status);
566 NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
568 struct cli_smb2_delete_on_close_state *state =
569 tevent_req_data(req,
570 struct cli_smb2_delete_on_close_state);
571 NTSTATUS status;
573 if (tevent_req_is_nterror(req, &status)) {
574 state->cli->raw_status = status;
575 tevent_req_received(req);
576 return status;
579 state->cli->raw_status = NT_STATUS_OK;
580 tevent_req_received(req);
581 return NT_STATUS_OK;
584 NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
586 TALLOC_CTX *frame = talloc_stackframe();
587 struct tevent_context *ev;
588 struct tevent_req *req;
589 NTSTATUS status = NT_STATUS_NO_MEMORY;
591 if (smbXcli_conn_has_async_calls(cli->conn)) {
593 * Can't use sync call while an async call is in flight
595 status = NT_STATUS_INVALID_PARAMETER;
596 goto fail;
598 ev = samba_tevent_context_init(frame);
599 if (ev == NULL) {
600 goto fail;
602 req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
603 if (req == NULL) {
604 goto fail;
606 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
607 goto fail;
609 status = cli_smb2_delete_on_close_recv(req);
610 fail:
611 TALLOC_FREE(frame);
612 return status;
615 /***************************************************************
616 Small wrapper that allows SMB2 to create a directory
617 Synchronous only.
618 ***************************************************************/
620 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
622 NTSTATUS status;
623 uint16_t fnum;
625 if (smbXcli_conn_has_async_calls(cli->conn)) {
627 * Can't use sync call while an async call is in flight
629 return NT_STATUS_INVALID_PARAMETER;
632 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
633 return NT_STATUS_INVALID_PARAMETER;
636 status = cli_smb2_create_fnum(cli,
637 dname,
638 0, /* create_flags */
639 FILE_READ_ATTRIBUTES, /* desired_access */
640 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
641 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
642 FILE_CREATE, /* create_disposition */
643 FILE_DIRECTORY_FILE, /* create_options */
644 &fnum,
645 NULL);
647 if (!NT_STATUS_IS_OK(status)) {
648 return status;
650 return cli_smb2_close_fnum(cli, fnum);
653 /***************************************************************
654 Small wrapper that allows SMB2 to delete a directory
655 Synchronous only.
656 ***************************************************************/
658 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
660 NTSTATUS status;
661 uint16_t fnum;
663 if (smbXcli_conn_has_async_calls(cli->conn)) {
665 * Can't use sync call while an async call is in flight
667 return NT_STATUS_INVALID_PARAMETER;
670 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
671 return NT_STATUS_INVALID_PARAMETER;
674 status = cli_smb2_create_fnum(cli,
675 dname,
676 0, /* create_flags */
677 DELETE_ACCESS, /* desired_access */
678 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
679 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
680 FILE_OPEN, /* create_disposition */
681 FILE_DIRECTORY_FILE|FILE_DELETE_ON_CLOSE, /* create_options */
682 &fnum,
683 NULL);
685 if (!NT_STATUS_IS_OK(status)) {
686 return status;
688 return cli_smb2_close_fnum(cli, fnum);
691 /***************************************************************
692 Small wrapper that allows SMB2 to unlink a pathname.
693 Synchronous only.
694 ***************************************************************/
696 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
698 NTSTATUS status;
699 uint16_t fnum;
701 if (smbXcli_conn_has_async_calls(cli->conn)) {
703 * Can't use sync call while an async call is in flight
705 return NT_STATUS_INVALID_PARAMETER;
708 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
709 return NT_STATUS_INVALID_PARAMETER;
712 status = cli_smb2_create_fnum(cli,
713 fname,
714 0, /* create_flags */
715 DELETE_ACCESS, /* desired_access */
716 FILE_ATTRIBUTE_NORMAL, /* file attributes */
717 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
718 FILE_OPEN, /* create_disposition */
719 FILE_DELETE_ON_CLOSE, /* create_options */
720 &fnum,
721 NULL);
723 if (!NT_STATUS_IS_OK(status)) {
724 return status;
726 return cli_smb2_close_fnum(cli, fnum);
729 /***************************************************************
730 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
731 ***************************************************************/
733 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
734 uint32_t dir_data_length,
735 struct file_info *finfo,
736 uint32_t *next_offset)
738 size_t namelen = 0;
739 size_t slen = 0;
740 size_t ret = 0;
742 if (dir_data_length < 4) {
743 return NT_STATUS_INFO_LENGTH_MISMATCH;
746 *next_offset = IVAL(dir_data, 0);
748 if (*next_offset > dir_data_length) {
749 return NT_STATUS_INFO_LENGTH_MISMATCH;
752 if (*next_offset != 0) {
753 /* Ensure we only read what in this record. */
754 dir_data_length = *next_offset;
757 if (dir_data_length < 105) {
758 return NT_STATUS_INFO_LENGTH_MISMATCH;
761 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
762 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
763 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
764 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
765 finfo->mode = CVAL(dir_data + 56, 0);
766 namelen = IVAL(dir_data + 60,0);
767 if (namelen > (dir_data_length - 104)) {
768 return NT_STATUS_INFO_LENGTH_MISMATCH;
770 slen = CVAL(dir_data + 68, 0);
771 if (slen > 24) {
772 return NT_STATUS_INFO_LENGTH_MISMATCH;
774 ret = pull_string_talloc(finfo,
775 dir_data,
776 FLAGS2_UNICODE_STRINGS,
777 &finfo->short_name,
778 dir_data + 70,
779 slen,
780 STR_UNICODE);
781 if (ret == (size_t)-1) {
782 /* Bad conversion. */
783 return NT_STATUS_INVALID_NETWORK_RESPONSE;
786 ret = pull_string_talloc(finfo,
787 dir_data,
788 FLAGS2_UNICODE_STRINGS,
789 &finfo->name,
790 dir_data + 104,
791 namelen,
792 STR_UNICODE);
793 if (ret == (size_t)-1) {
794 /* Bad conversion. */
795 return NT_STATUS_INVALID_NETWORK_RESPONSE;
797 return NT_STATUS_OK;
800 /*******************************************************************
801 Given a filename - get its directory name
802 ********************************************************************/
804 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
805 const char *dir,
806 char **parent,
807 const char **name)
809 char *p;
810 ptrdiff_t len;
812 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
814 if (p == NULL) {
815 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
816 return false;
818 if (name) {
819 *name = dir;
821 return true;
824 len = p-dir;
826 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
827 return false;
829 (*parent)[len] = '\0';
831 if (name) {
832 *name = p+1;
834 return true;
837 /***************************************************************
838 Wrapper that allows SMB2 to list a directory.
839 Synchronous only.
840 ***************************************************************/
842 NTSTATUS cli_smb2_list(struct cli_state *cli,
843 const char *pathname,
844 uint16_t attribute,
845 NTSTATUS (*fn)(const char *,
846 struct file_info *,
847 const char *,
848 void *),
849 void *state)
851 NTSTATUS status;
852 uint16_t fnum = 0xffff;
853 char *parent_dir = NULL;
854 const char *mask = NULL;
855 struct smb2_hnd *ph = NULL;
856 bool processed_file = false;
857 TALLOC_CTX *frame = talloc_stackframe();
858 TALLOC_CTX *subframe = NULL;
859 bool mask_has_wild;
861 if (smbXcli_conn_has_async_calls(cli->conn)) {
863 * Can't use sync call while an async call is in flight
865 status = NT_STATUS_INVALID_PARAMETER;
866 goto fail;
869 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
870 status = NT_STATUS_INVALID_PARAMETER;
871 goto fail;
874 /* Get the directory name. */
875 if (!windows_parent_dirname(frame,
876 pathname,
877 &parent_dir,
878 &mask)) {
879 status = NT_STATUS_NO_MEMORY;
880 goto fail;
883 mask_has_wild = ms_has_wild(mask);
885 status = cli_smb2_create_fnum(cli,
886 parent_dir,
887 0, /* create_flags */
888 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
889 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
890 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
891 FILE_OPEN, /* create_disposition */
892 FILE_DIRECTORY_FILE, /* create_options */
893 &fnum,
894 NULL);
896 if (!NT_STATUS_IS_OK(status)) {
897 goto fail;
900 status = map_fnum_to_smb2_handle(cli,
901 fnum,
902 &ph);
903 if (!NT_STATUS_IS_OK(status)) {
904 goto fail;
907 do {
908 uint8_t *dir_data = NULL;
909 uint32_t dir_data_length = 0;
910 uint32_t next_offset = 0;
911 subframe = talloc_stackframe();
913 status = smb2cli_query_directory(cli->conn,
914 cli->timeout,
915 cli->smb2.session,
916 cli->smb2.tcon,
917 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
918 0, /* flags */
919 0, /* file_index */
920 ph->fid_persistent,
921 ph->fid_volatile,
922 mask,
923 0xffff,
924 subframe,
925 &dir_data,
926 &dir_data_length);
928 if (!NT_STATUS_IS_OK(status)) {
929 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
930 break;
932 goto fail;
935 do {
936 struct file_info *finfo = talloc_zero(subframe,
937 struct file_info);
939 if (finfo == NULL) {
940 status = NT_STATUS_NO_MEMORY;
941 goto fail;
944 status = parse_finfo_id_both_directory_info(dir_data,
945 dir_data_length,
946 finfo,
947 &next_offset);
949 if (!NT_STATUS_IS_OK(status)) {
950 goto fail;
953 if (dir_check_ftype((uint32_t)finfo->mode,
954 (uint32_t)attribute)) {
956 * Only process if attributes match.
957 * On SMB1 server does this, so on
958 * SMB2 we need to emulate in the
959 * client.
961 * https://bugzilla.samba.org/show_bug.cgi?id=10260
963 processed_file = true;
965 status = fn(cli->dfs_mountpoint,
966 finfo,
967 pathname,
968 state);
970 if (!NT_STATUS_IS_OK(status)) {
971 break;
975 TALLOC_FREE(finfo);
977 /* Move to next entry. */
978 if (next_offset) {
979 dir_data += next_offset;
980 dir_data_length -= next_offset;
982 } while (next_offset != 0);
984 TALLOC_FREE(subframe);
986 if (!mask_has_wild) {
988 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
989 * when handed a non-wildcard path. Do it
990 * for the server (with a non-wildcard path
991 * there should only ever be one file returned.
993 status = STATUS_NO_MORE_FILES;
994 break;
997 } while (NT_STATUS_IS_OK(status));
999 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
1000 status = NT_STATUS_OK;
1003 if (NT_STATUS_IS_OK(status) && !processed_file) {
1005 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
1006 * if no files match. Emulate this in the client.
1008 status = NT_STATUS_NO_SUCH_FILE;
1011 fail:
1013 if (fnum != 0xffff) {
1014 cli_smb2_close_fnum(cli, fnum);
1017 cli->raw_status = status;
1019 TALLOC_FREE(subframe);
1020 TALLOC_FREE(frame);
1021 return status;
1024 /***************************************************************
1025 Wrapper that allows SMB2 to query a path info (basic level).
1026 Synchronous only.
1027 ***************************************************************/
1029 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
1030 const char *name,
1031 SMB_STRUCT_STAT *sbuf,
1032 uint32_t *attributes)
1034 NTSTATUS status;
1035 struct smb_create_returns cr;
1036 uint16_t fnum = 0xffff;
1037 size_t namelen = strlen(name);
1039 if (smbXcli_conn_has_async_calls(cli->conn)) {
1041 * Can't use sync call while an async call is in flight
1043 return NT_STATUS_INVALID_PARAMETER;
1046 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1047 return NT_STATUS_INVALID_PARAMETER;
1050 /* SMB2 is pickier about pathnames. Ensure it doesn't
1051 end in a '\' */
1052 if (namelen > 0 && name[namelen-1] == '\\') {
1053 char *modname = talloc_strdup(talloc_tos(), name);
1054 modname[namelen-1] = '\0';
1055 name = modname;
1058 /* This is commonly used as a 'cd'. Try qpathinfo on
1059 a directory handle first. */
1061 status = cli_smb2_create_fnum(cli,
1062 name,
1063 0, /* create_flags */
1064 FILE_READ_ATTRIBUTES, /* desired_access */
1065 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1066 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1067 FILE_OPEN, /* create_disposition */
1068 FILE_DIRECTORY_FILE, /* create_options */
1069 &fnum,
1070 &cr);
1072 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
1073 /* Maybe a file ? */
1074 status = cli_smb2_create_fnum(cli,
1075 name,
1076 0, /* create_flags */
1077 FILE_READ_ATTRIBUTES, /* desired_access */
1078 0, /* file attributes */
1079 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1080 FILE_OPEN, /* create_disposition */
1081 0, /* create_options */
1082 &fnum,
1083 &cr);
1086 if (!NT_STATUS_IS_OK(status)) {
1087 return status;
1090 status = cli_smb2_close_fnum(cli, fnum);
1092 ZERO_STRUCTP(sbuf);
1094 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
1095 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
1096 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
1097 sbuf->st_ex_size = cr.end_of_file;
1098 *attributes = cr.file_attributes;
1100 return status;
1103 /***************************************************************
1104 Helper function for pathname operations.
1105 ***************************************************************/
1107 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
1108 const char *name,
1109 uint32_t desired_access,
1110 uint16_t *pfnum)
1112 NTSTATUS status;
1113 size_t namelen = strlen(name);
1114 TALLOC_CTX *frame = talloc_stackframe();
1116 /* SMB2 is pickier about pathnames. Ensure it doesn't
1117 end in a '\' */
1118 if (namelen > 0 && name[namelen-1] == '\\') {
1119 char *modname = talloc_strdup(frame, name);
1120 if (modname == NULL) {
1121 status = NT_STATUS_NO_MEMORY;
1122 goto fail;
1124 modname[namelen-1] = '\0';
1125 name = modname;
1128 /* Try to open a file handle first. */
1129 status = cli_smb2_create_fnum(cli,
1130 name,
1131 0, /* create_flags */
1132 desired_access,
1133 0, /* file attributes */
1134 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1135 FILE_OPEN, /* create_disposition */
1136 0, /* create_options */
1137 pfnum,
1138 NULL);
1140 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
1141 status = cli_smb2_create_fnum(cli,
1142 name,
1143 0, /* create_flags */
1144 desired_access,
1145 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1146 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1147 FILE_OPEN, /* create_disposition */
1148 FILE_DIRECTORY_FILE, /* create_options */
1149 pfnum,
1150 NULL);
1153 fail:
1155 TALLOC_FREE(frame);
1156 return status;
1159 /***************************************************************
1160 Wrapper that allows SMB2 to query a path info (ALTNAME level).
1161 Synchronous only.
1162 ***************************************************************/
1164 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
1165 const char *name,
1166 fstring alt_name)
1168 NTSTATUS status;
1169 DATA_BLOB outbuf = data_blob_null;
1170 uint16_t fnum = 0xffff;
1171 struct smb2_hnd *ph = NULL;
1172 uint32_t altnamelen = 0;
1173 TALLOC_CTX *frame = talloc_stackframe();
1175 if (smbXcli_conn_has_async_calls(cli->conn)) {
1177 * Can't use sync call while an async call is in flight
1179 status = NT_STATUS_INVALID_PARAMETER;
1180 goto fail;
1183 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1184 status = NT_STATUS_INVALID_PARAMETER;
1185 goto fail;
1188 status = get_fnum_from_path(cli,
1189 name,
1190 FILE_READ_ATTRIBUTES,
1191 &fnum);
1193 if (!NT_STATUS_IS_OK(status)) {
1194 goto fail;
1197 status = map_fnum_to_smb2_handle(cli,
1198 fnum,
1199 &ph);
1200 if (!NT_STATUS_IS_OK(status)) {
1201 goto fail;
1204 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1205 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1207 status = smb2cli_query_info(cli->conn,
1208 cli->timeout,
1209 cli->smb2.session,
1210 cli->smb2.tcon,
1211 1, /* in_info_type */
1212 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1213 0xFFFF, /* in_max_output_length */
1214 NULL, /* in_input_buffer */
1215 0, /* in_additional_info */
1216 0, /* in_flags */
1217 ph->fid_persistent,
1218 ph->fid_volatile,
1219 frame,
1220 &outbuf);
1222 if (!NT_STATUS_IS_OK(status)) {
1223 goto fail;
1226 /* Parse the reply. */
1227 if (outbuf.length < 4) {
1228 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1229 goto fail;
1232 altnamelen = IVAL(outbuf.data, 0);
1233 if (altnamelen > outbuf.length - 4) {
1234 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1235 goto fail;
1238 if (altnamelen > 0) {
1239 size_t ret = 0;
1240 char *short_name = NULL;
1241 ret = pull_string_talloc(frame,
1242 outbuf.data,
1243 FLAGS2_UNICODE_STRINGS,
1244 &short_name,
1245 outbuf.data + 4,
1246 altnamelen,
1247 STR_UNICODE);
1248 if (ret == (size_t)-1) {
1249 /* Bad conversion. */
1250 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1251 goto fail;
1254 fstrcpy(alt_name, short_name);
1255 } else {
1256 alt_name[0] = '\0';
1259 status = NT_STATUS_OK;
1261 fail:
1263 if (fnum != 0xffff) {
1264 cli_smb2_close_fnum(cli, fnum);
1267 cli->raw_status = status;
1269 TALLOC_FREE(frame);
1270 return status;
1274 /***************************************************************
1275 Wrapper that allows SMB2 to query a fnum info (basic level).
1276 Synchronous only.
1277 ***************************************************************/
1279 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1280 uint16_t fnum,
1281 uint16_t *mode,
1282 off_t *size,
1283 struct timespec *create_time,
1284 struct timespec *access_time,
1285 struct timespec *write_time,
1286 struct timespec *change_time,
1287 SMB_INO_T *ino)
1289 NTSTATUS status;
1290 DATA_BLOB outbuf = data_blob_null;
1291 struct smb2_hnd *ph = NULL;
1292 TALLOC_CTX *frame = talloc_stackframe();
1294 if (smbXcli_conn_has_async_calls(cli->conn)) {
1296 * Can't use sync call while an async call is in flight
1298 status = NT_STATUS_INVALID_PARAMETER;
1299 goto fail;
1302 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1303 status = NT_STATUS_INVALID_PARAMETER;
1304 goto fail;
1307 status = map_fnum_to_smb2_handle(cli,
1308 fnum,
1309 &ph);
1310 if (!NT_STATUS_IS_OK(status)) {
1311 goto fail;
1314 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1315 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1317 status = smb2cli_query_info(cli->conn,
1318 cli->timeout,
1319 cli->smb2.session,
1320 cli->smb2.tcon,
1321 1, /* in_info_type */
1322 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1323 0xFFFF, /* in_max_output_length */
1324 NULL, /* in_input_buffer */
1325 0, /* in_additional_info */
1326 0, /* in_flags */
1327 ph->fid_persistent,
1328 ph->fid_volatile,
1329 frame,
1330 &outbuf);
1331 if (!NT_STATUS_IS_OK(status)) {
1332 goto fail;
1335 /* Parse the reply. */
1336 if (outbuf.length < 0x60) {
1337 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1338 goto fail;
1341 if (create_time) {
1342 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1344 if (access_time) {
1345 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1347 if (write_time) {
1348 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1350 if (change_time) {
1351 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1353 if (mode) {
1354 uint32_t attr = IVAL(outbuf.data, 0x20);
1355 *mode = (uint16_t)attr;
1357 if (size) {
1358 uint64_t file_size = BVAL(outbuf.data, 0x30);
1359 *size = (off_t)file_size;
1361 if (ino) {
1362 uint64_t file_index = BVAL(outbuf.data, 0x40);
1363 *ino = (SMB_INO_T)file_index;
1366 fail:
1368 cli->raw_status = status;
1370 TALLOC_FREE(frame);
1371 return status;
1374 /***************************************************************
1375 Wrapper that allows SMB2 to query an fnum.
1376 Implement on top of cli_smb2_qfileinfo_basic().
1377 Synchronous only.
1378 ***************************************************************/
1380 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1381 uint16_t fnum,
1382 uint16_t *attr,
1383 off_t *size,
1384 time_t *change_time,
1385 time_t *access_time,
1386 time_t *write_time)
1388 struct timespec access_time_ts;
1389 struct timespec write_time_ts;
1390 struct timespec change_time_ts;
1391 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1392 fnum,
1393 attr,
1394 size,
1395 NULL,
1396 &access_time_ts,
1397 &write_time_ts,
1398 &change_time_ts,
1399 NULL);
1401 cli->raw_status = status;
1403 if (!NT_STATUS_IS_OK(status)) {
1404 return status;
1407 if (change_time) {
1408 *change_time = change_time_ts.tv_sec;
1410 if (access_time) {
1411 *access_time = access_time_ts.tv_sec;
1413 if (write_time) {
1414 *write_time = write_time_ts.tv_sec;
1416 return NT_STATUS_OK;
1419 /***************************************************************
1420 Wrapper that allows SMB2 to get pathname attributes.
1421 Synchronous only.
1422 ***************************************************************/
1424 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1425 const char *name,
1426 uint16_t *attr,
1427 off_t *size,
1428 time_t *write_time)
1430 NTSTATUS status;
1431 uint16_t fnum = 0xffff;
1432 struct smb2_hnd *ph = NULL;
1433 TALLOC_CTX *frame = talloc_stackframe();
1435 if (smbXcli_conn_has_async_calls(cli->conn)) {
1437 * Can't use sync call while an async call is in flight
1439 status = NT_STATUS_INVALID_PARAMETER;
1440 goto fail;
1443 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1444 status = NT_STATUS_INVALID_PARAMETER;
1445 goto fail;
1448 status = get_fnum_from_path(cli,
1449 name,
1450 FILE_READ_ATTRIBUTES,
1451 &fnum);
1453 if (!NT_STATUS_IS_OK(status)) {
1454 goto fail;
1457 status = map_fnum_to_smb2_handle(cli,
1458 fnum,
1459 &ph);
1460 if (!NT_STATUS_IS_OK(status)) {
1461 goto fail;
1463 status = cli_smb2_getattrE(cli,
1464 fnum,
1465 attr,
1466 size,
1467 NULL,
1468 NULL,
1469 write_time);
1470 if (!NT_STATUS_IS_OK(status)) {
1471 goto fail;
1474 fail:
1476 if (fnum != 0xffff) {
1477 cli_smb2_close_fnum(cli, fnum);
1480 cli->raw_status = status;
1482 TALLOC_FREE(frame);
1483 return status;
1486 /***************************************************************
1487 Wrapper that allows SMB2 to query a pathname info (basic level).
1488 Implement on top of cli_smb2_qfileinfo_basic().
1489 Synchronous only.
1490 ***************************************************************/
1492 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1493 const char *name,
1494 struct timespec *create_time,
1495 struct timespec *access_time,
1496 struct timespec *write_time,
1497 struct timespec *change_time,
1498 off_t *size,
1499 uint16_t *mode,
1500 SMB_INO_T *ino)
1502 NTSTATUS status;
1503 struct smb2_hnd *ph = NULL;
1504 uint16_t fnum = 0xffff;
1505 TALLOC_CTX *frame = talloc_stackframe();
1507 if (smbXcli_conn_has_async_calls(cli->conn)) {
1509 * Can't use sync call while an async call is in flight
1511 status = NT_STATUS_INVALID_PARAMETER;
1512 goto fail;
1515 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1516 status = NT_STATUS_INVALID_PARAMETER;
1517 goto fail;
1520 status = get_fnum_from_path(cli,
1521 name,
1522 FILE_READ_ATTRIBUTES,
1523 &fnum);
1525 if (!NT_STATUS_IS_OK(status)) {
1526 goto fail;
1529 status = map_fnum_to_smb2_handle(cli,
1530 fnum,
1531 &ph);
1532 if (!NT_STATUS_IS_OK(status)) {
1533 goto fail;
1536 status = cli_smb2_qfileinfo_basic(cli,
1537 fnum,
1538 mode,
1539 size,
1540 create_time,
1541 access_time,
1542 write_time,
1543 change_time,
1544 ino);
1546 fail:
1548 if (fnum != 0xffff) {
1549 cli_smb2_close_fnum(cli, fnum);
1552 cli->raw_status = status;
1554 TALLOC_FREE(frame);
1555 return status;
1558 /***************************************************************
1559 Wrapper that allows SMB2 to query pathname streams.
1560 Synchronous only.
1561 ***************************************************************/
1563 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1564 const char *name,
1565 TALLOC_CTX *mem_ctx,
1566 unsigned int *pnum_streams,
1567 struct stream_struct **pstreams)
1569 NTSTATUS status;
1570 struct smb2_hnd *ph = NULL;
1571 uint16_t fnum = 0xffff;
1572 DATA_BLOB outbuf = data_blob_null;
1573 TALLOC_CTX *frame = talloc_stackframe();
1575 if (smbXcli_conn_has_async_calls(cli->conn)) {
1577 * Can't use sync call while an async call is in flight
1579 status = NT_STATUS_INVALID_PARAMETER;
1580 goto fail;
1583 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1584 status = NT_STATUS_INVALID_PARAMETER;
1585 goto fail;
1588 status = get_fnum_from_path(cli,
1589 name,
1590 FILE_READ_ATTRIBUTES,
1591 &fnum);
1593 if (!NT_STATUS_IS_OK(status)) {
1594 goto fail;
1597 status = map_fnum_to_smb2_handle(cli,
1598 fnum,
1599 &ph);
1600 if (!NT_STATUS_IS_OK(status)) {
1601 goto fail;
1604 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1605 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1607 status = smb2cli_query_info(cli->conn,
1608 cli->timeout,
1609 cli->smb2.session,
1610 cli->smb2.tcon,
1611 1, /* in_info_type */
1612 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1613 0xFFFF, /* in_max_output_length */
1614 NULL, /* in_input_buffer */
1615 0, /* in_additional_info */
1616 0, /* in_flags */
1617 ph->fid_persistent,
1618 ph->fid_volatile,
1619 frame,
1620 &outbuf);
1622 if (!NT_STATUS_IS_OK(status)) {
1623 goto fail;
1626 /* Parse the reply. */
1627 if (!parse_streams_blob(mem_ctx,
1628 outbuf.data,
1629 outbuf.length,
1630 pnum_streams,
1631 pstreams)) {
1632 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1633 goto fail;
1636 fail:
1638 if (fnum != 0xffff) {
1639 cli_smb2_close_fnum(cli, fnum);
1642 cli->raw_status = status;
1644 TALLOC_FREE(frame);
1645 return status;
1648 /***************************************************************
1649 Wrapper that allows SMB2 to set pathname attributes.
1650 Synchronous only.
1651 ***************************************************************/
1653 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1654 const char *name,
1655 uint16_t attr,
1656 time_t mtime)
1658 NTSTATUS status;
1659 uint16_t fnum = 0xffff;
1660 struct smb2_hnd *ph = NULL;
1661 uint8_t inbuf_store[40];
1662 DATA_BLOB inbuf = data_blob_null;
1663 TALLOC_CTX *frame = talloc_stackframe();
1665 if (smbXcli_conn_has_async_calls(cli->conn)) {
1667 * Can't use sync call while an async call is in flight
1669 status = NT_STATUS_INVALID_PARAMETER;
1670 goto fail;
1673 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1674 status = NT_STATUS_INVALID_PARAMETER;
1675 goto fail;
1678 status = get_fnum_from_path(cli,
1679 name,
1680 FILE_WRITE_ATTRIBUTES,
1681 &fnum);
1683 if (!NT_STATUS_IS_OK(status)) {
1684 goto fail;
1687 status = map_fnum_to_smb2_handle(cli,
1688 fnum,
1689 &ph);
1690 if (!NT_STATUS_IS_OK(status)) {
1691 goto fail;
1694 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1695 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1697 inbuf.data = inbuf_store;
1698 inbuf.length = sizeof(inbuf_store);
1699 data_blob_clear(&inbuf);
1702 * SMB1 uses attr == 0 to clear all attributes
1703 * on a file (end up with FILE_ATTRIBUTE_NORMAL),
1704 * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
1705 * request attribute change.
1707 * SMB2 uses exactly the reverse. Unfortunately as the
1708 * cli_setatr() ABI is exposed inside libsmbclient,
1709 * we must make the SMB2 cli_smb2_setatr() call
1710 * export the same ABI as the SMB1 cli_setatr()
1711 * which calls it. This means reversing the sense
1712 * of the requested attr argument if it's zero
1713 * or FILE_ATTRIBUTE_NORMAL.
1715 * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
1718 if (attr == 0) {
1719 attr = FILE_ATTRIBUTE_NORMAL;
1720 } else if (attr == FILE_ATTRIBUTE_NORMAL) {
1721 attr = 0;
1724 SSVAL(inbuf.data, 32, attr);
1725 if (mtime != 0) {
1726 put_long_date((char *)inbuf.data + 16,mtime);
1728 /* Set all the other times to -1. */
1729 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1730 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1731 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1733 status = smb2cli_set_info(cli->conn,
1734 cli->timeout,
1735 cli->smb2.session,
1736 cli->smb2.tcon,
1737 1, /* in_info_type */
1738 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1739 &inbuf, /* in_input_buffer */
1740 0, /* in_additional_info */
1741 ph->fid_persistent,
1742 ph->fid_volatile);
1743 fail:
1745 if (fnum != 0xffff) {
1746 cli_smb2_close_fnum(cli, fnum);
1749 cli->raw_status = status;
1751 TALLOC_FREE(frame);
1752 return status;
1755 /***************************************************************
1756 Wrapper that allows SMB2 to set file handle times.
1757 Synchronous only.
1758 ***************************************************************/
1760 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1761 uint16_t fnum,
1762 time_t change_time,
1763 time_t access_time,
1764 time_t write_time)
1766 NTSTATUS status;
1767 struct smb2_hnd *ph = NULL;
1768 uint8_t inbuf_store[40];
1769 DATA_BLOB inbuf = data_blob_null;
1771 if (smbXcli_conn_has_async_calls(cli->conn)) {
1773 * Can't use sync call while an async call is in flight
1775 return NT_STATUS_INVALID_PARAMETER;
1778 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1779 return NT_STATUS_INVALID_PARAMETER;
1782 status = map_fnum_to_smb2_handle(cli,
1783 fnum,
1784 &ph);
1785 if (!NT_STATUS_IS_OK(status)) {
1786 return status;
1789 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1790 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1792 inbuf.data = inbuf_store;
1793 inbuf.length = sizeof(inbuf_store);
1794 data_blob_clear(&inbuf);
1796 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1797 if (change_time != 0) {
1798 put_long_date((char *)inbuf.data + 24, change_time);
1800 if (access_time != 0) {
1801 put_long_date((char *)inbuf.data + 8, access_time);
1803 if (write_time != 0) {
1804 put_long_date((char *)inbuf.data + 16, write_time);
1807 cli->raw_status = smb2cli_set_info(cli->conn,
1808 cli->timeout,
1809 cli->smb2.session,
1810 cli->smb2.tcon,
1811 1, /* in_info_type */
1812 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1813 &inbuf, /* in_input_buffer */
1814 0, /* in_additional_info */
1815 ph->fid_persistent,
1816 ph->fid_volatile);
1818 return cli->raw_status;
1821 /***************************************************************
1822 Wrapper that allows SMB2 to query disk attributes (size).
1823 Synchronous only.
1824 ***************************************************************/
1826 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
1827 uint64_t *bsize, uint64_t *total, uint64_t *avail)
1829 NTSTATUS status;
1830 uint16_t fnum = 0xffff;
1831 DATA_BLOB outbuf = data_blob_null;
1832 struct smb2_hnd *ph = NULL;
1833 uint32_t sectors_per_unit = 0;
1834 uint32_t bytes_per_sector = 0;
1835 uint64_t total_size = 0;
1836 uint64_t size_free = 0;
1837 TALLOC_CTX *frame = talloc_stackframe();
1839 if (smbXcli_conn_has_async_calls(cli->conn)) {
1841 * Can't use sync call while an async call is in flight
1843 status = NT_STATUS_INVALID_PARAMETER;
1844 goto fail;
1847 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1848 status = NT_STATUS_INVALID_PARAMETER;
1849 goto fail;
1852 /* First open the top level directory. */
1853 status = cli_smb2_create_fnum(cli,
1854 path,
1855 0, /* create_flags */
1856 FILE_READ_ATTRIBUTES, /* desired_access */
1857 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1858 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1859 FILE_OPEN, /* create_disposition */
1860 FILE_DIRECTORY_FILE, /* create_options */
1861 &fnum,
1862 NULL);
1864 if (!NT_STATUS_IS_OK(status)) {
1865 goto fail;
1868 status = map_fnum_to_smb2_handle(cli,
1869 fnum,
1870 &ph);
1871 if (!NT_STATUS_IS_OK(status)) {
1872 goto fail;
1875 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1876 level 3 (SMB_FS_SIZE_INFORMATION). */
1878 status = smb2cli_query_info(cli->conn,
1879 cli->timeout,
1880 cli->smb2.session,
1881 cli->smb2.tcon,
1882 2, /* in_info_type */
1883 3, /* in_file_info_class */
1884 0xFFFF, /* in_max_output_length */
1885 NULL, /* in_input_buffer */
1886 0, /* in_additional_info */
1887 0, /* in_flags */
1888 ph->fid_persistent,
1889 ph->fid_volatile,
1890 frame,
1891 &outbuf);
1892 if (!NT_STATUS_IS_OK(status)) {
1893 goto fail;
1896 /* Parse the reply. */
1897 if (outbuf.length != 24) {
1898 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1899 goto fail;
1902 total_size = BVAL(outbuf.data, 0);
1903 size_free = BVAL(outbuf.data, 8);
1904 sectors_per_unit = IVAL(outbuf.data, 16);
1905 bytes_per_sector = IVAL(outbuf.data, 20);
1907 if (bsize) {
1908 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
1910 if (total) {
1911 *total = total_size;
1913 if (avail) {
1914 *avail = size_free;
1917 status = NT_STATUS_OK;
1919 fail:
1921 if (fnum != 0xffff) {
1922 cli_smb2_close_fnum(cli, fnum);
1925 cli->raw_status = status;
1927 TALLOC_FREE(frame);
1928 return status;
1931 /***************************************************************
1932 Wrapper that allows SMB2 to query file system attributes.
1933 Synchronous only.
1934 ***************************************************************/
1936 NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
1938 NTSTATUS status;
1939 uint16_t fnum = 0xffff;
1940 DATA_BLOB outbuf = data_blob_null;
1941 struct smb2_hnd *ph = NULL;
1942 TALLOC_CTX *frame = talloc_stackframe();
1944 if (smbXcli_conn_has_async_calls(cli->conn)) {
1946 * Can't use sync call while an async call is in flight
1948 status = NT_STATUS_INVALID_PARAMETER;
1949 goto fail;
1952 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1953 status = NT_STATUS_INVALID_PARAMETER;
1954 goto fail;
1957 /* First open the top level directory. */
1958 status =
1959 cli_smb2_create_fnum(cli, "", 0, /* create_flags */
1960 FILE_READ_ATTRIBUTES, /* desired_access */
1961 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1962 FILE_SHARE_READ | FILE_SHARE_WRITE |
1963 FILE_SHARE_DELETE, /* share_access */
1964 FILE_OPEN, /* create_disposition */
1965 FILE_DIRECTORY_FILE, /* create_options */
1966 &fnum,
1967 NULL);
1969 if (!NT_STATUS_IS_OK(status)) {
1970 goto fail;
1973 status = map_fnum_to_smb2_handle(cli, fnum, &ph);
1974 if (!NT_STATUS_IS_OK(status)) {
1975 goto fail;
1978 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
1979 cli->smb2.tcon, 2, /* in_info_type */
1980 5, /* in_file_info_class */
1981 0xFFFF, /* in_max_output_length */
1982 NULL, /* in_input_buffer */
1983 0, /* in_additional_info */
1984 0, /* in_flags */
1985 ph->fid_persistent, ph->fid_volatile, frame,
1986 &outbuf);
1987 if (!NT_STATUS_IS_OK(status)) {
1988 goto fail;
1991 if (outbuf.length < 12) {
1992 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1993 goto fail;
1996 *fs_attr = IVAL(outbuf.data, 0);
1998 fail:
2000 if (fnum != 0xffff) {
2001 cli_smb2_close_fnum(cli, fnum);
2004 cli->raw_status = status;
2006 TALLOC_FREE(frame);
2007 return status;
2010 /***************************************************************
2011 Wrapper that allows SMB2 to query a security descriptor.
2012 Synchronous only.
2013 ***************************************************************/
2015 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
2016 uint16_t fnum,
2017 uint32_t sec_info,
2018 TALLOC_CTX *mem_ctx,
2019 struct security_descriptor **ppsd)
2021 NTSTATUS status;
2022 DATA_BLOB outbuf = data_blob_null;
2023 struct smb2_hnd *ph = NULL;
2024 struct security_descriptor *lsd = NULL;
2025 TALLOC_CTX *frame = talloc_stackframe();
2027 if (smbXcli_conn_has_async_calls(cli->conn)) {
2029 * Can't use sync call while an async call is in flight
2031 status = NT_STATUS_INVALID_PARAMETER;
2032 goto fail;
2035 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2036 status = NT_STATUS_INVALID_PARAMETER;
2037 goto fail;
2040 status = map_fnum_to_smb2_handle(cli,
2041 fnum,
2042 &ph);
2043 if (!NT_STATUS_IS_OK(status)) {
2044 goto fail;
2047 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
2049 status = smb2cli_query_info(cli->conn,
2050 cli->timeout,
2051 cli->smb2.session,
2052 cli->smb2.tcon,
2053 3, /* in_info_type */
2054 0, /* in_file_info_class */
2055 0xFFFF, /* in_max_output_length */
2056 NULL, /* in_input_buffer */
2057 sec_info, /* in_additional_info */
2058 0, /* in_flags */
2059 ph->fid_persistent,
2060 ph->fid_volatile,
2061 frame,
2062 &outbuf);
2064 if (!NT_STATUS_IS_OK(status)) {
2065 goto fail;
2068 /* Parse the reply. */
2069 status = unmarshall_sec_desc(mem_ctx,
2070 outbuf.data,
2071 outbuf.length,
2072 &lsd);
2074 if (!NT_STATUS_IS_OK(status)) {
2075 goto fail;
2078 if (ppsd != NULL) {
2079 *ppsd = lsd;
2080 } else {
2081 TALLOC_FREE(lsd);
2084 fail:
2086 cli->raw_status = status;
2088 TALLOC_FREE(frame);
2089 return status;
2092 /***************************************************************
2093 Wrapper that allows SMB2 to set a security descriptor.
2094 Synchronous only.
2095 ***************************************************************/
2097 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
2098 uint16_t fnum,
2099 uint32_t sec_info,
2100 const struct security_descriptor *sd)
2102 NTSTATUS status;
2103 DATA_BLOB inbuf = data_blob_null;
2104 struct smb2_hnd *ph = NULL;
2105 TALLOC_CTX *frame = talloc_stackframe();
2107 if (smbXcli_conn_has_async_calls(cli->conn)) {
2109 * Can't use sync call while an async call is in flight
2111 status = NT_STATUS_INVALID_PARAMETER;
2112 goto fail;
2115 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2116 status = NT_STATUS_INVALID_PARAMETER;
2117 goto fail;
2120 status = map_fnum_to_smb2_handle(cli,
2121 fnum,
2122 &ph);
2123 if (!NT_STATUS_IS_OK(status)) {
2124 goto fail;
2127 status = marshall_sec_desc(frame,
2129 &inbuf.data,
2130 &inbuf.length);
2132 if (!NT_STATUS_IS_OK(status)) {
2133 goto fail;
2136 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
2138 status = smb2cli_set_info(cli->conn,
2139 cli->timeout,
2140 cli->smb2.session,
2141 cli->smb2.tcon,
2142 3, /* in_info_type */
2143 0, /* in_file_info_class */
2144 &inbuf, /* in_input_buffer */
2145 sec_info, /* in_additional_info */
2146 ph->fid_persistent,
2147 ph->fid_volatile);
2149 fail:
2151 cli->raw_status = status;
2153 TALLOC_FREE(frame);
2154 return status;
2157 /***************************************************************
2158 Wrapper that allows SMB2 to rename a file.
2159 Synchronous only.
2160 ***************************************************************/
2162 NTSTATUS cli_smb2_rename(struct cli_state *cli,
2163 const char *fname_src,
2164 const char *fname_dst,
2165 bool replace)
2167 NTSTATUS status;
2168 DATA_BLOB inbuf = data_blob_null;
2169 uint16_t fnum = 0xffff;
2170 struct smb2_hnd *ph = NULL;
2171 smb_ucs2_t *converted_str = NULL;
2172 size_t converted_size_bytes = 0;
2173 size_t namelen = 0;
2174 TALLOC_CTX *frame = talloc_stackframe();
2176 if (smbXcli_conn_has_async_calls(cli->conn)) {
2178 * Can't use sync call while an async call is in flight
2180 status = NT_STATUS_INVALID_PARAMETER;
2181 goto fail;
2184 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2185 status = NT_STATUS_INVALID_PARAMETER;
2186 goto fail;
2189 status = get_fnum_from_path(cli,
2190 fname_src,
2191 DELETE_ACCESS,
2192 &fnum);
2194 if (!NT_STATUS_IS_OK(status)) {
2195 goto fail;
2198 status = map_fnum_to_smb2_handle(cli,
2199 fnum,
2200 &ph);
2201 if (!NT_STATUS_IS_OK(status)) {
2202 goto fail;
2205 /* SMB2 is pickier about pathnames. Ensure it doesn't
2206 start in a '\' */
2207 if (*fname_dst == '\\') {
2208 fname_dst++;
2211 /* SMB2 is pickier about pathnames. Ensure it doesn't
2212 end in a '\' */
2213 namelen = strlen(fname_dst);
2214 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
2215 char *modname = talloc_strdup(frame, fname_dst);
2216 modname[namelen-1] = '\0';
2217 fname_dst = modname;
2220 if (!push_ucs2_talloc(frame,
2221 &converted_str,
2222 fname_dst,
2223 &converted_size_bytes)) {
2224 status = NT_STATUS_INVALID_PARAMETER;
2225 goto fail;
2228 /* W2K8 insists the dest name is not null
2229 terminated. Remove the last 2 zero bytes
2230 and reduce the name length. */
2232 if (converted_size_bytes < 2) {
2233 status = NT_STATUS_INVALID_PARAMETER;
2234 goto fail;
2236 converted_size_bytes -= 2;
2238 inbuf = data_blob_talloc_zero(frame,
2239 20 + converted_size_bytes);
2240 if (inbuf.data == NULL) {
2241 status = NT_STATUS_NO_MEMORY;
2242 goto fail;
2245 if (replace) {
2246 SCVAL(inbuf.data, 0, 1);
2249 SIVAL(inbuf.data, 16, converted_size_bytes);
2250 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
2252 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
2253 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
2255 status = smb2cli_set_info(cli->conn,
2256 cli->timeout,
2257 cli->smb2.session,
2258 cli->smb2.tcon,
2259 1, /* in_info_type */
2260 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
2261 &inbuf, /* in_input_buffer */
2262 0, /* in_additional_info */
2263 ph->fid_persistent,
2264 ph->fid_volatile);
2266 fail:
2268 if (fnum != 0xffff) {
2269 cli_smb2_close_fnum(cli, fnum);
2272 cli->raw_status = status;
2274 TALLOC_FREE(frame);
2275 return status;
2278 /***************************************************************
2279 Wrapper that allows SMB2 to set an EA on a fnum.
2280 Synchronous only.
2281 ***************************************************************/
2283 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
2284 uint16_t fnum,
2285 const char *ea_name,
2286 const char *ea_val,
2287 size_t ea_len)
2289 NTSTATUS status;
2290 DATA_BLOB inbuf = data_blob_null;
2291 size_t bloblen = 0;
2292 char *ea_name_ascii = NULL;
2293 size_t namelen = 0;
2294 struct smb2_hnd *ph = NULL;
2295 TALLOC_CTX *frame = talloc_stackframe();
2297 if (smbXcli_conn_has_async_calls(cli->conn)) {
2299 * Can't use sync call while an async call is in flight
2301 status = NT_STATUS_INVALID_PARAMETER;
2302 goto fail;
2305 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2306 status = NT_STATUS_INVALID_PARAMETER;
2307 goto fail;
2310 status = map_fnum_to_smb2_handle(cli,
2311 fnum,
2312 &ph);
2313 if (!NT_STATUS_IS_OK(status)) {
2314 goto fail;
2317 /* Marshall the SMB2 EA data. */
2318 if (ea_len > 0xFFFF) {
2319 status = NT_STATUS_INVALID_PARAMETER;
2320 goto fail;
2323 if (!push_ascii_talloc(frame,
2324 &ea_name_ascii,
2325 ea_name,
2326 &namelen)) {
2327 status = NT_STATUS_INVALID_PARAMETER;
2328 goto fail;
2331 if (namelen < 2 || namelen > 0xFF) {
2332 status = NT_STATUS_INVALID_PARAMETER;
2333 goto fail;
2336 bloblen = 8 + ea_len + namelen;
2337 /* Round up to a 4 byte boundary. */
2338 bloblen = ((bloblen + 3)&~3);
2340 inbuf = data_blob_talloc_zero(frame, bloblen);
2341 if (inbuf.data == NULL) {
2342 status = NT_STATUS_NO_MEMORY;
2343 goto fail;
2345 /* namelen doesn't include the NULL byte. */
2346 SCVAL(inbuf.data, 5, namelen - 1);
2347 SSVAL(inbuf.data, 6, ea_len);
2348 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2349 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2351 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2352 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2354 status = smb2cli_set_info(cli->conn,
2355 cli->timeout,
2356 cli->smb2.session,
2357 cli->smb2.tcon,
2358 1, /* in_info_type */
2359 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2360 &inbuf, /* in_input_buffer */
2361 0, /* in_additional_info */
2362 ph->fid_persistent,
2363 ph->fid_volatile);
2365 fail:
2367 cli->raw_status = status;
2369 TALLOC_FREE(frame);
2370 return status;
2373 /***************************************************************
2374 Wrapper that allows SMB2 to set an EA on a pathname.
2375 Synchronous only.
2376 ***************************************************************/
2378 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2379 const char *name,
2380 const char *ea_name,
2381 const char *ea_val,
2382 size_t ea_len)
2384 NTSTATUS status;
2385 uint16_t fnum = 0xffff;
2387 if (smbXcli_conn_has_async_calls(cli->conn)) {
2389 * Can't use sync call while an async call is in flight
2391 status = NT_STATUS_INVALID_PARAMETER;
2392 goto fail;
2395 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2396 status = NT_STATUS_INVALID_PARAMETER;
2397 goto fail;
2400 status = get_fnum_from_path(cli,
2401 name,
2402 FILE_WRITE_EA,
2403 &fnum);
2405 if (!NT_STATUS_IS_OK(status)) {
2406 goto fail;
2409 status = cli_set_ea_fnum(cli,
2410 fnum,
2411 ea_name,
2412 ea_val,
2413 ea_len);
2414 if (!NT_STATUS_IS_OK(status)) {
2415 goto fail;
2418 fail:
2420 if (fnum != 0xffff) {
2421 cli_smb2_close_fnum(cli, fnum);
2424 cli->raw_status = status;
2426 return status;
2429 /***************************************************************
2430 Wrapper that allows SMB2 to get an EA list on a pathname.
2431 Synchronous only.
2432 ***************************************************************/
2434 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2435 const char *name,
2436 TALLOC_CTX *ctx,
2437 size_t *pnum_eas,
2438 struct ea_struct **pea_array)
2440 NTSTATUS status;
2441 uint16_t fnum = 0xffff;
2442 DATA_BLOB outbuf = data_blob_null;
2443 struct smb2_hnd *ph = NULL;
2444 struct ea_list *ea_list = NULL;
2445 struct ea_list *eal = NULL;
2446 size_t ea_count = 0;
2447 TALLOC_CTX *frame = talloc_stackframe();
2449 *pnum_eas = 0;
2450 *pea_array = NULL;
2452 if (smbXcli_conn_has_async_calls(cli->conn)) {
2454 * Can't use sync call while an async call is in flight
2456 status = NT_STATUS_INVALID_PARAMETER;
2457 goto fail;
2460 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2461 status = NT_STATUS_INVALID_PARAMETER;
2462 goto fail;
2465 status = get_fnum_from_path(cli,
2466 name,
2467 FILE_READ_EA,
2468 &fnum);
2470 if (!NT_STATUS_IS_OK(status)) {
2471 goto fail;
2474 status = map_fnum_to_smb2_handle(cli,
2475 fnum,
2476 &ph);
2477 if (!NT_STATUS_IS_OK(status)) {
2478 goto fail;
2481 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2482 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2484 status = smb2cli_query_info(cli->conn,
2485 cli->timeout,
2486 cli->smb2.session,
2487 cli->smb2.tcon,
2488 1, /* in_info_type */
2489 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2490 0xFFFF, /* in_max_output_length */
2491 NULL, /* in_input_buffer */
2492 0, /* in_additional_info */
2493 0, /* in_flags */
2494 ph->fid_persistent,
2495 ph->fid_volatile,
2496 frame,
2497 &outbuf);
2499 if (!NT_STATUS_IS_OK(status)) {
2500 goto fail;
2503 /* Parse the reply. */
2504 ea_list = read_nttrans_ea_list(ctx,
2505 (const char *)outbuf.data,
2506 outbuf.length);
2507 if (ea_list == NULL) {
2508 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2509 goto fail;
2512 /* Convert to an array. */
2513 for (eal = ea_list; eal; eal = eal->next) {
2514 ea_count++;
2517 if (ea_count) {
2518 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2519 if (*pea_array == NULL) {
2520 status = NT_STATUS_NO_MEMORY;
2521 goto fail;
2523 ea_count = 0;
2524 for (eal = ea_list; eal; eal = eal->next) {
2525 (*pea_array)[ea_count++] = eal->ea;
2527 *pnum_eas = ea_count;
2530 fail:
2532 if (fnum != 0xffff) {
2533 cli_smb2_close_fnum(cli, fnum);
2536 cli->raw_status = status;
2538 TALLOC_FREE(frame);
2539 return status;
2542 /***************************************************************
2543 Wrapper that allows SMB2 to get user quota.
2544 Synchronous only.
2545 ***************************************************************/
2547 NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
2548 int quota_fnum,
2549 SMB_NTQUOTA_STRUCT *pqt)
2551 NTSTATUS status;
2552 DATA_BLOB inbuf = data_blob_null;
2553 DATA_BLOB outbuf = data_blob_null;
2554 struct smb2_hnd *ph = NULL;
2555 TALLOC_CTX *frame = talloc_stackframe();
2556 unsigned sid_len;
2557 unsigned int offset;
2558 uint8_t *buf;
2560 if (smbXcli_conn_has_async_calls(cli->conn)) {
2562 * Can't use sync call while an async call is in flight
2564 status = NT_STATUS_INVALID_PARAMETER;
2565 goto fail;
2568 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2569 status = NT_STATUS_INVALID_PARAMETER;
2570 goto fail;
2573 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2574 if (!NT_STATUS_IS_OK(status)) {
2575 goto fail;
2578 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
2580 inbuf = data_blob_talloc_zero(frame, 24 + sid_len);
2581 if (inbuf.data == NULL) {
2582 status = NT_STATUS_NO_MEMORY;
2583 goto fail;
2586 buf = inbuf.data;
2588 SCVAL(buf, 0, 1); /* ReturnSingle */
2589 SCVAL(buf, 1, 0); /* RestartScan */
2590 SSVAL(buf, 2, 0); /* Reserved */
2591 if (8 + sid_len < 8) {
2592 status = NT_STATUS_INVALID_PARAMETER;
2593 goto fail;
2595 SIVAL(buf, 4, 8 + sid_len); /* SidListLength */
2596 SIVAL(buf, 8, 0); /* StartSidLength */
2597 SIVAL(buf, 12, 0); /* StartSidOffset */
2598 SIVAL(buf, 16, 0); /* NextEntryOffset */
2599 SIVAL(buf, 20, sid_len); /* SidLength */
2600 sid_linearize(buf + 24, sid_len, &pqt->sid);
2602 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2603 cli->smb2.tcon, 4, /* in_info_type */
2604 0, /* in_file_info_class */
2605 0xFFFF, /* in_max_output_length */
2606 &inbuf, /* in_input_buffer */
2607 0, /* in_additional_info */
2608 0, /* in_flags */
2609 ph->fid_persistent, ph->fid_volatile, frame,
2610 &outbuf);
2612 if (!NT_STATUS_IS_OK(status)) {
2613 goto fail;
2616 if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
2617 pqt)) {
2618 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2619 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
2622 fail:
2623 cli->raw_status = status;
2625 TALLOC_FREE(frame);
2626 return status;
2629 /***************************************************************
2630 Wrapper that allows SMB2 to list user quota.
2631 Synchronous only.
2632 ***************************************************************/
2634 NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
2635 TALLOC_CTX *mem_ctx,
2636 int quota_fnum,
2637 SMB_NTQUOTA_LIST **pqt_list,
2638 bool first)
2640 NTSTATUS status;
2641 DATA_BLOB inbuf = data_blob_null;
2642 DATA_BLOB outbuf = data_blob_null;
2643 struct smb2_hnd *ph = NULL;
2644 TALLOC_CTX *frame = talloc_stackframe();
2645 uint8_t *buf;
2647 if (smbXcli_conn_has_async_calls(cli->conn)) {
2649 * Can't use sync call while an async call is in flight
2651 status = NT_STATUS_INVALID_PARAMETER;
2652 goto cleanup;
2655 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2656 status = NT_STATUS_INVALID_PARAMETER;
2657 goto cleanup;
2660 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2661 if (!NT_STATUS_IS_OK(status)) {
2662 goto cleanup;
2665 inbuf = data_blob_talloc_zero(frame, 16);
2666 if (inbuf.data == NULL) {
2667 status = NT_STATUS_NO_MEMORY;
2668 goto cleanup;
2671 buf = inbuf.data;
2673 SCVAL(buf, 0, 0); /* ReturnSingle */
2674 SCVAL(buf, 1, first ? 1 : 0); /* RestartScan */
2675 SSVAL(buf, 2, 0); /* Reserved */
2676 SIVAL(buf, 4, 0); /* SidListLength */
2677 SIVAL(buf, 8, 0); /* StartSidLength */
2678 SIVAL(buf, 12, 0); /* StartSidOffset */
2680 status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
2681 cli->smb2.tcon, 4, /* in_info_type */
2682 0, /* in_file_info_class */
2683 0xFFFF, /* in_max_output_length */
2684 &inbuf, /* in_input_buffer */
2685 0, /* in_additional_info */
2686 0, /* in_flags */
2687 ph->fid_persistent, ph->fid_volatile, frame,
2688 &outbuf);
2690 if (!NT_STATUS_IS_OK(status)) {
2691 goto cleanup;
2694 status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
2695 pqt_list);
2697 cleanup:
2698 cli->raw_status = status;
2700 TALLOC_FREE(frame);
2701 return status;
2704 /***************************************************************
2705 Wrapper that allows SMB2 to get file system quota.
2706 Synchronous only.
2707 ***************************************************************/
2709 NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
2710 int quota_fnum,
2711 SMB_NTQUOTA_STRUCT *pqt)
2713 NTSTATUS status;
2714 DATA_BLOB outbuf = data_blob_null;
2715 struct smb2_hnd *ph = NULL;
2716 TALLOC_CTX *frame = talloc_stackframe();
2718 if (smbXcli_conn_has_async_calls(cli->conn)) {
2720 * Can't use sync call while an async call is in flight
2722 status = NT_STATUS_INVALID_PARAMETER;
2723 goto cleanup;
2726 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2727 status = NT_STATUS_INVALID_PARAMETER;
2728 goto cleanup;
2731 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2732 if (!NT_STATUS_IS_OK(status)) {
2733 goto cleanup;
2736 status = smb2cli_query_info(
2737 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
2738 2, /* in_info_type */
2739 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
2740 0xFFFF, /* in_max_output_length */
2741 NULL, /* in_input_buffer */
2742 0, /* in_additional_info */
2743 0, /* in_flags */
2744 ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
2746 if (!NT_STATUS_IS_OK(status)) {
2747 goto cleanup;
2750 status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
2752 cleanup:
2753 cli->raw_status = status;
2755 TALLOC_FREE(frame);
2756 return status;
2759 /***************************************************************
2760 Wrapper that allows SMB2 to set user quota.
2761 Synchronous only.
2762 ***************************************************************/
2764 NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
2765 int quota_fnum,
2766 SMB_NTQUOTA_LIST *qtl)
2768 NTSTATUS status;
2769 DATA_BLOB inbuf = data_blob_null;
2770 struct smb2_hnd *ph = NULL;
2771 TALLOC_CTX *frame = talloc_stackframe();
2773 if (smbXcli_conn_has_async_calls(cli->conn)) {
2775 * Can't use sync call while an async call is in flight
2777 status = NT_STATUS_INVALID_PARAMETER;
2778 goto cleanup;
2781 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2782 status = NT_STATUS_INVALID_PARAMETER;
2783 goto cleanup;
2786 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2787 if (!NT_STATUS_IS_OK(status)) {
2788 goto cleanup;
2791 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
2792 if (!NT_STATUS_IS_OK(status)) {
2793 goto cleanup;
2796 status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
2797 cli->smb2.tcon, 4, /* in_info_type */
2798 0, /* in_file_info_class */
2799 &inbuf, /* in_input_buffer */
2800 0, /* in_additional_info */
2801 ph->fid_persistent, ph->fid_volatile);
2802 cleanup:
2804 cli->raw_status = status;
2806 TALLOC_FREE(frame);
2808 return status;
2811 NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
2812 int quota_fnum,
2813 SMB_NTQUOTA_STRUCT *pqt)
2815 NTSTATUS status;
2816 DATA_BLOB inbuf = data_blob_null;
2817 struct smb2_hnd *ph = NULL;
2818 TALLOC_CTX *frame = talloc_stackframe();
2820 if (smbXcli_conn_has_async_calls(cli->conn)) {
2822 * Can't use sync call while an async call is in flight
2824 status = NT_STATUS_INVALID_PARAMETER;
2825 goto cleanup;
2828 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2829 status = NT_STATUS_INVALID_PARAMETER;
2830 goto cleanup;
2833 status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
2834 if (!NT_STATUS_IS_OK(status)) {
2835 goto cleanup;
2838 status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
2839 if (!NT_STATUS_IS_OK(status)) {
2840 goto cleanup;
2843 status = smb2cli_set_info(
2844 cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
2845 2, /* in_info_type */
2846 SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
2847 &inbuf, /* in_input_buffer */
2848 0, /* in_additional_info */
2849 ph->fid_persistent, ph->fid_volatile);
2850 cleanup:
2851 cli->raw_status = status;
2853 TALLOC_FREE(frame);
2854 return status;
2857 struct cli_smb2_read_state {
2858 struct tevent_context *ev;
2859 struct cli_state *cli;
2860 struct smb2_hnd *ph;
2861 uint64_t start_offset;
2862 uint32_t size;
2863 uint32_t received;
2864 uint8_t *buf;
2867 static void cli_smb2_read_done(struct tevent_req *subreq);
2869 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
2870 struct tevent_context *ev,
2871 struct cli_state *cli,
2872 uint16_t fnum,
2873 off_t offset,
2874 size_t size)
2876 NTSTATUS status;
2877 struct tevent_req *req, *subreq;
2878 struct cli_smb2_read_state *state;
2880 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
2881 if (req == NULL) {
2882 return NULL;
2884 state->ev = ev;
2885 state->cli = cli;
2886 state->start_offset = (uint64_t)offset;
2887 state->size = (uint32_t)size;
2888 state->received = 0;
2889 state->buf = NULL;
2891 status = map_fnum_to_smb2_handle(cli,
2892 fnum,
2893 &state->ph);
2894 if (tevent_req_nterror(req, status)) {
2895 return tevent_req_post(req, ev);
2898 subreq = smb2cli_read_send(state,
2899 state->ev,
2900 state->cli->conn,
2901 state->cli->timeout,
2902 state->cli->smb2.session,
2903 state->cli->smb2.tcon,
2904 state->size,
2905 state->start_offset,
2906 state->ph->fid_persistent,
2907 state->ph->fid_volatile,
2908 0, /* minimum_count */
2909 0); /* remaining_bytes */
2911 if (tevent_req_nomem(subreq, req)) {
2912 return tevent_req_post(req, ev);
2914 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
2915 return req;
2918 static void cli_smb2_read_done(struct tevent_req *subreq)
2920 struct tevent_req *req = tevent_req_callback_data(
2921 subreq, struct tevent_req);
2922 struct cli_smb2_read_state *state = tevent_req_data(
2923 req, struct cli_smb2_read_state);
2924 NTSTATUS status;
2926 status = smb2cli_read_recv(subreq, state,
2927 &state->buf, &state->received);
2928 if (tevent_req_nterror(req, status)) {
2929 return;
2932 if (state->received > state->size) {
2933 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2934 return;
2937 tevent_req_done(req);
2940 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
2941 ssize_t *received,
2942 uint8_t **rcvbuf)
2944 NTSTATUS status;
2945 struct cli_smb2_read_state *state = tevent_req_data(
2946 req, struct cli_smb2_read_state);
2948 if (tevent_req_is_nterror(req, &status)) {
2949 state->cli->raw_status = status;
2950 return status;
2953 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2954 * better make sure that you copy it away before you talloc_free(req).
2955 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2957 *received = (ssize_t)state->received;
2958 *rcvbuf = state->buf;
2959 state->cli->raw_status = NT_STATUS_OK;
2960 return NT_STATUS_OK;
2963 struct cli_smb2_write_state {
2964 struct tevent_context *ev;
2965 struct cli_state *cli;
2966 struct smb2_hnd *ph;
2967 uint32_t flags;
2968 const uint8_t *buf;
2969 uint64_t offset;
2970 uint32_t size;
2971 uint32_t written;
2974 static void cli_smb2_write_written(struct tevent_req *req);
2976 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
2977 struct tevent_context *ev,
2978 struct cli_state *cli,
2979 uint16_t fnum,
2980 uint16_t mode,
2981 const uint8_t *buf,
2982 off_t offset,
2983 size_t size)
2985 NTSTATUS status;
2986 struct tevent_req *req, *subreq = NULL;
2987 struct cli_smb2_write_state *state = NULL;
2989 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
2990 if (req == NULL) {
2991 return NULL;
2993 state->ev = ev;
2994 state->cli = cli;
2995 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2996 state->flags = (uint32_t)mode;
2997 state->buf = buf;
2998 state->offset = (uint64_t)offset;
2999 state->size = (uint32_t)size;
3000 state->written = 0;
3002 status = map_fnum_to_smb2_handle(cli,
3003 fnum,
3004 &state->ph);
3005 if (tevent_req_nterror(req, status)) {
3006 return tevent_req_post(req, ev);
3009 subreq = smb2cli_write_send(state,
3010 state->ev,
3011 state->cli->conn,
3012 state->cli->timeout,
3013 state->cli->smb2.session,
3014 state->cli->smb2.tcon,
3015 state->size,
3016 state->offset,
3017 state->ph->fid_persistent,
3018 state->ph->fid_volatile,
3019 0, /* remaining_bytes */
3020 state->flags, /* flags */
3021 state->buf);
3023 if (tevent_req_nomem(subreq, req)) {
3024 return tevent_req_post(req, ev);
3026 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
3027 return req;
3030 static void cli_smb2_write_written(struct tevent_req *subreq)
3032 struct tevent_req *req = tevent_req_callback_data(
3033 subreq, struct tevent_req);
3034 struct cli_smb2_write_state *state = tevent_req_data(
3035 req, struct cli_smb2_write_state);
3036 NTSTATUS status;
3037 uint32_t written;
3039 status = smb2cli_write_recv(subreq, &written);
3040 TALLOC_FREE(subreq);
3041 if (tevent_req_nterror(req, status)) {
3042 return;
3045 state->written = written;
3047 tevent_req_done(req);
3050 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
3051 size_t *pwritten)
3053 struct cli_smb2_write_state *state = tevent_req_data(
3054 req, struct cli_smb2_write_state);
3055 NTSTATUS status;
3057 if (tevent_req_is_nterror(req, &status)) {
3058 state->cli->raw_status = status;
3059 tevent_req_received(req);
3060 return status;
3063 if (pwritten != NULL) {
3064 *pwritten = (size_t)state->written;
3066 state->cli->raw_status = NT_STATUS_OK;
3067 tevent_req_received(req);
3068 return NT_STATUS_OK;
3071 /***************************************************************
3072 Wrapper that allows SMB2 async write using an fnum.
3073 This is mostly cut-and-paste from Volker's code inside
3074 source3/libsmb/clireadwrite.c, adapted for SMB2.
3076 Done this way so I can reuse all the logic inside cli_push()
3077 for free :-).
3078 ***************************************************************/
3080 struct cli_smb2_writeall_state {
3081 struct tevent_context *ev;
3082 struct cli_state *cli;
3083 struct smb2_hnd *ph;
3084 uint32_t flags;
3085 const uint8_t *buf;
3086 uint64_t offset;
3087 uint32_t size;
3088 uint32_t written;
3091 static void cli_smb2_writeall_written(struct tevent_req *req);
3093 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
3094 struct tevent_context *ev,
3095 struct cli_state *cli,
3096 uint16_t fnum,
3097 uint16_t mode,
3098 const uint8_t *buf,
3099 off_t offset,
3100 size_t size)
3102 NTSTATUS status;
3103 struct tevent_req *req, *subreq = NULL;
3104 struct cli_smb2_writeall_state *state = NULL;
3105 uint32_t to_write;
3106 uint32_t max_size;
3107 bool ok;
3109 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
3110 if (req == NULL) {
3111 return NULL;
3113 state->ev = ev;
3114 state->cli = cli;
3115 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
3116 state->flags = (uint32_t)mode;
3117 state->buf = buf;
3118 state->offset = (uint64_t)offset;
3119 state->size = (uint32_t)size;
3120 state->written = 0;
3122 status = map_fnum_to_smb2_handle(cli,
3123 fnum,
3124 &state->ph);
3125 if (tevent_req_nterror(req, status)) {
3126 return tevent_req_post(req, ev);
3129 to_write = state->size;
3130 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3131 to_write = MIN(max_size, to_write);
3132 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3133 if (ok) {
3134 to_write = MIN(max_size, to_write);
3137 subreq = smb2cli_write_send(state,
3138 state->ev,
3139 state->cli->conn,
3140 state->cli->timeout,
3141 state->cli->smb2.session,
3142 state->cli->smb2.tcon,
3143 to_write,
3144 state->offset,
3145 state->ph->fid_persistent,
3146 state->ph->fid_volatile,
3147 0, /* remaining_bytes */
3148 state->flags, /* flags */
3149 state->buf + state->written);
3151 if (tevent_req_nomem(subreq, req)) {
3152 return tevent_req_post(req, ev);
3154 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3155 return req;
3158 static void cli_smb2_writeall_written(struct tevent_req *subreq)
3160 struct tevent_req *req = tevent_req_callback_data(
3161 subreq, struct tevent_req);
3162 struct cli_smb2_writeall_state *state = tevent_req_data(
3163 req, struct cli_smb2_writeall_state);
3164 NTSTATUS status;
3165 uint32_t written, to_write;
3166 uint32_t max_size;
3167 bool ok;
3169 status = smb2cli_write_recv(subreq, &written);
3170 TALLOC_FREE(subreq);
3171 if (tevent_req_nterror(req, status)) {
3172 return;
3175 state->written += written;
3177 if (state->written > state->size) {
3178 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3179 return;
3182 to_write = state->size - state->written;
3184 if (to_write == 0) {
3185 tevent_req_done(req);
3186 return;
3189 max_size = smb2cli_conn_max_write_size(state->cli->conn);
3190 to_write = MIN(max_size, to_write);
3191 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
3192 if (ok) {
3193 to_write = MIN(max_size, to_write);
3196 subreq = smb2cli_write_send(state,
3197 state->ev,
3198 state->cli->conn,
3199 state->cli->timeout,
3200 state->cli->smb2.session,
3201 state->cli->smb2.tcon,
3202 to_write,
3203 state->offset + state->written,
3204 state->ph->fid_persistent,
3205 state->ph->fid_volatile,
3206 0, /* remaining_bytes */
3207 state->flags, /* flags */
3208 state->buf + state->written);
3210 if (tevent_req_nomem(subreq, req)) {
3211 return;
3213 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
3216 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
3217 size_t *pwritten)
3219 struct cli_smb2_writeall_state *state = tevent_req_data(
3220 req, struct cli_smb2_writeall_state);
3221 NTSTATUS status;
3223 if (tevent_req_is_nterror(req, &status)) {
3224 state->cli->raw_status = status;
3225 return status;
3227 if (pwritten != NULL) {
3228 *pwritten = (size_t)state->written;
3230 state->cli->raw_status = NT_STATUS_OK;
3231 return NT_STATUS_OK;
3234 struct cli_smb2_splice_state {
3235 struct tevent_context *ev;
3236 struct cli_state *cli;
3237 struct smb2_hnd *src_ph;
3238 struct smb2_hnd *dst_ph;
3239 int (*splice_cb)(off_t n, void *priv);
3240 void *priv;
3241 off_t written;
3242 off_t size;
3243 off_t src_offset;
3244 off_t dst_offset;
3245 bool resized;
3246 struct req_resume_key_rsp resume_rsp;
3247 struct srv_copychunk_copy cc_copy;
3250 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3251 struct tevent_req *req);
3253 static void cli_splice_copychunk_done(struct tevent_req *subreq)
3255 struct tevent_req *req = tevent_req_callback_data(
3256 subreq, struct tevent_req);
3257 struct cli_smb2_splice_state *state =
3258 tevent_req_data(req,
3259 struct cli_smb2_splice_state);
3260 struct smbXcli_conn *conn = state->cli->conn;
3261 DATA_BLOB out_input_buffer = data_blob_null;
3262 DATA_BLOB out_output_buffer = data_blob_null;
3263 struct srv_copychunk_rsp cc_copy_rsp;
3264 enum ndr_err_code ndr_ret;
3265 NTSTATUS status;
3267 status = smb2cli_ioctl_recv(subreq, state,
3268 &out_input_buffer,
3269 &out_output_buffer);
3270 TALLOC_FREE(subreq);
3271 if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
3272 state->resized) && tevent_req_nterror(req, status)) {
3273 return;
3276 ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
3277 (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
3278 if (ndr_ret != NDR_ERR_SUCCESS) {
3279 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
3280 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3281 return;
3284 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
3285 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
3286 cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
3287 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
3288 max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
3289 tevent_req_nterror(req, status)) {
3290 return;
3293 state->resized = true;
3294 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
3295 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
3296 } else {
3297 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3298 (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
3299 (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
3300 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3301 return;
3303 state->src_offset += cc_copy_rsp.total_bytes_written;
3304 state->dst_offset += cc_copy_rsp.total_bytes_written;
3305 state->written += cc_copy_rsp.total_bytes_written;
3306 if (!state->splice_cb(state->written, state->priv)) {
3307 tevent_req_nterror(req, NT_STATUS_CANCELLED);
3308 return;
3312 cli_splice_copychunk_send(state, req);
3315 static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
3316 struct tevent_req *req)
3318 struct tevent_req *subreq;
3319 enum ndr_err_code ndr_ret;
3320 struct smbXcli_conn *conn = state->cli->conn;
3321 struct srv_copychunk_copy *cc_copy = &state->cc_copy;
3322 off_t src_offset = state->src_offset;
3323 off_t dst_offset = state->dst_offset;
3324 uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
3325 state->size - state->written);
3326 DATA_BLOB in_input_buffer = data_blob_null;
3327 DATA_BLOB in_output_buffer = data_blob_null;
3329 if (state->size - state->written == 0) {
3330 tevent_req_done(req);
3331 return;
3334 cc_copy->chunk_count = 0;
3335 while (req_len) {
3336 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
3337 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
3338 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
3339 smb2cli_conn_cc_chunk_len(conn));
3340 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
3341 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3342 return;
3344 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
3345 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
3346 (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
3347 tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
3348 return;
3350 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3351 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
3352 cc_copy->chunk_count++;
3355 ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
3356 (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
3357 if (ndr_ret != NDR_ERR_SUCCESS) {
3358 DEBUG(0, ("failed to marshall copy chunk req\n"));
3359 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
3360 return;
3363 subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
3364 state->cli->timeout,
3365 state->cli->smb2.session,
3366 state->cli->smb2.tcon,
3367 state->dst_ph->fid_persistent, /* in_fid_persistent */
3368 state->dst_ph->fid_volatile, /* in_fid_volatile */
3369 FSCTL_SRV_COPYCHUNK_WRITE,
3370 0, /* in_max_input_length */
3371 &in_input_buffer,
3372 12, /* in_max_output_length */
3373 &in_output_buffer,
3374 SMB2_IOCTL_FLAG_IS_FSCTL);
3375 if (tevent_req_nomem(subreq, req)) {
3376 return;
3378 tevent_req_set_callback(subreq,
3379 cli_splice_copychunk_done,
3380 req);
3383 static void cli_splice_key_done(struct tevent_req *subreq)
3385 struct tevent_req *req = tevent_req_callback_data(
3386 subreq, struct tevent_req);
3387 struct cli_smb2_splice_state *state =
3388 tevent_req_data(req,
3389 struct cli_smb2_splice_state);
3390 enum ndr_err_code ndr_ret;
3391 NTSTATUS status;
3393 DATA_BLOB out_input_buffer = data_blob_null;
3394 DATA_BLOB out_output_buffer = data_blob_null;
3396 status = smb2cli_ioctl_recv(subreq, state,
3397 &out_input_buffer,
3398 &out_output_buffer);
3399 TALLOC_FREE(subreq);
3400 if (tevent_req_nterror(req, status)) {
3401 return;
3404 ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
3405 state, &state->resume_rsp,
3406 (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
3407 if (ndr_ret != NDR_ERR_SUCCESS) {
3408 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
3409 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
3410 return;
3413 memcpy(&state->cc_copy.source_key,
3414 &state->resume_rsp.resume_key,
3415 sizeof state->resume_rsp.resume_key);
3417 cli_splice_copychunk_send(state, req);
3420 struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
3421 struct tevent_context *ev,
3422 struct cli_state *cli,
3423 uint16_t src_fnum, uint16_t dst_fnum,
3424 off_t size, off_t src_offset, off_t dst_offset,
3425 int (*splice_cb)(off_t n, void *priv),
3426 void *priv)
3428 struct tevent_req *req;
3429 struct tevent_req *subreq;
3430 struct cli_smb2_splice_state *state;
3431 NTSTATUS status;
3432 DATA_BLOB in_input_buffer = data_blob_null;
3433 DATA_BLOB in_output_buffer = data_blob_null;
3435 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
3436 if (req == NULL) {
3437 return NULL;
3439 state->cli = cli;
3440 state->ev = ev;
3441 state->splice_cb = splice_cb;
3442 state->priv = priv;
3443 state->size = size;
3444 state->written = 0;
3445 state->src_offset = src_offset;
3446 state->dst_offset = dst_offset;
3447 state->cc_copy.chunks = talloc_array(state,
3448 struct srv_copychunk,
3449 smb2cli_conn_cc_max_chunks(cli->conn));
3450 if (state->cc_copy.chunks == NULL) {
3451 return NULL;
3454 status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
3455 if (tevent_req_nterror(req, status))
3456 return tevent_req_post(req, ev);
3458 status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
3459 if (tevent_req_nterror(req, status))
3460 return tevent_req_post(req, ev);
3462 subreq = smb2cli_ioctl_send(state, ev, cli->conn,
3463 cli->timeout,
3464 cli->smb2.session,
3465 cli->smb2.tcon,
3466 state->src_ph->fid_persistent, /* in_fid_persistent */
3467 state->src_ph->fid_volatile, /* in_fid_volatile */
3468 FSCTL_SRV_REQUEST_RESUME_KEY,
3469 0, /* in_max_input_length */
3470 &in_input_buffer,
3471 32, /* in_max_output_length */
3472 &in_output_buffer,
3473 SMB2_IOCTL_FLAG_IS_FSCTL);
3474 if (tevent_req_nomem(subreq, req)) {
3475 return NULL;
3477 tevent_req_set_callback(subreq,
3478 cli_splice_key_done,
3479 req);
3481 return req;
3484 NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
3486 struct cli_smb2_splice_state *state = tevent_req_data(
3487 req, struct cli_smb2_splice_state);
3488 NTSTATUS status;
3490 if (tevent_req_is_nterror(req, &status)) {
3491 state->cli->raw_status = status;
3492 tevent_req_received(req);
3493 return status;
3495 if (written != NULL) {
3496 *written = state->written;
3498 state->cli->raw_status = NT_STATUS_OK;
3499 tevent_req_received(req);
3500 return NT_STATUS_OK;
3503 /***************************************************************
3504 SMB2 enum shadow copy data.
3505 ***************************************************************/
3507 struct cli_smb2_shadow_copy_data_fnum_state {
3508 struct cli_state *cli;
3509 uint16_t fnum;
3510 struct smb2_hnd *ph;
3511 DATA_BLOB out_input_buffer;
3512 DATA_BLOB out_output_buffer;
3515 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
3517 static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
3518 TALLOC_CTX *mem_ctx,
3519 struct tevent_context *ev,
3520 struct cli_state *cli,
3521 uint16_t fnum,
3522 bool get_names)
3524 struct tevent_req *req, *subreq;
3525 struct cli_smb2_shadow_copy_data_fnum_state *state;
3526 NTSTATUS status;
3528 req = tevent_req_create(mem_ctx, &state,
3529 struct cli_smb2_shadow_copy_data_fnum_state);
3530 if (req == NULL) {
3531 return NULL;
3534 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3535 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
3536 return tevent_req_post(req, ev);
3539 state->cli = cli;
3540 state->fnum = fnum;
3542 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
3543 if (tevent_req_nterror(req, status)) {
3544 return tevent_req_post(req, ev);
3548 * TODO. Under SMB2 we should send a zero max_output_length
3549 * ioctl to get the required size, then send another ioctl
3550 * to get the data, but the current SMB1 implementation just
3551 * does one roundtrip with a 64K buffer size. Do the same
3552 * for now. JRA.
3555 subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
3556 state->cli->timeout,
3557 state->cli->smb2.session,
3558 state->cli->smb2.tcon,
3559 state->ph->fid_persistent, /* in_fid_persistent */
3560 state->ph->fid_volatile, /* in_fid_volatile */
3561 FSCTL_GET_SHADOW_COPY_DATA,
3562 0, /* in_max_input_length */
3563 NULL, /* in_input_buffer */
3564 get_names ?
3565 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
3566 NULL, /* in_output_buffer */
3567 SMB2_IOCTL_FLAG_IS_FSCTL);
3569 if (tevent_req_nomem(subreq, req)) {
3570 return tevent_req_post(req, ev);
3572 tevent_req_set_callback(subreq,
3573 cli_smb2_shadow_copy_data_fnum_done,
3574 req);
3576 return req;
3579 static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
3581 struct tevent_req *req = tevent_req_callback_data(
3582 subreq, struct tevent_req);
3583 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3584 req, struct cli_smb2_shadow_copy_data_fnum_state);
3585 NTSTATUS status;
3587 status = smb2cli_ioctl_recv(subreq, state,
3588 &state->out_input_buffer,
3589 &state->out_output_buffer);
3590 TALLOC_FREE(subreq);
3591 if (tevent_req_nterror(req, status)) {
3592 return;
3594 tevent_req_done(req);
3597 static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
3598 TALLOC_CTX *mem_ctx,
3599 bool get_names,
3600 char ***pnames,
3601 int *pnum_names)
3603 struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
3604 req, struct cli_smb2_shadow_copy_data_fnum_state);
3605 char **names = NULL;
3606 uint32_t num_names = 0;
3607 uint32_t num_names_returned = 0;
3608 uint32_t dlength = 0;
3609 uint32_t i;
3610 uint8_t *endp = NULL;
3611 NTSTATUS status;
3613 if (tevent_req_is_nterror(req, &status)) {
3614 return status;
3617 if (state->out_output_buffer.length < 16) {
3618 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3621 num_names = IVAL(state->out_output_buffer.data, 0);
3622 num_names_returned = IVAL(state->out_output_buffer.data, 4);
3623 dlength = IVAL(state->out_output_buffer.data, 8);
3625 if (num_names > 0x7FFFFFFF) {
3626 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3629 if (get_names == false) {
3630 *pnum_names = (int)num_names;
3631 return NT_STATUS_OK;
3633 if (num_names != num_names_returned) {
3634 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3636 if (dlength + 12 < 12) {
3637 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3640 * NB. The below is an allowable return if there are
3641 * more snapshots than the buffer size we told the
3642 * server we can receive. We currently don't support
3643 * this.
3645 if (dlength + 12 > state->out_output_buffer.length) {
3646 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3648 if (state->out_output_buffer.length +
3649 (2 * sizeof(SHADOW_COPY_LABEL)) <
3650 state->out_output_buffer.length) {
3651 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3654 names = talloc_array(mem_ctx, char *, num_names_returned);
3655 if (names == NULL) {
3656 return NT_STATUS_NO_MEMORY;
3659 endp = state->out_output_buffer.data +
3660 state->out_output_buffer.length;
3662 for (i=0; i<num_names_returned; i++) {
3663 bool ret;
3664 uint8_t *src;
3665 size_t converted_size;
3667 src = state->out_output_buffer.data + 12 +
3668 (i * 2 * sizeof(SHADOW_COPY_LABEL));
3670 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
3671 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3673 ret = convert_string_talloc(
3674 names, CH_UTF16LE, CH_UNIX,
3675 src, 2 * sizeof(SHADOW_COPY_LABEL),
3676 &names[i], &converted_size);
3677 if (!ret) {
3678 TALLOC_FREE(names);
3679 return NT_STATUS_INVALID_NETWORK_RESPONSE;
3682 *pnum_names = num_names;
3683 *pnames = names;
3684 return NT_STATUS_OK;
3687 NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
3688 struct cli_state *cli,
3689 uint16_t fnum,
3690 bool get_names,
3691 char ***pnames,
3692 int *pnum_names)
3694 TALLOC_CTX *frame = talloc_stackframe();
3695 struct tevent_context *ev;
3696 struct tevent_req *req;
3697 NTSTATUS status = NT_STATUS_NO_MEMORY;
3699 if (smbXcli_conn_has_async_calls(cli->conn)) {
3701 * Can't use sync call while an async call is in flight
3703 status = NT_STATUS_INVALID_PARAMETER;
3704 goto fail;
3706 ev = samba_tevent_context_init(frame);
3707 if (ev == NULL) {
3708 goto fail;
3710 req = cli_smb2_shadow_copy_data_fnum_send(frame,
3712 cli,
3713 fnum,
3714 get_names);
3715 if (req == NULL) {
3716 goto fail;
3718 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3719 goto fail;
3721 status = cli_smb2_shadow_copy_data_fnum_recv(req,
3722 mem_ctx,
3723 get_names,
3724 pnames,
3725 pnum_names);
3726 fail:
3727 cli->raw_status = status;
3729 TALLOC_FREE(frame);
3730 return status;
3733 /***************************************************************
3734 Wrapper that allows SMB2 to truncate a file.
3735 Synchronous only.
3736 ***************************************************************/
3738 NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
3739 uint16_t fnum,
3740 uint64_t newsize)
3742 NTSTATUS status;
3743 DATA_BLOB inbuf = data_blob_null;
3744 struct smb2_hnd *ph = NULL;
3745 TALLOC_CTX *frame = talloc_stackframe();
3747 if (smbXcli_conn_has_async_calls(cli->conn)) {
3749 * Can't use sync call while an async call is in flight
3751 status = NT_STATUS_INVALID_PARAMETER;
3752 goto fail;
3755 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
3756 status = NT_STATUS_INVALID_PARAMETER;
3757 goto fail;
3760 status = map_fnum_to_smb2_handle(cli,
3761 fnum,
3762 &ph);
3763 if (!NT_STATUS_IS_OK(status)) {
3764 goto fail;
3767 inbuf = data_blob_talloc_zero(frame, 8);
3768 if (inbuf.data == NULL) {
3769 status = NT_STATUS_NO_MEMORY;
3770 goto fail;
3773 SBVAL(inbuf.data, 0, newsize);
3775 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
3776 level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
3778 status = smb2cli_set_info(cli->conn,
3779 cli->timeout,
3780 cli->smb2.session,
3781 cli->smb2.tcon,
3782 1, /* in_info_type */
3783 /* in_file_info_class */
3784 SMB_FILE_END_OF_FILE_INFORMATION - 1000,
3785 &inbuf, /* in_input_buffer */
3786 0, /* in_additional_info */
3787 ph->fid_persistent,
3788 ph->fid_volatile);
3790 fail:
3792 cli->raw_status = status;
3794 TALLOC_FREE(frame);
3795 return status;