2 Unix SMB/CIFS implementation.
3 SMB torture tester - deny mode scanning functions
4 Copyright (C) Andrew Tridgell 2001
5 Copyright (C) David Mulder 2019
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "system/filesys.h"
23 #include "libcli/smb2/smb2.h"
24 #include "libcli/smb2/smb2_calls.h"
25 #include "libcli/security/security.h"
26 #include "torture/util.h"
27 #include "torture/smb2/proto.h"
29 #define MAXIMUM_ALLOWED_FILE "torture_maximum_allowed"
30 static bool torture_smb2_maximum_allowed(struct torture_context
*tctx
,
31 struct smb2_tree
*tree
)
33 struct security_descriptor
*sd
= NULL
, *sd_orig
= NULL
;
34 struct smb2_create io
= {0};
35 TALLOC_CTX
*mem_ctx
= NULL
;
36 struct smb2_handle fnum
= {{0}}, fnum1
= {{0}};
41 union smb_setfileinfo set
;
42 const char *owner_sid
= NULL
;
43 bool has_restore_privilege
, has_backup_privilege
, has_system_security_privilege
;
45 mem_ctx
= talloc_init("torture_maximum_allowed");
46 torture_assert_goto(tctx
, mem_ctx
!= NULL
, ret
, done
,
47 "talloc allocation failed\n");
49 if (!torture_setting_bool(tctx
, "sacl_support", true))
50 torture_warning(tctx
, "Skipping SACL related tests!\n");
52 sd
= security_descriptor_dacl_create(mem_ctx
,
54 SID_NT_AUTHENTICATED_USERS
,
55 SEC_ACE_TYPE_ACCESS_ALLOWED
,
58 torture_assert_goto(tctx
, sd
!= NULL
, ret
, done
,
59 "security descriptor creation failed\n");
62 smb2_util_unlink(tree
, MAXIMUM_ALLOWED_FILE
);
64 /* create initial file with restrictive SD */
65 io
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
66 io
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
67 io
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
68 io
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
69 io
.in
.fname
= MAXIMUM_ALLOWED_FILE
;
72 status
= smb2_create(tree
, mem_ctx
, &io
);
73 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
74 talloc_asprintf(tctx
, "Incorrect status %s - should be %s\n",
75 nt_errstr(status
), nt_errstr(NT_STATUS_OK
)));
76 fnum
= io
.out
.file
.handle
;
78 /* the correct answers for this test depends on whether the
79 user has restore privileges. To find that out we first need
80 to know our SID - get it from the owner_sid of the file we
82 q
.query_secdesc
.level
= RAW_FILEINFO_SEC_DESC
;
83 q
.query_secdesc
.in
.file
.handle
= fnum
;
84 q
.query_secdesc
.in
.secinfo_flags
= SECINFO_DACL
| SECINFO_OWNER
;
85 status
= smb2_getinfo_file(tree
, tctx
, &q
);
86 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, set_sd
,
87 talloc_asprintf(tctx
, "Incorrect status %s - should be %s\n",
88 nt_errstr(status
), nt_errstr(NT_STATUS_OK
)));
89 sd_orig
= q
.query_secdesc
.out
.sd
;
91 owner_sid
= dom_sid_string(tctx
, sd_orig
->owner_sid
);
93 status
= torture_smb2_check_privilege(tree
,
95 sec_privilege_name(SEC_PRIV_RESTORE
));
96 has_restore_privilege
= NT_STATUS_IS_OK(status
);
97 torture_comment(tctx
, "Checked SEC_PRIV_RESTORE for %s - %s\n",
99 has_restore_privilege
?"Yes":"No");
101 status
= torture_smb2_check_privilege(tree
,
103 sec_privilege_name(SEC_PRIV_BACKUP
));
104 has_backup_privilege
= NT_STATUS_IS_OK(status
);
105 torture_comment(tctx
, "Checked SEC_PRIV_BACKUP for %s - %s\n",
107 has_backup_privilege
?"Yes":"No");
109 status
= torture_smb2_check_privilege(tree
,
111 sec_privilege_name(SEC_PRIV_SECURITY
));
112 has_system_security_privilege
= NT_STATUS_IS_OK(status
);
113 torture_comment(tctx
, "Checked SEC_PRIV_SECURITY for %s - %s\n",
115 has_system_security_privilege
?"Yes":"No");
117 smb2_util_close(tree
, fnum
);
119 for (i
= 0; i
< 32; i
++) {
120 uint32_t mask
= SEC_FLAG_MAXIMUM_ALLOWED
| (1u << i
);
122 * SEC_GENERIC_EXECUTE is a complete subset of
123 * SEC_GENERIC_READ when mapped to specific bits,
124 * so we need to include it in the basic OK mask.
126 uint32_t ok_mask
= SEC_RIGHTS_FILE_READ
| SEC_GENERIC_READ
| SEC_GENERIC_EXECUTE
|
127 SEC_STD_DELETE
| SEC_STD_WRITE_DAC
;
130 * Now SEC_RIGHTS_PRIV_RESTORE and SEC_RIGHTS_PRIV_BACKUP
131 * don't include any generic bits (they're used directly
132 * in the fileserver where the generic bits have already
133 * been mapped into file specific bits) we need to add the
134 * generic bits to the ok_mask when we have these privileges.
136 if (has_restore_privilege
) {
137 ok_mask
|= SEC_RIGHTS_PRIV_RESTORE
|SEC_GENERIC_WRITE
;
139 if (has_backup_privilege
) {
140 ok_mask
|= SEC_RIGHTS_PRIV_BACKUP
|SEC_GENERIC_READ
;
142 if (has_system_security_privilege
) {
143 ok_mask
|= SEC_FLAG_SYSTEM_SECURITY
;
146 /* Skip all SACL related tests. */
147 if ((!torture_setting_bool(tctx
, "sacl_support", true)) &&
148 (mask
& SEC_FLAG_SYSTEM_SECURITY
))
151 io
= (struct smb2_create
){0};
152 io
.in
.desired_access
= mask
;
153 io
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
154 io
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
155 io
.in
.impersonation_level
=
156 NTCREATEX_IMPERSONATION_ANONYMOUS
;
157 io
.in
.fname
= MAXIMUM_ALLOWED_FILE
;
159 status
= smb2_create(tree
, mem_ctx
, &io
);
160 if (mask
& ok_mask
||
161 mask
== SEC_FLAG_MAXIMUM_ALLOWED
) {
162 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
,
163 set_sd
, talloc_asprintf(tctx
,
164 "Incorrect status %s - should be %s\n",
165 nt_errstr(status
), nt_errstr(NT_STATUS_OK
)));
167 if (mask
& SEC_FLAG_SYSTEM_SECURITY
) {
168 torture_assert_ntstatus_equal_goto(tctx
,
169 status
, NT_STATUS_PRIVILEGE_NOT_HELD
,
170 ret
, set_sd
, talloc_asprintf(tctx
,
171 "Incorrect status %s - should be %s\n",
173 nt_errstr(NT_STATUS_PRIVILEGE_NOT_HELD
)));
175 torture_assert_ntstatus_equal_goto(tctx
,
176 status
, NT_STATUS_ACCESS_DENIED
,
177 ret
, set_sd
, talloc_asprintf(tctx
,
178 "Incorrect status %s - should be %s\n",
180 nt_errstr(NT_STATUS_ACCESS_DENIED
)));
184 fnum
= io
.out
.file
.handle
;
186 smb2_util_close(tree
, fnum
);
190 io
.in
.desired_access
= SEC_STD_WRITE_DAC
;
191 io
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
192 io
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
193 io
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
194 io
.in
.fname
= MAXIMUM_ALLOWED_FILE
;
196 status
= smb2_create(tree
, mem_ctx
, &io
);
197 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
198 talloc_asprintf(tctx
, "Incorrect status %s - should be %s\n",
199 nt_errstr(status
), nt_errstr(NT_STATUS_OK
)));
200 fnum1
= io
.out
.file
.handle
;
202 sd
= security_descriptor_dacl_create(tctx
,
204 SID_NT_AUTHENTICATED_USERS
,
205 SEC_ACE_TYPE_ACCESS_ALLOWED
,
209 set
.set_secdesc
.level
= RAW_SFILEINFO_SEC_DESC
;
210 set
.set_secdesc
.in
.file
.handle
= fnum1
;
211 set
.set_secdesc
.in
.secinfo_flags
= SECINFO_DACL
;
212 set
.set_secdesc
.in
.sd
= sd
;
214 status
= smb2_setinfo_file(tree
, &set
);
215 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
216 talloc_asprintf(tctx
, "Incorrect status %s - should be %s\n",
217 nt_errstr(status
), nt_errstr(NT_STATUS_OK
)));
220 smb2_util_close(tree
, fnum1
);
221 smb2_util_unlink(tree
, MAXIMUM_ALLOWED_FILE
);
222 talloc_free(mem_ctx
);
226 static bool torture_smb2_read_only_file(struct torture_context
*tctx
,
227 struct smb2_tree
*tree
)
229 struct smb2_create c
;
230 struct smb2_handle h
= {{0}};
234 smb2_deltree(tree
, MAXIMUM_ALLOWED_FILE
);
236 c
= (struct smb2_create
) {
237 .in
.desired_access
= SEC_RIGHTS_FILE_ALL
,
238 .in
.file_attributes
= FILE_ATTRIBUTE_READONLY
,
239 .in
.create_disposition
= NTCREATEX_DISP_CREATE
,
240 .in
.fname
= MAXIMUM_ALLOWED_FILE
,
243 status
= smb2_create(tree
, tctx
, &c
);
244 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
245 "smb2_create failed\n");
246 h
= c
.out
.file
.handle
;
247 smb2_util_close(tree
, h
);
250 c
= (struct smb2_create
) {
251 .in
.desired_access
= SEC_FLAG_MAXIMUM_ALLOWED
,
252 .in
.file_attributes
= FILE_ATTRIBUTE_READONLY
,
253 .in
.create_disposition
= NTCREATEX_DISP_OPEN
,
254 .in
.fname
= MAXIMUM_ALLOWED_FILE
,
257 status
= smb2_create(tree
, tctx
, &c
);
258 torture_assert_ntstatus_ok_goto(
259 tctx
, status
, ret
, done
,
260 "Failed to open READ-ONLY file with SEC_FLAG_MAXIMUM_ALLOWED\n");
261 h
= c
.out
.file
.handle
;
262 smb2_util_close(tree
, h
);
266 if (!smb2_util_handle_empty(h
)) {
267 smb2_util_close(tree
, h
);
269 smb2_deltree(tree
, MAXIMUM_ALLOWED_FILE
);
273 struct torture_suite
*torture_smb2_max_allowed(TALLOC_CTX
*ctx
)
275 struct torture_suite
*suite
= torture_suite_create(ctx
, "maximum_allowed");
277 torture_suite_add_1smb2_test(suite
, "maximum_allowed", torture_smb2_maximum_allowed
);
278 torture_suite_add_1smb2_test(suite
, "read_only", torture_smb2_read_only_file
);