.gitignore: Ignore tag files from GNU Global tool
[Samba.git] / source3 / libsmb / cli_smb2_fnum.c
blob1e2047ef6763e20cd72870ea2b4483838833589a
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 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;
505 if (smbXcli_conn_has_async_calls(cli->conn)) {
507 * Can't use sync call while an async call is in flight
509 status = NT_STATUS_INVALID_PARAMETER;
510 goto fail;
513 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
514 status = NT_STATUS_INVALID_PARAMETER;
515 goto fail;
518 /* Get the directory name. */
519 if (!windows_parent_dirname(frame,
520 pathname,
521 &parent_dir,
522 &mask)) {
523 status = NT_STATUS_NO_MEMORY;
524 goto fail;
527 status = cli_smb2_create_fnum(cli,
528 parent_dir,
529 0, /* create_flags */
530 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
531 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
532 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
533 FILE_OPEN, /* create_disposition */
534 FILE_DIRECTORY_FILE, /* create_options */
535 &fnum,
536 NULL);
538 if (!NT_STATUS_IS_OK(status)) {
539 goto fail;
542 status = map_fnum_to_smb2_handle(cli,
543 fnum,
544 &ph);
545 if (!NT_STATUS_IS_OK(status)) {
546 goto fail;
549 do {
550 uint8_t *dir_data = NULL;
551 uint32_t dir_data_length = 0;
552 uint32_t next_offset = 0;
553 subframe = talloc_stackframe();
555 status = smb2cli_query_directory(cli->conn,
556 cli->timeout,
557 cli->smb2.session,
558 cli->smb2.tcon,
559 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
560 0, /* flags */
561 0, /* file_index */
562 ph->fid_persistent,
563 ph->fid_volatile,
564 mask,
565 0xffff,
566 subframe,
567 &dir_data,
568 &dir_data_length);
570 if (!NT_STATUS_IS_OK(status)) {
571 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
572 break;
574 goto fail;
577 do {
578 struct file_info *finfo = talloc_zero(subframe,
579 struct file_info);
581 if (finfo == NULL) {
582 status = NT_STATUS_NO_MEMORY;
583 goto fail;
586 status = parse_finfo_id_both_directory_info(dir_data,
587 dir_data_length,
588 finfo,
589 &next_offset);
591 if (!NT_STATUS_IS_OK(status)) {
592 goto fail;
595 if (dir_check_ftype((uint32_t)finfo->mode,
596 (uint32_t)attribute)) {
598 * Only process if attributes match.
599 * On SMB1 server does this, so on
600 * SMB2 we need to emulate in the
601 * client.
603 * https://bugzilla.samba.org/show_bug.cgi?id=10260
605 processed_file = true;
607 status = fn(cli->dfs_mountpoint,
608 finfo,
609 pathname,
610 state);
612 if (!NT_STATUS_IS_OK(status)) {
613 break;
617 TALLOC_FREE(finfo);
619 /* Move to next entry. */
620 if (next_offset) {
621 dir_data += next_offset;
622 dir_data_length -= next_offset;
624 } while (next_offset != 0);
626 TALLOC_FREE(subframe);
628 } while (NT_STATUS_IS_OK(status));
630 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
631 status = NT_STATUS_OK;
634 if (NT_STATUS_IS_OK(status) && !processed_file) {
636 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
637 * if no files match. Emulate this in the client.
639 status = NT_STATUS_NO_SUCH_FILE;
642 fail:
644 if (fnum != 0xffff) {
645 cli_smb2_close_fnum(cli, fnum);
647 TALLOC_FREE(subframe);
648 TALLOC_FREE(frame);
649 return status;
652 /***************************************************************
653 Wrapper that allows SMB2 to query a path info (basic level).
654 Synchronous only.
655 ***************************************************************/
657 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
658 const char *name,
659 SMB_STRUCT_STAT *sbuf,
660 uint32_t *attributes)
662 NTSTATUS status;
663 struct smb2_create_returns cr;
664 uint16_t fnum = 0xffff;
665 size_t namelen = strlen(name);
667 if (smbXcli_conn_has_async_calls(cli->conn)) {
669 * Can't use sync call while an async call is in flight
671 return NT_STATUS_INVALID_PARAMETER;
674 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
675 return NT_STATUS_INVALID_PARAMETER;
678 /* SMB2 is pickier about pathnames. Ensure it doesn't
679 end in a '\' */
680 if (namelen > 0 && name[namelen-1] == '\\') {
681 char *modname = talloc_strdup(talloc_tos(), name);
682 modname[namelen-1] = '\0';
683 name = modname;
686 /* This is commonly used as a 'cd'. Try qpathinfo on
687 a directory handle first. */
689 status = cli_smb2_create_fnum(cli,
690 name,
691 0, /* create_flags */
692 FILE_READ_ATTRIBUTES, /* desired_access */
693 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
694 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
695 FILE_OPEN, /* create_disposition */
696 FILE_DIRECTORY_FILE, /* create_options */
697 &fnum,
698 &cr);
700 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
701 /* Maybe a file ? */
702 status = cli_smb2_create_fnum(cli,
703 name,
704 0, /* create_flags */
705 FILE_READ_ATTRIBUTES, /* desired_access */
706 0, /* file attributes */
707 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
708 FILE_OPEN, /* create_disposition */
709 0, /* create_options */
710 &fnum,
711 &cr);
714 if (!NT_STATUS_IS_OK(status)) {
715 return status;
718 cli_smb2_close_fnum(cli, fnum);
720 ZERO_STRUCTP(sbuf);
722 sbuf->st_ex_atime = nt_time_to_unix_timespec(&cr.last_access_time);
723 sbuf->st_ex_mtime = nt_time_to_unix_timespec(&cr.last_write_time);
724 sbuf->st_ex_ctime = nt_time_to_unix_timespec(&cr.change_time);
725 sbuf->st_ex_size = cr.end_of_file;
726 *attributes = cr.file_attributes;
728 return NT_STATUS_OK;
731 /***************************************************************
732 Helper function for pathname operations.
733 ***************************************************************/
735 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
736 const char *name,
737 uint32_t desired_access,
738 uint16_t *pfnum)
740 NTSTATUS status;
741 size_t namelen = strlen(name);
742 TALLOC_CTX *frame = talloc_stackframe();
744 /* SMB2 is pickier about pathnames. Ensure it doesn't
745 end in a '\' */
746 if (namelen > 0 && name[namelen-1] == '\\') {
747 char *modname = talloc_strdup(frame, name);
748 if (modname == NULL) {
749 status = NT_STATUS_NO_MEMORY;
750 goto fail;
752 modname[namelen-1] = '\0';
753 name = modname;
756 /* Try to open a file handle first. */
757 status = cli_smb2_create_fnum(cli,
758 name,
759 0, /* create_flags */
760 desired_access,
761 0, /* file attributes */
762 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
763 FILE_OPEN, /* create_disposition */
764 0, /* create_options */
765 pfnum,
766 NULL);
768 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
769 status = cli_smb2_create_fnum(cli,
770 name,
771 0, /* create_flags */
772 desired_access,
773 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
774 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
775 FILE_OPEN, /* create_disposition */
776 FILE_DIRECTORY_FILE, /* create_options */
777 pfnum,
778 NULL);
781 fail:
783 TALLOC_FREE(frame);
784 return status;
787 /***************************************************************
788 Wrapper that allows SMB2 to query a path info (ALTNAME level).
789 Synchronous only.
790 ***************************************************************/
792 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
793 const char *name,
794 fstring alt_name)
796 NTSTATUS status;
797 DATA_BLOB outbuf = data_blob_null;
798 uint16_t fnum = 0xffff;
799 struct smb2_hnd *ph = NULL;
800 uint32_t altnamelen = 0;
801 TALLOC_CTX *frame = talloc_stackframe();
803 if (smbXcli_conn_has_async_calls(cli->conn)) {
805 * Can't use sync call while an async call is in flight
807 status = NT_STATUS_INVALID_PARAMETER;
808 goto fail;
811 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
812 status = NT_STATUS_INVALID_PARAMETER;
813 goto fail;
816 status = get_fnum_from_path(cli,
817 name,
818 FILE_READ_ATTRIBUTES,
819 &fnum);
821 if (!NT_STATUS_IS_OK(status)) {
822 goto fail;
825 status = map_fnum_to_smb2_handle(cli,
826 fnum,
827 &ph);
828 if (!NT_STATUS_IS_OK(status)) {
829 goto fail;
832 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
833 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
835 status = smb2cli_query_info(cli->conn,
836 cli->timeout,
837 cli->smb2.session,
838 cli->smb2.tcon,
839 1, /* in_info_type */
840 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
841 0xFFFF, /* in_max_output_length */
842 NULL, /* in_input_buffer */
843 0, /* in_additional_info */
844 0, /* in_flags */
845 ph->fid_persistent,
846 ph->fid_volatile,
847 frame,
848 &outbuf);
850 if (!NT_STATUS_IS_OK(status)) {
851 goto fail;
854 /* Parse the reply. */
855 if (outbuf.length < 4) {
856 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
857 goto fail;
860 altnamelen = IVAL(outbuf.data, 0);
861 if (altnamelen > outbuf.length - 4) {
862 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
863 goto fail;
866 if (altnamelen > 0) {
867 size_t ret = 0;
868 char *short_name = NULL;
869 ret = pull_string_talloc(frame,
870 outbuf.data,
871 FLAGS2_UNICODE_STRINGS,
872 &short_name,
873 outbuf.data + 4,
874 altnamelen,
875 STR_UNICODE);
876 if (ret == (size_t)-1) {
877 /* Bad conversion. */
878 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
879 goto fail;
882 fstrcpy(alt_name, short_name);
883 } else {
884 alt_name[0] = '\0';
887 status = NT_STATUS_OK;
889 fail:
891 if (fnum != 0xffff) {
892 cli_smb2_close_fnum(cli, fnum);
894 TALLOC_FREE(frame);
895 return status;
899 /***************************************************************
900 Wrapper that allows SMB2 to query a fnum info (basic level).
901 Synchronous only.
902 ***************************************************************/
904 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
905 uint16_t fnum,
906 uint16_t *mode,
907 off_t *size,
908 struct timespec *create_time,
909 struct timespec *access_time,
910 struct timespec *write_time,
911 struct timespec *change_time,
912 SMB_INO_T *ino)
914 NTSTATUS status;
915 DATA_BLOB outbuf = data_blob_null;
916 struct smb2_hnd *ph = NULL;
917 TALLOC_CTX *frame = talloc_stackframe();
919 if (smbXcli_conn_has_async_calls(cli->conn)) {
921 * Can't use sync call while an async call is in flight
923 status = NT_STATUS_INVALID_PARAMETER;
924 goto fail;
927 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
928 status = NT_STATUS_INVALID_PARAMETER;
929 goto fail;
932 status = map_fnum_to_smb2_handle(cli,
933 fnum,
934 &ph);
935 if (!NT_STATUS_IS_OK(status)) {
936 goto fail;
939 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
940 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
942 status = smb2cli_query_info(cli->conn,
943 cli->timeout,
944 cli->smb2.session,
945 cli->smb2.tcon,
946 1, /* in_info_type */
947 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
948 0xFFFF, /* in_max_output_length */
949 NULL, /* in_input_buffer */
950 0, /* in_additional_info */
951 0, /* in_flags */
952 ph->fid_persistent,
953 ph->fid_volatile,
954 frame,
955 &outbuf);
956 if (!NT_STATUS_IS_OK(status)) {
957 goto fail;
960 /* Parse the reply. */
961 if (outbuf.length < 0x60) {
962 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
963 goto fail;
966 if (create_time) {
967 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
969 if (access_time) {
970 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
972 if (write_time) {
973 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
975 if (change_time) {
976 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
978 if (mode) {
979 uint32_t attr = IVAL(outbuf.data, 0x20);
980 *mode = (uint16_t)attr;
982 if (size) {
983 uint64_t file_size = BVAL(outbuf.data, 0x30);
984 *size = (off_t)file_size;
986 if (ino) {
987 uint64_t file_index = BVAL(outbuf.data, 0x40);
988 *ino = (SMB_INO_T)file_index;
991 fail:
993 TALLOC_FREE(frame);
994 return status;
997 /***************************************************************
998 Wrapper that allows SMB2 to query an fnum.
999 Implement on top of cli_smb2_qfileinfo_basic().
1000 Synchronous only.
1001 ***************************************************************/
1003 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1004 uint16_t fnum,
1005 uint16_t *attr,
1006 off_t *size,
1007 time_t *change_time,
1008 time_t *access_time,
1009 time_t *write_time)
1011 struct timespec access_time_ts;
1012 struct timespec write_time_ts;
1013 struct timespec change_time_ts;
1014 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1015 fnum,
1016 attr,
1017 size,
1018 NULL,
1019 &access_time_ts,
1020 &write_time_ts,
1021 &change_time_ts,
1022 NULL);
1024 if (!NT_STATUS_IS_OK(status)) {
1025 return status;
1028 if (change_time) {
1029 *change_time = change_time_ts.tv_sec;
1031 if (access_time) {
1032 *access_time = access_time_ts.tv_sec;
1034 if (write_time) {
1035 *write_time = write_time_ts.tv_sec;
1037 return NT_STATUS_OK;
1040 /***************************************************************
1041 Wrapper that allows SMB2 to get pathname attributes.
1042 Synchronous only.
1043 ***************************************************************/
1045 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1046 const char *name,
1047 uint16_t *attr,
1048 off_t *size,
1049 time_t *write_time)
1051 NTSTATUS status;
1052 uint16_t fnum = 0xffff;
1053 struct smb2_hnd *ph = NULL;
1054 TALLOC_CTX *frame = talloc_stackframe();
1056 if (smbXcli_conn_has_async_calls(cli->conn)) {
1058 * Can't use sync call while an async call is in flight
1060 status = NT_STATUS_INVALID_PARAMETER;
1061 goto fail;
1064 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1065 status = NT_STATUS_INVALID_PARAMETER;
1066 goto fail;
1069 status = get_fnum_from_path(cli,
1070 name,
1071 FILE_READ_ATTRIBUTES,
1072 &fnum);
1074 if (!NT_STATUS_IS_OK(status)) {
1075 goto fail;
1078 status = map_fnum_to_smb2_handle(cli,
1079 fnum,
1080 &ph);
1081 if (!NT_STATUS_IS_OK(status)) {
1082 goto fail;
1084 status = cli_smb2_getattrE(cli,
1085 fnum,
1086 attr,
1087 size,
1088 NULL,
1089 NULL,
1090 write_time);
1091 if (!NT_STATUS_IS_OK(status)) {
1092 goto fail;
1095 fail:
1097 if (fnum != 0xffff) {
1098 cli_smb2_close_fnum(cli, fnum);
1101 TALLOC_FREE(frame);
1102 return status;
1105 /***************************************************************
1106 Wrapper that allows SMB2 to query a pathname info (basic level).
1107 Implement on top of cli_smb2_qfileinfo_basic().
1108 Synchronous only.
1109 ***************************************************************/
1111 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1112 const char *name,
1113 struct timespec *create_time,
1114 struct timespec *access_time,
1115 struct timespec *write_time,
1116 struct timespec *change_time,
1117 off_t *size,
1118 uint16_t *mode,
1119 SMB_INO_T *ino)
1121 NTSTATUS status;
1122 struct smb2_hnd *ph = NULL;
1123 uint16_t fnum = 0xffff;
1124 TALLOC_CTX *frame = talloc_stackframe();
1126 if (smbXcli_conn_has_async_calls(cli->conn)) {
1128 * Can't use sync call while an async call is in flight
1130 status = NT_STATUS_INVALID_PARAMETER;
1131 goto fail;
1134 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1135 status = NT_STATUS_INVALID_PARAMETER;
1136 goto fail;
1139 status = get_fnum_from_path(cli,
1140 name,
1141 FILE_READ_ATTRIBUTES,
1142 &fnum);
1144 if (!NT_STATUS_IS_OK(status)) {
1145 goto fail;
1148 status = map_fnum_to_smb2_handle(cli,
1149 fnum,
1150 &ph);
1151 if (!NT_STATUS_IS_OK(status)) {
1152 goto fail;
1155 status = cli_smb2_qfileinfo_basic(cli,
1156 fnum,
1157 mode,
1158 size,
1159 create_time,
1160 access_time,
1161 write_time,
1162 change_time,
1163 ino);
1165 fail:
1167 if (fnum != 0xffff) {
1168 cli_smb2_close_fnum(cli, fnum);
1171 TALLOC_FREE(frame);
1172 return status;
1175 /***************************************************************
1176 Wrapper that allows SMB2 to query pathname streams.
1177 Synchronous only.
1178 ***************************************************************/
1180 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1181 const char *name,
1182 TALLOC_CTX *mem_ctx,
1183 unsigned int *pnum_streams,
1184 struct stream_struct **pstreams)
1186 NTSTATUS status;
1187 struct smb2_hnd *ph = NULL;
1188 uint16_t fnum = 0xffff;
1189 DATA_BLOB outbuf = data_blob_null;
1190 TALLOC_CTX *frame = talloc_stackframe();
1192 if (smbXcli_conn_has_async_calls(cli->conn)) {
1194 * Can't use sync call while an async call is in flight
1196 status = NT_STATUS_INVALID_PARAMETER;
1197 goto fail;
1200 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1201 status = NT_STATUS_INVALID_PARAMETER;
1202 goto fail;
1205 status = get_fnum_from_path(cli,
1206 name,
1207 FILE_READ_ATTRIBUTES,
1208 &fnum);
1210 if (!NT_STATUS_IS_OK(status)) {
1211 goto fail;
1214 status = map_fnum_to_smb2_handle(cli,
1215 fnum,
1216 &ph);
1217 if (!NT_STATUS_IS_OK(status)) {
1218 goto fail;
1221 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1222 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1224 status = smb2cli_query_info(cli->conn,
1225 cli->timeout,
1226 cli->smb2.session,
1227 cli->smb2.tcon,
1228 1, /* in_info_type */
1229 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1230 0xFFFF, /* in_max_output_length */
1231 NULL, /* in_input_buffer */
1232 0, /* in_additional_info */
1233 0, /* in_flags */
1234 ph->fid_persistent,
1235 ph->fid_volatile,
1236 frame,
1237 &outbuf);
1239 if (!NT_STATUS_IS_OK(status)) {
1240 goto fail;
1243 /* Parse the reply. */
1244 if (!parse_streams_blob(mem_ctx,
1245 outbuf.data,
1246 outbuf.length,
1247 pnum_streams,
1248 pstreams)) {
1249 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1250 goto fail;
1253 fail:
1255 if (fnum != 0xffff) {
1256 cli_smb2_close_fnum(cli, fnum);
1259 TALLOC_FREE(frame);
1260 return status;
1263 /***************************************************************
1264 Wrapper that allows SMB2 to set pathname attributes.
1265 Synchronous only.
1266 ***************************************************************/
1268 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1269 const char *name,
1270 uint16_t attr,
1271 time_t mtime)
1273 NTSTATUS status;
1274 uint16_t fnum = 0xffff;
1275 struct smb2_hnd *ph = NULL;
1276 uint8_t inbuf_store[40];
1277 DATA_BLOB inbuf = data_blob_null;
1278 TALLOC_CTX *frame = talloc_stackframe();
1280 if (smbXcli_conn_has_async_calls(cli->conn)) {
1282 * Can't use sync call while an async call is in flight
1284 status = NT_STATUS_INVALID_PARAMETER;
1285 goto fail;
1288 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1289 status = NT_STATUS_INVALID_PARAMETER;
1290 goto fail;
1293 status = get_fnum_from_path(cli,
1294 name,
1295 FILE_WRITE_ATTRIBUTES,
1296 &fnum);
1298 if (!NT_STATUS_IS_OK(status)) {
1299 goto fail;
1302 status = map_fnum_to_smb2_handle(cli,
1303 fnum,
1304 &ph);
1305 if (!NT_STATUS_IS_OK(status)) {
1306 goto fail;
1309 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1310 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1312 inbuf.data = inbuf_store;
1313 inbuf.length = sizeof(inbuf_store);
1314 data_blob_clear(&inbuf);
1316 SSVAL(inbuf.data, 32, attr);
1317 if (mtime != 0) {
1318 put_long_date((char *)inbuf.data + 16,mtime);
1320 /* Set all the other times to -1. */
1321 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1322 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1323 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1325 status = smb2cli_set_info(cli->conn,
1326 cli->timeout,
1327 cli->smb2.session,
1328 cli->smb2.tcon,
1329 1, /* in_info_type */
1330 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1331 &inbuf, /* in_input_buffer */
1332 0, /* in_additional_info */
1333 ph->fid_persistent,
1334 ph->fid_volatile);
1335 fail:
1337 if (fnum != 0xffff) {
1338 cli_smb2_close_fnum(cli, fnum);
1341 TALLOC_FREE(frame);
1342 return status;
1345 /***************************************************************
1346 Wrapper that allows SMB2 to set file handle times.
1347 Synchronous only.
1348 ***************************************************************/
1350 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1351 uint16_t fnum,
1352 time_t change_time,
1353 time_t access_time,
1354 time_t write_time)
1356 NTSTATUS status;
1357 struct smb2_hnd *ph = NULL;
1358 uint8_t inbuf_store[40];
1359 DATA_BLOB inbuf = data_blob_null;
1361 if (smbXcli_conn_has_async_calls(cli->conn)) {
1363 * Can't use sync call while an async call is in flight
1365 return NT_STATUS_INVALID_PARAMETER;
1368 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1369 return NT_STATUS_INVALID_PARAMETER;
1372 status = map_fnum_to_smb2_handle(cli,
1373 fnum,
1374 &ph);
1375 if (!NT_STATUS_IS_OK(status)) {
1376 return status;
1379 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1380 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1382 inbuf.data = inbuf_store;
1383 inbuf.length = sizeof(inbuf_store);
1384 data_blob_clear(&inbuf);
1386 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1387 if (change_time != 0) {
1388 put_long_date((char *)inbuf.data + 24, change_time);
1390 if (access_time != 0) {
1391 put_long_date((char *)inbuf.data + 8, access_time);
1393 if (write_time != 0) {
1394 put_long_date((char *)inbuf.data + 16, write_time);
1397 return smb2cli_set_info(cli->conn,
1398 cli->timeout,
1399 cli->smb2.session,
1400 cli->smb2.tcon,
1401 1, /* in_info_type */
1402 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1403 &inbuf, /* in_input_buffer */
1404 0, /* in_additional_info */
1405 ph->fid_persistent,
1406 ph->fid_volatile);
1409 /***************************************************************
1410 Wrapper that allows SMB2 to query disk attributes (size).
1411 Synchronous only.
1412 ***************************************************************/
1414 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
1416 NTSTATUS status;
1417 uint16_t fnum = 0xffff;
1418 DATA_BLOB outbuf = data_blob_null;
1419 struct smb2_hnd *ph = NULL;
1420 uint32_t sectors_per_unit = 0;
1421 uint32_t bytes_per_sector = 0;
1422 uint64_t total_size = 0;
1423 uint64_t size_free = 0;
1424 TALLOC_CTX *frame = talloc_stackframe();
1426 if (smbXcli_conn_has_async_calls(cli->conn)) {
1428 * Can't use sync call while an async call is in flight
1430 status = NT_STATUS_INVALID_PARAMETER;
1431 goto fail;
1434 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1435 status = NT_STATUS_INVALID_PARAMETER;
1436 goto fail;
1439 /* First open the top level directory. */
1440 status = cli_smb2_create_fnum(cli,
1442 0, /* create_flags */
1443 FILE_READ_ATTRIBUTES, /* desired_access */
1444 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1445 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1446 FILE_OPEN, /* create_disposition */
1447 FILE_DIRECTORY_FILE, /* create_options */
1448 &fnum,
1449 NULL);
1451 if (!NT_STATUS_IS_OK(status)) {
1452 goto fail;
1455 status = map_fnum_to_smb2_handle(cli,
1456 fnum,
1457 &ph);
1458 if (!NT_STATUS_IS_OK(status)) {
1459 goto fail;
1462 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1463 level 3 (SMB_FS_SIZE_INFORMATION). */
1465 status = smb2cli_query_info(cli->conn,
1466 cli->timeout,
1467 cli->smb2.session,
1468 cli->smb2.tcon,
1469 2, /* in_info_type */
1470 3, /* in_file_info_class */
1471 0xFFFF, /* in_max_output_length */
1472 NULL, /* in_input_buffer */
1473 0, /* in_additional_info */
1474 0, /* in_flags */
1475 ph->fid_persistent,
1476 ph->fid_volatile,
1477 frame,
1478 &outbuf);
1479 if (!NT_STATUS_IS_OK(status)) {
1480 goto fail;
1483 /* Parse the reply. */
1484 if (outbuf.length != 24) {
1485 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1486 goto fail;
1489 total_size = BVAL(outbuf.data, 0);
1490 size_free = BVAL(outbuf.data, 8);
1491 sectors_per_unit = IVAL(outbuf.data, 16);
1492 bytes_per_sector = IVAL(outbuf.data, 20);
1494 if (bsize) {
1495 *bsize = (int)(sectors_per_unit * bytes_per_sector);
1497 if (total) {
1498 *total = (int)total_size;
1500 if (avail) {
1501 *avail = (int)size_free;
1504 status = NT_STATUS_OK;
1506 fail:
1508 if (fnum != 0xffff) {
1509 cli_smb2_close_fnum(cli, fnum);
1512 TALLOC_FREE(frame);
1513 return status;
1516 /***************************************************************
1517 Wrapper that allows SMB2 to query a security descriptor.
1518 Synchronous only.
1519 ***************************************************************/
1521 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
1522 uint16_t fnum,
1523 uint32_t sec_info,
1524 TALLOC_CTX *mem_ctx,
1525 struct security_descriptor **ppsd)
1527 NTSTATUS status;
1528 DATA_BLOB outbuf = data_blob_null;
1529 struct smb2_hnd *ph = NULL;
1530 struct security_descriptor *lsd = NULL;
1531 TALLOC_CTX *frame = talloc_stackframe();
1533 if (smbXcli_conn_has_async_calls(cli->conn)) {
1535 * Can't use sync call while an async call is in flight
1537 status = NT_STATUS_INVALID_PARAMETER;
1538 goto fail;
1541 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1542 status = NT_STATUS_INVALID_PARAMETER;
1543 goto fail;
1546 status = map_fnum_to_smb2_handle(cli,
1547 fnum,
1548 &ph);
1549 if (!NT_STATUS_IS_OK(status)) {
1550 goto fail;
1553 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1555 status = smb2cli_query_info(cli->conn,
1556 cli->timeout,
1557 cli->smb2.session,
1558 cli->smb2.tcon,
1559 3, /* in_info_type */
1560 0, /* in_file_info_class */
1561 0xFFFF, /* in_max_output_length */
1562 NULL, /* in_input_buffer */
1563 sec_info, /* in_additional_info */
1564 0, /* in_flags */
1565 ph->fid_persistent,
1566 ph->fid_volatile,
1567 frame,
1568 &outbuf);
1570 if (!NT_STATUS_IS_OK(status)) {
1571 goto fail;
1574 /* Parse the reply. */
1575 status = unmarshall_sec_desc(mem_ctx,
1576 outbuf.data,
1577 outbuf.length,
1578 &lsd);
1580 if (!NT_STATUS_IS_OK(status)) {
1581 goto fail;
1584 if (ppsd != NULL) {
1585 *ppsd = lsd;
1586 } else {
1587 TALLOC_FREE(lsd);
1590 fail:
1592 TALLOC_FREE(frame);
1593 return status;
1596 /***************************************************************
1597 Wrapper that allows SMB2 to set a security descriptor.
1598 Synchronous only.
1599 ***************************************************************/
1601 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
1602 uint16_t fnum,
1603 uint32_t sec_info,
1604 const struct security_descriptor *sd)
1606 NTSTATUS status;
1607 DATA_BLOB inbuf = data_blob_null;
1608 struct smb2_hnd *ph = NULL;
1609 TALLOC_CTX *frame = talloc_stackframe();
1611 if (smbXcli_conn_has_async_calls(cli->conn)) {
1613 * Can't use sync call while an async call is in flight
1615 status = NT_STATUS_INVALID_PARAMETER;
1616 goto fail;
1619 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1620 status = NT_STATUS_INVALID_PARAMETER;
1621 goto fail;
1624 status = map_fnum_to_smb2_handle(cli,
1625 fnum,
1626 &ph);
1627 if (!NT_STATUS_IS_OK(status)) {
1628 goto fail;
1631 status = marshall_sec_desc(frame,
1633 &inbuf.data,
1634 &inbuf.length);
1636 if (!NT_STATUS_IS_OK(status)) {
1637 goto fail;
1640 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1642 status = smb2cli_set_info(cli->conn,
1643 cli->timeout,
1644 cli->smb2.session,
1645 cli->smb2.tcon,
1646 3, /* in_info_type */
1647 0, /* in_file_info_class */
1648 &inbuf, /* in_input_buffer */
1649 sec_info, /* in_additional_info */
1650 ph->fid_persistent,
1651 ph->fid_volatile);
1653 fail:
1655 TALLOC_FREE(frame);
1656 return status;
1659 /***************************************************************
1660 Wrapper that allows SMB2 to rename a file.
1661 Synchronous only.
1662 ***************************************************************/
1664 NTSTATUS cli_smb2_rename(struct cli_state *cli,
1665 const char *fname_src,
1666 const char *fname_dst)
1668 NTSTATUS status;
1669 DATA_BLOB inbuf = data_blob_null;
1670 uint16_t fnum = 0xffff;
1671 struct smb2_hnd *ph = NULL;
1672 smb_ucs2_t *converted_str = NULL;
1673 size_t converted_size_bytes = 0;
1674 size_t namelen = 0;
1675 TALLOC_CTX *frame = talloc_stackframe();
1677 if (smbXcli_conn_has_async_calls(cli->conn)) {
1679 * Can't use sync call while an async call is in flight
1681 status = NT_STATUS_INVALID_PARAMETER;
1682 goto fail;
1685 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1686 status = NT_STATUS_INVALID_PARAMETER;
1687 goto fail;
1690 status = get_fnum_from_path(cli,
1691 fname_src,
1692 DELETE_ACCESS,
1693 &fnum);
1695 if (!NT_STATUS_IS_OK(status)) {
1696 goto fail;
1699 status = map_fnum_to_smb2_handle(cli,
1700 fnum,
1701 &ph);
1702 if (!NT_STATUS_IS_OK(status)) {
1703 goto fail;
1706 /* SMB2 is pickier about pathnames. Ensure it doesn't
1707 start in a '\' */
1708 if (*fname_dst == '\\') {
1709 fname_dst++;
1712 /* SMB2 is pickier about pathnames. Ensure it doesn't
1713 end in a '\' */
1714 namelen = strlen(fname_dst);
1715 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
1716 char *modname = talloc_strdup(frame, fname_dst);
1717 modname[namelen-1] = '\0';
1718 fname_dst = modname;
1721 if (!push_ucs2_talloc(frame,
1722 &converted_str,
1723 fname_dst,
1724 &converted_size_bytes)) {
1725 status = NT_STATUS_INVALID_PARAMETER;
1726 goto fail;
1729 /* W2K8 insists the dest name is not null
1730 terminated. Remove the last 2 zero bytes
1731 and reduce the name length. */
1733 if (converted_size_bytes < 2) {
1734 status = NT_STATUS_INVALID_PARAMETER;
1735 goto fail;
1737 converted_size_bytes -= 2;
1739 inbuf = data_blob_talloc_zero(frame,
1740 20 + converted_size_bytes);
1741 if (inbuf.data == NULL) {
1742 status = NT_STATUS_NO_MEMORY;
1743 goto fail;
1746 SIVAL(inbuf.data, 16, converted_size_bytes);
1747 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
1749 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
1750 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
1752 status = smb2cli_set_info(cli->conn,
1753 cli->timeout,
1754 cli->smb2.session,
1755 cli->smb2.tcon,
1756 1, /* in_info_type */
1757 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
1758 &inbuf, /* in_input_buffer */
1759 0, /* in_additional_info */
1760 ph->fid_persistent,
1761 ph->fid_volatile);
1763 fail:
1765 if (fnum != 0xffff) {
1766 cli_smb2_close_fnum(cli, fnum);
1769 TALLOC_FREE(frame);
1770 return status;
1773 /***************************************************************
1774 Wrapper that allows SMB2 to set an EA on a fnum.
1775 Synchronous only.
1776 ***************************************************************/
1778 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
1779 uint16_t fnum,
1780 const char *ea_name,
1781 const char *ea_val,
1782 size_t ea_len)
1784 NTSTATUS status;
1785 DATA_BLOB inbuf = data_blob_null;
1786 size_t bloblen = 0;
1787 char *ea_name_ascii = NULL;
1788 size_t namelen = 0;
1789 struct smb2_hnd *ph = NULL;
1790 TALLOC_CTX *frame = talloc_stackframe();
1792 if (smbXcli_conn_has_async_calls(cli->conn)) {
1794 * Can't use sync call while an async call is in flight
1796 status = NT_STATUS_INVALID_PARAMETER;
1797 goto fail;
1800 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1801 status = NT_STATUS_INVALID_PARAMETER;
1802 goto fail;
1805 status = map_fnum_to_smb2_handle(cli,
1806 fnum,
1807 &ph);
1808 if (!NT_STATUS_IS_OK(status)) {
1809 goto fail;
1812 /* Marshall the SMB2 EA data. */
1813 if (ea_len > 0xFFFF) {
1814 status = NT_STATUS_INVALID_PARAMETER;
1815 goto fail;
1818 if (!push_ascii_talloc(frame,
1819 &ea_name_ascii,
1820 ea_name,
1821 &namelen)) {
1822 status = NT_STATUS_INVALID_PARAMETER;
1823 goto fail;
1826 if (namelen < 2 || namelen > 0xFF) {
1827 status = NT_STATUS_INVALID_PARAMETER;
1828 goto fail;
1831 bloblen = 8 + ea_len + namelen;
1832 /* Round up to a 4 byte boundary. */
1833 bloblen = ((bloblen + 3)&~3);
1835 inbuf = data_blob_talloc_zero(frame, bloblen);
1836 if (inbuf.data == NULL) {
1837 status = NT_STATUS_NO_MEMORY;
1838 goto fail;
1840 /* namelen doesn't include the NULL byte. */
1841 SCVAL(inbuf.data, 5, namelen - 1);
1842 SSVAL(inbuf.data, 6, ea_len);
1843 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
1844 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
1846 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1847 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
1849 status = smb2cli_set_info(cli->conn,
1850 cli->timeout,
1851 cli->smb2.session,
1852 cli->smb2.tcon,
1853 1, /* in_info_type */
1854 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
1855 &inbuf, /* in_input_buffer */
1856 0, /* in_additional_info */
1857 ph->fid_persistent,
1858 ph->fid_volatile);
1860 fail:
1862 TALLOC_FREE(frame);
1863 return status;
1866 /***************************************************************
1867 Wrapper that allows SMB2 to set an EA on a pathname.
1868 Synchronous only.
1869 ***************************************************************/
1871 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
1872 const char *name,
1873 const char *ea_name,
1874 const char *ea_val,
1875 size_t ea_len)
1877 NTSTATUS status;
1878 uint16_t fnum = 0xffff;
1880 if (smbXcli_conn_has_async_calls(cli->conn)) {
1882 * Can't use sync call while an async call is in flight
1884 status = NT_STATUS_INVALID_PARAMETER;
1885 goto fail;
1888 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1889 status = NT_STATUS_INVALID_PARAMETER;
1890 goto fail;
1893 status = get_fnum_from_path(cli,
1894 name,
1895 FILE_WRITE_EA,
1896 &fnum);
1898 if (!NT_STATUS_IS_OK(status)) {
1899 goto fail;
1902 status = cli_set_ea_fnum(cli,
1903 fnum,
1904 ea_name,
1905 ea_val,
1906 ea_len);
1907 if (!NT_STATUS_IS_OK(status)) {
1908 goto fail;
1911 fail:
1913 if (fnum != 0xffff) {
1914 cli_smb2_close_fnum(cli, fnum);
1917 return status;
1920 /***************************************************************
1921 Wrapper that allows SMB2 to get an EA list on a pathname.
1922 Synchronous only.
1923 ***************************************************************/
1925 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
1926 const char *name,
1927 TALLOC_CTX *ctx,
1928 size_t *pnum_eas,
1929 struct ea_struct **pea_array)
1931 NTSTATUS status;
1932 uint16_t fnum = 0xffff;
1933 DATA_BLOB outbuf = data_blob_null;
1934 struct smb2_hnd *ph = NULL;
1935 struct ea_list *ea_list = NULL;
1936 struct ea_list *eal = NULL;
1937 size_t ea_count = 0;
1938 TALLOC_CTX *frame = talloc_stackframe();
1940 *pnum_eas = 0;
1941 *pea_array = NULL;
1943 if (smbXcli_conn_has_async_calls(cli->conn)) {
1945 * Can't use sync call while an async call is in flight
1947 status = NT_STATUS_INVALID_PARAMETER;
1948 goto fail;
1951 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1952 status = NT_STATUS_INVALID_PARAMETER;
1953 goto fail;
1956 status = get_fnum_from_path(cli,
1957 name,
1958 FILE_READ_EA,
1959 &fnum);
1961 if (!NT_STATUS_IS_OK(status)) {
1962 goto fail;
1965 status = map_fnum_to_smb2_handle(cli,
1966 fnum,
1967 &ph);
1968 if (!NT_STATUS_IS_OK(status)) {
1969 goto fail;
1972 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1973 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
1975 status = smb2cli_query_info(cli->conn,
1976 cli->timeout,
1977 cli->smb2.session,
1978 cli->smb2.tcon,
1979 1, /* in_info_type */
1980 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
1981 0xFFFF, /* in_max_output_length */
1982 NULL, /* in_input_buffer */
1983 0, /* in_additional_info */
1984 0, /* in_flags */
1985 ph->fid_persistent,
1986 ph->fid_volatile,
1987 frame,
1988 &outbuf);
1990 if (!NT_STATUS_IS_OK(status)) {
1991 goto fail;
1994 /* Parse the reply. */
1995 ea_list = read_nttrans_ea_list(ctx,
1996 (const char *)outbuf.data,
1997 outbuf.length);
1998 if (ea_list == NULL) {
1999 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2000 goto fail;
2003 /* Convert to an array. */
2004 for (eal = ea_list; eal; eal = eal->next) {
2005 ea_count++;
2008 if (ea_count) {
2009 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2010 if (*pea_array == NULL) {
2011 status = NT_STATUS_NO_MEMORY;
2012 goto fail;
2014 ea_count = 0;
2015 for (eal = ea_list; eal; eal = eal->next) {
2016 (*pea_array)[ea_count++] = ea_list->ea;
2018 *pnum_eas = ea_count;
2021 fail:
2023 if (fnum != 0xffff) {
2024 cli_smb2_close_fnum(cli, fnum);
2027 TALLOC_FREE(frame);
2028 return status;
2031 struct cli_smb2_read_state {
2032 struct tevent_context *ev;
2033 struct cli_state *cli;
2034 struct smb2_hnd *ph;
2035 uint64_t start_offset;
2036 uint32_t size;
2037 uint32_t received;
2038 uint8_t *buf;
2041 static void cli_smb2_read_done(struct tevent_req *subreq);
2043 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
2044 struct tevent_context *ev,
2045 struct cli_state *cli,
2046 uint16_t fnum,
2047 off_t offset,
2048 size_t size)
2050 NTSTATUS status;
2051 struct tevent_req *req, *subreq;
2052 struct cli_smb2_read_state *state;
2054 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
2055 if (req == NULL) {
2056 return NULL;
2058 state->ev = ev;
2059 state->cli = cli;
2060 state->start_offset = (uint64_t)offset;
2061 state->size = (uint32_t)size;
2062 state->received = 0;
2063 state->buf = NULL;
2065 status = map_fnum_to_smb2_handle(cli,
2066 fnum,
2067 &state->ph);
2068 if (tevent_req_nterror(req, status)) {
2069 return tevent_req_post(req, ev);
2072 subreq = smb2cli_read_send(state,
2073 state->ev,
2074 state->cli->conn,
2075 state->cli->timeout,
2076 state->cli->smb2.session,
2077 state->cli->smb2.tcon,
2078 state->size,
2079 state->start_offset,
2080 state->ph->fid_persistent,
2081 state->ph->fid_volatile,
2082 0, /* minimum_count */
2083 0); /* remaining_bytes */
2085 if (tevent_req_nomem(subreq, req)) {
2086 return tevent_req_post(req, ev);
2088 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
2089 return req;
2092 static void cli_smb2_read_done(struct tevent_req *subreq)
2094 struct tevent_req *req = tevent_req_callback_data(
2095 subreq, struct tevent_req);
2096 struct cli_smb2_read_state *state = tevent_req_data(
2097 req, struct cli_smb2_read_state);
2098 NTSTATUS status;
2100 status = smb2cli_read_recv(subreq, state,
2101 &state->buf, &state->received);
2102 if (tevent_req_nterror(req, status)) {
2103 return;
2106 if (state->received > state->size) {
2107 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2108 return;
2111 tevent_req_done(req);
2114 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
2115 ssize_t *received,
2116 uint8_t **rcvbuf)
2118 NTSTATUS status;
2119 struct cli_smb2_read_state *state = tevent_req_data(
2120 req, struct cli_smb2_read_state);
2122 if (tevent_req_is_nterror(req, &status)) {
2123 return status;
2126 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2127 * better make sure that you copy it away before you talloc_free(req).
2128 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2130 *received = (ssize_t)state->received;
2131 *rcvbuf = state->buf;
2132 return NT_STATUS_OK;
2135 struct cli_smb2_write_state {
2136 struct tevent_context *ev;
2137 struct cli_state *cli;
2138 struct smb2_hnd *ph;
2139 uint32_t flags;
2140 const uint8_t *buf;
2141 uint64_t offset;
2142 uint32_t size;
2143 uint32_t written;
2146 static void cli_smb2_write_written(struct tevent_req *req);
2148 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
2149 struct tevent_context *ev,
2150 struct cli_state *cli,
2151 uint16_t fnum,
2152 uint16_t mode,
2153 const uint8_t *buf,
2154 off_t offset,
2155 size_t size)
2157 NTSTATUS status;
2158 struct tevent_req *req, *subreq = NULL;
2159 struct cli_smb2_write_state *state = NULL;
2161 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
2162 if (req == NULL) {
2163 return NULL;
2165 state->ev = ev;
2166 state->cli = cli;
2167 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2168 state->flags = (uint32_t)mode;
2169 state->buf = buf;
2170 state->offset = (uint64_t)offset;
2171 state->size = (uint32_t)size;
2172 state->written = 0;
2174 status = map_fnum_to_smb2_handle(cli,
2175 fnum,
2176 &state->ph);
2177 if (tevent_req_nterror(req, status)) {
2178 return tevent_req_post(req, ev);
2181 subreq = smb2cli_write_send(state,
2182 state->ev,
2183 state->cli->conn,
2184 state->cli->timeout,
2185 state->cli->smb2.session,
2186 state->cli->smb2.tcon,
2187 state->size,
2188 state->offset,
2189 state->ph->fid_persistent,
2190 state->ph->fid_volatile,
2191 0, /* remaining_bytes */
2192 state->flags, /* flags */
2193 state->buf);
2195 if (tevent_req_nomem(subreq, req)) {
2196 return tevent_req_post(req, ev);
2198 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
2199 return req;
2202 static void cli_smb2_write_written(struct tevent_req *subreq)
2204 struct tevent_req *req = tevent_req_callback_data(
2205 subreq, struct tevent_req);
2206 struct cli_smb2_write_state *state = tevent_req_data(
2207 req, struct cli_smb2_write_state);
2208 NTSTATUS status;
2209 uint32_t written;
2211 status = smb2cli_write_recv(subreq, &written);
2212 TALLOC_FREE(subreq);
2213 if (tevent_req_nterror(req, status)) {
2214 return;
2217 state->written = written;
2219 tevent_req_done(req);
2222 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
2223 size_t *pwritten)
2225 struct cli_smb2_write_state *state = tevent_req_data(
2226 req, struct cli_smb2_write_state);
2227 NTSTATUS status;
2229 if (tevent_req_is_nterror(req, &status)) {
2230 tevent_req_received(req);
2231 return status;
2234 if (pwritten != NULL) {
2235 *pwritten = (size_t)state->written;
2237 tevent_req_received(req);
2238 return NT_STATUS_OK;
2241 /***************************************************************
2242 Wrapper that allows SMB2 async write using an fnum.
2243 This is mostly cut-and-paste from Volker's code inside
2244 source3/libsmb/clireadwrite.c, adapted for SMB2.
2246 Done this way so I can reuse all the logic inside cli_push()
2247 for free :-).
2248 ***************************************************************/
2250 struct cli_smb2_writeall_state {
2251 struct tevent_context *ev;
2252 struct cli_state *cli;
2253 struct smb2_hnd *ph;
2254 uint32_t flags;
2255 const uint8_t *buf;
2256 uint64_t offset;
2257 uint32_t size;
2258 uint32_t written;
2261 static void cli_smb2_writeall_written(struct tevent_req *req);
2263 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
2264 struct tevent_context *ev,
2265 struct cli_state *cli,
2266 uint16_t fnum,
2267 uint16_t mode,
2268 const uint8_t *buf,
2269 off_t offset,
2270 size_t size)
2272 NTSTATUS status;
2273 struct tevent_req *req, *subreq = NULL;
2274 struct cli_smb2_writeall_state *state = NULL;
2275 uint32_t to_write;
2276 uint32_t max_size;
2277 bool ok;
2279 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
2280 if (req == NULL) {
2281 return NULL;
2283 state->ev = ev;
2284 state->cli = cli;
2285 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2286 state->flags = (uint32_t)mode;
2287 state->buf = buf;
2288 state->offset = (uint64_t)offset;
2289 state->size = (uint32_t)size;
2290 state->written = 0;
2292 status = map_fnum_to_smb2_handle(cli,
2293 fnum,
2294 &state->ph);
2295 if (tevent_req_nterror(req, status)) {
2296 return tevent_req_post(req, ev);
2299 to_write = state->size;
2300 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2301 to_write = MIN(max_size, to_write);
2302 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2303 if (ok) {
2304 to_write = MIN(max_size, to_write);
2307 subreq = smb2cli_write_send(state,
2308 state->ev,
2309 state->cli->conn,
2310 state->cli->timeout,
2311 state->cli->smb2.session,
2312 state->cli->smb2.tcon,
2313 to_write,
2314 state->offset,
2315 state->ph->fid_persistent,
2316 state->ph->fid_volatile,
2317 0, /* remaining_bytes */
2318 state->flags, /* flags */
2319 state->buf + state->written);
2321 if (tevent_req_nomem(subreq, req)) {
2322 return tevent_req_post(req, ev);
2324 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2325 return req;
2328 static void cli_smb2_writeall_written(struct tevent_req *subreq)
2330 struct tevent_req *req = tevent_req_callback_data(
2331 subreq, struct tevent_req);
2332 struct cli_smb2_writeall_state *state = tevent_req_data(
2333 req, struct cli_smb2_writeall_state);
2334 NTSTATUS status;
2335 uint32_t written, to_write;
2336 uint32_t max_size;
2337 bool ok;
2339 status = smb2cli_write_recv(subreq, &written);
2340 TALLOC_FREE(subreq);
2341 if (tevent_req_nterror(req, status)) {
2342 return;
2345 state->written += written;
2347 if (state->written > state->size) {
2348 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2349 return;
2352 to_write = state->size - state->written;
2354 if (to_write == 0) {
2355 tevent_req_done(req);
2356 return;
2359 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2360 to_write = MIN(max_size, to_write);
2361 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2362 if (ok) {
2363 to_write = MIN(max_size, to_write);
2366 subreq = smb2cli_write_send(state,
2367 state->ev,
2368 state->cli->conn,
2369 state->cli->timeout,
2370 state->cli->smb2.session,
2371 state->cli->smb2.tcon,
2372 to_write,
2373 state->offset + state->written,
2374 state->ph->fid_persistent,
2375 state->ph->fid_volatile,
2376 0, /* remaining_bytes */
2377 state->flags, /* flags */
2378 state->buf + state->written);
2380 if (tevent_req_nomem(subreq, req)) {
2381 return;
2383 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2386 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
2387 size_t *pwritten)
2389 struct cli_smb2_writeall_state *state = tevent_req_data(
2390 req, struct cli_smb2_writeall_state);
2391 NTSTATUS status;
2393 if (tevent_req_is_nterror(req, &status)) {
2394 return status;
2396 if (pwritten != NULL) {
2397 *pwritten = (size_t)state->written;
2399 return NT_STATUS_OK;