s3: libsmb : The short name length is only a one byte field.
[Samba/wip.git] / source3 / libsmb / cli_smb2_fnum.c
blob3253f9df9c63f08fb73bdef5ea9ae1b162d7f0d6
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 smb2_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 NTSTATUS (*fn)(const char *,
490 struct file_info *,
491 const char *,
492 void *),
493 void *state)
495 NTSTATUS status;
496 uint16_t fnum = 0xffff;
497 char *parent_dir = NULL;
498 const char *mask = NULL;
499 struct smb2_hnd *ph = NULL;
500 TALLOC_CTX *frame = talloc_stackframe();
501 TALLOC_CTX *subframe = NULL;
503 if (smbXcli_conn_has_async_calls(cli->conn)) {
505 * Can't use sync call while an async call is in flight
507 status = NT_STATUS_INVALID_PARAMETER;
508 goto fail;
511 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
512 status = NT_STATUS_INVALID_PARAMETER;
513 goto fail;
516 /* Get the directory name. */
517 if (!windows_parent_dirname(frame,
518 pathname,
519 &parent_dir,
520 &mask)) {
521 status = NT_STATUS_NO_MEMORY;
522 goto fail;
525 status = cli_smb2_create_fnum(cli,
526 parent_dir,
527 0, /* create_flags */
528 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
529 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
530 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
531 FILE_OPEN, /* create_disposition */
532 FILE_DIRECTORY_FILE, /* create_options */
533 &fnum,
534 NULL);
536 if (!NT_STATUS_IS_OK(status)) {
537 goto fail;
540 status = map_fnum_to_smb2_handle(cli,
541 fnum,
542 &ph);
543 if (!NT_STATUS_IS_OK(status)) {
544 goto fail;
547 do {
548 uint8_t *dir_data = NULL;
549 uint32_t dir_data_length = 0;
550 uint32_t next_offset = 0;
551 subframe = talloc_stackframe();
553 status = smb2cli_query_directory(cli->conn,
554 cli->timeout,
555 cli->smb2.session,
556 cli->smb2.tcon,
557 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
558 0, /* flags */
559 0, /* file_index */
560 ph->fid_persistent,
561 ph->fid_volatile,
562 mask,
563 0xffff,
564 subframe,
565 &dir_data,
566 &dir_data_length);
568 if (!NT_STATUS_IS_OK(status)) {
569 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
570 break;
572 goto fail;
575 do {
576 struct file_info *finfo = talloc_zero(subframe,
577 struct file_info);
579 if (finfo == NULL) {
580 status = NT_STATUS_NO_MEMORY;
581 goto fail;
584 status = parse_finfo_id_both_directory_info(dir_data,
585 dir_data_length,
586 finfo,
587 &next_offset);
589 if (!NT_STATUS_IS_OK(status)) {
590 goto fail;
593 status = fn(cli->dfs_mountpoint,
594 finfo,
595 pathname,
596 state);
598 if (!NT_STATUS_IS_OK(status)) {
599 break;
602 TALLOC_FREE(finfo);
604 /* Move to next entry. */
605 if (next_offset) {
606 dir_data += next_offset;
607 dir_data_length -= next_offset;
609 } while (next_offset != 0);
611 TALLOC_FREE(subframe);
613 } while (NT_STATUS_IS_OK(status));
615 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
616 status = NT_STATUS_OK;
619 fail:
621 if (fnum != 0xffff) {
622 cli_smb2_close_fnum(cli, fnum);
624 TALLOC_FREE(subframe);
625 TALLOC_FREE(frame);
626 return status;
629 /***************************************************************
630 Wrapper that allows SMB2 to query a path info (basic level).
631 Synchronous only.
632 ***************************************************************/
634 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
635 const char *name,
636 SMB_STRUCT_STAT *sbuf,
637 uint32_t *attributes)
639 NTSTATUS status;
640 struct smb2_create_returns cr;
641 uint16_t fnum = 0xffff;
642 size_t namelen = strlen(name);
644 if (smbXcli_conn_has_async_calls(cli->conn)) {
646 * Can't use sync call while an async call is in flight
648 return NT_STATUS_INVALID_PARAMETER;
651 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
652 return NT_STATUS_INVALID_PARAMETER;
655 /* SMB2 is pickier about pathnames. Ensure it doesn't
656 end in a '\' */
657 if (namelen > 0 && name[namelen-1] == '\\') {
658 char *modname = talloc_strdup(talloc_tos(), name);
659 modname[namelen-1] = '\0';
660 name = modname;
663 /* This is commonly used as a 'cd'. Try qpathinfo on
664 a directory handle first. */
666 status = cli_smb2_create_fnum(cli,
667 name,
668 0, /* create_flags */
669 FILE_READ_ATTRIBUTES, /* desired_access */
670 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
671 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
672 FILE_OPEN, /* create_disposition */
673 FILE_DIRECTORY_FILE, /* create_options */
674 &fnum,
675 &cr);
677 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
678 /* Maybe a file ? */
679 status = cli_smb2_create_fnum(cli,
680 name,
681 0, /* create_flags */
682 FILE_READ_ATTRIBUTES, /* desired_access */
683 0, /* file attributes */
684 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
685 FILE_OPEN, /* create_disposition */
686 0, /* create_options */
687 &fnum,
688 &cr);
691 if (!NT_STATUS_IS_OK(status)) {
692 return status;
695 cli_smb2_close_fnum(cli, fnum);
697 ZERO_STRUCTP(sbuf);
699 sbuf->st_ex_atime = nt_time_to_unix_timespec(&cr.last_access_time);
700 sbuf->st_ex_mtime = nt_time_to_unix_timespec(&cr.last_write_time);
701 sbuf->st_ex_ctime = nt_time_to_unix_timespec(&cr.change_time);
702 sbuf->st_ex_size = cr.end_of_file;
703 *attributes = cr.file_attributes;
705 return NT_STATUS_OK;
708 /***************************************************************
709 Helper function for pathname operations.
710 ***************************************************************/
712 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
713 const char *name,
714 uint32_t desired_access,
715 uint16_t *pfnum)
717 NTSTATUS status;
718 size_t namelen = strlen(name);
719 TALLOC_CTX *frame = talloc_stackframe();
721 /* SMB2 is pickier about pathnames. Ensure it doesn't
722 end in a '\' */
723 if (namelen > 0 && name[namelen-1] == '\\') {
724 char *modname = talloc_strdup(frame, name);
725 if (modname == NULL) {
726 status = NT_STATUS_NO_MEMORY;
727 goto fail;
729 modname[namelen-1] = '\0';
730 name = modname;
733 /* Try to open a file handle first. */
734 status = cli_smb2_create_fnum(cli,
735 name,
736 0, /* create_flags */
737 desired_access,
738 0, /* file attributes */
739 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
740 FILE_OPEN, /* create_disposition */
741 0, /* create_options */
742 pfnum,
743 NULL);
745 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
746 status = cli_smb2_create_fnum(cli,
747 name,
748 0, /* create_flags */
749 desired_access,
750 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
751 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
752 FILE_OPEN, /* create_disposition */
753 FILE_DIRECTORY_FILE, /* create_options */
754 pfnum,
755 NULL);
758 fail:
760 TALLOC_FREE(frame);
761 return status;
764 /***************************************************************
765 Wrapper that allows SMB2 to query a path info (ALTNAME level).
766 Synchronous only.
767 ***************************************************************/
769 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
770 const char *name,
771 fstring alt_name)
773 NTSTATUS status;
774 DATA_BLOB outbuf = data_blob_null;
775 uint16_t fnum = 0xffff;
776 struct smb2_hnd *ph = NULL;
777 uint32_t altnamelen = 0;
778 TALLOC_CTX *frame = talloc_stackframe();
780 if (smbXcli_conn_has_async_calls(cli->conn)) {
782 * Can't use sync call while an async call is in flight
784 status = NT_STATUS_INVALID_PARAMETER;
785 goto fail;
788 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
789 status = NT_STATUS_INVALID_PARAMETER;
790 goto fail;
793 status = get_fnum_from_path(cli,
794 name,
795 FILE_READ_ATTRIBUTES,
796 &fnum);
798 if (!NT_STATUS_IS_OK(status)) {
799 goto fail;
802 status = map_fnum_to_smb2_handle(cli,
803 fnum,
804 &ph);
805 if (!NT_STATUS_IS_OK(status)) {
806 goto fail;
809 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
810 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
812 status = smb2cli_query_info(cli->conn,
813 cli->timeout,
814 cli->smb2.session,
815 cli->smb2.tcon,
816 1, /* in_info_type */
817 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
818 0xFFFF, /* in_max_output_length */
819 NULL, /* in_input_buffer */
820 0, /* in_additional_info */
821 0, /* in_flags */
822 ph->fid_persistent,
823 ph->fid_volatile,
824 frame,
825 &outbuf);
827 if (!NT_STATUS_IS_OK(status)) {
828 goto fail;
831 /* Parse the reply. */
832 if (outbuf.length < 4) {
833 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
834 goto fail;
837 altnamelen = IVAL(outbuf.data, 0);
838 if (altnamelen > outbuf.length - 4) {
839 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
840 goto fail;
843 if (altnamelen > 0) {
844 size_t ret = 0;
845 char *short_name = NULL;
846 ret = pull_string_talloc(frame,
847 outbuf.data,
848 FLAGS2_UNICODE_STRINGS,
849 &short_name,
850 outbuf.data + 4,
851 altnamelen,
852 STR_UNICODE);
853 if (ret == (size_t)-1) {
854 /* Bad conversion. */
855 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
856 goto fail;
859 fstrcpy(alt_name, short_name);
860 } else {
861 alt_name[0] = '\0';
864 status = NT_STATUS_OK;
866 fail:
868 if (fnum != 0xffff) {
869 cli_smb2_close_fnum(cli, fnum);
871 TALLOC_FREE(frame);
872 return status;
876 /***************************************************************
877 Wrapper that allows SMB2 to query a fnum info (basic level).
878 Synchronous only.
879 ***************************************************************/
881 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
882 uint16_t fnum,
883 uint16_t *mode,
884 off_t *size,
885 struct timespec *create_time,
886 struct timespec *access_time,
887 struct timespec *write_time,
888 struct timespec *change_time,
889 SMB_INO_T *ino)
891 NTSTATUS status;
892 DATA_BLOB outbuf = data_blob_null;
893 struct smb2_hnd *ph = NULL;
894 TALLOC_CTX *frame = talloc_stackframe();
896 if (smbXcli_conn_has_async_calls(cli->conn)) {
898 * Can't use sync call while an async call is in flight
900 status = NT_STATUS_INVALID_PARAMETER;
901 goto fail;
904 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
905 status = NT_STATUS_INVALID_PARAMETER;
906 goto fail;
909 status = map_fnum_to_smb2_handle(cli,
910 fnum,
911 &ph);
912 if (!NT_STATUS_IS_OK(status)) {
913 goto fail;
916 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
917 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
919 status = smb2cli_query_info(cli->conn,
920 cli->timeout,
921 cli->smb2.session,
922 cli->smb2.tcon,
923 1, /* in_info_type */
924 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
925 0xFFFF, /* in_max_output_length */
926 NULL, /* in_input_buffer */
927 0, /* in_additional_info */
928 0, /* in_flags */
929 ph->fid_persistent,
930 ph->fid_volatile,
931 frame,
932 &outbuf);
933 if (!NT_STATUS_IS_OK(status)) {
934 goto fail;
937 /* Parse the reply. */
938 if (outbuf.length < 0x60) {
939 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
940 goto fail;
943 if (create_time) {
944 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
946 if (access_time) {
947 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
949 if (write_time) {
950 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
952 if (change_time) {
953 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
955 if (mode) {
956 uint32_t attr = IVAL(outbuf.data, 0x20);
957 *mode = (uint16_t)attr;
959 if (size) {
960 uint64_t file_size = BVAL(outbuf.data, 0x30);
961 *size = (off_t)file_size;
963 if (ino) {
964 uint64_t file_index = BVAL(outbuf.data, 0x40);
965 *ino = (SMB_INO_T)file_index;
968 fail:
970 TALLOC_FREE(frame);
971 return status;
974 /***************************************************************
975 Wrapper that allows SMB2 to query an fnum.
976 Implement on top of cli_smb2_qfileinfo_basic().
977 Synchronous only.
978 ***************************************************************/
980 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
981 uint16_t fnum,
982 uint16_t *attr,
983 off_t *size,
984 time_t *change_time,
985 time_t *access_time,
986 time_t *write_time)
988 struct timespec access_time_ts;
989 struct timespec write_time_ts;
990 struct timespec change_time_ts;
991 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
992 fnum,
993 attr,
994 size,
995 NULL,
996 &access_time_ts,
997 &write_time_ts,
998 &change_time_ts,
999 NULL);
1001 if (!NT_STATUS_IS_OK(status)) {
1002 return status;
1005 if (change_time) {
1006 *change_time = change_time_ts.tv_sec;
1008 if (access_time) {
1009 *access_time = access_time_ts.tv_sec;
1011 if (write_time) {
1012 *write_time = write_time_ts.tv_sec;
1014 return NT_STATUS_OK;
1017 /***************************************************************
1018 Wrapper that allows SMB2 to get pathname attributes.
1019 Synchronous only.
1020 ***************************************************************/
1022 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1023 const char *name,
1024 uint16_t *attr,
1025 off_t *size,
1026 time_t *write_time)
1028 NTSTATUS status;
1029 uint16_t fnum = 0xffff;
1030 struct smb2_hnd *ph = NULL;
1031 TALLOC_CTX *frame = talloc_stackframe();
1033 if (smbXcli_conn_has_async_calls(cli->conn)) {
1035 * Can't use sync call while an async call is in flight
1037 status = NT_STATUS_INVALID_PARAMETER;
1038 goto fail;
1041 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1042 status = NT_STATUS_INVALID_PARAMETER;
1043 goto fail;
1046 status = get_fnum_from_path(cli,
1047 name,
1048 FILE_READ_ATTRIBUTES,
1049 &fnum);
1051 if (!NT_STATUS_IS_OK(status)) {
1052 goto fail;
1055 status = map_fnum_to_smb2_handle(cli,
1056 fnum,
1057 &ph);
1058 if (!NT_STATUS_IS_OK(status)) {
1059 goto fail;
1061 status = cli_smb2_getattrE(cli,
1062 fnum,
1063 attr,
1064 size,
1065 NULL,
1066 NULL,
1067 write_time);
1068 if (!NT_STATUS_IS_OK(status)) {
1069 goto fail;
1072 fail:
1074 if (fnum != 0xffff) {
1075 cli_smb2_close_fnum(cli, fnum);
1078 TALLOC_FREE(frame);
1079 return status;
1082 /***************************************************************
1083 Wrapper that allows SMB2 to query a pathname info (basic level).
1084 Implement on top of cli_smb2_qfileinfo_basic().
1085 Synchronous only.
1086 ***************************************************************/
1088 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1089 const char *name,
1090 struct timespec *create_time,
1091 struct timespec *access_time,
1092 struct timespec *write_time,
1093 struct timespec *change_time,
1094 off_t *size,
1095 uint16_t *mode,
1096 SMB_INO_T *ino)
1098 NTSTATUS status;
1099 struct smb2_hnd *ph = NULL;
1100 uint16_t fnum = 0xffff;
1101 TALLOC_CTX *frame = talloc_stackframe();
1103 if (smbXcli_conn_has_async_calls(cli->conn)) {
1105 * Can't use sync call while an async call is in flight
1107 status = NT_STATUS_INVALID_PARAMETER;
1108 goto fail;
1111 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1112 status = NT_STATUS_INVALID_PARAMETER;
1113 goto fail;
1116 status = get_fnum_from_path(cli,
1117 name,
1118 FILE_READ_ATTRIBUTES,
1119 &fnum);
1121 if (!NT_STATUS_IS_OK(status)) {
1122 goto fail;
1125 status = map_fnum_to_smb2_handle(cli,
1126 fnum,
1127 &ph);
1128 if (!NT_STATUS_IS_OK(status)) {
1129 goto fail;
1132 status = cli_smb2_qfileinfo_basic(cli,
1133 fnum,
1134 mode,
1135 size,
1136 create_time,
1137 access_time,
1138 write_time,
1139 change_time,
1140 ino);
1142 fail:
1144 if (fnum != 0xffff) {
1145 cli_smb2_close_fnum(cli, fnum);
1148 TALLOC_FREE(frame);
1149 return status;
1152 /***************************************************************
1153 Wrapper that allows SMB2 to query pathname streams.
1154 Synchronous only.
1155 ***************************************************************/
1157 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1158 const char *name,
1159 TALLOC_CTX *mem_ctx,
1160 unsigned int *pnum_streams,
1161 struct stream_struct **pstreams)
1163 NTSTATUS status;
1164 struct smb2_hnd *ph = NULL;
1165 uint16_t fnum = 0xffff;
1166 DATA_BLOB outbuf = data_blob_null;
1167 TALLOC_CTX *frame = talloc_stackframe();
1169 if (smbXcli_conn_has_async_calls(cli->conn)) {
1171 * Can't use sync call while an async call is in flight
1173 status = NT_STATUS_INVALID_PARAMETER;
1174 goto fail;
1177 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1178 status = NT_STATUS_INVALID_PARAMETER;
1179 goto fail;
1182 status = get_fnum_from_path(cli,
1183 name,
1184 FILE_READ_ATTRIBUTES,
1185 &fnum);
1187 if (!NT_STATUS_IS_OK(status)) {
1188 goto fail;
1191 status = map_fnum_to_smb2_handle(cli,
1192 fnum,
1193 &ph);
1194 if (!NT_STATUS_IS_OK(status)) {
1195 goto fail;
1198 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1199 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1201 status = smb2cli_query_info(cli->conn,
1202 cli->timeout,
1203 cli->smb2.session,
1204 cli->smb2.tcon,
1205 1, /* in_info_type */
1206 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1207 0xFFFF, /* in_max_output_length */
1208 NULL, /* in_input_buffer */
1209 0, /* in_additional_info */
1210 0, /* in_flags */
1211 ph->fid_persistent,
1212 ph->fid_volatile,
1213 frame,
1214 &outbuf);
1216 if (!NT_STATUS_IS_OK(status)) {
1217 goto fail;
1220 /* Parse the reply. */
1221 if (!parse_streams_blob(mem_ctx,
1222 outbuf.data,
1223 outbuf.length,
1224 pnum_streams,
1225 pstreams)) {
1226 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1227 goto fail;
1230 fail:
1232 if (fnum != 0xffff) {
1233 cli_smb2_close_fnum(cli, fnum);
1236 TALLOC_FREE(frame);
1237 return status;
1240 /***************************************************************
1241 Wrapper that allows SMB2 to set pathname attributes.
1242 Synchronous only.
1243 ***************************************************************/
1245 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1246 const char *name,
1247 uint16_t attr,
1248 time_t mtime)
1250 NTSTATUS status;
1251 uint16_t fnum = 0xffff;
1252 struct smb2_hnd *ph = NULL;
1253 uint8_t inbuf_store[40];
1254 DATA_BLOB inbuf = data_blob_null;
1255 TALLOC_CTX *frame = talloc_stackframe();
1257 if (smbXcli_conn_has_async_calls(cli->conn)) {
1259 * Can't use sync call while an async call is in flight
1261 status = NT_STATUS_INVALID_PARAMETER;
1262 goto fail;
1265 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1266 status = NT_STATUS_INVALID_PARAMETER;
1267 goto fail;
1270 status = get_fnum_from_path(cli,
1271 name,
1272 FILE_WRITE_ATTRIBUTES,
1273 &fnum);
1275 if (!NT_STATUS_IS_OK(status)) {
1276 goto fail;
1279 status = map_fnum_to_smb2_handle(cli,
1280 fnum,
1281 &ph);
1282 if (!NT_STATUS_IS_OK(status)) {
1283 goto fail;
1286 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1287 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1289 inbuf.data = inbuf_store;
1290 inbuf.length = sizeof(inbuf_store);
1291 data_blob_clear(&inbuf);
1293 SIVAL(inbuf.data,32,attr);
1294 if (mtime != 0) {
1295 put_long_date((char *)inbuf.data + 16,mtime);
1297 /* Set all the other times to -1. */
1298 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1299 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1300 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1302 status = smb2cli_set_info(cli->conn,
1303 cli->timeout,
1304 cli->smb2.session,
1305 cli->smb2.tcon,
1306 1, /* in_info_type */
1307 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1308 &inbuf, /* in_input_buffer */
1309 0, /* in_additional_info */
1310 ph->fid_persistent,
1311 ph->fid_volatile);
1312 fail:
1314 if (fnum != 0xffff) {
1315 cli_smb2_close_fnum(cli, fnum);
1318 TALLOC_FREE(frame);
1319 return status;
1322 /***************************************************************
1323 Wrapper that allows SMB2 to set file handle times.
1324 Synchronous only.
1325 ***************************************************************/
1327 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1328 uint16_t fnum,
1329 time_t change_time,
1330 time_t access_time,
1331 time_t write_time)
1333 NTSTATUS status;
1334 struct smb2_hnd *ph = NULL;
1335 uint8_t inbuf_store[40];
1336 DATA_BLOB inbuf = data_blob_null;
1338 if (smbXcli_conn_has_async_calls(cli->conn)) {
1340 * Can't use sync call while an async call is in flight
1342 return NT_STATUS_INVALID_PARAMETER;
1345 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1346 return NT_STATUS_INVALID_PARAMETER;
1349 status = map_fnum_to_smb2_handle(cli,
1350 fnum,
1351 &ph);
1352 if (!NT_STATUS_IS_OK(status)) {
1353 return status;
1356 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1357 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1359 inbuf.data = inbuf_store;
1360 inbuf.length = sizeof(inbuf_store);
1361 data_blob_clear(&inbuf);
1363 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1364 if (change_time != 0) {
1365 put_long_date((char *)inbuf.data + 24, change_time);
1367 if (access_time != 0) {
1368 put_long_date((char *)inbuf.data + 8, access_time);
1370 if (write_time != 0) {
1371 put_long_date((char *)inbuf.data + 16, write_time);
1374 return smb2cli_set_info(cli->conn,
1375 cli->timeout,
1376 cli->smb2.session,
1377 cli->smb2.tcon,
1378 1, /* in_info_type */
1379 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1380 &inbuf, /* in_input_buffer */
1381 0, /* in_additional_info */
1382 ph->fid_persistent,
1383 ph->fid_volatile);
1386 /***************************************************************
1387 Wrapper that allows SMB2 to query disk attributes (size).
1388 Synchronous only.
1389 ***************************************************************/
1391 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
1393 NTSTATUS status;
1394 uint16_t fnum = 0xffff;
1395 DATA_BLOB outbuf = data_blob_null;
1396 struct smb2_hnd *ph = NULL;
1397 uint32_t sectors_per_unit = 0;
1398 uint32_t bytes_per_sector = 0;
1399 uint64_t total_size = 0;
1400 uint64_t size_free = 0;
1401 TALLOC_CTX *frame = talloc_stackframe();
1403 if (smbXcli_conn_has_async_calls(cli->conn)) {
1405 * Can't use sync call while an async call is in flight
1407 status = NT_STATUS_INVALID_PARAMETER;
1408 goto fail;
1411 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1412 status = NT_STATUS_INVALID_PARAMETER;
1413 goto fail;
1416 /* First open the top level directory. */
1417 status = cli_smb2_create_fnum(cli,
1419 0, /* create_flags */
1420 FILE_READ_ATTRIBUTES, /* desired_access */
1421 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1422 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1423 FILE_OPEN, /* create_disposition */
1424 FILE_DIRECTORY_FILE, /* create_options */
1425 &fnum,
1426 NULL);
1428 if (!NT_STATUS_IS_OK(status)) {
1429 goto fail;
1432 status = map_fnum_to_smb2_handle(cli,
1433 fnum,
1434 &ph);
1435 if (!NT_STATUS_IS_OK(status)) {
1436 goto fail;
1439 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1440 level 3 (SMB_FS_SIZE_INFORMATION). */
1442 status = smb2cli_query_info(cli->conn,
1443 cli->timeout,
1444 cli->smb2.session,
1445 cli->smb2.tcon,
1446 2, /* in_info_type */
1447 3, /* in_file_info_class */
1448 0xFFFF, /* in_max_output_length */
1449 NULL, /* in_input_buffer */
1450 0, /* in_additional_info */
1451 0, /* in_flags */
1452 ph->fid_persistent,
1453 ph->fid_volatile,
1454 frame,
1455 &outbuf);
1456 if (!NT_STATUS_IS_OK(status)) {
1457 goto fail;
1460 /* Parse the reply. */
1461 if (outbuf.length != 24) {
1462 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1463 goto fail;
1466 total_size = BVAL(outbuf.data, 0);
1467 size_free = BVAL(outbuf.data, 8);
1468 sectors_per_unit = IVAL(outbuf.data, 16);
1469 bytes_per_sector = IVAL(outbuf.data, 20);
1471 if (bsize) {
1472 *bsize = (int)(sectors_per_unit * bytes_per_sector);
1474 if (total) {
1475 *total = (int)total_size;
1477 if (avail) {
1478 *avail = (int)size_free;
1481 status = NT_STATUS_OK;
1483 fail:
1485 if (fnum != 0xffff) {
1486 cli_smb2_close_fnum(cli, fnum);
1489 TALLOC_FREE(frame);
1490 return status;
1493 /***************************************************************
1494 Wrapper that allows SMB2 to query a security descriptor.
1495 Synchronous only.
1496 ***************************************************************/
1498 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
1499 uint16_t fnum,
1500 uint32_t sec_info,
1501 TALLOC_CTX *mem_ctx,
1502 struct security_descriptor **ppsd)
1504 NTSTATUS status;
1505 DATA_BLOB outbuf = data_blob_null;
1506 struct smb2_hnd *ph = NULL;
1507 struct security_descriptor *lsd = NULL;
1508 TALLOC_CTX *frame = talloc_stackframe();
1510 if (smbXcli_conn_has_async_calls(cli->conn)) {
1512 * Can't use sync call while an async call is in flight
1514 status = NT_STATUS_INVALID_PARAMETER;
1515 goto fail;
1518 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1519 status = NT_STATUS_INVALID_PARAMETER;
1520 goto fail;
1523 status = map_fnum_to_smb2_handle(cli,
1524 fnum,
1525 &ph);
1526 if (!NT_STATUS_IS_OK(status)) {
1527 goto fail;
1530 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1532 status = smb2cli_query_info(cli->conn,
1533 cli->timeout,
1534 cli->smb2.session,
1535 cli->smb2.tcon,
1536 3, /* in_info_type */
1537 0, /* in_file_info_class */
1538 0xFFFF, /* in_max_output_length */
1539 NULL, /* in_input_buffer */
1540 sec_info, /* in_additional_info */
1541 0, /* in_flags */
1542 ph->fid_persistent,
1543 ph->fid_volatile,
1544 frame,
1545 &outbuf);
1547 if (!NT_STATUS_IS_OK(status)) {
1548 goto fail;
1551 /* Parse the reply. */
1552 status = unmarshall_sec_desc(mem_ctx,
1553 outbuf.data,
1554 outbuf.length,
1555 &lsd);
1557 if (!NT_STATUS_IS_OK(status)) {
1558 goto fail;
1561 if (ppsd != NULL) {
1562 *ppsd = lsd;
1563 } else {
1564 TALLOC_FREE(lsd);
1567 fail:
1569 TALLOC_FREE(frame);
1570 return status;
1573 /***************************************************************
1574 Wrapper that allows SMB2 to set a security descriptor.
1575 Synchronous only.
1576 ***************************************************************/
1578 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
1579 uint16_t fnum,
1580 uint32_t sec_info,
1581 const struct security_descriptor *sd)
1583 NTSTATUS status;
1584 DATA_BLOB inbuf = data_blob_null;
1585 struct smb2_hnd *ph = NULL;
1586 TALLOC_CTX *frame = talloc_stackframe();
1588 if (smbXcli_conn_has_async_calls(cli->conn)) {
1590 * Can't use sync call while an async call is in flight
1592 status = NT_STATUS_INVALID_PARAMETER;
1593 goto fail;
1596 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1597 status = NT_STATUS_INVALID_PARAMETER;
1598 goto fail;
1601 status = map_fnum_to_smb2_handle(cli,
1602 fnum,
1603 &ph);
1604 if (!NT_STATUS_IS_OK(status)) {
1605 goto fail;
1608 status = marshall_sec_desc(frame,
1610 &inbuf.data,
1611 &inbuf.length);
1613 if (!NT_STATUS_IS_OK(status)) {
1614 goto fail;
1617 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1619 status = smb2cli_set_info(cli->conn,
1620 cli->timeout,
1621 cli->smb2.session,
1622 cli->smb2.tcon,
1623 3, /* in_info_type */
1624 0, /* in_file_info_class */
1625 &inbuf, /* in_input_buffer */
1626 sec_info, /* in_additional_info */
1627 ph->fid_persistent,
1628 ph->fid_volatile);
1630 fail:
1632 TALLOC_FREE(frame);
1633 return status;
1636 /***************************************************************
1637 Wrapper that allows SMB2 to rename a file.
1638 Synchronous only.
1639 ***************************************************************/
1641 NTSTATUS cli_smb2_rename(struct cli_state *cli,
1642 const char *fname_src,
1643 const char *fname_dst)
1645 NTSTATUS status;
1646 DATA_BLOB inbuf = data_blob_null;
1647 uint16_t fnum = 0xffff;
1648 struct smb2_hnd *ph = NULL;
1649 smb_ucs2_t *converted_str = NULL;
1650 size_t converted_size_bytes = 0;
1651 size_t namelen = 0;
1652 TALLOC_CTX *frame = talloc_stackframe();
1654 if (smbXcli_conn_has_async_calls(cli->conn)) {
1656 * Can't use sync call while an async call is in flight
1658 status = NT_STATUS_INVALID_PARAMETER;
1659 goto fail;
1662 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1663 status = NT_STATUS_INVALID_PARAMETER;
1664 goto fail;
1667 status = get_fnum_from_path(cli,
1668 fname_src,
1669 DELETE_ACCESS,
1670 &fnum);
1672 if (!NT_STATUS_IS_OK(status)) {
1673 goto fail;
1676 status = map_fnum_to_smb2_handle(cli,
1677 fnum,
1678 &ph);
1679 if (!NT_STATUS_IS_OK(status)) {
1680 goto fail;
1683 /* SMB2 is pickier about pathnames. Ensure it doesn't
1684 start in a '\' */
1685 if (*fname_dst == '\\') {
1686 fname_dst++;
1689 /* SMB2 is pickier about pathnames. Ensure it doesn't
1690 end in a '\' */
1691 namelen = strlen(fname_dst);
1692 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
1693 char *modname = talloc_strdup(frame, fname_dst);
1694 modname[namelen-1] = '\0';
1695 fname_dst = modname;
1698 if (!push_ucs2_talloc(frame,
1699 &converted_str,
1700 fname_dst,
1701 &converted_size_bytes)) {
1702 status = NT_STATUS_INVALID_PARAMETER;
1703 goto fail;
1706 /* W2K8 insists the dest name is not null
1707 terminated. Remove the last 2 zero bytes
1708 and reduce the name length. */
1710 if (converted_size_bytes < 2) {
1711 status = NT_STATUS_INVALID_PARAMETER;
1712 goto fail;
1714 converted_size_bytes -= 2;
1716 inbuf = data_blob_talloc_zero(frame,
1717 20 + converted_size_bytes);
1718 if (inbuf.data == NULL) {
1719 status = NT_STATUS_NO_MEMORY;
1720 goto fail;
1723 SIVAL(inbuf.data, 16, converted_size_bytes);
1724 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
1726 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
1727 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
1729 status = smb2cli_set_info(cli->conn,
1730 cli->timeout,
1731 cli->smb2.session,
1732 cli->smb2.tcon,
1733 1, /* in_info_type */
1734 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
1735 &inbuf, /* in_input_buffer */
1736 0, /* in_additional_info */
1737 ph->fid_persistent,
1738 ph->fid_volatile);
1740 fail:
1742 if (fnum != 0xffff) {
1743 cli_smb2_close_fnum(cli, fnum);
1746 TALLOC_FREE(frame);
1747 return status;
1750 /***************************************************************
1751 Wrapper that allows SMB2 to set an EA on a fnum.
1752 Synchronous only.
1753 ***************************************************************/
1755 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
1756 uint16_t fnum,
1757 const char *ea_name,
1758 const char *ea_val,
1759 size_t ea_len)
1761 NTSTATUS status;
1762 DATA_BLOB inbuf = data_blob_null;
1763 size_t bloblen = 0;
1764 char *ea_name_ascii = NULL;
1765 size_t namelen = 0;
1766 struct smb2_hnd *ph = NULL;
1767 TALLOC_CTX *frame = talloc_stackframe();
1769 if (smbXcli_conn_has_async_calls(cli->conn)) {
1771 * Can't use sync call while an async call is in flight
1773 status = NT_STATUS_INVALID_PARAMETER;
1774 goto fail;
1777 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1778 status = NT_STATUS_INVALID_PARAMETER;
1779 goto fail;
1782 status = map_fnum_to_smb2_handle(cli,
1783 fnum,
1784 &ph);
1785 if (!NT_STATUS_IS_OK(status)) {
1786 goto fail;
1789 /* Marshall the SMB2 EA data. */
1790 if (ea_len > 0xFFFF) {
1791 status = NT_STATUS_INVALID_PARAMETER;
1792 goto fail;
1795 if (!push_ascii_talloc(frame,
1796 &ea_name_ascii,
1797 ea_name,
1798 &namelen)) {
1799 status = NT_STATUS_INVALID_PARAMETER;
1800 goto fail;
1803 if (namelen < 2 || namelen > 0xFF) {
1804 status = NT_STATUS_INVALID_PARAMETER;
1805 goto fail;
1808 bloblen = 8 + ea_len + namelen;
1809 /* Round up to a 4 byte boundary. */
1810 bloblen = ((bloblen + 3)&~3);
1812 inbuf = data_blob_talloc_zero(frame, bloblen);
1813 if (inbuf.data == NULL) {
1814 status = NT_STATUS_NO_MEMORY;
1815 goto fail;
1817 /* namelen doesn't include the NULL byte. */
1818 SCVAL(inbuf.data, 5, namelen - 1);
1819 SSVAL(inbuf.data, 6, ea_len);
1820 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
1821 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
1823 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1824 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
1826 status = smb2cli_set_info(cli->conn,
1827 cli->timeout,
1828 cli->smb2.session,
1829 cli->smb2.tcon,
1830 1, /* in_info_type */
1831 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
1832 &inbuf, /* in_input_buffer */
1833 0, /* in_additional_info */
1834 ph->fid_persistent,
1835 ph->fid_volatile);
1837 fail:
1839 TALLOC_FREE(frame);
1840 return status;
1843 /***************************************************************
1844 Wrapper that allows SMB2 to set an EA on a pathname.
1845 Synchronous only.
1846 ***************************************************************/
1848 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
1849 const char *name,
1850 const char *ea_name,
1851 const char *ea_val,
1852 size_t ea_len)
1854 NTSTATUS status;
1855 uint16_t fnum = 0xffff;
1857 if (smbXcli_conn_has_async_calls(cli->conn)) {
1859 * Can't use sync call while an async call is in flight
1861 status = NT_STATUS_INVALID_PARAMETER;
1862 goto fail;
1865 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1866 status = NT_STATUS_INVALID_PARAMETER;
1867 goto fail;
1870 status = get_fnum_from_path(cli,
1871 name,
1872 FILE_WRITE_EA,
1873 &fnum);
1875 if (!NT_STATUS_IS_OK(status)) {
1876 goto fail;
1879 status = cli_set_ea_fnum(cli,
1880 fnum,
1881 ea_name,
1882 ea_val,
1883 ea_len);
1884 if (!NT_STATUS_IS_OK(status)) {
1885 goto fail;
1888 fail:
1890 if (fnum != 0xffff) {
1891 cli_smb2_close_fnum(cli, fnum);
1894 return status;
1897 /***************************************************************
1898 Wrapper that allows SMB2 to get an EA list on a pathname.
1899 Synchronous only.
1900 ***************************************************************/
1902 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
1903 const char *name,
1904 TALLOC_CTX *ctx,
1905 size_t *pnum_eas,
1906 struct ea_struct **pea_array)
1908 NTSTATUS status;
1909 uint16_t fnum = 0xffff;
1910 DATA_BLOB outbuf = data_blob_null;
1911 struct smb2_hnd *ph = NULL;
1912 struct ea_list *ea_list = NULL;
1913 struct ea_list *eal = NULL;
1914 size_t ea_count = 0;
1915 TALLOC_CTX *frame = talloc_stackframe();
1917 *pnum_eas = 0;
1918 *pea_array = NULL;
1920 if (smbXcli_conn_has_async_calls(cli->conn)) {
1922 * Can't use sync call while an async call is in flight
1924 status = NT_STATUS_INVALID_PARAMETER;
1925 goto fail;
1928 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1929 status = NT_STATUS_INVALID_PARAMETER;
1930 goto fail;
1933 status = get_fnum_from_path(cli,
1934 name,
1935 FILE_READ_EA,
1936 &fnum);
1938 if (!NT_STATUS_IS_OK(status)) {
1939 goto fail;
1942 status = map_fnum_to_smb2_handle(cli,
1943 fnum,
1944 &ph);
1945 if (!NT_STATUS_IS_OK(status)) {
1946 goto fail;
1949 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1950 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
1952 status = smb2cli_query_info(cli->conn,
1953 cli->timeout,
1954 cli->smb2.session,
1955 cli->smb2.tcon,
1956 1, /* in_info_type */
1957 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
1958 0xFFFF, /* in_max_output_length */
1959 NULL, /* in_input_buffer */
1960 0, /* in_additional_info */
1961 0, /* in_flags */
1962 ph->fid_persistent,
1963 ph->fid_volatile,
1964 frame,
1965 &outbuf);
1967 if (!NT_STATUS_IS_OK(status)) {
1968 goto fail;
1971 /* Parse the reply. */
1972 ea_list = read_nttrans_ea_list(ctx,
1973 (const char *)outbuf.data,
1974 outbuf.length);
1975 if (ea_list == NULL) {
1976 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1977 goto fail;
1980 /* Convert to an array. */
1981 for (eal = ea_list; eal; eal = eal->next) {
1982 ea_count++;
1985 if (ea_count) {
1986 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
1987 if (*pea_array == NULL) {
1988 status = NT_STATUS_NO_MEMORY;
1989 goto fail;
1991 ea_count = 0;
1992 for (eal = ea_list; eal; eal = eal->next) {
1993 (*pea_array)[ea_count++] = ea_list->ea;
1995 *pnum_eas = ea_count;
1998 fail:
2000 TALLOC_FREE(frame);
2001 return status;
2004 struct cli_smb2_read_state {
2005 struct tevent_context *ev;
2006 struct cli_state *cli;
2007 struct smb2_hnd *ph;
2008 uint64_t start_offset;
2009 uint32_t size;
2010 uint32_t received;
2011 uint8_t *buf;
2014 static void cli_smb2_read_done(struct tevent_req *subreq);
2016 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
2017 struct tevent_context *ev,
2018 struct cli_state *cli,
2019 uint16_t fnum,
2020 off_t offset,
2021 size_t size)
2023 NTSTATUS status;
2024 struct tevent_req *req, *subreq;
2025 struct cli_smb2_read_state *state;
2027 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
2028 if (req == NULL) {
2029 return NULL;
2031 state->ev = ev;
2032 state->cli = cli;
2033 state->start_offset = (uint64_t)offset;
2034 state->size = (uint32_t)size;
2035 state->received = 0;
2036 state->buf = NULL;
2038 status = map_fnum_to_smb2_handle(cli,
2039 fnum,
2040 &state->ph);
2041 if (tevent_req_nterror(req, status)) {
2042 return tevent_req_post(req, ev);
2045 subreq = smb2cli_read_send(state,
2046 state->ev,
2047 state->cli->conn,
2048 state->cli->timeout,
2049 state->cli->smb2.session,
2050 state->cli->smb2.tcon,
2051 state->size,
2052 state->start_offset,
2053 state->ph->fid_persistent,
2054 state->ph->fid_volatile,
2055 0, /* minimum_count */
2056 0); /* remaining_bytes */
2058 if (tevent_req_nomem(subreq, req)) {
2059 return tevent_req_post(req, ev);
2061 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
2062 return req;
2065 static void cli_smb2_read_done(struct tevent_req *subreq)
2067 struct tevent_req *req = tevent_req_callback_data(
2068 subreq, struct tevent_req);
2069 struct cli_smb2_read_state *state = tevent_req_data(
2070 req, struct cli_smb2_read_state);
2071 NTSTATUS status;
2073 status = smb2cli_read_recv(subreq, state,
2074 &state->buf, &state->received);
2075 if (tevent_req_nterror(req, status)) {
2076 return;
2079 if (state->received > state->size) {
2080 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2081 return;
2084 tevent_req_done(req);
2087 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
2088 ssize_t *received,
2089 uint8_t **rcvbuf)
2091 NTSTATUS status;
2092 struct cli_smb2_read_state *state = tevent_req_data(
2093 req, struct cli_smb2_read_state);
2095 if (tevent_req_is_nterror(req, &status)) {
2096 return status;
2099 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2100 * better make sure that you copy it away before you talloc_free(req).
2101 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2103 *received = (ssize_t)state->received;
2104 *rcvbuf = state->buf;
2105 return NT_STATUS_OK;
2108 struct cli_smb2_write_state {
2109 struct tevent_context *ev;
2110 struct cli_state *cli;
2111 struct smb2_hnd *ph;
2112 uint32_t flags;
2113 const uint8_t *buf;
2114 uint64_t offset;
2115 uint32_t size;
2116 uint32_t written;
2119 static void cli_smb2_write_written(struct tevent_req *req);
2121 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
2122 struct tevent_context *ev,
2123 struct cli_state *cli,
2124 uint16_t fnum,
2125 uint16_t mode,
2126 const uint8_t *buf,
2127 off_t offset,
2128 size_t size)
2130 NTSTATUS status;
2131 struct tevent_req *req, *subreq = NULL;
2132 struct cli_smb2_write_state *state = NULL;
2134 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
2135 if (req == NULL) {
2136 return NULL;
2138 state->ev = ev;
2139 state->cli = cli;
2140 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2141 state->flags = (uint32_t)mode;
2142 state->buf = buf;
2143 state->offset = (uint64_t)offset;
2144 state->size = (uint32_t)size;
2145 state->written = 0;
2147 status = map_fnum_to_smb2_handle(cli,
2148 fnum,
2149 &state->ph);
2150 if (tevent_req_nterror(req, status)) {
2151 return tevent_req_post(req, ev);
2154 subreq = smb2cli_write_send(state,
2155 state->ev,
2156 state->cli->conn,
2157 state->cli->timeout,
2158 state->cli->smb2.session,
2159 state->cli->smb2.tcon,
2160 state->size,
2161 state->offset,
2162 state->ph->fid_persistent,
2163 state->ph->fid_volatile,
2164 0, /* remaining_bytes */
2165 state->flags, /* flags */
2166 state->buf);
2168 if (tevent_req_nomem(subreq, req)) {
2169 return tevent_req_post(req, ev);
2171 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
2172 return req;
2175 static void cli_smb2_write_written(struct tevent_req *subreq)
2177 struct tevent_req *req = tevent_req_callback_data(
2178 subreq, struct tevent_req);
2179 struct cli_smb2_write_state *state = tevent_req_data(
2180 req, struct cli_smb2_write_state);
2181 NTSTATUS status;
2182 uint32_t written;
2184 status = smb2cli_write_recv(subreq, &written);
2185 TALLOC_FREE(subreq);
2186 if (tevent_req_nterror(req, status)) {
2187 return;
2190 state->written = written;
2192 tevent_req_done(req);
2195 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
2196 size_t *pwritten)
2198 struct cli_smb2_write_state *state = tevent_req_data(
2199 req, struct cli_smb2_write_state);
2200 NTSTATUS status;
2202 if (tevent_req_is_nterror(req, &status)) {
2203 tevent_req_received(req);
2204 return status;
2207 if (pwritten != NULL) {
2208 *pwritten = (size_t)state->written;
2210 tevent_req_received(req);
2211 return NT_STATUS_OK;
2214 /***************************************************************
2215 Wrapper that allows SMB2 async write using an fnum.
2216 This is mostly cut-and-paste from Volker's code inside
2217 source3/libsmb/clireadwrite.c, adapted for SMB2.
2219 Done this way so I can reuse all the logic inside cli_push()
2220 for free :-).
2221 ***************************************************************/
2223 struct cli_smb2_writeall_state {
2224 struct tevent_context *ev;
2225 struct cli_state *cli;
2226 struct smb2_hnd *ph;
2227 uint32_t flags;
2228 const uint8_t *buf;
2229 uint64_t offset;
2230 uint32_t size;
2231 uint32_t written;
2234 static void cli_smb2_writeall_written(struct tevent_req *req);
2236 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
2237 struct tevent_context *ev,
2238 struct cli_state *cli,
2239 uint16_t fnum,
2240 uint16_t mode,
2241 const uint8_t *buf,
2242 off_t offset,
2243 size_t size)
2245 NTSTATUS status;
2246 struct tevent_req *req, *subreq = NULL;
2247 struct cli_smb2_writeall_state *state = NULL;
2248 uint32_t to_write;
2249 uint32_t max_size;
2250 bool ok;
2252 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
2253 if (req == NULL) {
2254 return NULL;
2256 state->ev = ev;
2257 state->cli = cli;
2258 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2259 state->flags = (uint32_t)mode;
2260 state->buf = buf;
2261 state->offset = (uint64_t)offset;
2262 state->size = (uint32_t)size;
2263 state->written = 0;
2265 status = map_fnum_to_smb2_handle(cli,
2266 fnum,
2267 &state->ph);
2268 if (tevent_req_nterror(req, status)) {
2269 return tevent_req_post(req, ev);
2272 to_write = state->size;
2273 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2274 to_write = MIN(max_size, to_write);
2275 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2276 if (ok) {
2277 to_write = MIN(max_size, to_write);
2280 subreq = smb2cli_write_send(state,
2281 state->ev,
2282 state->cli->conn,
2283 state->cli->timeout,
2284 state->cli->smb2.session,
2285 state->cli->smb2.tcon,
2286 to_write,
2287 state->offset,
2288 state->ph->fid_persistent,
2289 state->ph->fid_volatile,
2290 0, /* remaining_bytes */
2291 state->flags, /* flags */
2292 state->buf + state->written);
2294 if (tevent_req_nomem(subreq, req)) {
2295 return tevent_req_post(req, ev);
2297 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2298 return req;
2301 static void cli_smb2_writeall_written(struct tevent_req *subreq)
2303 struct tevent_req *req = tevent_req_callback_data(
2304 subreq, struct tevent_req);
2305 struct cli_smb2_writeall_state *state = tevent_req_data(
2306 req, struct cli_smb2_writeall_state);
2307 NTSTATUS status;
2308 uint32_t written, to_write;
2309 uint32_t max_size;
2310 bool ok;
2312 status = smb2cli_write_recv(subreq, &written);
2313 TALLOC_FREE(subreq);
2314 if (tevent_req_nterror(req, status)) {
2315 return;
2318 state->written += written;
2320 if (state->written > state->size) {
2321 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2322 return;
2325 to_write = state->size - state->written;
2327 if (to_write == 0) {
2328 tevent_req_done(req);
2329 return;
2332 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2333 to_write = MIN(max_size, to_write);
2334 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2335 if (ok) {
2336 to_write = MIN(max_size, to_write);
2339 subreq = smb2cli_write_send(state,
2340 state->ev,
2341 state->cli->conn,
2342 state->cli->timeout,
2343 state->cli->smb2.session,
2344 state->cli->smb2.tcon,
2345 to_write,
2346 state->offset + state->written,
2347 state->ph->fid_persistent,
2348 state->ph->fid_volatile,
2349 0, /* remaining_bytes */
2350 state->flags, /* flags */
2351 state->buf + state->written);
2353 if (tevent_req_nomem(subreq, req)) {
2354 return;
2356 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2359 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
2360 size_t *pwritten)
2362 struct cli_smb2_writeall_state *state = tevent_req_data(
2363 req, struct cli_smb2_writeall_state);
2364 NTSTATUS status;
2366 if (tevent_req_is_nterror(req, &status)) {
2367 return status;
2369 if (pwritten != NULL) {
2370 *pwritten = (size_t)state->written;
2372 return NT_STATUS_OK;