Line data Source code
1 : /*
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
6 :
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.
11 :
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.
16 :
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/>.
19 : */
20 :
21 : #include "includes.h"
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"
28 :
29 : #define MAXIMUM_ALLOWED_FILE "torture_maximum_allowed"
30 5 : static bool torture_smb2_maximum_allowed(struct torture_context *tctx,
31 : struct smb2_tree *tree)
32 : {
33 5 : struct security_descriptor *sd = NULL, *sd_orig = NULL;
34 5 : struct smb2_create io = {0};
35 5 : TALLOC_CTX *mem_ctx = NULL;
36 5 : struct smb2_handle fnum = {{0}}, fnum1 = {{0}};
37 0 : int i;
38 5 : bool ret = true;
39 0 : NTSTATUS status;
40 0 : union smb_fileinfo q;
41 0 : union smb_setfileinfo set;
42 5 : const char *owner_sid = NULL;
43 0 : bool has_restore_privilege, has_backup_privilege, has_system_security_privilege;
44 :
45 5 : mem_ctx = talloc_init("torture_maximum_allowed");
46 5 : torture_assert_goto(tctx, mem_ctx != NULL, ret, done,
47 : "talloc allocation failed\n");
48 :
49 5 : if (!torture_setting_bool(tctx, "sacl_support", true))
50 0 : torture_warning(tctx, "Skipping SACL related tests!\n");
51 :
52 5 : sd = security_descriptor_dacl_create(mem_ctx,
53 : 0, NULL, NULL,
54 : SID_NT_AUTHENTICATED_USERS,
55 : SEC_ACE_TYPE_ACCESS_ALLOWED,
56 : SEC_RIGHTS_FILE_READ,
57 : 0, NULL);
58 5 : torture_assert_goto(tctx, sd != NULL, ret, done,
59 : "security descriptor creation failed\n");
60 :
61 : /* Blank slate */
62 5 : smb2_util_unlink(tree, MAXIMUM_ALLOWED_FILE);
63 :
64 : /* create initial file with restrictive SD */
65 5 : io.in.desired_access = SEC_RIGHTS_FILE_ALL;
66 5 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
67 5 : io.in.create_disposition = NTCREATEX_DISP_CREATE;
68 5 : io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
69 5 : io.in.fname = MAXIMUM_ALLOWED_FILE;
70 5 : io.in.sec_desc = sd;
71 :
72 5 : status = smb2_create(tree, mem_ctx, &io);
73 5 : 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 5 : fnum = io.out.file.handle;
77 :
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
81 : just created */
82 5 : q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
83 5 : q.query_secdesc.in.file.handle = fnum;
84 5 : q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
85 5 : status = smb2_getinfo_file(tree, tctx, &q);
86 5 : 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 5 : sd_orig = q.query_secdesc.out.sd;
90 :
91 5 : owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
92 :
93 5 : status = torture_smb2_check_privilege(tree,
94 : owner_sid,
95 : sec_privilege_name(SEC_PRIV_RESTORE));
96 5 : has_restore_privilege = NT_STATUS_IS_OK(status);
97 5 : torture_comment(tctx, "Checked SEC_PRIV_RESTORE for %s - %s\n",
98 : owner_sid,
99 : has_restore_privilege?"Yes":"No");
100 :
101 5 : status = torture_smb2_check_privilege(tree,
102 : owner_sid,
103 : sec_privilege_name(SEC_PRIV_BACKUP));
104 5 : has_backup_privilege = NT_STATUS_IS_OK(status);
105 5 : torture_comment(tctx, "Checked SEC_PRIV_BACKUP for %s - %s\n",
106 : owner_sid,
107 : has_backup_privilege?"Yes":"No");
108 :
109 5 : status = torture_smb2_check_privilege(tree,
110 : owner_sid,
111 : sec_privilege_name(SEC_PRIV_SECURITY));
112 5 : has_system_security_privilege = NT_STATUS_IS_OK(status);
113 5 : torture_comment(tctx, "Checked SEC_PRIV_SECURITY for %s - %s\n",
114 : owner_sid,
115 : has_system_security_privilege?"Yes":"No");
116 :
117 5 : smb2_util_close(tree, fnum);
118 :
119 40 : for (i = 0; i < 32; i++) {
120 40 : uint32_t mask = SEC_FLAG_MAXIMUM_ALLOWED | (1u << i);
121 : /*
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.
125 : */
126 40 : uint32_t ok_mask = SEC_RIGHTS_FILE_READ | SEC_GENERIC_READ | SEC_GENERIC_EXECUTE |
127 : SEC_STD_DELETE | SEC_STD_WRITE_DAC;
128 :
129 : /*
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.
135 : */
136 40 : if (has_restore_privilege) {
137 6 : ok_mask |= SEC_RIGHTS_PRIV_RESTORE|SEC_GENERIC_WRITE;
138 : }
139 40 : if (has_backup_privilege) {
140 6 : ok_mask |= SEC_RIGHTS_PRIV_BACKUP|SEC_GENERIC_READ;
141 : }
142 40 : if (has_system_security_privilege) {
143 6 : ok_mask |= SEC_FLAG_SYSTEM_SECURITY;
144 : }
145 :
146 : /* Skip all SACL related tests. */
147 40 : if ((!torture_setting_bool(tctx, "sacl_support", true)) &&
148 0 : (mask & SEC_FLAG_SYSTEM_SECURITY))
149 0 : continue;
150 :
151 40 : io = (struct smb2_create){0};
152 40 : io.in.desired_access = mask;
153 40 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
154 40 : io.in.create_disposition = NTCREATEX_DISP_OPEN;
155 40 : io.in.impersonation_level =
156 : NTCREATEX_IMPERSONATION_ANONYMOUS;
157 40 : io.in.fname = MAXIMUM_ALLOWED_FILE;
158 :
159 40 : status = smb2_create(tree, mem_ctx, &io);
160 40 : if (mask & ok_mask ||
161 : mask == SEC_FLAG_MAXIMUM_ALLOWED) {
162 14 : 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)));
166 : } else {
167 26 : if (mask & SEC_FLAG_SYSTEM_SECURITY) {
168 0 : 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",
172 : nt_errstr(status),
173 : nt_errstr(NT_STATUS_PRIVILEGE_NOT_HELD)));
174 : } else {
175 26 : 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",
179 : nt_errstr(status),
180 : nt_errstr(NT_STATUS_ACCESS_DENIED)));
181 : }
182 : }
183 :
184 35 : fnum = io.out.file.handle;
185 :
186 35 : smb2_util_close(tree, fnum);
187 : }
188 :
189 0 : set_sd:
190 5 : io.in.desired_access = SEC_STD_WRITE_DAC;
191 5 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
192 5 : io.in.create_disposition = NTCREATEX_DISP_OPEN;
193 5 : io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
194 5 : io.in.fname = MAXIMUM_ALLOWED_FILE;
195 :
196 5 : status = smb2_create(tree, mem_ctx, &io);
197 5 : 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 5 : fnum1 = io.out.file.handle;
201 :
202 5 : sd = security_descriptor_dacl_create(tctx,
203 : 0, NULL, NULL,
204 : SID_NT_AUTHENTICATED_USERS,
205 : SEC_ACE_TYPE_ACCESS_ALLOWED,
206 : SEC_STD_DELETE,
207 : 0,
208 : NULL);
209 5 : set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
210 5 : set.set_secdesc.in.file.handle = fnum1;
211 5 : set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
212 5 : set.set_secdesc.in.sd = sd;
213 :
214 5 : status = smb2_setinfo_file(tree, &set);
215 5 : 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)));
218 :
219 5 : done:
220 5 : smb2_util_close(tree, fnum1);
221 5 : smb2_util_unlink(tree, MAXIMUM_ALLOWED_FILE);
222 5 : talloc_free(mem_ctx);
223 5 : return ret;
224 : }
225 :
226 5 : static bool torture_smb2_read_only_file(struct torture_context *tctx,
227 : struct smb2_tree *tree)
228 : {
229 0 : struct smb2_create c;
230 5 : struct smb2_handle h = {{0}};
231 5 : bool ret = true;
232 0 : NTSTATUS status;
233 :
234 5 : smb2_deltree(tree, MAXIMUM_ALLOWED_FILE);
235 :
236 5 : 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,
241 : };
242 :
243 5 : status = smb2_create(tree, tctx, &c);
244 5 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
245 : "smb2_create failed\n");
246 5 : h = c.out.file.handle;
247 5 : smb2_util_close(tree, h);
248 5 : ZERO_STRUCT(h);
249 :
250 5 : 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,
255 : };
256 :
257 5 : status = smb2_create(tree, tctx, &c);
258 5 : torture_assert_ntstatus_ok_goto(
259 : tctx, status, ret, done,
260 : "Failed to open READ-ONLY file with SEC_FLAG_MAXIMUM_ALLOWED\n");
261 5 : h = c.out.file.handle;
262 5 : smb2_util_close(tree, h);
263 5 : ZERO_STRUCT(h);
264 :
265 5 : done:
266 5 : if (!smb2_util_handle_empty(h)) {
267 0 : smb2_util_close(tree, h);
268 : }
269 5 : smb2_deltree(tree, MAXIMUM_ALLOWED_FILE);
270 5 : return ret;
271 : }
272 :
273 2354 : struct torture_suite *torture_smb2_max_allowed(TALLOC_CTX *ctx)
274 : {
275 2354 : struct torture_suite *suite = torture_suite_create(ctx, "maximum_allowed");
276 :
277 2354 : torture_suite_add_1smb2_test(suite, "maximum_allowed", torture_smb2_maximum_allowed);
278 2354 : torture_suite_add_1smb2_test(suite, "read_only", torture_smb2_read_only_file);
279 2354 : return suite;
280 : }
|