2 Unix SMB/CIFS implementation.
4 Copyright (C) Jeremy Allison 2022.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "torture/proto.h"
24 #include "../libcli/smb/smbXcli_base.h"
25 #include "libcli/security/security.h"
26 #include "libsmb/proto.h"
27 #include "auth/credentials/credentials.h"
28 #include "auth/gensec/gensec.h"
29 #include "auth_generic.h"
30 #include "../librpc/ndr/libndr.h"
31 #include "libsmb/clirap.h"
32 #include "async_smb.h"
33 #include "../lib/util/tevent_ntstatus.h"
34 #include "lib/util/time_basic.h"
36 extern fstring host
, workgroup
, share
, password
, username
, myname
;
37 extern struct cli_credentials
*torture_creds
;
40 * Open an SMB1 file readonly and return the create time.
42 static NTSTATUS
get_smb1_crtime(struct cli_state
*cli
,
44 struct timespec
*pcrtime
)
48 struct timespec crtime
= {0};
54 status
= smb1cli_ntcreatex(cli
->conn
,
60 OPLOCK_NONE
, /* CreatFlags */
61 0, /* RootDirectoryFid */
64 SEC_FILE_READ_ATTRIBUTE
, /* DesiredAccess */
65 0, /* AllocationSize */
66 FILE_ATTRIBUTE_NORMAL
, /* FileAttributes */
69 FILE_SHARE_DELETE
, /* ShareAccess */
70 FILE_OPEN
, /* CreateDisposition */
71 0, /* CreateOptions */
72 2, /* ImpersonationLevel */
73 0, /* SecurityFlags */
75 if (!NT_STATUS_IS_OK(status
)) {
80 * Get the create time. Note - we can use
81 * a higher-level cli_XXX function here
82 * for SMB1 as cli_qfileinfo_basic()
83 * doesn't use any pathnames, only fnums
84 * so it isn't affected by DFS pathnames.
86 status
= cli_qfileinfo_basic(cli
,
90 &crtime
, /* create_time */
91 NULL
, /* access_time */
92 NULL
, /* write_time */
93 NULL
, /* change_time */
95 if (NT_STATUS_IS_OK(status
)) {
99 (void)smb1cli_close(cli
->conn
,
105 0); /* last_modified */
110 * Check a crtime matches a given SMB1 path.
112 static bool smb1_crtime_matches(struct cli_state
*cli
,
113 const char *match_pathname
,
114 struct timespec crtime_tomatch
,
115 const char *test_pathname
)
117 struct timespec test_crtime
= { 0 };
121 status
= get_smb1_crtime(cli
,
124 if (!NT_STATUS_IS_OK(status
)) {
125 printf("%s: Failed to get crtime "
132 equal
= (timespec_compare(&test_crtime
, &crtime_tomatch
) == 0);
134 struct timeval_buf test_buf
;
135 struct timeval_buf tomatch_buf
;
136 printf("%s: crtime mismatch "
137 "%s:crtime_tomatch=%s, %s:test_crtime = %s\n",
140 timespec_string_buf(&crtime_tomatch
,
144 timespec_string_buf(&test_crtime
,
153 * Delete an SMB1 file on a DFS share.
155 static NTSTATUS
smb1_dfs_delete(struct cli_state
*cli
,
156 const char *pathname
)
165 status
= smb1cli_ntcreatex(cli
->conn
,
171 OPLOCK_NONE
, /* CreatFlags */
172 0, /* RootDirectoryFid */
174 SEC_STD_DELETE
, /* DesiredAccess */
175 0, /* AllocationSize */
176 FILE_ATTRIBUTE_NORMAL
, /* FileAttributes */
179 FILE_SHARE_DELETE
, /* ShareAccess */
180 FILE_OPEN
, /* CreateDisposition */
181 0, /* CreateOptions */
182 2, /* ImpersonationLevel */
183 0, /* SecurityFlags */
185 if (!NT_STATUS_IS_OK(status
)) {
190 * Set delete on close. Note - we can use
191 * a higher-level cli_XXX function here
192 * for SMB1 as cli_nt_delete_on_close()
193 * doesn't use any pathnames, only fnums
194 * so it isn't affected by DFS pathnames.
198 status
= cli_nt_delete_on_close(cli
, fnum
, 1);
199 if (!NT_STATUS_IS_OK(status
)) {
202 return smb1cli_close(cli
->conn
,
208 0); /* last_modified */
211 static void smb1_mv_done(struct tevent_req
*subreq
);
213 struct smb1_mv_state
{
217 static struct tevent_req
*smb1_mv_send(TALLOC_CTX
*mem_ctx
,
218 struct tevent_context
*ev
,
219 struct cli_state
*cli
,
220 const char *src_dfs_name
,
221 const char *target_name
)
223 uint8_t *bytes
= NULL
;
224 struct tevent_req
*req
= NULL
;
225 struct tevent_req
*subreq
= NULL
;
226 struct smb1_mv_state
*state
= NULL
;
228 req
= tevent_req_create(mem_ctx
,
230 struct smb1_mv_state
);
235 PUSH_LE_U16(state
->vwv
,
237 FILE_ATTRIBUTE_SYSTEM
|
238 FILE_ATTRIBUTE_HIDDEN
|
239 FILE_ATTRIBUTE_DIRECTORY
);
241 bytes
= talloc_array(state
, uint8_t, 1);
242 if (tevent_req_nomem(bytes
, req
)) {
243 return tevent_req_post(req
, ev
);
246 bytes
= smb_bytes_push_str(bytes
,
247 smbXcli_conn_use_unicode(cli
->conn
),
249 strlen(src_dfs_name
)+1,
251 if (tevent_req_nomem(bytes
, req
)) {
252 return tevent_req_post(req
, ev
);
255 bytes
= talloc_realloc(state
,
258 talloc_get_size(bytes
)+1);
259 if (tevent_req_nomem(bytes
, req
)) {
260 return tevent_req_post(req
, ev
);
263 bytes
[talloc_get_size(bytes
)-1] = 4;
264 bytes
= smb_bytes_push_str(bytes
,
265 smbXcli_conn_use_unicode(cli
->conn
),
267 strlen(target_name
)+1,
269 if (tevent_req_nomem(bytes
, req
)) {
270 return tevent_req_post(req
, ev
);
273 subreq
= cli_smb_send(state
,
277 0, /* additional_flags */
278 0, /* additional_flags2 */
281 talloc_get_size(bytes
),
283 if (tevent_req_nomem(subreq
, req
)) {
284 return tevent_req_post(req
, ev
);
286 tevent_req_set_callback(subreq
, smb1_mv_done
, req
);
290 static void smb1_mv_done(struct tevent_req
*subreq
)
292 NTSTATUS status
= cli_smb_recv(subreq
,
300 tevent_req_simple_finish_ntstatus(subreq
,
304 static NTSTATUS
smb1_mv_recv(struct tevent_req
*req
)
306 return tevent_req_simple_recv_ntstatus(req
);
310 * Rename an SMB1 file on a DFS share. SMBmv version.
312 static NTSTATUS
smb1_mv(struct cli_state
*cli
,
313 const char *src_dfs_name
,
314 const char *target_name
)
316 TALLOC_CTX
*frame
= NULL
;
317 struct tevent_context
*ev
;
318 struct tevent_req
*req
;
321 frame
= talloc_stackframe();
323 ev
= samba_tevent_context_init(frame
);
325 status
= NT_STATUS_NO_MEMORY
;
329 req
= smb1_mv_send(frame
,
335 status
= NT_STATUS_NO_MEMORY
;
339 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
343 status
= smb1_mv_recv(req
);
351 static bool test_smb1_mv(struct cli_state
*cli
,
352 const char *src_dfs_name
)
354 struct timespec test_timespec
= { 0 };
357 status
= smb1_mv(cli
,
359 "BAD\\BAD\\renamed_file");
360 if (!NT_STATUS_IS_OK(status
)) {
361 printf("%s:%d SMBmv of %s -> %s should succeed "
366 "BAD\\BAD\\renamed_file",
371 /* Ensure we did rename. */
372 status
= get_smb1_crtime(cli
,
373 "BAD\\BAD\\renamed_file",
375 if (!NT_STATUS_IS_OK(status
)) {
376 printf("%s:%d Failed to get crtime "
380 "BAD\\BAD\\renamed_file",
386 status
= smb1_mv(cli
,
387 "BAD\\BAD\\renamed_file",
389 if (!NT_STATUS_IS_OK(status
)) {
390 printf("%s:%d SMBmv of %s -> %s should succeed "
394 "BAD\\BAD\\renamed_file",
400 /* Ensure we did put it back. */
401 status
= get_smb1_crtime(cli
,
404 if (!NT_STATUS_IS_OK(status
)) {
405 printf("%s:%d Failed to get crtime "
414 /* Try with a non-DFS name. */
415 status
= smb1_mv(cli
,
418 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_PATH_SYNTAX_BAD
)) {
419 /* Fails I think as target becomes "" on server. */
420 printf("%s:%d SMBmv of %s -> %s should get "
421 "NT_STATUS_OBJECT_PATH_SYNTAX_BAD got %s\n",
430 /* Try with a non-DFS name. */
431 status
= smb1_mv(cli
,
433 "BAD\\renamed_file");
434 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_PATH_SYNTAX_BAD
)) {
435 /* Fails I think as target becomes "" on server. */
436 printf("%s:%d SMBmv of %s -> %s should get "
437 "NT_STATUS_OBJECT_PATH_SYNTAX_BAD got %s\n",
448 static void smb1_setpathinfo_done(struct tevent_req
*subreq
);
450 struct smb1_setpathinfo_state
{
456 static struct tevent_req
*smb1_setpathinfo_send(TALLOC_CTX
*mem_ctx
,
457 struct tevent_context
*ev
,
458 struct cli_state
*cli
,
459 const char *src_dfs_name
,
460 const char *target_name
,
463 struct tevent_req
*req
= NULL
;
464 struct tevent_req
*subreq
= NULL
;
465 struct smb1_setpathinfo_state
*state
= NULL
;
466 smb_ucs2_t
*converted_str
= NULL
;
467 size_t converted_size_bytes
= 0;
470 req
= tevent_req_create(mem_ctx
,
472 struct smb1_setpathinfo_state
);
477 PUSH_LE_U16(&state
->setup
, 0, TRANSACT2_SETPATHINFO
);
479 state
->param
= talloc_zero_array(state
, uint8_t, 6);
480 if (tevent_req_nomem(state
->param
, req
)) {
481 return tevent_req_post(req
, ev
);
483 PUSH_LE_U16(state
->param
, 0, info_level
);
485 state
->param
= trans2_bytes_push_str(state
->param
,
486 smbXcli_conn_use_unicode(cli
->conn
),
488 strlen(src_dfs_name
)+1,
490 if (tevent_req_nomem(state
->param
, req
)) {
491 return tevent_req_post(req
, ev
);
494 ok
= push_ucs2_talloc(state
,
497 &converted_size_bytes
);
499 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
500 return tevent_req_post(req
, ev
);
504 * W2K8 insists the dest name is not null
505 * terminated. Remove the last 2 zero bytes
506 * and reduce the name length.
509 if (converted_size_bytes
< 2) {
510 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
511 return tevent_req_post(req
, ev
);
513 converted_size_bytes
-= 2;
515 state
->data
= talloc_zero_array(state
,
517 12 + converted_size_bytes
);
518 if (tevent_req_nomem(state
->data
, req
)) {
519 return tevent_req_post(req
, ev
);
522 SIVAL(state
->data
, 8, converted_size_bytes
);
523 memcpy(state
->data
+ 12, converted_str
, converted_size_bytes
);
525 subreq
= cli_trans_send(state
, /* mem ctx. */
528 0,/* additional_flags2 */
529 SMBtrans2
, /* cmd. */
530 NULL
,/* pipe name. */
534 &state
->setup
,/* setup. */
535 1,/* num setup uint16_t words. */
536 0,/* max returned setup. */
537 state
->param
,/* param. */
538 talloc_get_size(state
->param
),/* num param. */
539 2,/* max returned param. */
540 state
->data
,/* data. */
541 talloc_get_size(state
->data
),/* num data. */
542 0);/* max returned data. */
544 if (tevent_req_nomem(subreq
, req
)) {
545 return tevent_req_post(req
, ev
);
547 tevent_req_set_callback(subreq
, smb1_setpathinfo_done
, req
);
551 static void smb1_setpathinfo_done(struct tevent_req
*subreq
)
553 NTSTATUS status
= cli_trans_recv(subreq
,
565 tevent_req_simple_finish_ntstatus(subreq
,
569 static NTSTATUS
smb1_setpathinfo_recv(struct tevent_req
*req
)
571 return tevent_req_simple_recv_ntstatus(req
);
575 * Rename or hardlink an SMB1 file on a DFS share. SMB1 setpathinfo
576 * (pathnames only) version.
578 static NTSTATUS
smb1_setpathinfo(struct cli_state
*cli
,
579 const char *src_dfs_name
,
580 const char *target_name
,
583 TALLOC_CTX
*frame
= NULL
;
584 struct tevent_context
*ev
;
585 struct tevent_req
*req
;
588 frame
= talloc_stackframe();
590 ev
= samba_tevent_context_init(frame
);
592 status
= NT_STATUS_NO_MEMORY
;
596 req
= smb1_setpathinfo_send(frame
,
603 status
= NT_STATUS_NO_MEMORY
;
607 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
611 status
= smb1_setpathinfo_recv(req
);
619 static NTSTATUS
smb1_setpathinfo_rename(struct cli_state
*cli
,
620 const char *src_dfs_name
,
621 const char *target_name
)
623 return smb1_setpathinfo(cli
,
626 SMB_FILE_RENAME_INFORMATION
);
629 static bool test_smb1_setpathinfo_rename(struct cli_state
*cli
,
630 const char *src_dfs_name
)
632 struct timespec test_crtime
= { 0 };
634 const char *putback_path
= NULL
;
637 * On Windows, setpathinfo rename where the target contains
638 * any directory separator returns STATUS_NOT_SUPPORTED.
640 * MS-SMB behavior note: <133> Section 3.3.5.10.6:
642 * "If the file name pointed to by the FileName parameter of the
643 * FILE_RENAME_INFORMATION structure contains a separator character,
644 * then the request fails with STATUS_NOT_SUPPORTED."
646 status
= smb1_setpathinfo_rename(cli
,
648 "BAD\\BAD\\renamed_file");
649 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)) {
650 printf("%s:%d SMB1 setpathinfo rename of %s -> %s should get "
651 "NT_STATUS_NOT_SUPPORTED got %s\n",
655 "BAD\\BAD\\renamed_file",
660 /* Try with a non-DFS name. */
661 status
= smb1_setpathinfo_rename(cli
,
664 if (!NT_STATUS_IS_OK(status
)) {
665 printf("%s:%d SMB1 setpathinfo rename of %s -> %s "
666 "should succeed got %s\n",
675 /* Ensure we did rename. */
676 status
= get_smb1_crtime(cli
,
677 "BAD\\BAD\\renamed_file",
679 if (!NT_STATUS_IS_OK(status
)) {
680 printf("%s:%d Failed to get crtime "
684 "BAD\\BAD\\renamed_file",
690 * To put it back we need to reverse the DFS-ness of src
691 * and destination paths.
693 putback_path
= strrchr(src_dfs_name
, '\\');
694 if (putback_path
== NULL
) {
695 printf("%s:%d non DFS path %s passed. Internal error\n",
701 /* Walk past the last '\\' */
705 status
= smb1_setpathinfo_rename(cli
,
706 "BAD\\BAD\\renamed_file",
708 if (!NT_STATUS_IS_OK(status
)) {
709 printf("%s:%d SMB1 setpathinfo rename of %s -> %s "
710 "should succeed got %s\n",
713 "BAD\\BAD\\renamed_file",
719 /* Ensure we did rename. */
720 status
= get_smb1_crtime(cli
,
723 if (!NT_STATUS_IS_OK(status
)) {
724 printf("%s:%d Failed to get crtime "
736 static NTSTATUS
smb1_setpathinfo_hardlink(struct cli_state
*cli
,
737 const char *src_dfs_name
,
738 const char *target_name
)
740 return smb1_setpathinfo(cli
,
743 SMB_FILE_LINK_INFORMATION
);
746 static bool test_smb1_setpathinfo_hardlink(struct cli_state
*cli
,
747 const char *src_dfs_name
)
752 * On Windows, setpathinfo rename where the target contains
753 * any directory separator returns STATUS_NOT_SUPPORTED.
755 * MS-SMB behavior note: <133> Section 3.3.5.10.6:
757 * "If the file name pointed to by the FileName parameter of the
758 * FILE_RENAME_INFORMATION structure contains a separator character,
759 * then the request fails with STATUS_NOT_SUPPORTED."
761 * setpathinfo info level SMB_FILE_LINK_INFORMATION
762 * seems to do the same, but this could be an artifact
763 * of the Windows version tested (Win2K8). I will
764 * revisit this when I'm able to test against
765 * a later Windows version with a DFS server.
767 status
= smb1_setpathinfo_hardlink(cli
,
770 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)) {
771 printf("%s:%d SMB1 setpathinfo hardlink of %s -> %s should get "
772 "NT_STATUS_NOT_SUPPORTED got %s\n",
781 /* Try with a non-DFS name. */
783 * At least on Windows 2008 this also fails with
784 * NT_STATUS_NOT_SUPPORTED, leading me to believe
785 * setting hardlinks is only supported via NTrename
788 status
= smb1_setpathinfo_hardlink(cli
,
791 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)) {
792 printf("%s:%d SMB1 setpathinfo hardlink of %s -> %s should get "
793 "NT_STATUS_NOT_SUPPORTED got %s\n",
804 static void smb1_ntrename_done(struct tevent_req
*subreq
);
806 struct smb1_ntrename_state
{
810 static struct tevent_req
*smb1_ntrename_send(TALLOC_CTX
*mem_ctx
,
811 struct tevent_context
*ev
,
812 struct cli_state
*cli
,
813 const char *src_dfs_name
,
814 const char *target_name
,
815 uint16_t rename_flag
)
817 struct tevent_req
*req
= NULL
;
818 struct tevent_req
*subreq
= NULL
;
819 struct smb1_ntrename_state
*state
= NULL
;
820 uint8_t *bytes
= NULL
;
822 req
= tevent_req_create(mem_ctx
,
824 struct smb1_ntrename_state
);
829 PUSH_LE_U16(state
->vwv
,
831 FILE_ATTRIBUTE_SYSTEM
|
832 FILE_ATTRIBUTE_HIDDEN
|
833 FILE_ATTRIBUTE_DIRECTORY
);
834 PUSH_LE_U16(state
->vwv
, 2, rename_flag
);
836 bytes
= talloc_array(state
, uint8_t, 1);
837 if (tevent_req_nomem(bytes
, req
)) {
838 return tevent_req_post(req
, ev
);
842 bytes
= smb_bytes_push_str(bytes
,
843 smbXcli_conn_use_unicode(cli
->conn
),
845 strlen(src_dfs_name
)+1,
847 if (tevent_req_nomem(bytes
, req
)) {
848 return tevent_req_post(req
, ev
);
850 bytes
= talloc_realloc(state
,
853 talloc_get_size(bytes
)+1);
854 if (tevent_req_nomem(bytes
, req
)) {
855 return tevent_req_post(req
, ev
);
858 bytes
[talloc_get_size(bytes
)-1] = 4;
859 bytes
= smb_bytes_push_str(bytes
,
860 smbXcli_conn_use_unicode(cli
->conn
),
862 strlen(target_name
)+1,
864 if (tevent_req_nomem(bytes
, req
)) {
865 return tevent_req_post(req
, ev
);
868 subreq
= cli_smb_send(state
,
872 0, /* additional_flags */
873 0, /* additional_flags2 */
876 talloc_get_size(bytes
),
878 if (tevent_req_nomem(subreq
, req
)) {
879 return tevent_req_post(req
, ev
);
881 tevent_req_set_callback(subreq
, smb1_ntrename_done
, req
);
885 static void smb1_ntrename_done(struct tevent_req
*subreq
)
887 NTSTATUS status
= cli_smb_recv(subreq
,
895 tevent_req_simple_finish_ntstatus(subreq
, status
);
898 static NTSTATUS
smb1_ntrename_recv(struct tevent_req
*req
)
900 return tevent_req_simple_recv_ntstatus(req
);
904 * Rename or hardlink an SMB1 file on a DFS share. SMB1 ntrename version.
907 static NTSTATUS
smb1_ntrename(struct cli_state
*cli
,
908 const char *src_dfs_name
,
909 const char *target_name
,
910 uint16_t rename_flag
)
912 TALLOC_CTX
*frame
= NULL
;
913 struct tevent_context
*ev
;
914 struct tevent_req
*req
;
917 frame
= talloc_stackframe();
919 ev
= samba_tevent_context_init(frame
);
921 status
= NT_STATUS_NO_MEMORY
;
925 req
= smb1_ntrename_send(frame
,
932 status
= NT_STATUS_NO_MEMORY
;
936 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
940 status
= smb1_ntrename_recv(req
);
948 * Rename an SMB1 file on a DFS share. SMB1 ntrename version.
950 static NTSTATUS
smb1_ntrename_rename(struct cli_state
*cli
,
951 const char *src_dfs_name
,
952 const char *target_name
)
954 return smb1_ntrename(cli
,
961 static bool test_smb1_ntrename_rename(struct cli_state
*cli
,
962 const char *src_dfs_name
)
964 struct timespec test_crtime
= { 0 };
967 /* Try with a non-DFS name. */
968 status
= smb1_ntrename_rename(cli
,
971 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_PATH_SYNTAX_BAD
)) {
972 /* Fails I think as target becomes "" on server. */
973 printf("%s:%d SMB1 ntrename rename of %s -> %s should get "
974 "NT_STATUS_OBJECT_PATH_SYNTAX_BAD got %s\n",
983 status
= smb1_ntrename_rename(cli
,
985 "BAD\\BAD\\renamed_file");
986 if (!NT_STATUS_IS_OK(status
)) {
987 printf("%s:%d SMB1 ntrename rename of %s -> %s should "
992 "BAD\\BAD\\renamed_file",
997 /* Ensure we did rename. */
998 status
= get_smb1_crtime(cli
,
999 "BAD\\BAD\\renamed_file",
1001 if (!NT_STATUS_IS_OK(status
)) {
1002 printf("%s:%d Failed to get crtime "
1006 "BAD\\BAD\\renamed_file",
1012 status
= smb1_ntrename_rename(cli
,
1013 "BAD\\BAD\\renamed_file",
1015 if (!NT_STATUS_IS_OK(status
)) {
1016 printf("%s:%d SMB1 ntrename rename of %s -> %s "
1017 "should succeed got %s\n",
1020 "BAD\\BAD\\renamed_file",
1026 /* Ensure we did rename. */
1027 status
= get_smb1_crtime(cli
,
1030 if (!NT_STATUS_IS_OK(status
)) {
1031 printf("%s:%d Failed to get crtime "
1044 * Hard link an SMB1 file on a DFS share. SMB1 ntrename version.
1046 static NTSTATUS
smb1_ntrename_hardlink(struct cli_state
*cli
,
1047 const char *src_dfs_name
,
1048 const char *target_name
)
1050 return smb1_ntrename(cli
,
1053 RENAME_FLAG_HARD_LINK
);
1056 static bool test_smb1_ntrename_hardlink(struct cli_state
*cli
,
1057 const char *src_dfs_name
)
1059 struct timespec test_crtime
= { 0 };
1061 bool retval
= false;
1063 /* Try with a non-DFS name. */
1064 status
= smb1_ntrename_hardlink(cli
,
1067 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_PATH_SYNTAX_BAD
)) {
1068 /* Fails I think as target becomes "" on server. */
1069 printf("%s:%d SMB1 ntrename of %s -> %s should get "
1070 "NT_STATUS_OBJECT_PATH_SYNTAX_BAD got %s\n",
1079 status
= smb1_ntrename_hardlink(cli
,
1082 if (!NT_STATUS_IS_OK(status
)) {
1083 printf("%s:%d SMB1 ntrename hardlink of %s -> %s "
1084 "should succeed got %s\n",
1093 /* Ensure we did hardlink. */
1094 status
= get_smb1_crtime(cli
,
1097 if (!NT_STATUS_IS_OK(status
)) {
1098 printf("%s:%d Failed to get crtime "
1107 retval
= smb1_crtime_matches(cli
,
1112 printf("%s:%d smb1_crtime_matches failed for "
1123 /* Remove the hardlink to clean up. */
1124 (void)smb1_dfs_delete(cli
, "BAD\\BAD\\hlink");
1128 static void smb1_setfileinfo_done(struct tevent_req
*subreq
);
1130 struct smb1_setfileinfo_state
{
1136 static struct tevent_req
*smb1_setfileinfo_send(TALLOC_CTX
*mem_ctx
,
1137 struct tevent_context
*ev
,
1138 struct cli_state
*cli
,
1140 const char *target_name
,
1141 uint16_t info_level
)
1143 struct tevent_req
*req
= NULL
;
1144 struct tevent_req
*subreq
= NULL
;
1145 struct smb1_setfileinfo_state
*state
= NULL
;
1146 smb_ucs2_t
*converted_str
= NULL
;
1147 size_t converted_size_bytes
= 0;
1150 req
= tevent_req_create(mem_ctx
,
1152 struct smb1_setfileinfo_state
);
1157 PUSH_LE_U16(&state
->setup
, 0, TRANSACT2_SETPATHINFO
);
1159 PUSH_LE_U16(state
->param
, 0, fnum
);
1160 PUSH_LE_U16(state
->param
, 2, info_level
);
1162 ok
= push_ucs2_talloc(state
,
1165 &converted_size_bytes
);
1167 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1168 return tevent_req_post(req
, ev
);
1172 * W2K8 insists the dest name is not null
1173 * terminated. Remove the last 2 zero bytes
1174 * and reduce the name length.
1177 if (converted_size_bytes
< 2) {
1178 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1179 return tevent_req_post(req
, ev
);
1181 converted_size_bytes
-= 2;
1183 state
->data
= talloc_zero_array(state
,
1185 12 + converted_size_bytes
);
1186 if (tevent_req_nomem(state
->data
, req
)) {
1187 return tevent_req_post(req
, ev
);
1190 SIVAL(state
->data
, 8, converted_size_bytes
);
1191 memcpy(state
->data
+ 12, converted_str
, converted_size_bytes
);
1193 subreq
= cli_trans_send(state
, /* mem ctx. */
1195 cli
,/* cli_state. */
1196 0,/* additional_flags2 */
1197 SMBtrans2
, /* cmd. */
1198 NULL
,/* pipe name. */
1202 &state
->setup
,/* setup. */
1203 1,/* num setup uint16_t words. */
1204 0,/* max returned setup. */
1205 state
->param
,/* param. */
1207 2,/* max returned param. */
1208 state
->data
,/* data. */
1209 talloc_get_size(state
->data
),/* num data. */
1210 0);/* max returned data. */
1212 if (tevent_req_nomem(subreq
, req
)) {
1213 return tevent_req_post(req
, ev
);
1215 tevent_req_set_callback(subreq
, smb1_setfileinfo_done
, req
);
1219 static void smb1_setfileinfo_done(struct tevent_req
*subreq
)
1221 NTSTATUS status
= cli_trans_recv(subreq
,
1233 tevent_req_simple_finish_ntstatus(subreq
,
1237 static NTSTATUS
smb1_setfileinfo_recv(struct tevent_req
*req
)
1239 return tevent_req_simple_recv_ntstatus(req
);
1243 * Rename or hardlink an SMB1 file on a DFS share.
1244 * setfileinfo (file handle + target pathname) version.
1246 static NTSTATUS
smb1_setfileinfo(struct cli_state
*cli
,
1248 const char *target_name
,
1249 uint16_t info_level
)
1251 TALLOC_CTX
*frame
= NULL
;
1252 struct tevent_context
*ev
;
1253 struct tevent_req
*req
;
1256 frame
= talloc_stackframe();
1258 ev
= samba_tevent_context_init(frame
);
1260 status
= NT_STATUS_NO_MEMORY
;
1264 req
= smb1_setfileinfo_send(frame
,
1271 status
= NT_STATUS_NO_MEMORY
;
1275 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
1279 status
= smb1_setfileinfo_recv(req
);
1287 static NTSTATUS
smb1_setfileinfo_rename(struct cli_state
*cli
,
1289 const char *target_name
)
1291 return smb1_setfileinfo(cli
,
1294 SMB_FILE_RENAME_INFORMATION
);
1298 * On Windows, rename using a file handle as source
1302 static bool test_smb1_setfileinfo_rename(struct cli_state
*cli
,
1303 const char *src_dfs_name
)
1305 uint16_t fnum
= (uint16_t)-1;
1307 bool retval
= false;
1309 /* First open the source file. */
1310 status
= smb1cli_ntcreatex(cli
->conn
,
1316 OPLOCK_NONE
, /* CreatFlags */
1317 0, /* RootDirectoryFid */
1318 SEC_STD_SYNCHRONIZE
|
1319 SEC_STD_DELETE
, /* DesiredAccess */
1320 0, /* AllocationSize */
1321 FILE_ATTRIBUTE_NORMAL
, /* FileAttributes */
1324 FILE_SHARE_DELETE
, /* ShareAccess */
1325 FILE_OPEN
, /* CreateDisposition */
1326 0, /* CreateOptions */
1327 2, /* ImpersonationLevel */
1328 0, /* SecurityFlags */
1330 if (!NT_STATUS_IS_OK(status
)) {
1331 printf("%s:%d failed to open %s, %s\n",
1340 * On Windows rename given a file handle returns
1341 * NT_STATUS_UNSUCCESSFUL (not documented in MS-SMB).
1344 status
= smb1_setfileinfo_rename(cli
,
1346 "BAD\\BAD\\renamed_file");
1347 if (!NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1348 printf("%s:%d SMB1 setfileinfo rename of %s -> %s should get "
1349 "NT_STATUS_UNSUCCESSFUL got %s\n",
1358 /* Try with a non-DFS name - still gets NT_STATUS_UNSUCCESSFUL. */
1359 status
= smb1_setfileinfo_rename(cli
,
1362 if (!NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1363 printf("%s:%d SMB1 setfileinfo rename of %s -> %s should get "
1364 "NT_STATUS_UNSUCCESSFUL got %s\n",
1377 if (fnum
!= (uint16_t)-1) {
1378 (void)smb1cli_close(cli
->conn
,
1384 0); /* last_modified */
1387 (void)smb1_dfs_delete(cli
, "BAD\\BAD\\renamed_file");
1392 static NTSTATUS
smb1_setfileinfo_hardlink(struct cli_state
*cli
,
1394 const char *target_name
)
1396 return smb1_setfileinfo(cli
,
1399 SMB_FILE_LINK_INFORMATION
);
1403 * On Windows, hardlink using a file handle as source
1407 static bool test_smb1_setfileinfo_hardlink(struct cli_state
*cli
,
1408 const char *src_dfs_name
)
1410 uint16_t fnum
= (uint16_t)-1;
1412 bool retval
= false;
1414 /* First open the source file. */
1415 status
= smb1cli_ntcreatex(cli
->conn
,
1421 OPLOCK_NONE
, /* CreatFlags */
1422 0, /* RootDirectoryFid */
1423 SEC_STD_SYNCHRONIZE
|
1424 SEC_RIGHTS_FILE_READ
, /* DesiredAccess */
1425 0, /* AllocationSize */
1426 FILE_ATTRIBUTE_NORMAL
, /* FileAttributes */
1429 FILE_SHARE_DELETE
, /* ShareAccess */
1430 FILE_OPEN
, /* CreateDisposition */
1431 0, /* CreateOptions */
1432 2, /* ImpersonationLevel */
1433 0, /* SecurityFlags */
1435 if (!NT_STATUS_IS_OK(status
)) {
1436 printf("%s:%d failed to open %s, %s\n",
1445 * On Windows hardlink given a file handle returns
1446 * NT_STATUS_UNSUCCESSFUL (not documented in MS-SMB).
1449 status
= smb1_setfileinfo_hardlink(cli
,
1452 if (!NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1453 printf("%s:%d SMB1 setfileinfo hardlink of %s -> %s should get "
1454 "NT_STATUS_UNSUCCESSFUL got %s\n",
1463 /* Try with a non-DFS name - still gets NT_STATUS_UNSUCCESSFUL. */
1464 status
= smb1_setfileinfo_hardlink(cli
,
1467 if (!NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1468 printf("%s:%d SMB1 setfileinfo hardlink of %s -> %s should get "
1469 "NT_STATUS_UNSUCCESSFUL got %s\n",
1482 if (fnum
!= (uint16_t)-1) {
1483 (void)smb1cli_close(cli
->conn
,
1489 0); /* last_modified */
1492 (void)smb1_dfs_delete(cli
, "BAD\\BAD\\hlink");
1499 * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/dc9978d7-6299-4c5a-a22d-a039cdc716ea
1501 * (Characters " \ / [ ] : | < > + = ; , * ?,
1502 * and control characters in range 0x00 through
1503 * 0x1F, inclusive, are illegal in a share name)
1505 * But Windows server only checks in DFS sharenames ':'. All other
1506 * share names are allowed.
1509 static bool test_smb1_dfs_sharenames(struct cli_state
*cli
,
1510 const char *dfs_root_share_name
,
1511 struct timespec root_crtime
)
1514 const char *test_str
= "/[]:|<>+=;,*?";
1517 bool crtime_matched
= false;
1519 /* Setup template pathname. */
1520 memcpy(test_path
, "\\SERVER\\X", 10);
1522 /* Test invalid control characters. */
1523 for (i
= 1; i
< 0x20; i
++) {
1525 crtime_matched
= smb1_crtime_matches(cli
,
1526 dfs_root_share_name
,
1529 if (!crtime_matched
) {
1534 /* Test explicit invalid characters. */
1535 for (p
= test_str
; *p
!= '\0'; p
++) {
1539 * Only ':' is treated as an INVALID sharename
1540 * for a DFS SERVER\\SHARE path.
1542 struct timespec test_crtime
= { 0 };
1543 NTSTATUS status
= get_smb1_crtime(cli
,
1546 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_INVALID
)) {
1547 printf("%s:%d Open of %s should get "
1548 "NT_STATUS_OBJECT_NAME_INVALID, got %s\n",
1556 crtime_matched
= smb1_crtime_matches(cli
,
1557 dfs_root_share_name
,
1560 if (!crtime_matched
) {
1569 * "Raw" test of SMB1 paths to a DFS share.
1570 * We must (mostly) use the lower level smb1cli_XXXX() interfaces,
1571 * not the cli_XXX() ones here as the ultimate goal is to fix our
1572 * cli_XXX() interfaces to work transparently over DFS.
1574 * So here, we're testing the server code, not the client code.
1576 * Passes cleanly against Windows.
1579 bool run_smb1_dfs_paths(int dummy
)
1581 struct cli_state
*cli
= NULL
;
1583 bool dfs_supported
= false;
1584 char *dfs_root_share_name
= NULL
;
1585 struct timespec root_crtime
= { 0 };
1586 struct timespec test_crtime
= { 0 };
1587 bool crtime_matched
= false;
1588 bool retval
= false;
1592 uint16_t fnum
= (uint16_t)-1;
1594 printf("Starting SMB1-DFS-PATHS\n");
1596 if (!torture_init_connection(&cli
)) {
1600 if (!torture_open_connection(&cli
, 0)) {
1604 /* Ensure this is a DFS share. */
1605 dfs_supported
= smbXcli_conn_dfs_supported(cli
->conn
);
1606 if (!dfs_supported
) {
1607 printf("Server %s does not support DFS\n",
1608 smbXcli_conn_remote_name(cli
->conn
));
1611 dfs_supported
= smbXcli_tcon_is_dfs_share(cli
->smb1
.tcon
);
1612 if (!dfs_supported
) {
1613 printf("Share %s does not support DFS\n",
1618 /* Start with an empty share. */
1619 (void)smb1_dfs_delete(cli
, "BAD\\BAD\\BAD");
1620 (void)smb1_dfs_delete(cli
, "BAD\\BAD\\file");
1621 (void)smb1_dfs_delete(cli
, "BAD\\BAD\\renamed_file");
1622 (void)smb1_dfs_delete(cli
, "BAD\\BAD\\hlink");
1625 * Create the "official" DFS share root name.
1627 dfs_root_share_name
= talloc_asprintf(talloc_tos(),
1629 smbXcli_conn_remote_name(cli
->conn
),
1631 if (dfs_root_share_name
== NULL
) {
1632 printf("Out of memory\n");
1636 /* Get the share root crtime. */
1637 status
= get_smb1_crtime(cli
,
1638 dfs_root_share_name
,
1640 if (!NT_STATUS_IS_OK(status
)) {
1641 printf("%s:%d Failed to get crtime for share root %s, (%s)\n",
1644 dfs_root_share_name
,
1650 * Test the Windows algorithm for parsing DFS names.
1653 * A single "SERVER" element should open and match the share root.
1655 crtime_matched
= smb1_crtime_matches(cli
,
1656 dfs_root_share_name
,
1658 smbXcli_conn_remote_name(cli
->conn
));
1659 if (!crtime_matched
) {
1660 printf("%s:%d Failed to match crtime for %s\n",
1663 smbXcli_conn_remote_name(cli
->conn
));
1667 /* An "" (empty) server name should open and match the share root. */
1668 crtime_matched
= smb1_crtime_matches(cli
,
1669 dfs_root_share_name
,
1672 if (!crtime_matched
) {
1673 printf("%s:%d Failed to match crtime for %s\n",
1681 * For SMB1 the server just strips off any number of leading '\\'
1682 * characters. Show this is the case.
1684 for (i
= 0; i
< 10; i
++) {
1685 char leading_backslash_name
[20];
1686 leading_backslash_name
[i
] = '\\';
1687 memcpy(&leading_backslash_name
[i
+1],
1689 strlen("SERVER")+1);
1691 crtime_matched
= smb1_crtime_matches(cli
,
1692 dfs_root_share_name
,
1694 leading_backslash_name
);
1695 if (!crtime_matched
) {
1696 printf("%s:%d Failed to match crtime for %s\n",
1699 leading_backslash_name
);
1704 /* A "BAD" server name should open and match the share root. */
1705 crtime_matched
= smb1_crtime_matches(cli
,
1706 dfs_root_share_name
,
1709 if (!crtime_matched
) {
1710 printf("%s:%d Failed to match crtime for %s\n",
1717 * A "BAD\\BAD" server and share name should open
1718 * and match the share root.
1720 crtime_matched
= smb1_crtime_matches(cli
,
1721 dfs_root_share_name
,
1724 if (!crtime_matched
) {
1725 printf("%s:%d Failed to match crtime for %s\n",
1732 * Trying to open "BAD\\BAD\\BAD" should get
1733 * NT_STATUS_OBJECT_NAME_NOT_FOUND.
1735 status
= get_smb1_crtime(cli
,
1738 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
1739 printf("%s:%d Open of %s should get "
1740 "STATUS_OBJECT_NAME_NOT_FOUND, got %s\n",
1748 * Trying to open "BAD\\BAD\\BAD\\BAD" should get
1749 * NT_STATUS_OBJECT_PATH_NOT_FOUND.
1751 status
= get_smb1_crtime(cli
,
1752 "BAD\\BAD\\BAD\\BAD",
1754 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_PATH_NOT_FOUND
)) {
1755 printf("%s:%d Open of %s should get "
1756 "STATUS_OBJECT_NAME_NOT_FOUND, got %s\n",
1759 "BAD\\BAD\\BAD\\BAD",
1764 * Test for invalid pathname characters in the servername.
1765 * They are ignored, and it still opens the share root.
1767 crtime_matched
= smb1_crtime_matches(cli
,
1768 dfs_root_share_name
,
1771 if (!crtime_matched
) {
1772 printf("%s:%d Failed to match crtime for %s\n",
1780 * Test for invalid pathname characters in the sharename.
1781 * Invalid sharename characters should still be flagged as
1782 * NT_STATUS_OBJECT_NAME_INVALID. It turns out only ':'
1783 * is considered an invalid sharename character.
1785 ok
= test_smb1_dfs_sharenames(cli
,
1786 dfs_root_share_name
,
1792 status
= smb1cli_ntcreatex(cli
->conn
,
1798 OPLOCK_NONE
, /* CreatFlags */
1799 0, /* RootDirectoryFid */
1800 SEC_STD_SYNCHRONIZE
|
1803 SEC_FILE_READ_ATTRIBUTE
, /* DesiredAccess */
1804 0, /* AllocationSize */
1805 FILE_ATTRIBUTE_NORMAL
, /* FileAttributes */
1808 FILE_SHARE_DELETE
, /* ShareAccess */
1809 FILE_CREATE
, /* CreateDisposition */
1810 0, /* CreateOptions */
1811 2, /* ImpersonationLevel */
1812 0, /* SecurityFlags */
1814 if (!NT_STATUS_IS_OK(status
)) {
1815 printf("%s:%d smb1cli_ntcreatex on %s returned %s\n",
1823 /* Close "file" handle. */
1824 (void)smb1cli_close(cli
->conn
,
1830 0); /* last_modified */
1831 fnum
= (uint16_t)-1;
1834 * Trying to open "BAD\\BAD\\file" should now get
1837 status
= get_smb1_crtime(cli
,
1840 if (!NT_STATUS_IS_OK(status
)) {
1841 printf("%s:%d Open of %s should succeed "
1851 * This crtime must be different from the root_crtime.
1852 * This checks we're actually correctly reading crtimes
1853 * from the filesystem.
1855 equal
= (timespec_compare(&test_crtime
, &root_crtime
) == 0);
1857 printf("%s:%d Error. crtime of %s must differ from "
1866 * Test different SMB1 renames
1870 /* SMBmv only does rename. */
1871 ok
= test_smb1_mv(cli
,
1877 ok
= test_smb1_setpathinfo_rename(cli
,
1883 ok
= test_smb1_setpathinfo_hardlink(cli
,
1889 ok
= test_smb1_setfileinfo_rename(cli
,
1895 ok
= test_smb1_setfileinfo_hardlink(cli
,
1901 ok
= test_smb1_ntrename_rename(cli
,
1907 ok
= test_smb1_ntrename_hardlink(cli
,
1917 if (fnum
!= (uint16_t)-1) {
1918 (void)smb1cli_close(cli
->conn
,
1924 0); /* last_modified */
1927 /* Delete anything we made. */
1928 (void)smb1_dfs_delete(cli
, "BAD\\BAD\\BAD");
1929 (void)smb1_dfs_delete(cli
, "BAD\\BAD\\file");
1930 (void)smb1_dfs_delete(cli
, "BAD\\BAD\\renamed_file");
1931 (void)smb1_dfs_delete(cli
, "BAD\\BAD\\hlink");
1936 * SMB1 Findfirst. This is a minimal implementation
1937 * that expects all filename returns in one packet.
1938 * We're only using this to test the search DFS pathname
1942 /****************************************************************************
1943 Calculate a safe next_entry_offset.
1944 ****************************************************************************/
1946 static size_t calc_next_entry_offset(const uint8_t *base
,
1947 const uint8_t *pdata_end
)
1949 size_t next_entry_offset
= (size_t)PULL_LE_U32(base
,0);
1951 if (next_entry_offset
== 0 ||
1952 base
+ next_entry_offset
< base
||
1953 base
+ next_entry_offset
> pdata_end
) {
1954 next_entry_offset
= pdata_end
- base
;
1956 return next_entry_offset
;
1959 static size_t get_filename(TALLOC_CTX
*ctx
,
1960 struct cli_state
*cli
,
1961 const uint8_t *base_ptr
,
1962 uint16_t recv_flags2
,
1964 const uint8_t *pdata_end
,
1965 struct file_info
*finfo
)
1968 const uint8_t *base
= p
;
1972 ZERO_STRUCTP(finfo
);
1974 if (pdata_end
- base
< 94) {
1975 return pdata_end
- base
;
1977 p
+= 4; /* next entry offset */
1978 p
+= 4; /* fileindex */
1979 /* Offset zero is "create time", not "change time". */
1981 finfo
->atime_ts
= interpret_long_date(BVAL(p
, 0));
1983 finfo
->mtime_ts
= interpret_long_date(BVAL(p
, 0));
1985 finfo
->ctime_ts
= interpret_long_date(BVAL(p
, 0));
1987 finfo
->size
= PULL_LE_U64(p
, 0);
1989 p
+= 8; /* alloc size */
1990 finfo
->attr
= PULL_LE_U32(p
, 0);
1992 namelen
= PULL_LE_U32(p
, 0);
1994 p
+= 4; /* EA size */
1995 slen
= PULL_LE_U8(p
, 0);
1997 /* Bad short name length. */
1998 return pdata_end
- base
;
2001 ret
= pull_string_talloc(ctx
,
2008 if (ret
== (size_t)-1) {
2009 return pdata_end
- base
;
2011 p
+= 24; /* short name */
2012 if (p
+ namelen
< p
|| p
+ namelen
> pdata_end
) {
2013 return pdata_end
- base
;
2015 ret
= pull_string_talloc(ctx
,
2022 if (ret
== (size_t)-1) {
2023 return pdata_end
- base
;
2025 return calc_next_entry_offset(base
, pdata_end
);
2028 /* Single shot SMB1 TRANS2 FindFirst. */
2030 static NTSTATUS
smb1_findfirst(TALLOC_CTX
*mem_ctx
,
2031 struct cli_state
*cli
,
2032 const char *search_name
,
2033 struct file_info
**names
,
2038 uint8_t *param
= NULL
;
2039 uint16_t recv_flags2
= 0;
2040 uint8_t *rparam
= NULL
;
2041 uint32_t num_rparam
= 0;
2042 uint8_t *rdata
= NULL
;
2043 uint32_t num_rdata
= 0;
2044 uint16_t num_names_returned
= 0;
2045 struct file_info
*finfo
= NULL
;
2047 uint8_t *data_end
= NULL
;
2050 PUSH_LE_U16(&setup
[0], 0, TRANSACT2_FINDFIRST
);
2052 param
= talloc_array(mem_ctx
, uint8_t, 12);
2053 if (param
== NULL
) {
2054 return NT_STATUS_NO_MEMORY
;
2057 PUSH_LE_U16(param
, 0, FILE_ATTRIBUTE_DIRECTORY
|
2058 FILE_ATTRIBUTE_SYSTEM
|
2059 FILE_ATTRIBUTE_HIDDEN
);
2060 PUSH_LE_U16(param
, 2, 1366); /* max_matches */
2061 PUSH_LE_U16(param
, 4, FLAG_TRANS2_FIND_CLOSE_IF_END
);
2062 PUSH_LE_U16(param
, 6, SMB_FIND_FILE_BOTH_DIRECTORY_INFO
); /* info_level */
2064 param
= trans2_bytes_push_str(param
,
2065 smbXcli_conn_use_unicode(cli
->conn
),
2067 strlen(search_name
)+1,
2069 if (param
== NULL
) {
2070 return NT_STATUS_NO_MEMORY
;
2074 * A one shot SMB1 findfirst will be enough to
2075 * return ".", "..", and "file".
2077 status
= cli_trans(mem_ctx
,
2079 SMBtrans2
, /* cmd */
2080 NULL
, /* pipe_name */
2085 1, /* num_setup uint16_t words */
2086 0, /* max returned setup */
2088 talloc_get_size(param
), /* num_param */
2089 10, /* max returned param */
2092 SMB_BUFFER_SIZE_MAX
, /* max returned data */
2093 /* Return values from here on.. */
2094 &recv_flags2
, /* recv_flags2 */
2096 0, /* min returned rsetup */
2097 NULL
, /* num_rsetup */
2099 6, /* min returned rparam */
2100 &num_rparam
, /* number of returned rparam */
2102 0, /* min returned rdata */
2104 if (!NT_STATUS_IS_OK(status
)) {
2108 num_names_returned
= PULL_LE_U16(rparam
, 2);
2110 finfo
= talloc_array(mem_ctx
, struct file_info
, num_names_returned
);
2111 if (param
== NULL
) {
2112 return NT_STATUS_NO_MEMORY
;
2116 data_end
= rdata
+ num_rdata
;
2118 for (i
= 0; i
< num_names_returned
; i
++) {
2119 if (p2
>= data_end
) {
2122 if (i
== num_names_returned
- 1) {
2123 /* Last entry - fixup the last offset length. */
2124 PUSH_LE_U32(p2
, 0, PTR_DIFF((rdata
+ num_rdata
), p2
));
2127 p2
+= get_filename(mem_ctx
,
2135 if (finfo
->name
== NULL
) {
2136 printf("%s:%d Unable to parse name from listing "
2137 "of %s, position %u\n",
2142 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
2147 return NT_STATUS_OK
;
2151 * Test a specific SMB1 findfirst path to see if it
2152 * matches a given file array.
2154 static bool test_smb1_findfirst_path(struct cli_state
*cli
,
2155 const char *search_path
,
2156 struct file_info
*root_finfo
,
2157 size_t num_root_finfo
)
2160 size_t num_finfo
= 0;
2161 struct file_info
*finfo
= NULL
;
2164 status
= smb1_findfirst(talloc_tos(),
2169 if (!NT_STATUS_IS_OK(status
)) {
2170 printf("%s:%d smb1findfirst on %s returned %s\n",
2178 if (num_finfo
!= num_root_finfo
) {
2179 printf("%s:%d On %s, num_finfo = %zu, num_root_finfo = %zu\n",
2187 for (i
= 0; i
< num_finfo
; i
++) {
2188 bool match
= strequal_m(finfo
[i
].name
,
2189 root_finfo
[i
].name
);
2191 printf("%s:%d Mismatch. For %s, at position %zu, "
2192 "finfo[i].name = %s, "
2193 "root_finfo[i].name = %s\n",
2199 root_finfo
[i
].name
);
2208 * "Raw" test of doing a SMB1 findfirst to a DFS share.
2209 * We must (mostly) use the lower level smb1cli_XXXX() interfaces,
2210 * not the cli_XXX() ones here as the ultimate goal is to fix our
2211 * cli_XXX() interfaces to work transparently over DFS.
2213 * So here, we're testing the server code, not the client code.
2215 * Passes cleanly against Windows.
2218 bool run_smb1_dfs_search_paths(int dummy
)
2220 struct cli_state
*cli
= NULL
;
2222 bool dfs_supported
= false;
2223 struct file_info
*root_finfo
= NULL
;
2224 size_t num_root_finfo
= 0;
2225 bool retval
= false;
2227 uint16_t fnum
= (uint16_t)-1;
2229 printf("Starting SMB1-DFS-SEARCH-PATHS\n");
2231 if (!torture_init_connection(&cli
)) {
2235 if (!torture_open_connection(&cli
, 0)) {
2239 /* Ensure this is a DFS share. */
2240 dfs_supported
= smbXcli_conn_dfs_supported(cli
->conn
);
2241 if (!dfs_supported
) {
2242 printf("Server %s does not support DFS\n",
2243 smbXcli_conn_remote_name(cli
->conn
));
2246 dfs_supported
= smbXcli_tcon_is_dfs_share(cli
->smb1
.tcon
);
2247 if (!dfs_supported
) {
2248 printf("Share %s does not support DFS\n",
2254 (void)smb1_dfs_delete(cli
, "BAD\\BAD\\file");
2256 /* Create a test file to search for. */
2257 status
= smb1cli_ntcreatex(cli
->conn
,
2263 OPLOCK_NONE
, /* CreatFlags */
2264 0, /* RootDirectoryFid */
2265 SEC_STD_SYNCHRONIZE
|
2268 SEC_FILE_READ_ATTRIBUTE
, /* DesiredAccess */
2269 0, /* AllocationSize */
2270 FILE_ATTRIBUTE_NORMAL
, /* FileAttributes */
2273 FILE_SHARE_DELETE
, /* ShareAccess */
2274 FILE_CREATE
, /* CreateDisposition */
2275 0, /* CreateOptions */
2276 2, /* ImpersonationLevel */
2277 0, /* SecurityFlags */
2279 if (!NT_STATUS_IS_OK(status
)) {
2280 printf("%s:%d smb1cli_ntcreatex on %s returned %s\n",
2288 /* Close "file" handle. */
2289 (void)smb1cli_close(cli
->conn
,
2295 0); /* last_modified */
2296 fnum
= (uint16_t)-1;
2298 /* Get the list of files in the share. */
2299 status
= smb1_findfirst(talloc_tos(),
2304 if (!NT_STATUS_IS_OK(status
)) {
2305 printf("%s:%d smb1findfirst on %s returned %s\n",
2314 * Try different search names. They should
2315 * all match the root directory list.
2317 ok
= test_smb1_findfirst_path(cli
,
2318 "\\SERVER\\SHARE\\*",
2325 ok
= test_smb1_findfirst_path(cli
,
2332 ok
= test_smb1_findfirst_path(cli
,
2339 ok
= test_smb1_findfirst_path(cli
,
2350 if (fnum
!= (uint16_t)-1) {
2351 (void)smb1cli_close(cli
->conn
,
2357 0); /* last_modified */
2360 /* Delete anything we made. */
2361 (void)smb1_dfs_delete(cli
, "BAD\\BAD\\file");
2365 static bool smb1_create_testfile(struct cli_state
*cli
,
2369 uint16_t fnum
= (uint16_t)-1;
2371 /* Create a test file. */
2372 status
= smb1cli_ntcreatex(cli
->conn
,
2378 OPLOCK_NONE
, /* CreatFlags */
2379 0, /* RootDirectoryFid */
2380 SEC_STD_SYNCHRONIZE
|
2383 SEC_FILE_READ_ATTRIBUTE
, /* DesiredAccess */
2384 0, /* AllocationSize */
2385 FILE_ATTRIBUTE_NORMAL
, /* FileAttributes */
2388 FILE_SHARE_DELETE
, /* ShareAccess */
2389 FILE_CREATE
, /* CreateDisposition */
2390 0, /* CreateOptions */
2391 2, /* ImpersonationLevel */
2392 0, /* SecurityFlags */
2394 if (!NT_STATUS_IS_OK(status
)) {
2395 printf("%s:%d smb1cli_ntcreatex on %s returned %s\n",
2403 /* Close "file" handle. */
2404 (void)smb1cli_close(cli
->conn
,
2410 0); /* last_modified */
2414 static NTSTATUS
smb1_unlink(struct cli_state
*cli
,
2418 uint8_t *bytes
= NULL
;
2420 PUSH_LE_U16(vwv
, 0, FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
);
2421 bytes
= talloc_array(talloc_tos(), uint8_t, 1);
2422 if (bytes
== NULL
) {
2423 return NT_STATUS_NO_MEMORY
;
2426 bytes
= smb_bytes_push_str(bytes
,
2427 smbXcli_conn_use_unicode(cli
->conn
),
2431 if (bytes
== NULL
) {
2432 return NT_STATUS_NO_MEMORY
;
2435 return cli_smb(talloc_tos(),
2437 SMBunlink
, /* command. */
2438 0, /* additional_flags. */
2441 talloc_get_size(bytes
), /* num_bytes. */
2443 NULL
, /* result parent. */
2445 NULL
, /* return wcount. */
2446 NULL
, /* return wvw. */
2447 NULL
, /* return byte count. */
2448 NULL
); /* return bytes. */
2451 static bool test_smb1_unlink(struct cli_state
*cli
)
2454 bool retval
= false;
2458 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\file");
2460 /* Create a test file. */
2461 ok
= smb1_create_testfile(cli
, "\\BAD\\BAD\\file");
2463 printf("%s:%d failed to create test file %s\n",
2466 "\\BAD\\BAD\\file");
2470 status
= smb1_unlink(cli
, "file");
2471 if (!NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
2472 printf("%s:%d SMB1unlink of %s should get "
2473 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
2480 status
= smb1_unlink(cli
, "\\BAD\\file");
2481 if (!NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
2482 printf("%s:%d SMB1unlink of %s should get "
2483 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
2490 status
= smb1_unlink(cli
, "\\BAD\\BAD\\file");
2491 if (!NT_STATUS_IS_OK(status
)) {
2492 printf("%s:%d SMB1unlink on %s returned %s\n",
2504 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\file");
2508 static NTSTATUS
smb1_mkdir(struct cli_state
*cli
,
2511 uint8_t *bytes
= NULL
;
2513 bytes
= talloc_array(talloc_tos(), uint8_t, 1);
2514 if (bytes
== NULL
) {
2515 return NT_STATUS_NO_MEMORY
;
2518 bytes
= smb_bytes_push_str(bytes
,
2519 smbXcli_conn_use_unicode(cli
->conn
),
2523 if (bytes
== NULL
) {
2524 return NT_STATUS_NO_MEMORY
;
2527 return cli_smb(talloc_tos(),
2529 SMBmkdir
, /* command. */
2530 0, /* additional_flags. */
2533 talloc_get_size(bytes
), /* num_bytes. */
2535 NULL
, /* result parent. */
2537 NULL
, /* return wcount. */
2538 NULL
, /* return wvw. */
2539 NULL
, /* return byte count. */
2540 NULL
); /* return bytes. */
2543 static bool test_smb1_mkdir(struct cli_state
*cli
)
2546 bool retval
= false;
2549 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\dir");
2551 status
= smb1_mkdir(cli
, "dir");
2552 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_COLLISION
)) {
2553 printf("%s:%d SMB1mkdir of %s should get "
2554 "NT_STATUS_OBJECT_NAME_COLLISION, got %s\n",
2561 status
= smb1_mkdir(cli
, "\\BAD\\dir");
2562 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_COLLISION
)) {
2563 printf("%s:%d SMB1mkdir of %s should get "
2564 "NT_STATUS_OBJECT_NAME_COLLISION, got %s\n",
2571 status
= smb1_mkdir(cli
, "\\BAD\\BAD\\dir");
2572 if (!NT_STATUS_IS_OK(status
)) {
2573 printf("%s:%d SMB1mkdir on %s returned %s\n",
2585 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\dir");
2589 static NTSTATUS
smb1_rmdir(struct cli_state
*cli
,
2592 uint8_t *bytes
= NULL
;
2594 bytes
= talloc_array(talloc_tos(), uint8_t, 1);
2595 if (bytes
== NULL
) {
2596 return NT_STATUS_NO_MEMORY
;
2599 bytes
= smb_bytes_push_str(bytes
,
2600 smbXcli_conn_use_unicode(cli
->conn
),
2604 if (bytes
== NULL
) {
2605 return NT_STATUS_NO_MEMORY
;
2608 return cli_smb(talloc_tos(),
2610 SMBrmdir
, /* command. */
2611 0, /* additional_flags. */
2614 talloc_get_size(bytes
), /* num_bytes. */
2616 NULL
, /* result parent. */
2618 NULL
, /* return wcount. */
2619 NULL
, /* return wvw. */
2620 NULL
, /* return byte count. */
2621 NULL
); /* return bytes. */
2624 static bool test_smb1_rmdir(struct cli_state
*cli
)
2627 bool retval
= false;
2630 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\dir");
2632 status
= smb1_mkdir(cli
, "\\BAD\\BAD\\dir");
2633 if (!NT_STATUS_IS_OK(status
)) {
2634 printf("%s:%d SMB1rmdir on %s returned %s\n",
2642 status
= smb1_rmdir(cli
, "dir");
2643 if (!NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
2644 printf("%s:%d SMB1rmdir of %s should get "
2645 "NT_STATUS_ACCESS_DENIED, got %s\n",
2652 status
= smb1_rmdir(cli
, "\\BAD\\dir");
2653 if (!NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
2654 printf("%s:%d SMB1rmdir of %s should get "
2655 "NT_STATUS_ACCESS_DENIED, got %s\n",
2662 status
= smb1_rmdir(cli
, "\\BAD\\BAD\\dir");
2663 if (!NT_STATUS_IS_OK(status
)) {
2664 printf("%s:%d SMB1rmdir on %s returned %s\n",
2676 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\dir");
2680 static NTSTATUS
smb1_ntcreatex(struct cli_state
*cli
,
2684 uint16_t fnum
= (uint16_t)-1;
2686 status
= smb1cli_ntcreatex(cli
->conn
,
2692 OPLOCK_NONE
, /* CreatFlags */
2693 0, /* RootDirectoryFid */
2694 SEC_STD_SYNCHRONIZE
|
2697 SEC_FILE_READ_ATTRIBUTE
, /* DesiredAccess */
2698 0, /* AllocationSize */
2699 FILE_ATTRIBUTE_NORMAL
, /* FileAttributes */
2702 FILE_SHARE_DELETE
, /* ShareAccess */
2703 FILE_CREATE
, /* CreateDisposition */
2704 0, /* CreateOptions */
2705 2, /* ImpersonationLevel */
2706 0, /* SecurityFlags */
2708 if (!NT_STATUS_IS_OK(status
)) {
2712 /* Close "file" handle. */
2713 (void)smb1cli_close(cli
->conn
,
2719 0); /* last_modified */
2720 return NT_STATUS_OK
;
2723 static bool test_smb1_ntcreatex(struct cli_state
*cli
)
2726 bool retval
= false;
2729 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\ntcreateXfile");
2731 status
= smb1_ntcreatex(cli
, "ntcreateXfile");
2732 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_COLLISION
)) {
2733 printf("%s:%d SMB1ntcreateX of %s should get "
2734 "NT_STATUS_OBJECT_NAME_COLLISION, got %s\n",
2741 status
= smb1_ntcreatex(cli
, "\\BAD\\ntcreateXfile");
2742 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_COLLISION
)) {
2743 printf("%s:%d SMB1ntcreateX of %s should get "
2744 "NT_STATUS_OBJECT_NAME_COLLISION, got %s\n",
2747 "\\BAD\\ntcreateXfile",
2751 status
= smb1_ntcreatex(cli
, "\\BAD\\BAD\\ntcreateXfile");
2752 if (!NT_STATUS_IS_OK(status
)) {
2753 printf("%s:%d SMB1ntcreateX on %s returned %s\n",
2756 "\\BAD\\BAD\\ntcreateXfile",
2765 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\ntcreateXfile");
2769 static NTSTATUS
smb1_nttrans_create(struct cli_state
*cli
,
2772 uint8_t *param
= NULL
;
2773 size_t converted_len
= 0;
2774 uint8_t *rparam
= NULL
;
2775 uint32_t num_rparam
= 0;
2776 uint16_t fnum
= (uint16_t)-1;
2779 param
= talloc_zero_array(talloc_tos(), uint8_t, 53);
2780 if (param
== NULL
) {
2781 return NT_STATUS_NO_MEMORY
;
2784 param
= trans2_bytes_push_str(param
,
2785 smbXcli_conn_use_unicode(cli
->conn
),
2789 if (param
== NULL
) {
2790 return NT_STATUS_NO_MEMORY
;
2793 PUSH_LE_U32(param
, 8, SEC_STD_SYNCHRONIZE
|
2796 SEC_FILE_READ_ATTRIBUTE
); /* DesiredAccess */
2797 PUSH_LE_U32(param
, 20, FILE_ATTRIBUTE_NORMAL
);
2798 PUSH_LE_U32(param
, 24, FILE_SHARE_READ
|
2800 FILE_SHARE_DELETE
); /* ShareAccess */
2801 PUSH_LE_U32(param
, 28, FILE_CREATE
);
2802 PUSH_LE_U32(param
, 44, converted_len
);
2803 PUSH_LE_U32(param
, 48, 0x02); /* ImpersonationLevel */
2805 status
= cli_trans(talloc_tos(),
2807 SMBnttrans
, /* trans cmd */
2808 NULL
, /* pipe_name */
2810 NT_TRANSACT_CREATE
, /* function */
2816 talloc_get_size(param
), /* num_param */
2817 128, /* max_param */
2821 NULL
, /* recv_flags2 */
2824 NULL
, /* num_rsetup */
2825 &rparam
, /* rparam */
2826 69, /* min_rparam */
2827 &num_rparam
, /* num_rparam */
2830 NULL
); /* num_rdata */
2831 if (!NT_STATUS_IS_OK(status
)) {
2834 fnum
= PULL_LE_U16(param
, 2);
2835 /* Close "file" handle. */
2836 (void)smb1cli_close(cli
->conn
,
2842 0); /* last_modified */
2843 return NT_STATUS_OK
;
2846 static bool test_smb1_nttrans_create(struct cli_state
*cli
)
2849 bool retval
= false;
2852 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\nttransfile");
2854 status
= smb1_nttrans_create(cli
, "nttransfile");
2855 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_COLLISION
)) {
2856 printf("%s:%d SMB1trans NT_TRANSACT_CREATE of %s should get "
2857 "NT_STATUS_OBJECT_NAME_COLLISION, got %s\n",
2864 status
= smb1_nttrans_create(cli
, "\\BAD\\nttransfile");
2865 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_COLLISION
)) {
2866 printf("%s:%d SMB1trans NT_TRANSACT_CREATE of %s should get "
2867 "NT_STATUS_OBJECT_NAME_COLLISION, got %s\n",
2870 "\\BAD\\nttransfile",
2874 status
= smb1_nttrans_create(cli
, "\\BAD\\BAD\\nttransfile");
2875 if (!NT_STATUS_IS_OK(status
)) {
2876 printf("%s:%d SMB1trans NT_TRANSACT_CREATE on %s returned %s\n",
2879 "\\BAD\\BAD\\nttransfile",
2888 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\nttransfile");
2892 struct smb1_openx_state
{
2899 static void smb1_openx_done(struct tevent_req
*subreq
);
2901 static struct tevent_req
*smb1_openx_send(TALLOC_CTX
*mem_ctx
,
2902 struct tevent_context
*ev
,
2903 struct cli_state
*cli
,
2906 struct tevent_req
*req
= NULL
;
2907 struct tevent_req
*subreq
= NULL
;
2908 uint16_t accessmode
= 0;
2909 struct smb1_openx_state
*state
= NULL
;
2910 uint8_t *bytes
= NULL
;
2913 req
= tevent_req_create(mem_ctx
, &state
, struct smb1_openx_state
);
2918 accessmode
= (DENY_NONE
<<4);
2919 accessmode
|= DOS_OPEN_RDONLY
;
2921 PUSH_LE_U8(state
->vwv
+ 0, 0, 0xFF);
2922 PUSH_LE_U16(state
->vwv
+ 3, 0, accessmode
);
2923 PUSH_LE_U16(state
->vwv
+ 4, 0,
2924 FILE_ATTRIBUTE_SYSTEM
|
2925 FILE_ATTRIBUTE_HIDDEN
|
2926 FILE_ATTRIBUTE_DIRECTORY
);
2927 PUSH_LE_U16(state
->vwv
+ 8,
2929 OPENX_FILE_CREATE_IF_NOT_EXIST
| OPENX_FILE_EXISTS_FAIL
);
2931 bytes
= talloc_array(state
, uint8_t, 0);
2932 if (tevent_req_nomem(bytes
, req
)) {
2933 return tevent_req_post(req
, ev
);
2935 bytes
= smb_bytes_push_str(bytes
,
2936 smbXcli_conn_use_unicode(cli
->conn
),
2940 if (tevent_req_nomem(bytes
, req
)) {
2941 return tevent_req_post(req
, ev
);
2944 state
->bytes
.iov_base
= (void *)bytes
;
2945 state
->bytes
.iov_len
= talloc_get_size(bytes
);
2946 subreq
= cli_smb_req_create(state
,
2950 0, /* additional_flags */
2951 0, /* additional_flags2 */
2953 state
->vwv
, /* vwv */
2955 &state
->bytes
); /* iovec */
2956 if (tevent_req_nomem(subreq
, req
)) {
2957 return tevent_req_post(req
, ev
);
2959 tevent_req_set_callback(subreq
, smb1_openx_done
, req
);
2961 status
= smb1cli_req_chain_submit(&subreq
, 1);
2962 if (tevent_req_nterror(req
, status
)) {
2963 return tevent_req_post(req
, ev
);
2968 static void smb1_openx_done(struct tevent_req
*subreq
)
2970 struct tevent_req
*req
= tevent_req_callback_data(
2971 subreq
, struct tevent_req
);
2972 struct smb1_openx_state
*state
= tevent_req_data(
2973 req
, struct smb1_openx_state
);
2975 uint16_t *vwv
= NULL
;
2978 status
= cli_smb_recv(subreq
,
2984 NULL
, /* num_rbytes */
2986 TALLOC_FREE(subreq
);
2987 if (tevent_req_nterror(req
, status
)) {
2990 state
->fnum
= PULL_LE_U16(vwv
+2, 0);
2991 tevent_req_done(req
);
2994 static NTSTATUS
smb1_openx_recv(struct tevent_req
*req
, uint16_t *pfnum
)
2996 struct smb1_openx_state
*state
= tevent_req_data(
2997 req
, struct smb1_openx_state
);
3000 if (tevent_req_is_nterror(req
, &status
)) {
3003 *pfnum
= state
->fnum
;
3004 return NT_STATUS_OK
;
3007 static NTSTATUS
smb1_openx(struct cli_state
*cli
, const char *path
)
3009 TALLOC_CTX
*frame
= talloc_stackframe();
3010 struct tevent_context
*ev
= NULL
;
3011 struct tevent_req
*req
= NULL
;
3012 uint16_t fnum
= (uint16_t)-1;
3013 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3015 ev
= samba_tevent_context_init(frame
);
3020 req
= smb1_openx_send(frame
,
3028 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3032 status
= smb1_openx_recv(req
, &fnum
);
3035 /* Close "file" handle. */
3036 if (fnum
!= (uint16_t)-1) {
3037 (void)smb1cli_close(cli
->conn
,
3043 0); /* last_modified */
3049 static bool test_smb1_openx(struct cli_state
*cli
)
3052 bool retval
= false;
3055 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\openxfile");
3057 status
= smb1_openx(cli
, "openxfile");
3058 if (!NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
3059 printf("%s:%d SMB1openx of %s should get "
3060 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3067 status
= smb1_openx(cli
, "\\BAD\\openxfile");
3068 if (!NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
3069 printf("%s:%d SMB1openx of %s should get "
3070 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3077 status
= smb1_openx(cli
, "\\BAD\\BAD\\openxfile");
3078 if (!NT_STATUS_IS_OK(status
)) {
3079 printf("%s:%d SMB1openx on %s returned %s\n",
3082 "\\BAD\\BAD\\openxfile",
3091 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\openxfile");
3095 static NTSTATUS
smb1_open(struct cli_state
*cli
,
3099 uint16_t vwv
[2] = { 0, 0};
3100 uint8_t *bytes
= NULL
;
3101 uint16_t accessmode
= 0;
3102 uint16_t *return_words
= NULL
;
3103 uint8_t return_wcount
= 0;
3106 accessmode
= (DENY_NONE
<<4);
3107 accessmode
|= DOS_OPEN_RDONLY
;
3109 PUSH_LE_U16(vwv
+ 0, 0, accessmode
);
3110 PUSH_LE_U16(vwv
+ 1, 0, FILE_ATTRIBUTE_NORMAL
);
3112 bytes
= talloc_array(talloc_tos(), uint8_t, 1);
3113 if (bytes
== NULL
) {
3114 return NT_STATUS_NO_MEMORY
;
3117 bytes
= smb_bytes_push_str(bytes
,
3118 smbXcli_conn_use_unicode(cli
->conn
),
3122 if (bytes
== NULL
) {
3123 return NT_STATUS_NO_MEMORY
;
3126 status
= cli_smb(talloc_tos(),
3128 SMBopen
, /* command. */
3129 0, /* additional_flags. */
3132 talloc_get_size(bytes
), /* num_bytes. */
3134 NULL
, /* result parent. */
3136 &return_wcount
, /* return wcount. */
3137 &return_words
, /* return wvw. */
3138 NULL
, /* return byte count. */
3139 NULL
); /* return bytes. */
3140 if (!NT_STATUS_IS_OK(status
)) {
3143 *pfnum
= PULL_LE_U16(return_words
, 0);
3147 static bool test_smb1_open(struct cli_state
*cli
)
3150 bool retval
= false;
3153 uint16_t fnum
= (uint16_t)-1;
3154 struct timespec testfile_crtime
= { 0 };
3155 struct timespec open_crtime
= { 0 };
3158 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\openfile");
3160 /* Create a test file. */
3161 ok
= smb1_create_testfile(cli
, "\\BAD\\BAD\\openfile");
3163 printf("%s:%d failed to create test file %s\n",
3166 "\\BAD\\BAD\\openfile");
3170 /* Get the test file crtime number. */
3171 status
= get_smb1_crtime(cli
,
3172 "\\BAD\\BAD\\openfile",
3174 if (!NT_STATUS_IS_OK(status
)) {
3175 printf("%s:%d Failed to get crtime for %s, (%s)\n",
3178 "\\BAD\\BAD\\openfile",
3183 status
= smb1_open(cli
, "openfile", &fnum
);
3184 if (!NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
3185 printf("%s:%d SMB1open of %s should get "
3186 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3193 status
= smb1_open(cli
, "\\BAD\\openfile", &fnum
);
3194 if (!NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
3195 printf("%s:%d SMB1open of %s should get "
3196 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3203 status
= smb1_open(cli
, "\\BAD\\BAD\\openfile", &fnum
);
3204 if (!NT_STATUS_IS_OK(status
)) {
3205 printf("%s:%d failed to open test file %s (%s)\n",
3208 "\\BAD\\BAD\\openfile",
3213 status
= cli_qfileinfo_basic(cli
,
3217 &open_crtime
, /* create_time */
3218 NULL
, /* access_time */
3219 NULL
, /* write_time */
3220 NULL
, /* change_time */
3222 if (!NT_STATUS_IS_OK(status
)) {
3223 printf("%s:%d failed to get crtime of test file %s (%s)\n",
3226 "\\BAD\\BAD\\openfile",
3230 equal
= (timespec_compare(&testfile_crtime
, &open_crtime
) == 0);
3232 printf("%s:%d crtime mismatch of test file %s\n",
3235 "\\BAD\\BAD\\openfile");
3243 /* Close "openfile" handle. */
3244 if (fnum
!= (uint16_t)-1) {
3245 (void)smb1cli_close(cli
->conn
,
3251 0); /* last_modified */
3253 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\openfile");
3257 static NTSTATUS
smb1_create(struct cli_state
*cli
,
3259 uint16_t smb1_operation
,
3262 uint16_t vwv
[3] = { 0, 0, 0};
3263 uint8_t *bytes
= NULL
;
3264 uint16_t *return_words
= NULL
;
3265 uint8_t return_wcount
= 0;
3268 PUSH_LE_U16(vwv
+ 0, 0, FILE_ATTRIBUTE_NORMAL
);
3270 bytes
= talloc_array(talloc_tos(), uint8_t, 1);
3271 if (bytes
== NULL
) {
3272 return NT_STATUS_NO_MEMORY
;
3275 bytes
= smb_bytes_push_str(bytes
,
3276 smbXcli_conn_use_unicode(cli
->conn
),
3280 if (bytes
== NULL
) {
3281 return NT_STATUS_NO_MEMORY
;
3284 status
= cli_smb(talloc_tos(),
3286 smb1_operation
, /* command. */
3287 0, /* additional_flags. */
3290 talloc_get_size(bytes
), /* num_bytes. */
3292 NULL
, /* result parent. */
3294 &return_wcount
, /* return wcount. */
3295 &return_words
, /* return wvw. */
3296 NULL
, /* return byte count. */
3297 NULL
); /* return bytes. */
3298 if (!NT_STATUS_IS_OK(status
)) {
3301 *pfnum
= PULL_LE_U16(return_words
, 0);
3305 static bool test_smb1_create(struct cli_state
*cli
)
3308 bool retval
= false;
3309 uint16_t fnum
= (uint16_t)-1;
3312 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\createfile");
3313 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\mknewfile");
3315 status
= smb1_create(cli
, "createfile", SMBcreate
, &fnum
);
3316 if (!NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
3317 printf("%s:%d SMB1create of %s should get "
3318 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3325 status
= smb1_create(cli
, "\\BAD\\createfile", SMBcreate
, &fnum
);
3326 if (!NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
3327 printf("%s:%d SMB1open of %s should get "
3328 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3335 status
= smb1_create(cli
, "\\BAD\\BAD\\createfile", SMBcreate
, &fnum
);
3336 if (!NT_STATUS_IS_OK(status
)) {
3337 printf("%s:%d failed to create file %s (%s)\n",
3340 "\\BAD\\BAD\\createfile",
3345 (void)smb1cli_close(cli
->conn
,
3351 0); /* last_modified */
3353 fnum
= (uint16_t)-1;
3355 /* Now do the same with SMBmknew */
3356 status
= smb1_create(cli
, "mknewfile", SMBmknew
, &fnum
);
3357 if (!NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
3358 printf("%s:%d SMB1mknew of %s should get "
3359 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3366 status
= smb1_create(cli
, "\\BAD\\mknewfile", SMBmknew
, &fnum
);
3367 if (!NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
3368 printf("%s:%d SMB1mknew of %s should get "
3369 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3376 status
= smb1_create(cli
, "\\BAD\\BAD\\mknewfile", SMBmknew
, &fnum
);
3377 if (!NT_STATUS_IS_OK(status
)) {
3378 printf("%s:%d failed to create file %s (%s)\n",
3381 "\\BAD\\BAD\\mknewfile",
3386 (void)smb1cli_close(cli
->conn
,
3392 0); /* last_modified */
3394 fnum
= (uint16_t)-1;
3400 /* Close "openfile" handle. */
3401 if (fnum
!= (uint16_t)-1) {
3402 (void)smb1cli_close(cli
->conn
,
3408 0); /* last_modified */
3410 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\createfile");
3411 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\mknewfile");
3415 static NTSTATUS
smb1_getatr(struct cli_state
*cli
,
3419 uint8_t *bytes
= NULL
;
3420 uint16_t *return_words
= NULL
;
3421 uint8_t return_wcount
= 0;
3424 bytes
= talloc_array(talloc_tos(), uint8_t, 1);
3425 if (bytes
== NULL
) {
3426 return NT_STATUS_NO_MEMORY
;
3429 bytes
= smb_bytes_push_str(bytes
,
3430 smbXcli_conn_use_unicode(cli
->conn
),
3434 if (bytes
== NULL
) {
3435 return NT_STATUS_NO_MEMORY
;
3438 status
= cli_smb(talloc_tos(),
3440 SMBgetatr
, /* command. */
3441 0, /* additional_flags. */
3444 talloc_get_size(bytes
), /* num_bytes. */
3446 NULL
, /* result parent. */
3448 &return_wcount
, /* return wcount. */
3449 &return_words
, /* return wvw. */
3450 NULL
, /* return byte count. */
3451 NULL
); /* return bytes. */
3452 if (!NT_STATUS_IS_OK(status
)) {
3455 *pattr
= PULL_LE_U16(return_words
, 0);
3459 static bool test_smb1_getatr(struct cli_state
*cli
)
3462 bool retval
= false;
3467 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\getatrfile");
3469 /* Create a test file. */
3470 ok
= smb1_create_testfile(cli
, "\\BAD\\BAD\\getatrfile");
3472 printf("%s:%d failed to create test file %s\n",
3475 "\\BAD\\BAD\\getatrfile");
3480 * We expect this to succeed, but get attributes of
3481 * the root directory.
3483 status
= smb1_getatr(cli
, "getatrfile", &attrs
);
3484 if (!NT_STATUS_IS_OK(status
)) {
3485 printf("%s:%d SMB1getatr of %s failed (%s)\n",
3492 if ((attrs
& FILE_ATTRIBUTE_DIRECTORY
) == 0) {
3493 printf("%s:%d error expected SMB1getatr of file %s "
3494 "to return directory attributes. Got 0x%x\n",
3498 (unsigned int)attrs
);
3503 * We expect this to succeed, but get attributes of
3504 * the root directory.
3506 status
= smb1_getatr(cli
, "\\BAD\\getatrfile", &attrs
);
3507 if (!NT_STATUS_IS_OK(status
)) {
3508 printf("%s:%d SMB1getatr of %s failed (%s)\n",
3511 "\\BAD\\getatrfile",
3515 if ((attrs
& FILE_ATTRIBUTE_DIRECTORY
) == 0) {
3516 printf("%s:%d error expected SMB1getatr of file %s "
3517 "to return directory attributes. Got 0x%x\n",
3520 "\\BAD\\getatrfile",
3521 (unsigned int)attrs
);
3526 * We expect this to succeed, and get attributes of
3529 status
= smb1_getatr(cli
, "\\BAD\\BAD\\getatrfile", &attrs
);
3530 if (!NT_STATUS_IS_OK(status
)) {
3531 printf("%s:%d SMB1getatr of %s failed (%s)\n",
3534 "\\BAD\\BAD\\getatrfile",
3538 if (attrs
& FILE_ATTRIBUTE_DIRECTORY
) {
3539 printf("%s:%d error expected SMB1getatr of file %s "
3540 "to return non-directory attributes. Got 0x%x\n",
3543 "\\BAD\\BAD\\getatrfile",
3544 (unsigned int)attrs
);
3552 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\getatrfile");
3556 static NTSTATUS
smb1_setatr(struct cli_state
*cli
,
3560 uint16_t vwv
[8] = { 0 };
3561 uint8_t *bytes
= NULL
;
3564 PUSH_LE_U16(vwv
, 0, attr
);
3565 bytes
= talloc_array(talloc_tos(), uint8_t, 1);
3566 if (bytes
== NULL
) {
3567 return NT_STATUS_NO_MEMORY
;
3570 bytes
= smb_bytes_push_str(bytes
,
3571 smbXcli_conn_use_unicode(cli
->conn
),
3575 if (bytes
== NULL
) {
3576 return NT_STATUS_NO_MEMORY
;
3578 status
= cli_smb(talloc_tos(),
3580 SMBsetatr
, /* command. */
3581 0, /* additional_flags. */
3584 talloc_get_size(bytes
), /* num_bytes. */
3586 NULL
, /* result parent. */
3588 NULL
, /* return wcount. */
3589 NULL
, /* return wvw. */
3590 NULL
, /* return byte count. */
3591 NULL
); /* return bytes. */
3592 if (!NT_STATUS_IS_OK(status
)) {
3598 static bool test_smb1_setatr(struct cli_state
*cli
)
3601 bool retval
= false;
3603 uint16_t file_attrs
= 0;
3604 uint16_t orig_file_attrs
= 0;
3607 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\setatrfile");
3609 /* Create a test file. */
3610 ok
= smb1_create_testfile(cli
, "\\BAD\\BAD\\setatrfile");
3612 printf("%s:%d failed to create test file %s\n",
3615 "\\BAD\\BAD\\setatrfile");
3618 /* Get it's original attributes. */
3619 status
= smb1_getatr(cli
, "\\BAD\\BAD\\setatrfile", &orig_file_attrs
);
3620 if (!NT_STATUS_IS_OK(status
)) {
3621 printf("%s:%d SMB1getatr of %s failed (%s)\n",
3624 "\\BAD\\BAD\\setatrfile",
3629 if (orig_file_attrs
& FILE_ATTRIBUTE_SYSTEM
) {
3630 printf("%s:%d orig_file_attrs of %s already has SYSTEM. "
3631 "Test cannot proceed.\n",
3634 "\\BAD\\BAD\\setatrfile");
3639 * Seems we can't set attrs on the root of a share,
3640 * even as Administrator.
3642 status
= smb1_setatr(cli
, "setatrfile", FILE_ATTRIBUTE_SYSTEM
);
3643 if (!NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
3644 printf("%s:%d SMB1setatr of %s should get "
3645 "NT_STATUS_ACCESS_DENIED, got %s\n",
3654 * Seems we can't set attrs on the root of a share,
3655 * even as Administrator.
3657 status
= smb1_setatr(cli
, "\\BAD\\setatrfile", FILE_ATTRIBUTE_SYSTEM
);
3658 if (!NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
3659 printf("%s:%d SMB1setatr of %s should get "
3660 "NT_STATUS_ACCESS_DENIED, got %s\n",
3663 "\\BAD\\setatrfile",
3668 status
= smb1_setatr(cli
,
3669 "\\BAD\\BAD\\setatrfile",
3670 FILE_ATTRIBUTE_SYSTEM
);
3671 if (!NT_STATUS_IS_OK(status
)) {
3672 printf("%s:%d SMB1setatr of %s failed (%s)\n",
3675 "\\BAD\\BAD\\setatrfile",
3679 status
= smb1_getatr(cli
, "\\BAD\\BAD\\setatrfile", &file_attrs
);
3680 if (!NT_STATUS_IS_OK(status
)) {
3681 printf("%s:%d SMB1getatr of %s failed (%s)\n",
3684 "\\BAD\\BAD\\setatrfile",
3689 if (file_attrs
!= FILE_ATTRIBUTE_SYSTEM
) {
3690 printf("%s:%d Failed to set SYSTEM attr on %s\n",
3693 "\\BAD\\BAD\\setatrfile");
3701 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\setatrfile");
3705 static NTSTATUS
smb1_chkpath(struct cli_state
*cli
,
3708 uint8_t *bytes
= NULL
;
3711 bytes
= talloc_array(talloc_tos(), uint8_t, 1);
3712 if (bytes
== NULL
) {
3713 return NT_STATUS_NO_MEMORY
;
3716 bytes
= smb_bytes_push_str(bytes
,
3717 smbXcli_conn_use_unicode(cli
->conn
),
3721 if (bytes
== NULL
) {
3722 return NT_STATUS_NO_MEMORY
;
3724 status
= cli_smb(talloc_tos(),
3726 SMBcheckpath
, /* command. */
3727 0, /* additional_flags. */
3730 talloc_get_size(bytes
), /* num_bytes. */
3732 NULL
, /* result parent. */
3734 NULL
, /* return wcount. */
3735 NULL
, /* return wvw. */
3736 NULL
, /* return byte count. */
3737 NULL
); /* return bytes. */
3738 if (!NT_STATUS_IS_OK(status
)) {
3744 static bool test_smb1_chkpath(struct cli_state
*cli
)
3747 bool retval
= false;
3751 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\chkpathfile");
3753 /* Create a test file. */
3754 ok
= smb1_create_testfile(cli
, "\\BAD\\BAD\\chkpathfile");
3756 printf("%s:%d failed to create test file %s\n",
3759 "\\BAD\\BAD\\chkpathfile");
3763 * Should succeed - "chkpathfile" maps to
3766 status
= smb1_chkpath(cli
, "chkpathfile");
3767 if (!NT_STATUS_IS_OK(status
)) {
3768 printf("%s:%d SMB1chkpath of %s failed (%s)\n",
3777 * Should succeed - "\\BAD\\chkpathfile" maps to
3780 status
= smb1_chkpath(cli
, "\\BAD\\chkpathfile");
3781 if (!NT_STATUS_IS_OK(status
)) {
3782 printf("%s:%d SMB1chkpath of %s failed (%s)\n",
3785 "\\BAD\\chkpathfile",
3791 * Should fail - "\\BAD\\BAD\\chkpathfile" maps to the
3792 * "\\BAD\\BAD\\chkpathfile", not a directory.
3794 status
= smb1_chkpath(cli
, "\\BAD\\BAD\\chkpathfile");
3795 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
3796 printf("%s:%d SMB1chkpath of %s should get "
3797 "NT_STATUS_NOT_A_DIRECTORY, got %s\n",
3800 "\\BAD\\BAD\\chkpathfile",
3809 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\chkpathfile");
3814 * Test BUG: https://bugzilla.samba.org/show_bug.cgi?id=15419
3817 static bool test_smb1_chkpath_bad(struct cli_state
*cli
)
3821 status
= smb1_chkpath(cli
, "\\x//\\/");
3822 if (!NT_STATUS_IS_OK(status
)) {
3823 printf("%s:%d SMB1chkpath of %s failed (%s)\n",
3833 static NTSTATUS
smb1_ctemp(struct cli_state
*cli
,
3837 uint16_t vwv
[3] = { 0 };
3838 uint8_t *bytes
= NULL
;
3840 uint16_t *return_words
= NULL
;
3841 uint8_t return_wcount
= 0;
3842 uint32_t return_bytecount
= 0;
3843 uint8_t *return_bytes
= NULL
;
3845 uint16_t fnum
= (uint16_t)-1;
3847 bytes
= talloc_array(talloc_tos(), uint8_t, 1);
3848 if (bytes
== NULL
) {
3849 return NT_STATUS_NO_MEMORY
;
3852 bytes
= smb_bytes_push_str(bytes
,
3853 smbXcli_conn_use_unicode(cli
->conn
),
3857 if (bytes
== NULL
) {
3858 return NT_STATUS_NO_MEMORY
;
3860 status
= cli_smb(talloc_tos(),
3862 SMBctemp
, /* command. */
3863 0, /* additional_flags. */
3866 talloc_get_size(bytes
), /* num_bytes. */
3868 NULL
, /* result parent. */
3870 &return_wcount
, /* return wcount. */
3871 &return_words
, /* return wvw. */
3872 &return_bytecount
, /* return byte count. */
3873 &return_bytes
); /* return bytes. */
3874 if (!NT_STATUS_IS_OK(status
)) {
3878 if (return_wcount
!= 1) {
3879 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
3882 fnum
= PULL_LE_U16(return_words
, 0);
3884 /* Delete the file by fnum. */
3885 status
= cli_nt_delete_on_close(cli
, fnum
, 1);
3886 if (!NT_STATUS_IS_OK(status
)) {
3889 (void)smb1cli_close(cli
->conn
,
3895 0); /* last_modified */
3896 fnum
= (uint16_t)-1;
3898 if (return_bytecount
< 2) {
3899 return NT_STATUS_DATA_ERROR
;
3902 sret
= pull_string_talloc(talloc_tos(),
3910 return NT_STATUS_NO_MEMORY
;
3916 static bool test_smb1_ctemp(struct cli_state
*cli
)
3919 bool retval
= false;
3920 char *retpath
= NULL
;
3923 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\ctemp_dir");
3925 status
= smb1_mkdir(cli
, "\\BAD\\BAD\\ctemp_dir");
3926 if (!NT_STATUS_IS_OK(status
)) {
3927 printf("%s:%d Failed to create %s (%s)\n",
3930 "\\BAD\\BAD\\ctemp_dir",
3936 * Windows returns NT_STATUS_FILE_IS_A_DIRECTORY
3937 * for all SMBctemp calls on a DFS share, no
3938 * matter what we put in the pathname.
3942 * When we fix smbd we'll need to detect running
3943 * in smbtorture3 against smbd here and modify
3944 * the expected behavior. Windows is simply
3947 status
= smb1_ctemp(cli
, "ctemp_dir", &retpath
);
3948 if (!NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
3949 printf("%s:%d SMB1ctemp of %s should get "
3950 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3957 status
= smb1_ctemp(cli
, "\\BAD\\ctemp_dir", &retpath
);
3958 if (!NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
3959 printf("%s:%d SMB1ctemp of %s should get "
3960 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3967 status
= smb1_ctemp(cli
, "\\BAD\\BAD\\ctemp_dir", &retpath
);
3968 if (!NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
3969 printf("%s:%d SMB1ctemp of %s should get "
3970 "NT_STATUS_FILE_IS_A_DIRECTORY, got %s\n",
3973 "\\BAD\\BAD\\ctemp_dir",
3982 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\ctemp_dir");
3986 static NTSTATUS
smb1_qpathinfo(struct cli_state
*cli
,
3991 uint8_t *param
= NULL
;
3992 uint16_t setup
[1] = { 0 };
3993 uint8_t *rdata
= NULL
;
3994 uint32_t num_rdata
= 0;
3996 PUSH_LE_U16(setup
, 0, TRANSACT2_QPATHINFO
);
3998 param
= talloc_zero_array(talloc_tos(), uint8_t, 6);
3999 if (param
== NULL
) {
4000 return NT_STATUS_NO_MEMORY
;
4002 PUSH_LE_U16(param
, 0, SMB_QUERY_FILE_BASIC_INFO
);
4004 param
= trans2_bytes_push_str(param
,
4005 smbXcli_conn_use_unicode(cli
->conn
),
4009 if (param
== NULL
) {
4010 return NT_STATUS_NO_MEMORY
;
4013 status
= cli_trans(talloc_tos(),
4015 SMBtrans2
, /* cmd */
4016 NULL
, /* pipe_name */
4021 1, /* num_setup uint16_t words */
4022 0, /* max returned setup */
4024 talloc_get_size(param
), /* num_param */
4025 2, /* max returned param */
4028 SMB_BUFFER_SIZE_MAX
, /* max returned data */
4029 /* Return values from here on.. */
4030 NULL
, /* recv_flags2 */
4032 0, /* min returned rsetup */
4033 NULL
, /* num_rsetup */
4035 0, /* min returned rparam */
4036 NULL
, /* number of returned rparam */
4038 36, /* min returned rdata */
4040 if (!NT_STATUS_IS_OK(status
)) {
4043 *pattrs
= PULL_LE_U32(rdata
, 32);
4044 return NT_STATUS_OK
;
4047 static bool test_smb1_qpathinfo(struct cli_state
*cli
)
4050 bool retval
= false;
4055 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\qpathinfo_file");
4057 /* Create a test file. */
4058 ok
= smb1_create_testfile(cli
, "\\BAD\\BAD\\qpathinfo_file");
4060 printf("%s:%d failed to create test file %s\n",
4063 "\\BAD\\BAD\\qpathinfo_file");
4067 /* Should get root dir attrs. */
4068 status
= smb1_qpathinfo(cli
, "qpathinfo_file", &attrs
);
4069 if (!NT_STATUS_IS_OK(status
)) {
4070 printf("%s:%d smb1_qpathinfo failed %s (%s)\n",
4077 if ((attrs
& FILE_ATTRIBUTE_DIRECTORY
) == 0) {
4078 printf("%s:%d expected FILE_ATTRIBUTE_DIRECTORY on %s "
4079 "got attribute 0x%x\n",
4083 (unsigned int)attrs
);
4087 /* Should get root dir attrs. */
4088 status
= smb1_qpathinfo(cli
, "\\BAD\\qpathinfo_file", &attrs
);
4089 if (!NT_STATUS_IS_OK(status
)) {
4090 printf("%s:%d smb1_qpathinfo failed %s (%s)\n",
4093 "\\BAD\\qpathinfo_file",
4097 if ((attrs
& FILE_ATTRIBUTE_DIRECTORY
) == 0) {
4098 printf("%s:%d expected FILE_ATTRIBUTE_DIRECTORY on %s "
4099 "got attribute 0x%x\n",
4102 "\\BAD\\qpathinfo_file",
4103 (unsigned int)attrs
);
4107 /* Should get file attrs. */
4108 status
= smb1_qpathinfo(cli
, "\\BAD\\BAD\\qpathinfo_file", &attrs
);
4109 if (!NT_STATUS_IS_OK(status
)) {
4110 printf("%s:%d smb1_qpathinfo failed %s (%s)\n",
4113 "\\BAD\\BAD\\qpathinfo_file",
4117 if ((attrs
& FILE_ATTRIBUTE_DIRECTORY
) != 0) {
4118 printf("%s:%d expected not FILE_ATTRIBUTE_DIRECTORY on %s "
4119 "got attribute 0x%x\n",
4122 "\\BAD\\BAD\\qpathinfo_file",
4123 (unsigned int)attrs
);
4130 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\qpathinfo_file");
4135 * "Raw" test of different SMB1 operations to a DFS share.
4136 * We must (mostly) use the lower level smb1cli_XXXX() interfaces,
4137 * not the cli_XXX() ones here as the ultimate goal is to fix our
4138 * cli_XXX() interfaces to work transparently over DFS.
4140 * So here, we're testing the server code, not the client code.
4142 * Passes cleanly against Windows.
4145 bool run_smb1_dfs_operations(int dummy
)
4147 struct cli_state
*cli
= NULL
;
4148 bool dfs_supported
= false;
4149 bool retval
= false;
4152 printf("Starting SMB1-DFS-OPS\n");
4154 if (!torture_init_connection(&cli
)) {
4158 if (!torture_open_connection(&cli
, 0)) {
4162 /* Ensure this is a DFS share. */
4163 dfs_supported
= smbXcli_conn_dfs_supported(cli
->conn
);
4164 if (!dfs_supported
) {
4165 printf("Server %s does not support DFS\n",
4166 smbXcli_conn_remote_name(cli
->conn
));
4169 dfs_supported
= smbXcli_tcon_is_dfs_share(cli
->smb1
.tcon
);
4170 if (!dfs_supported
) {
4171 printf("Share %s does not support DFS\n",
4176 ok
= test_smb1_unlink(cli
);
4181 ok
= test_smb1_mkdir(cli
);
4186 ok
= test_smb1_rmdir(cli
);
4191 ok
= test_smb1_ntcreatex(cli
);
4196 ok
= test_smb1_nttrans_create(cli
);
4201 ok
= test_smb1_openx(cli
);
4206 ok
= test_smb1_open(cli
);
4211 ok
= test_smb1_create(cli
);
4216 ok
= test_smb1_getatr(cli
);
4221 ok
= test_smb1_setatr(cli
);
4226 ok
= test_smb1_chkpath(cli
);
4231 ok
= test_smb1_ctemp(cli
);
4236 ok
= test_smb1_qpathinfo(cli
);
4245 /* Delete anything we made. */
4246 (void)smb1_dfs_delete(cli
, "\\BAD\\BAD\\file");
4251 * Test BUG: https://bugzilla.samba.org/show_bug.cgi?id=15419
4254 bool run_smb1_dfs_check_badpath(int dummy
)
4256 struct cli_state
*cli
= NULL
;
4257 bool dfs_supported
= false;
4259 printf("Starting SMB1-DFS-CHECK-BADPATH\n");
4261 if (!torture_init_connection(&cli
)) {
4265 if (!torture_open_connection(&cli
, 0)) {
4269 /* Ensure this is a DFS share. */
4270 dfs_supported
= smbXcli_conn_dfs_supported(cli
->conn
);
4271 if (!dfs_supported
) {
4272 printf("Server %s does not support DFS\n",
4273 smbXcli_conn_remote_name(cli
->conn
));
4276 dfs_supported
= smbXcli_tcon_is_dfs_share(cli
->smb1
.tcon
);
4277 if (!dfs_supported
) {
4278 printf("Share %s does not support DFS\n",
4283 return test_smb1_chkpath_bad(cli
);