lib: talloc: Allow destructors to reparent the object they're called on.
[Samba.git] / source3 / libsmb / cli_smb2_fnum.c
blobaeade88e24daa24ed981ad1d7a719de09fd9a9b8
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 "smb2cli.h"
34 #include "cli_smb2_fnum.h"
35 #include "trans2.h"
36 #include "clirap.h"
37 #include "../libcli/smb/smb2_create_blob.h"
38 #include "libsmb/proto.h"
39 #include "lib/util/tevent_ntstatus.h"
40 #include "../libcli/security/security.h"
41 #include "lib/util_ea.h"
43 struct smb2_hnd {
44 uint64_t fid_persistent;
45 uint64_t fid_volatile;
49 * Handle mapping code.
52 /***************************************************************
53 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
54 Ensures handle is owned by cli struct.
55 ***************************************************************/
57 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
58 const struct smb2_hnd *ph, /* In */
59 uint16_t *pfnum) /* Out */
61 int ret;
62 struct idr_context *idp = cli->smb2.open_handles;
63 struct smb2_hnd *owned_h = talloc_memdup(cli,
64 ph,
65 sizeof(struct smb2_hnd));
67 if (owned_h == NULL) {
68 return NT_STATUS_NO_MEMORY;
71 if (idp == NULL) {
72 /* Lazy init */
73 cli->smb2.open_handles = idr_init(cli);
74 if (cli->smb2.open_handles == NULL) {
75 TALLOC_FREE(owned_h);
76 return NT_STATUS_NO_MEMORY;
78 idp = cli->smb2.open_handles;
81 ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
82 if (ret == -1) {
83 TALLOC_FREE(owned_h);
84 return NT_STATUS_NO_MEMORY;
87 *pfnum = (uint16_t)ret;
88 return NT_STATUS_OK;
91 /***************************************************************
92 Return the smb2_hnd pointer associated with the given fnum.
93 ***************************************************************/
95 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
96 uint16_t fnum, /* In */
97 struct smb2_hnd **pph) /* Out */
99 struct idr_context *idp = cli->smb2.open_handles;
101 if (idp == NULL) {
102 return NT_STATUS_INVALID_PARAMETER;
104 *pph = (struct smb2_hnd *)idr_find(idp, fnum);
105 if (*pph == NULL) {
106 return NT_STATUS_INVALID_HANDLE;
108 return NT_STATUS_OK;
111 /***************************************************************
112 Delete the fnum to smb2_hnd mapping. Zeros out handle on
113 successful return.
114 ***************************************************************/
116 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
117 struct smb2_hnd **pph, /* In */
118 uint16_t fnum) /* In */
120 struct idr_context *idp = cli->smb2.open_handles;
121 struct smb2_hnd *ph;
123 if (idp == NULL) {
124 return NT_STATUS_INVALID_PARAMETER;
127 ph = (struct smb2_hnd *)idr_find(idp, fnum);
128 if (ph != *pph) {
129 return NT_STATUS_INVALID_PARAMETER;
131 idr_remove(idp, fnum);
132 TALLOC_FREE(*pph);
133 return NT_STATUS_OK;
136 /***************************************************************
137 Oplock mapping code.
138 ***************************************************************/
140 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
142 if (create_flags & REQUEST_BATCH_OPLOCK) {
143 return SMB2_OPLOCK_LEVEL_BATCH;
144 } else if (create_flags & REQUEST_OPLOCK) {
145 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
148 /* create_flags doesn't do a level2 request. */
149 return SMB2_OPLOCK_LEVEL_NONE;
152 /***************************************************************
153 Small wrapper that allows SMB2 create to return a uint16_t fnum.
154 Synchronous only.
155 ***************************************************************/
157 NTSTATUS cli_smb2_create_fnum(struct cli_state *cli,
158 const char *fname,
159 uint32_t create_flags,
160 uint32_t desired_access,
161 uint32_t file_attributes,
162 uint32_t share_access,
163 uint32_t create_disposition,
164 uint32_t create_options,
165 uint16_t *pfid,
166 struct smb_create_returns *cr)
168 NTSTATUS status;
169 struct smb2_hnd h;
171 if (smbXcli_conn_has_async_calls(cli->conn)) {
173 * Can't use sync call while an async call is in flight
175 return NT_STATUS_INVALID_PARAMETER;
178 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
179 return NT_STATUS_INVALID_PARAMETER;
182 if (cli->backup_intent) {
183 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
186 /* SMB2 is pickier about pathnames. Ensure it doesn't
187 start in a '\' */
188 if (*fname == '\\') {
189 fname++;
192 status = smb2cli_create(cli->conn,
193 cli->timeout,
194 cli->smb2.session,
195 cli->smb2.tcon,
196 fname,
197 flags_to_smb2_oplock(create_flags),
198 SMB2_IMPERSONATION_IMPERSONATION,
199 desired_access,
200 file_attributes,
201 share_access,
202 create_disposition,
203 create_options,
204 NULL,
205 &h.fid_persistent,
206 &h.fid_volatile,
207 cr);
209 if (NT_STATUS_IS_OK(status)) {
210 status = map_smb2_handle_to_fnum(cli, &h, pfid);
213 return status;
216 /***************************************************************
217 Small wrapper that allows SMB2 close to use a uint16_t fnum.
218 Synchronous only.
219 ***************************************************************/
221 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
223 struct smb2_hnd *ph = NULL;
224 NTSTATUS status;
226 if (smbXcli_conn_has_async_calls(cli->conn)) {
228 * Can't use sync call while an async call is in flight
230 return NT_STATUS_INVALID_PARAMETER;
233 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
234 return NT_STATUS_INVALID_PARAMETER;
237 status = map_fnum_to_smb2_handle(cli,
238 fnum,
239 &ph);
240 if (!NT_STATUS_IS_OK(status)) {
241 return status;
244 status = smb2cli_close(cli->conn,
245 cli->timeout,
246 cli->smb2.session,
247 cli->smb2.tcon,
249 ph->fid_persistent,
250 ph->fid_volatile);
252 /* Delete the fnum -> handle mapping. */
253 if (NT_STATUS_IS_OK(status)) {
254 status = delete_smb2_handle_mapping(cli, &ph, fnum);
257 return status;
260 /***************************************************************
261 Small wrapper that allows SMB2 to create a directory
262 Synchronous only.
263 ***************************************************************/
265 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
267 NTSTATUS status;
268 uint16_t fnum;
270 if (smbXcli_conn_has_async_calls(cli->conn)) {
272 * Can't use sync call while an async call is in flight
274 return NT_STATUS_INVALID_PARAMETER;
277 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
278 return NT_STATUS_INVALID_PARAMETER;
281 status = cli_smb2_create_fnum(cli,
282 dname,
283 0, /* create_flags */
284 FILE_READ_ATTRIBUTES, /* desired_access */
285 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
286 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
287 FILE_CREATE, /* create_disposition */
288 FILE_DIRECTORY_FILE, /* create_options */
289 &fnum,
290 NULL);
292 if (!NT_STATUS_IS_OK(status)) {
293 return status;
295 return cli_smb2_close_fnum(cli, fnum);
298 /***************************************************************
299 Small wrapper that allows SMB2 to delete a directory
300 Synchronous only.
301 ***************************************************************/
303 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
305 NTSTATUS status;
306 uint16_t fnum;
308 if (smbXcli_conn_has_async_calls(cli->conn)) {
310 * Can't use sync call while an async call is in flight
312 return NT_STATUS_INVALID_PARAMETER;
315 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
316 return NT_STATUS_INVALID_PARAMETER;
319 status = cli_smb2_create_fnum(cli,
320 dname,
321 0, /* create_flags */
322 DELETE_ACCESS, /* desired_access */
323 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
324 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
325 FILE_OPEN, /* create_disposition */
326 FILE_DIRECTORY_FILE|FILE_DELETE_ON_CLOSE, /* create_options */
327 &fnum,
328 NULL);
330 if (!NT_STATUS_IS_OK(status)) {
331 return status;
333 return cli_smb2_close_fnum(cli, fnum);
336 /***************************************************************
337 Small wrapper that allows SMB2 to unlink a pathname.
338 Synchronous only.
339 ***************************************************************/
341 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
343 NTSTATUS status;
344 uint16_t fnum;
346 if (smbXcli_conn_has_async_calls(cli->conn)) {
348 * Can't use sync call while an async call is in flight
350 return NT_STATUS_INVALID_PARAMETER;
353 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
354 return NT_STATUS_INVALID_PARAMETER;
357 status = cli_smb2_create_fnum(cli,
358 fname,
359 0, /* create_flags */
360 DELETE_ACCESS, /* desired_access */
361 FILE_ATTRIBUTE_NORMAL, /* file attributes */
362 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
363 FILE_OPEN, /* create_disposition */
364 FILE_DELETE_ON_CLOSE, /* create_options */
365 &fnum,
366 NULL);
368 if (!NT_STATUS_IS_OK(status)) {
369 return status;
371 return cli_smb2_close_fnum(cli, fnum);
374 /***************************************************************
375 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
376 ***************************************************************/
378 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
379 uint32_t dir_data_length,
380 struct file_info *finfo,
381 uint32_t *next_offset)
383 size_t namelen = 0;
384 size_t slen = 0;
385 size_t ret = 0;
387 if (dir_data_length < 4) {
388 return NT_STATUS_INFO_LENGTH_MISMATCH;
391 *next_offset = IVAL(dir_data, 0);
393 if (*next_offset > dir_data_length) {
394 return NT_STATUS_INFO_LENGTH_MISMATCH;
397 if (*next_offset != 0) {
398 /* Ensure we only read what in this record. */
399 dir_data_length = *next_offset;
402 if (dir_data_length < 105) {
403 return NT_STATUS_INFO_LENGTH_MISMATCH;
406 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
407 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
408 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
409 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
410 finfo->mode = CVAL(dir_data + 56, 0);
411 namelen = IVAL(dir_data + 60,0);
412 if (namelen > (dir_data_length - 104)) {
413 return NT_STATUS_INFO_LENGTH_MISMATCH;
415 slen = CVAL(dir_data + 68, 0);
416 if (slen > 24) {
417 return NT_STATUS_INFO_LENGTH_MISMATCH;
419 ret = pull_string_talloc(finfo,
420 dir_data,
421 FLAGS2_UNICODE_STRINGS,
422 &finfo->short_name,
423 dir_data + 70,
424 slen,
425 STR_UNICODE);
426 if (ret == (size_t)-1) {
427 /* Bad conversion. */
428 return NT_STATUS_INVALID_NETWORK_RESPONSE;
431 ret = pull_string_talloc(finfo,
432 dir_data,
433 FLAGS2_UNICODE_STRINGS,
434 &finfo->name,
435 dir_data + 104,
436 namelen,
437 STR_UNICODE);
438 if (ret == (size_t)-1) {
439 /* Bad conversion. */
440 return NT_STATUS_INVALID_NETWORK_RESPONSE;
442 return NT_STATUS_OK;
445 /*******************************************************************
446 Given a filename - get its directory name
447 ********************************************************************/
449 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
450 const char *dir,
451 char **parent,
452 const char **name)
454 char *p;
455 ptrdiff_t len;
457 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
459 if (p == NULL) {
460 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
461 return false;
463 if (name) {
464 *name = dir;
466 return true;
469 len = p-dir;
471 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
472 return false;
474 (*parent)[len] = '\0';
476 if (name) {
477 *name = p+1;
479 return true;
482 /***************************************************************
483 Wrapper that allows SMB2 to list a directory.
484 Synchronous only.
485 ***************************************************************/
487 NTSTATUS cli_smb2_list(struct cli_state *cli,
488 const char *pathname,
489 uint16_t attribute,
490 NTSTATUS (*fn)(const char *,
491 struct file_info *,
492 const char *,
493 void *),
494 void *state)
496 NTSTATUS status;
497 uint16_t fnum = 0xffff;
498 char *parent_dir = NULL;
499 const char *mask = NULL;
500 struct smb2_hnd *ph = NULL;
501 bool processed_file = false;
502 TALLOC_CTX *frame = talloc_stackframe();
503 TALLOC_CTX *subframe = NULL;
504 bool mask_has_wild;
506 if (smbXcli_conn_has_async_calls(cli->conn)) {
508 * Can't use sync call while an async call is in flight
510 status = NT_STATUS_INVALID_PARAMETER;
511 goto fail;
514 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
515 status = NT_STATUS_INVALID_PARAMETER;
516 goto fail;
519 /* Get the directory name. */
520 if (!windows_parent_dirname(frame,
521 pathname,
522 &parent_dir,
523 &mask)) {
524 status = NT_STATUS_NO_MEMORY;
525 goto fail;
528 mask_has_wild = ms_has_wild(mask);
530 status = cli_smb2_create_fnum(cli,
531 parent_dir,
532 0, /* create_flags */
533 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
534 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
535 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
536 FILE_OPEN, /* create_disposition */
537 FILE_DIRECTORY_FILE, /* create_options */
538 &fnum,
539 NULL);
541 if (!NT_STATUS_IS_OK(status)) {
542 goto fail;
545 status = map_fnum_to_smb2_handle(cli,
546 fnum,
547 &ph);
548 if (!NT_STATUS_IS_OK(status)) {
549 goto fail;
552 do {
553 uint8_t *dir_data = NULL;
554 uint32_t dir_data_length = 0;
555 uint32_t next_offset = 0;
556 subframe = talloc_stackframe();
558 status = smb2cli_query_directory(cli->conn,
559 cli->timeout,
560 cli->smb2.session,
561 cli->smb2.tcon,
562 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
563 0, /* flags */
564 0, /* file_index */
565 ph->fid_persistent,
566 ph->fid_volatile,
567 mask,
568 0xffff,
569 subframe,
570 &dir_data,
571 &dir_data_length);
573 if (!NT_STATUS_IS_OK(status)) {
574 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
575 break;
577 goto fail;
580 do {
581 struct file_info *finfo = talloc_zero(subframe,
582 struct file_info);
584 if (finfo == NULL) {
585 status = NT_STATUS_NO_MEMORY;
586 goto fail;
589 status = parse_finfo_id_both_directory_info(dir_data,
590 dir_data_length,
591 finfo,
592 &next_offset);
594 if (!NT_STATUS_IS_OK(status)) {
595 goto fail;
598 if (dir_check_ftype((uint32_t)finfo->mode,
599 (uint32_t)attribute)) {
601 * Only process if attributes match.
602 * On SMB1 server does this, so on
603 * SMB2 we need to emulate in the
604 * client.
606 * https://bugzilla.samba.org/show_bug.cgi?id=10260
608 processed_file = true;
610 status = fn(cli->dfs_mountpoint,
611 finfo,
612 pathname,
613 state);
615 if (!NT_STATUS_IS_OK(status)) {
616 break;
620 TALLOC_FREE(finfo);
622 /* Move to next entry. */
623 if (next_offset) {
624 dir_data += next_offset;
625 dir_data_length -= next_offset;
627 } while (next_offset != 0);
629 TALLOC_FREE(subframe);
631 if (!mask_has_wild) {
633 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
634 * when handed a non-wildcard path. Do it
635 * for the server (with a non-wildcard path
636 * there should only ever be one file returned.
638 status = STATUS_NO_MORE_FILES;
639 break;
642 } while (NT_STATUS_IS_OK(status));
644 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
645 status = NT_STATUS_OK;
648 if (NT_STATUS_IS_OK(status) && !processed_file) {
650 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
651 * if no files match. Emulate this in the client.
653 status = NT_STATUS_NO_SUCH_FILE;
656 fail:
658 if (fnum != 0xffff) {
659 cli_smb2_close_fnum(cli, fnum);
661 TALLOC_FREE(subframe);
662 TALLOC_FREE(frame);
663 return status;
666 /***************************************************************
667 Wrapper that allows SMB2 to query a path info (basic level).
668 Synchronous only.
669 ***************************************************************/
671 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
672 const char *name,
673 SMB_STRUCT_STAT *sbuf,
674 uint32_t *attributes)
676 NTSTATUS status;
677 struct smb_create_returns cr;
678 uint16_t fnum = 0xffff;
679 size_t namelen = strlen(name);
681 if (smbXcli_conn_has_async_calls(cli->conn)) {
683 * Can't use sync call while an async call is in flight
685 return NT_STATUS_INVALID_PARAMETER;
688 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
689 return NT_STATUS_INVALID_PARAMETER;
692 /* SMB2 is pickier about pathnames. Ensure it doesn't
693 end in a '\' */
694 if (namelen > 0 && name[namelen-1] == '\\') {
695 char *modname = talloc_strdup(talloc_tos(), name);
696 modname[namelen-1] = '\0';
697 name = modname;
700 /* This is commonly used as a 'cd'. Try qpathinfo on
701 a directory handle first. */
703 status = cli_smb2_create_fnum(cli,
704 name,
705 0, /* create_flags */
706 FILE_READ_ATTRIBUTES, /* desired_access */
707 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
708 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
709 FILE_OPEN, /* create_disposition */
710 FILE_DIRECTORY_FILE, /* create_options */
711 &fnum,
712 &cr);
714 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
715 /* Maybe a file ? */
716 status = cli_smb2_create_fnum(cli,
717 name,
718 0, /* create_flags */
719 FILE_READ_ATTRIBUTES, /* desired_access */
720 0, /* file attributes */
721 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
722 FILE_OPEN, /* create_disposition */
723 0, /* create_options */
724 &fnum,
725 &cr);
728 if (!NT_STATUS_IS_OK(status)) {
729 return status;
732 cli_smb2_close_fnum(cli, fnum);
734 ZERO_STRUCTP(sbuf);
736 sbuf->st_ex_atime = nt_time_to_unix_timespec(&cr.last_access_time);
737 sbuf->st_ex_mtime = nt_time_to_unix_timespec(&cr.last_write_time);
738 sbuf->st_ex_ctime = nt_time_to_unix_timespec(&cr.change_time);
739 sbuf->st_ex_size = cr.end_of_file;
740 *attributes = cr.file_attributes;
742 return NT_STATUS_OK;
745 /***************************************************************
746 Helper function for pathname operations.
747 ***************************************************************/
749 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
750 const char *name,
751 uint32_t desired_access,
752 uint16_t *pfnum)
754 NTSTATUS status;
755 size_t namelen = strlen(name);
756 TALLOC_CTX *frame = talloc_stackframe();
758 /* SMB2 is pickier about pathnames. Ensure it doesn't
759 end in a '\' */
760 if (namelen > 0 && name[namelen-1] == '\\') {
761 char *modname = talloc_strdup(frame, name);
762 if (modname == NULL) {
763 status = NT_STATUS_NO_MEMORY;
764 goto fail;
766 modname[namelen-1] = '\0';
767 name = modname;
770 /* Try to open a file handle first. */
771 status = cli_smb2_create_fnum(cli,
772 name,
773 0, /* create_flags */
774 desired_access,
775 0, /* file attributes */
776 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
777 FILE_OPEN, /* create_disposition */
778 0, /* create_options */
779 pfnum,
780 NULL);
782 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
783 status = cli_smb2_create_fnum(cli,
784 name,
785 0, /* create_flags */
786 desired_access,
787 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
788 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
789 FILE_OPEN, /* create_disposition */
790 FILE_DIRECTORY_FILE, /* create_options */
791 pfnum,
792 NULL);
795 fail:
797 TALLOC_FREE(frame);
798 return status;
801 /***************************************************************
802 Wrapper that allows SMB2 to query a path info (ALTNAME level).
803 Synchronous only.
804 ***************************************************************/
806 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
807 const char *name,
808 fstring alt_name)
810 NTSTATUS status;
811 DATA_BLOB outbuf = data_blob_null;
812 uint16_t fnum = 0xffff;
813 struct smb2_hnd *ph = NULL;
814 uint32_t altnamelen = 0;
815 TALLOC_CTX *frame = talloc_stackframe();
817 if (smbXcli_conn_has_async_calls(cli->conn)) {
819 * Can't use sync call while an async call is in flight
821 status = NT_STATUS_INVALID_PARAMETER;
822 goto fail;
825 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
826 status = NT_STATUS_INVALID_PARAMETER;
827 goto fail;
830 status = get_fnum_from_path(cli,
831 name,
832 FILE_READ_ATTRIBUTES,
833 &fnum);
835 if (!NT_STATUS_IS_OK(status)) {
836 goto fail;
839 status = map_fnum_to_smb2_handle(cli,
840 fnum,
841 &ph);
842 if (!NT_STATUS_IS_OK(status)) {
843 goto fail;
846 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
847 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
849 status = smb2cli_query_info(cli->conn,
850 cli->timeout,
851 cli->smb2.session,
852 cli->smb2.tcon,
853 1, /* in_info_type */
854 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
855 0xFFFF, /* in_max_output_length */
856 NULL, /* in_input_buffer */
857 0, /* in_additional_info */
858 0, /* in_flags */
859 ph->fid_persistent,
860 ph->fid_volatile,
861 frame,
862 &outbuf);
864 if (!NT_STATUS_IS_OK(status)) {
865 goto fail;
868 /* Parse the reply. */
869 if (outbuf.length < 4) {
870 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
871 goto fail;
874 altnamelen = IVAL(outbuf.data, 0);
875 if (altnamelen > outbuf.length - 4) {
876 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
877 goto fail;
880 if (altnamelen > 0) {
881 size_t ret = 0;
882 char *short_name = NULL;
883 ret = pull_string_talloc(frame,
884 outbuf.data,
885 FLAGS2_UNICODE_STRINGS,
886 &short_name,
887 outbuf.data + 4,
888 altnamelen,
889 STR_UNICODE);
890 if (ret == (size_t)-1) {
891 /* Bad conversion. */
892 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
893 goto fail;
896 fstrcpy(alt_name, short_name);
897 } else {
898 alt_name[0] = '\0';
901 status = NT_STATUS_OK;
903 fail:
905 if (fnum != 0xffff) {
906 cli_smb2_close_fnum(cli, fnum);
908 TALLOC_FREE(frame);
909 return status;
913 /***************************************************************
914 Wrapper that allows SMB2 to query a fnum info (basic level).
915 Synchronous only.
916 ***************************************************************/
918 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
919 uint16_t fnum,
920 uint16_t *mode,
921 off_t *size,
922 struct timespec *create_time,
923 struct timespec *access_time,
924 struct timespec *write_time,
925 struct timespec *change_time,
926 SMB_INO_T *ino)
928 NTSTATUS status;
929 DATA_BLOB outbuf = data_blob_null;
930 struct smb2_hnd *ph = NULL;
931 TALLOC_CTX *frame = talloc_stackframe();
933 if (smbXcli_conn_has_async_calls(cli->conn)) {
935 * Can't use sync call while an async call is in flight
937 status = NT_STATUS_INVALID_PARAMETER;
938 goto fail;
941 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
942 status = NT_STATUS_INVALID_PARAMETER;
943 goto fail;
946 status = map_fnum_to_smb2_handle(cli,
947 fnum,
948 &ph);
949 if (!NT_STATUS_IS_OK(status)) {
950 goto fail;
953 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
954 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
956 status = smb2cli_query_info(cli->conn,
957 cli->timeout,
958 cli->smb2.session,
959 cli->smb2.tcon,
960 1, /* in_info_type */
961 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
962 0xFFFF, /* in_max_output_length */
963 NULL, /* in_input_buffer */
964 0, /* in_additional_info */
965 0, /* in_flags */
966 ph->fid_persistent,
967 ph->fid_volatile,
968 frame,
969 &outbuf);
970 if (!NT_STATUS_IS_OK(status)) {
971 goto fail;
974 /* Parse the reply. */
975 if (outbuf.length < 0x60) {
976 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
977 goto fail;
980 if (create_time) {
981 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
983 if (access_time) {
984 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
986 if (write_time) {
987 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
989 if (change_time) {
990 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
992 if (mode) {
993 uint32_t attr = IVAL(outbuf.data, 0x20);
994 *mode = (uint16_t)attr;
996 if (size) {
997 uint64_t file_size = BVAL(outbuf.data, 0x30);
998 *size = (off_t)file_size;
1000 if (ino) {
1001 uint64_t file_index = BVAL(outbuf.data, 0x40);
1002 *ino = (SMB_INO_T)file_index;
1005 fail:
1007 TALLOC_FREE(frame);
1008 return status;
1011 /***************************************************************
1012 Wrapper that allows SMB2 to query an fnum.
1013 Implement on top of cli_smb2_qfileinfo_basic().
1014 Synchronous only.
1015 ***************************************************************/
1017 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1018 uint16_t fnum,
1019 uint16_t *attr,
1020 off_t *size,
1021 time_t *change_time,
1022 time_t *access_time,
1023 time_t *write_time)
1025 struct timespec access_time_ts;
1026 struct timespec write_time_ts;
1027 struct timespec change_time_ts;
1028 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1029 fnum,
1030 attr,
1031 size,
1032 NULL,
1033 &access_time_ts,
1034 &write_time_ts,
1035 &change_time_ts,
1036 NULL);
1038 if (!NT_STATUS_IS_OK(status)) {
1039 return status;
1042 if (change_time) {
1043 *change_time = change_time_ts.tv_sec;
1045 if (access_time) {
1046 *access_time = access_time_ts.tv_sec;
1048 if (write_time) {
1049 *write_time = write_time_ts.tv_sec;
1051 return NT_STATUS_OK;
1054 /***************************************************************
1055 Wrapper that allows SMB2 to get pathname attributes.
1056 Synchronous only.
1057 ***************************************************************/
1059 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1060 const char *name,
1061 uint16_t *attr,
1062 off_t *size,
1063 time_t *write_time)
1065 NTSTATUS status;
1066 uint16_t fnum = 0xffff;
1067 struct smb2_hnd *ph = NULL;
1068 TALLOC_CTX *frame = talloc_stackframe();
1070 if (smbXcli_conn_has_async_calls(cli->conn)) {
1072 * Can't use sync call while an async call is in flight
1074 status = NT_STATUS_INVALID_PARAMETER;
1075 goto fail;
1078 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1079 status = NT_STATUS_INVALID_PARAMETER;
1080 goto fail;
1083 status = get_fnum_from_path(cli,
1084 name,
1085 FILE_READ_ATTRIBUTES,
1086 &fnum);
1088 if (!NT_STATUS_IS_OK(status)) {
1089 goto fail;
1092 status = map_fnum_to_smb2_handle(cli,
1093 fnum,
1094 &ph);
1095 if (!NT_STATUS_IS_OK(status)) {
1096 goto fail;
1098 status = cli_smb2_getattrE(cli,
1099 fnum,
1100 attr,
1101 size,
1102 NULL,
1103 NULL,
1104 write_time);
1105 if (!NT_STATUS_IS_OK(status)) {
1106 goto fail;
1109 fail:
1111 if (fnum != 0xffff) {
1112 cli_smb2_close_fnum(cli, fnum);
1115 TALLOC_FREE(frame);
1116 return status;
1119 /***************************************************************
1120 Wrapper that allows SMB2 to query a pathname info (basic level).
1121 Implement on top of cli_smb2_qfileinfo_basic().
1122 Synchronous only.
1123 ***************************************************************/
1125 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1126 const char *name,
1127 struct timespec *create_time,
1128 struct timespec *access_time,
1129 struct timespec *write_time,
1130 struct timespec *change_time,
1131 off_t *size,
1132 uint16_t *mode,
1133 SMB_INO_T *ino)
1135 NTSTATUS status;
1136 struct smb2_hnd *ph = NULL;
1137 uint16_t fnum = 0xffff;
1138 TALLOC_CTX *frame = talloc_stackframe();
1140 if (smbXcli_conn_has_async_calls(cli->conn)) {
1142 * Can't use sync call while an async call is in flight
1144 status = NT_STATUS_INVALID_PARAMETER;
1145 goto fail;
1148 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1149 status = NT_STATUS_INVALID_PARAMETER;
1150 goto fail;
1153 status = get_fnum_from_path(cli,
1154 name,
1155 FILE_READ_ATTRIBUTES,
1156 &fnum);
1158 if (!NT_STATUS_IS_OK(status)) {
1159 goto fail;
1162 status = map_fnum_to_smb2_handle(cli,
1163 fnum,
1164 &ph);
1165 if (!NT_STATUS_IS_OK(status)) {
1166 goto fail;
1169 status = cli_smb2_qfileinfo_basic(cli,
1170 fnum,
1171 mode,
1172 size,
1173 create_time,
1174 access_time,
1175 write_time,
1176 change_time,
1177 ino);
1179 fail:
1181 if (fnum != 0xffff) {
1182 cli_smb2_close_fnum(cli, fnum);
1185 TALLOC_FREE(frame);
1186 return status;
1189 /***************************************************************
1190 Wrapper that allows SMB2 to query pathname streams.
1191 Synchronous only.
1192 ***************************************************************/
1194 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1195 const char *name,
1196 TALLOC_CTX *mem_ctx,
1197 unsigned int *pnum_streams,
1198 struct stream_struct **pstreams)
1200 NTSTATUS status;
1201 struct smb2_hnd *ph = NULL;
1202 uint16_t fnum = 0xffff;
1203 DATA_BLOB outbuf = data_blob_null;
1204 TALLOC_CTX *frame = talloc_stackframe();
1206 if (smbXcli_conn_has_async_calls(cli->conn)) {
1208 * Can't use sync call while an async call is in flight
1210 status = NT_STATUS_INVALID_PARAMETER;
1211 goto fail;
1214 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1215 status = NT_STATUS_INVALID_PARAMETER;
1216 goto fail;
1219 status = get_fnum_from_path(cli,
1220 name,
1221 FILE_READ_ATTRIBUTES,
1222 &fnum);
1224 if (!NT_STATUS_IS_OK(status)) {
1225 goto fail;
1228 status = map_fnum_to_smb2_handle(cli,
1229 fnum,
1230 &ph);
1231 if (!NT_STATUS_IS_OK(status)) {
1232 goto fail;
1235 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1236 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1238 status = smb2cli_query_info(cli->conn,
1239 cli->timeout,
1240 cli->smb2.session,
1241 cli->smb2.tcon,
1242 1, /* in_info_type */
1243 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1244 0xFFFF, /* in_max_output_length */
1245 NULL, /* in_input_buffer */
1246 0, /* in_additional_info */
1247 0, /* in_flags */
1248 ph->fid_persistent,
1249 ph->fid_volatile,
1250 frame,
1251 &outbuf);
1253 if (!NT_STATUS_IS_OK(status)) {
1254 goto fail;
1257 /* Parse the reply. */
1258 if (!parse_streams_blob(mem_ctx,
1259 outbuf.data,
1260 outbuf.length,
1261 pnum_streams,
1262 pstreams)) {
1263 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1264 goto fail;
1267 fail:
1269 if (fnum != 0xffff) {
1270 cli_smb2_close_fnum(cli, fnum);
1273 TALLOC_FREE(frame);
1274 return status;
1277 /***************************************************************
1278 Wrapper that allows SMB2 to set pathname attributes.
1279 Synchronous only.
1280 ***************************************************************/
1282 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1283 const char *name,
1284 uint16_t attr,
1285 time_t mtime)
1287 NTSTATUS status;
1288 uint16_t fnum = 0xffff;
1289 struct smb2_hnd *ph = NULL;
1290 uint8_t inbuf_store[40];
1291 DATA_BLOB inbuf = data_blob_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 = get_fnum_from_path(cli,
1308 name,
1309 FILE_WRITE_ATTRIBUTES,
1310 &fnum);
1312 if (!NT_STATUS_IS_OK(status)) {
1313 goto fail;
1316 status = map_fnum_to_smb2_handle(cli,
1317 fnum,
1318 &ph);
1319 if (!NT_STATUS_IS_OK(status)) {
1320 goto fail;
1323 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1324 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1326 inbuf.data = inbuf_store;
1327 inbuf.length = sizeof(inbuf_store);
1328 data_blob_clear(&inbuf);
1330 SSVAL(inbuf.data, 32, attr);
1331 if (mtime != 0) {
1332 put_long_date((char *)inbuf.data + 16,mtime);
1334 /* Set all the other times to -1. */
1335 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1336 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1337 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1339 status = smb2cli_set_info(cli->conn,
1340 cli->timeout,
1341 cli->smb2.session,
1342 cli->smb2.tcon,
1343 1, /* in_info_type */
1344 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1345 &inbuf, /* in_input_buffer */
1346 0, /* in_additional_info */
1347 ph->fid_persistent,
1348 ph->fid_volatile);
1349 fail:
1351 if (fnum != 0xffff) {
1352 cli_smb2_close_fnum(cli, fnum);
1355 TALLOC_FREE(frame);
1356 return status;
1359 /***************************************************************
1360 Wrapper that allows SMB2 to set file handle times.
1361 Synchronous only.
1362 ***************************************************************/
1364 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1365 uint16_t fnum,
1366 time_t change_time,
1367 time_t access_time,
1368 time_t write_time)
1370 NTSTATUS status;
1371 struct smb2_hnd *ph = NULL;
1372 uint8_t inbuf_store[40];
1373 DATA_BLOB inbuf = data_blob_null;
1375 if (smbXcli_conn_has_async_calls(cli->conn)) {
1377 * Can't use sync call while an async call is in flight
1379 return NT_STATUS_INVALID_PARAMETER;
1382 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1383 return NT_STATUS_INVALID_PARAMETER;
1386 status = map_fnum_to_smb2_handle(cli,
1387 fnum,
1388 &ph);
1389 if (!NT_STATUS_IS_OK(status)) {
1390 return status;
1393 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1394 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1396 inbuf.data = inbuf_store;
1397 inbuf.length = sizeof(inbuf_store);
1398 data_blob_clear(&inbuf);
1400 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1401 if (change_time != 0) {
1402 put_long_date((char *)inbuf.data + 24, change_time);
1404 if (access_time != 0) {
1405 put_long_date((char *)inbuf.data + 8, access_time);
1407 if (write_time != 0) {
1408 put_long_date((char *)inbuf.data + 16, write_time);
1411 return smb2cli_set_info(cli->conn,
1412 cli->timeout,
1413 cli->smb2.session,
1414 cli->smb2.tcon,
1415 1, /* in_info_type */
1416 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1417 &inbuf, /* in_input_buffer */
1418 0, /* in_additional_info */
1419 ph->fid_persistent,
1420 ph->fid_volatile);
1423 /***************************************************************
1424 Wrapper that allows SMB2 to query disk attributes (size).
1425 Synchronous only.
1426 ***************************************************************/
1428 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
1430 NTSTATUS status;
1431 uint16_t fnum = 0xffff;
1432 DATA_BLOB outbuf = data_blob_null;
1433 struct smb2_hnd *ph = NULL;
1434 uint32_t sectors_per_unit = 0;
1435 uint32_t bytes_per_sector = 0;
1436 uint64_t total_size = 0;
1437 uint64_t size_free = 0;
1438 TALLOC_CTX *frame = talloc_stackframe();
1440 if (smbXcli_conn_has_async_calls(cli->conn)) {
1442 * Can't use sync call while an async call is in flight
1444 status = NT_STATUS_INVALID_PARAMETER;
1445 goto fail;
1448 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1449 status = NT_STATUS_INVALID_PARAMETER;
1450 goto fail;
1453 /* First open the top level directory. */
1454 status = cli_smb2_create_fnum(cli,
1456 0, /* create_flags */
1457 FILE_READ_ATTRIBUTES, /* desired_access */
1458 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1459 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1460 FILE_OPEN, /* create_disposition */
1461 FILE_DIRECTORY_FILE, /* create_options */
1462 &fnum,
1463 NULL);
1465 if (!NT_STATUS_IS_OK(status)) {
1466 goto fail;
1469 status = map_fnum_to_smb2_handle(cli,
1470 fnum,
1471 &ph);
1472 if (!NT_STATUS_IS_OK(status)) {
1473 goto fail;
1476 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1477 level 3 (SMB_FS_SIZE_INFORMATION). */
1479 status = smb2cli_query_info(cli->conn,
1480 cli->timeout,
1481 cli->smb2.session,
1482 cli->smb2.tcon,
1483 2, /* in_info_type */
1484 3, /* in_file_info_class */
1485 0xFFFF, /* in_max_output_length */
1486 NULL, /* in_input_buffer */
1487 0, /* in_additional_info */
1488 0, /* in_flags */
1489 ph->fid_persistent,
1490 ph->fid_volatile,
1491 frame,
1492 &outbuf);
1493 if (!NT_STATUS_IS_OK(status)) {
1494 goto fail;
1497 /* Parse the reply. */
1498 if (outbuf.length != 24) {
1499 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1500 goto fail;
1503 total_size = BVAL(outbuf.data, 0);
1504 size_free = BVAL(outbuf.data, 8);
1505 sectors_per_unit = IVAL(outbuf.data, 16);
1506 bytes_per_sector = IVAL(outbuf.data, 20);
1508 if (bsize) {
1509 *bsize = (int)(sectors_per_unit * bytes_per_sector);
1511 if (total) {
1512 *total = (int)total_size;
1514 if (avail) {
1515 *avail = (int)size_free;
1518 status = NT_STATUS_OK;
1520 fail:
1522 if (fnum != 0xffff) {
1523 cli_smb2_close_fnum(cli, fnum);
1526 TALLOC_FREE(frame);
1527 return status;
1530 /***************************************************************
1531 Wrapper that allows SMB2 to query a security descriptor.
1532 Synchronous only.
1533 ***************************************************************/
1535 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
1536 uint16_t fnum,
1537 uint32_t sec_info,
1538 TALLOC_CTX *mem_ctx,
1539 struct security_descriptor **ppsd)
1541 NTSTATUS status;
1542 DATA_BLOB outbuf = data_blob_null;
1543 struct smb2_hnd *ph = NULL;
1544 struct security_descriptor *lsd = NULL;
1545 TALLOC_CTX *frame = talloc_stackframe();
1547 if (smbXcli_conn_has_async_calls(cli->conn)) {
1549 * Can't use sync call while an async call is in flight
1551 status = NT_STATUS_INVALID_PARAMETER;
1552 goto fail;
1555 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1556 status = NT_STATUS_INVALID_PARAMETER;
1557 goto fail;
1560 status = map_fnum_to_smb2_handle(cli,
1561 fnum,
1562 &ph);
1563 if (!NT_STATUS_IS_OK(status)) {
1564 goto fail;
1567 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1569 status = smb2cli_query_info(cli->conn,
1570 cli->timeout,
1571 cli->smb2.session,
1572 cli->smb2.tcon,
1573 3, /* in_info_type */
1574 0, /* in_file_info_class */
1575 0xFFFF, /* in_max_output_length */
1576 NULL, /* in_input_buffer */
1577 sec_info, /* in_additional_info */
1578 0, /* in_flags */
1579 ph->fid_persistent,
1580 ph->fid_volatile,
1581 frame,
1582 &outbuf);
1584 if (!NT_STATUS_IS_OK(status)) {
1585 goto fail;
1588 /* Parse the reply. */
1589 status = unmarshall_sec_desc(mem_ctx,
1590 outbuf.data,
1591 outbuf.length,
1592 &lsd);
1594 if (!NT_STATUS_IS_OK(status)) {
1595 goto fail;
1598 if (ppsd != NULL) {
1599 *ppsd = lsd;
1600 } else {
1601 TALLOC_FREE(lsd);
1604 fail:
1606 TALLOC_FREE(frame);
1607 return status;
1610 /***************************************************************
1611 Wrapper that allows SMB2 to set a security descriptor.
1612 Synchronous only.
1613 ***************************************************************/
1615 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
1616 uint16_t fnum,
1617 uint32_t sec_info,
1618 const struct security_descriptor *sd)
1620 NTSTATUS status;
1621 DATA_BLOB inbuf = data_blob_null;
1622 struct smb2_hnd *ph = NULL;
1623 TALLOC_CTX *frame = talloc_stackframe();
1625 if (smbXcli_conn_has_async_calls(cli->conn)) {
1627 * Can't use sync call while an async call is in flight
1629 status = NT_STATUS_INVALID_PARAMETER;
1630 goto fail;
1633 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1634 status = NT_STATUS_INVALID_PARAMETER;
1635 goto fail;
1638 status = map_fnum_to_smb2_handle(cli,
1639 fnum,
1640 &ph);
1641 if (!NT_STATUS_IS_OK(status)) {
1642 goto fail;
1645 status = marshall_sec_desc(frame,
1647 &inbuf.data,
1648 &inbuf.length);
1650 if (!NT_STATUS_IS_OK(status)) {
1651 goto fail;
1654 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1656 status = smb2cli_set_info(cli->conn,
1657 cli->timeout,
1658 cli->smb2.session,
1659 cli->smb2.tcon,
1660 3, /* in_info_type */
1661 0, /* in_file_info_class */
1662 &inbuf, /* in_input_buffer */
1663 sec_info, /* in_additional_info */
1664 ph->fid_persistent,
1665 ph->fid_volatile);
1667 fail:
1669 TALLOC_FREE(frame);
1670 return status;
1673 /***************************************************************
1674 Wrapper that allows SMB2 to rename a file.
1675 Synchronous only.
1676 ***************************************************************/
1678 NTSTATUS cli_smb2_rename(struct cli_state *cli,
1679 const char *fname_src,
1680 const char *fname_dst)
1682 NTSTATUS status;
1683 DATA_BLOB inbuf = data_blob_null;
1684 uint16_t fnum = 0xffff;
1685 struct smb2_hnd *ph = NULL;
1686 smb_ucs2_t *converted_str = NULL;
1687 size_t converted_size_bytes = 0;
1688 size_t namelen = 0;
1689 TALLOC_CTX *frame = talloc_stackframe();
1691 if (smbXcli_conn_has_async_calls(cli->conn)) {
1693 * Can't use sync call while an async call is in flight
1695 status = NT_STATUS_INVALID_PARAMETER;
1696 goto fail;
1699 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1700 status = NT_STATUS_INVALID_PARAMETER;
1701 goto fail;
1704 status = get_fnum_from_path(cli,
1705 fname_src,
1706 DELETE_ACCESS,
1707 &fnum);
1709 if (!NT_STATUS_IS_OK(status)) {
1710 goto fail;
1713 status = map_fnum_to_smb2_handle(cli,
1714 fnum,
1715 &ph);
1716 if (!NT_STATUS_IS_OK(status)) {
1717 goto fail;
1720 /* SMB2 is pickier about pathnames. Ensure it doesn't
1721 start in a '\' */
1722 if (*fname_dst == '\\') {
1723 fname_dst++;
1726 /* SMB2 is pickier about pathnames. Ensure it doesn't
1727 end in a '\' */
1728 namelen = strlen(fname_dst);
1729 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
1730 char *modname = talloc_strdup(frame, fname_dst);
1731 modname[namelen-1] = '\0';
1732 fname_dst = modname;
1735 if (!push_ucs2_talloc(frame,
1736 &converted_str,
1737 fname_dst,
1738 &converted_size_bytes)) {
1739 status = NT_STATUS_INVALID_PARAMETER;
1740 goto fail;
1743 /* W2K8 insists the dest name is not null
1744 terminated. Remove the last 2 zero bytes
1745 and reduce the name length. */
1747 if (converted_size_bytes < 2) {
1748 status = NT_STATUS_INVALID_PARAMETER;
1749 goto fail;
1751 converted_size_bytes -= 2;
1753 inbuf = data_blob_talloc_zero(frame,
1754 20 + converted_size_bytes);
1755 if (inbuf.data == NULL) {
1756 status = NT_STATUS_NO_MEMORY;
1757 goto fail;
1760 SIVAL(inbuf.data, 16, converted_size_bytes);
1761 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
1763 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
1764 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
1766 status = smb2cli_set_info(cli->conn,
1767 cli->timeout,
1768 cli->smb2.session,
1769 cli->smb2.tcon,
1770 1, /* in_info_type */
1771 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
1772 &inbuf, /* in_input_buffer */
1773 0, /* in_additional_info */
1774 ph->fid_persistent,
1775 ph->fid_volatile);
1777 fail:
1779 if (fnum != 0xffff) {
1780 cli_smb2_close_fnum(cli, fnum);
1783 TALLOC_FREE(frame);
1784 return status;
1787 /***************************************************************
1788 Wrapper that allows SMB2 to set an EA on a fnum.
1789 Synchronous only.
1790 ***************************************************************/
1792 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
1793 uint16_t fnum,
1794 const char *ea_name,
1795 const char *ea_val,
1796 size_t ea_len)
1798 NTSTATUS status;
1799 DATA_BLOB inbuf = data_blob_null;
1800 size_t bloblen = 0;
1801 char *ea_name_ascii = NULL;
1802 size_t namelen = 0;
1803 struct smb2_hnd *ph = NULL;
1804 TALLOC_CTX *frame = talloc_stackframe();
1806 if (smbXcli_conn_has_async_calls(cli->conn)) {
1808 * Can't use sync call while an async call is in flight
1810 status = NT_STATUS_INVALID_PARAMETER;
1811 goto fail;
1814 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1815 status = NT_STATUS_INVALID_PARAMETER;
1816 goto fail;
1819 status = map_fnum_to_smb2_handle(cli,
1820 fnum,
1821 &ph);
1822 if (!NT_STATUS_IS_OK(status)) {
1823 goto fail;
1826 /* Marshall the SMB2 EA data. */
1827 if (ea_len > 0xFFFF) {
1828 status = NT_STATUS_INVALID_PARAMETER;
1829 goto fail;
1832 if (!push_ascii_talloc(frame,
1833 &ea_name_ascii,
1834 ea_name,
1835 &namelen)) {
1836 status = NT_STATUS_INVALID_PARAMETER;
1837 goto fail;
1840 if (namelen < 2 || namelen > 0xFF) {
1841 status = NT_STATUS_INVALID_PARAMETER;
1842 goto fail;
1845 bloblen = 8 + ea_len + namelen;
1846 /* Round up to a 4 byte boundary. */
1847 bloblen = ((bloblen + 3)&~3);
1849 inbuf = data_blob_talloc_zero(frame, bloblen);
1850 if (inbuf.data == NULL) {
1851 status = NT_STATUS_NO_MEMORY;
1852 goto fail;
1854 /* namelen doesn't include the NULL byte. */
1855 SCVAL(inbuf.data, 5, namelen - 1);
1856 SSVAL(inbuf.data, 6, ea_len);
1857 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
1858 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
1860 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1861 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
1863 status = smb2cli_set_info(cli->conn,
1864 cli->timeout,
1865 cli->smb2.session,
1866 cli->smb2.tcon,
1867 1, /* in_info_type */
1868 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
1869 &inbuf, /* in_input_buffer */
1870 0, /* in_additional_info */
1871 ph->fid_persistent,
1872 ph->fid_volatile);
1874 fail:
1876 TALLOC_FREE(frame);
1877 return status;
1880 /***************************************************************
1881 Wrapper that allows SMB2 to set an EA on a pathname.
1882 Synchronous only.
1883 ***************************************************************/
1885 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
1886 const char *name,
1887 const char *ea_name,
1888 const char *ea_val,
1889 size_t ea_len)
1891 NTSTATUS status;
1892 uint16_t fnum = 0xffff;
1894 if (smbXcli_conn_has_async_calls(cli->conn)) {
1896 * Can't use sync call while an async call is in flight
1898 status = NT_STATUS_INVALID_PARAMETER;
1899 goto fail;
1902 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1903 status = NT_STATUS_INVALID_PARAMETER;
1904 goto fail;
1907 status = get_fnum_from_path(cli,
1908 name,
1909 FILE_WRITE_EA,
1910 &fnum);
1912 if (!NT_STATUS_IS_OK(status)) {
1913 goto fail;
1916 status = cli_set_ea_fnum(cli,
1917 fnum,
1918 ea_name,
1919 ea_val,
1920 ea_len);
1921 if (!NT_STATUS_IS_OK(status)) {
1922 goto fail;
1925 fail:
1927 if (fnum != 0xffff) {
1928 cli_smb2_close_fnum(cli, fnum);
1931 return status;
1934 /***************************************************************
1935 Wrapper that allows SMB2 to get an EA list on a pathname.
1936 Synchronous only.
1937 ***************************************************************/
1939 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
1940 const char *name,
1941 TALLOC_CTX *ctx,
1942 size_t *pnum_eas,
1943 struct ea_struct **pea_array)
1945 NTSTATUS status;
1946 uint16_t fnum = 0xffff;
1947 DATA_BLOB outbuf = data_blob_null;
1948 struct smb2_hnd *ph = NULL;
1949 struct ea_list *ea_list = NULL;
1950 struct ea_list *eal = NULL;
1951 size_t ea_count = 0;
1952 TALLOC_CTX *frame = talloc_stackframe();
1954 *pnum_eas = 0;
1955 *pea_array = NULL;
1957 if (smbXcli_conn_has_async_calls(cli->conn)) {
1959 * Can't use sync call while an async call is in flight
1961 status = NT_STATUS_INVALID_PARAMETER;
1962 goto fail;
1965 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1966 status = NT_STATUS_INVALID_PARAMETER;
1967 goto fail;
1970 status = get_fnum_from_path(cli,
1971 name,
1972 FILE_READ_EA,
1973 &fnum);
1975 if (!NT_STATUS_IS_OK(status)) {
1976 goto fail;
1979 status = map_fnum_to_smb2_handle(cli,
1980 fnum,
1981 &ph);
1982 if (!NT_STATUS_IS_OK(status)) {
1983 goto fail;
1986 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1987 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
1989 status = smb2cli_query_info(cli->conn,
1990 cli->timeout,
1991 cli->smb2.session,
1992 cli->smb2.tcon,
1993 1, /* in_info_type */
1994 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
1995 0xFFFF, /* in_max_output_length */
1996 NULL, /* in_input_buffer */
1997 0, /* in_additional_info */
1998 0, /* in_flags */
1999 ph->fid_persistent,
2000 ph->fid_volatile,
2001 frame,
2002 &outbuf);
2004 if (!NT_STATUS_IS_OK(status)) {
2005 goto fail;
2008 /* Parse the reply. */
2009 ea_list = read_nttrans_ea_list(ctx,
2010 (const char *)outbuf.data,
2011 outbuf.length);
2012 if (ea_list == NULL) {
2013 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2014 goto fail;
2017 /* Convert to an array. */
2018 for (eal = ea_list; eal; eal = eal->next) {
2019 ea_count++;
2022 if (ea_count) {
2023 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2024 if (*pea_array == NULL) {
2025 status = NT_STATUS_NO_MEMORY;
2026 goto fail;
2028 ea_count = 0;
2029 for (eal = ea_list; eal; eal = eal->next) {
2030 (*pea_array)[ea_count++] = ea_list->ea;
2032 *pnum_eas = ea_count;
2035 fail:
2037 if (fnum != 0xffff) {
2038 cli_smb2_close_fnum(cli, fnum);
2041 TALLOC_FREE(frame);
2042 return status;
2045 struct cli_smb2_read_state {
2046 struct tevent_context *ev;
2047 struct cli_state *cli;
2048 struct smb2_hnd *ph;
2049 uint64_t start_offset;
2050 uint32_t size;
2051 uint32_t received;
2052 uint8_t *buf;
2055 static void cli_smb2_read_done(struct tevent_req *subreq);
2057 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
2058 struct tevent_context *ev,
2059 struct cli_state *cli,
2060 uint16_t fnum,
2061 off_t offset,
2062 size_t size)
2064 NTSTATUS status;
2065 struct tevent_req *req, *subreq;
2066 struct cli_smb2_read_state *state;
2068 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
2069 if (req == NULL) {
2070 return NULL;
2072 state->ev = ev;
2073 state->cli = cli;
2074 state->start_offset = (uint64_t)offset;
2075 state->size = (uint32_t)size;
2076 state->received = 0;
2077 state->buf = NULL;
2079 status = map_fnum_to_smb2_handle(cli,
2080 fnum,
2081 &state->ph);
2082 if (tevent_req_nterror(req, status)) {
2083 return tevent_req_post(req, ev);
2086 subreq = smb2cli_read_send(state,
2087 state->ev,
2088 state->cli->conn,
2089 state->cli->timeout,
2090 state->cli->smb2.session,
2091 state->cli->smb2.tcon,
2092 state->size,
2093 state->start_offset,
2094 state->ph->fid_persistent,
2095 state->ph->fid_volatile,
2096 0, /* minimum_count */
2097 0); /* remaining_bytes */
2099 if (tevent_req_nomem(subreq, req)) {
2100 return tevent_req_post(req, ev);
2102 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
2103 return req;
2106 static void cli_smb2_read_done(struct tevent_req *subreq)
2108 struct tevent_req *req = tevent_req_callback_data(
2109 subreq, struct tevent_req);
2110 struct cli_smb2_read_state *state = tevent_req_data(
2111 req, struct cli_smb2_read_state);
2112 NTSTATUS status;
2114 status = smb2cli_read_recv(subreq, state,
2115 &state->buf, &state->received);
2116 if (tevent_req_nterror(req, status)) {
2117 return;
2120 if (state->received > state->size) {
2121 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2122 return;
2125 tevent_req_done(req);
2128 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
2129 ssize_t *received,
2130 uint8_t **rcvbuf)
2132 NTSTATUS status;
2133 struct cli_smb2_read_state *state = tevent_req_data(
2134 req, struct cli_smb2_read_state);
2136 if (tevent_req_is_nterror(req, &status)) {
2137 return status;
2140 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2141 * better make sure that you copy it away before you talloc_free(req).
2142 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2144 *received = (ssize_t)state->received;
2145 *rcvbuf = state->buf;
2146 return NT_STATUS_OK;
2149 struct cli_smb2_write_state {
2150 struct tevent_context *ev;
2151 struct cli_state *cli;
2152 struct smb2_hnd *ph;
2153 uint32_t flags;
2154 const uint8_t *buf;
2155 uint64_t offset;
2156 uint32_t size;
2157 uint32_t written;
2160 static void cli_smb2_write_written(struct tevent_req *req);
2162 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
2163 struct tevent_context *ev,
2164 struct cli_state *cli,
2165 uint16_t fnum,
2166 uint16_t mode,
2167 const uint8_t *buf,
2168 off_t offset,
2169 size_t size)
2171 NTSTATUS status;
2172 struct tevent_req *req, *subreq = NULL;
2173 struct cli_smb2_write_state *state = NULL;
2175 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
2176 if (req == NULL) {
2177 return NULL;
2179 state->ev = ev;
2180 state->cli = cli;
2181 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2182 state->flags = (uint32_t)mode;
2183 state->buf = buf;
2184 state->offset = (uint64_t)offset;
2185 state->size = (uint32_t)size;
2186 state->written = 0;
2188 status = map_fnum_to_smb2_handle(cli,
2189 fnum,
2190 &state->ph);
2191 if (tevent_req_nterror(req, status)) {
2192 return tevent_req_post(req, ev);
2195 subreq = smb2cli_write_send(state,
2196 state->ev,
2197 state->cli->conn,
2198 state->cli->timeout,
2199 state->cli->smb2.session,
2200 state->cli->smb2.tcon,
2201 state->size,
2202 state->offset,
2203 state->ph->fid_persistent,
2204 state->ph->fid_volatile,
2205 0, /* remaining_bytes */
2206 state->flags, /* flags */
2207 state->buf);
2209 if (tevent_req_nomem(subreq, req)) {
2210 return tevent_req_post(req, ev);
2212 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
2213 return req;
2216 static void cli_smb2_write_written(struct tevent_req *subreq)
2218 struct tevent_req *req = tevent_req_callback_data(
2219 subreq, struct tevent_req);
2220 struct cli_smb2_write_state *state = tevent_req_data(
2221 req, struct cli_smb2_write_state);
2222 NTSTATUS status;
2223 uint32_t written;
2225 status = smb2cli_write_recv(subreq, &written);
2226 TALLOC_FREE(subreq);
2227 if (tevent_req_nterror(req, status)) {
2228 return;
2231 state->written = written;
2233 tevent_req_done(req);
2236 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
2237 size_t *pwritten)
2239 struct cli_smb2_write_state *state = tevent_req_data(
2240 req, struct cli_smb2_write_state);
2241 NTSTATUS status;
2243 if (tevent_req_is_nterror(req, &status)) {
2244 tevent_req_received(req);
2245 return status;
2248 if (pwritten != NULL) {
2249 *pwritten = (size_t)state->written;
2251 tevent_req_received(req);
2252 return NT_STATUS_OK;
2255 /***************************************************************
2256 Wrapper that allows SMB2 async write using an fnum.
2257 This is mostly cut-and-paste from Volker's code inside
2258 source3/libsmb/clireadwrite.c, adapted for SMB2.
2260 Done this way so I can reuse all the logic inside cli_push()
2261 for free :-).
2262 ***************************************************************/
2264 struct cli_smb2_writeall_state {
2265 struct tevent_context *ev;
2266 struct cli_state *cli;
2267 struct smb2_hnd *ph;
2268 uint32_t flags;
2269 const uint8_t *buf;
2270 uint64_t offset;
2271 uint32_t size;
2272 uint32_t written;
2275 static void cli_smb2_writeall_written(struct tevent_req *req);
2277 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
2278 struct tevent_context *ev,
2279 struct cli_state *cli,
2280 uint16_t fnum,
2281 uint16_t mode,
2282 const uint8_t *buf,
2283 off_t offset,
2284 size_t size)
2286 NTSTATUS status;
2287 struct tevent_req *req, *subreq = NULL;
2288 struct cli_smb2_writeall_state *state = NULL;
2289 uint32_t to_write;
2290 uint32_t max_size;
2291 bool ok;
2293 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
2294 if (req == NULL) {
2295 return NULL;
2297 state->ev = ev;
2298 state->cli = cli;
2299 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2300 state->flags = (uint32_t)mode;
2301 state->buf = buf;
2302 state->offset = (uint64_t)offset;
2303 state->size = (uint32_t)size;
2304 state->written = 0;
2306 status = map_fnum_to_smb2_handle(cli,
2307 fnum,
2308 &state->ph);
2309 if (tevent_req_nterror(req, status)) {
2310 return tevent_req_post(req, ev);
2313 to_write = state->size;
2314 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2315 to_write = MIN(max_size, to_write);
2316 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2317 if (ok) {
2318 to_write = MIN(max_size, to_write);
2321 subreq = smb2cli_write_send(state,
2322 state->ev,
2323 state->cli->conn,
2324 state->cli->timeout,
2325 state->cli->smb2.session,
2326 state->cli->smb2.tcon,
2327 to_write,
2328 state->offset,
2329 state->ph->fid_persistent,
2330 state->ph->fid_volatile,
2331 0, /* remaining_bytes */
2332 state->flags, /* flags */
2333 state->buf + state->written);
2335 if (tevent_req_nomem(subreq, req)) {
2336 return tevent_req_post(req, ev);
2338 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2339 return req;
2342 static void cli_smb2_writeall_written(struct tevent_req *subreq)
2344 struct tevent_req *req = tevent_req_callback_data(
2345 subreq, struct tevent_req);
2346 struct cli_smb2_writeall_state *state = tevent_req_data(
2347 req, struct cli_smb2_writeall_state);
2348 NTSTATUS status;
2349 uint32_t written, to_write;
2350 uint32_t max_size;
2351 bool ok;
2353 status = smb2cli_write_recv(subreq, &written);
2354 TALLOC_FREE(subreq);
2355 if (tevent_req_nterror(req, status)) {
2356 return;
2359 state->written += written;
2361 if (state->written > state->size) {
2362 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2363 return;
2366 to_write = state->size - state->written;
2368 if (to_write == 0) {
2369 tevent_req_done(req);
2370 return;
2373 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2374 to_write = MIN(max_size, to_write);
2375 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2376 if (ok) {
2377 to_write = MIN(max_size, to_write);
2380 subreq = smb2cli_write_send(state,
2381 state->ev,
2382 state->cli->conn,
2383 state->cli->timeout,
2384 state->cli->smb2.session,
2385 state->cli->smb2.tcon,
2386 to_write,
2387 state->offset + state->written,
2388 state->ph->fid_persistent,
2389 state->ph->fid_volatile,
2390 0, /* remaining_bytes */
2391 state->flags, /* flags */
2392 state->buf + state->written);
2394 if (tevent_req_nomem(subreq, req)) {
2395 return;
2397 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2400 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
2401 size_t *pwritten)
2403 struct cli_smb2_writeall_state *state = tevent_req_data(
2404 req, struct cli_smb2_writeall_state);
2405 NTSTATUS status;
2407 if (tevent_req_is_nterror(req, &status)) {
2408 return status;
2410 if (pwritten != NULL) {
2411 *pwritten = (size_t)state->written;
2413 return NT_STATUS_OK;