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 1 : bool torture_smb2_maximum_allowed(struct torture_context *tctx,
31 : struct smb2_tree *tree)
32 : {
33 1 : struct security_descriptor *sd = NULL, *sd_orig = NULL;
34 1 : struct smb2_create io = {0};
35 1 : TALLOC_CTX *mem_ctx = NULL;
36 1 : struct smb2_handle fnum = {{0}};
37 : int i;
38 1 : bool ret = true;
39 : NTSTATUS status;
40 : union smb_fileinfo q;
41 1 : const char *owner_sid = NULL;
42 : bool has_restore_privilege, has_backup_privilege, has_system_security_privilege;
43 :
44 1 : mem_ctx = talloc_init("torture_maximum_allowed");
45 1 : torture_assert_goto(tctx, mem_ctx != NULL, ret, done,
46 : "talloc allocation failed\n");
47 :
48 1 : if (!torture_setting_bool(tctx, "sacl_support", true))
49 0 : torture_warning(tctx, "Skipping SACL related tests!\n");
50 :
51 1 : sd = security_descriptor_dacl_create(mem_ctx,
52 : 0, NULL, NULL,
53 : SID_NT_AUTHENTICATED_USERS,
54 : SEC_ACE_TYPE_ACCESS_ALLOWED,
55 : SEC_RIGHTS_FILE_READ,
56 : 0, NULL);
57 1 : torture_assert_goto(tctx, sd != NULL, ret, done,
58 : "security descriptor creation failed\n");
59 :
60 : /* Blank slate */
61 1 : smb2_util_unlink(tree, MAXIMUM_ALLOWED_FILE);
62 :
63 : /* create initial file with restrictive SD */
64 1 : io.in.desired_access = SEC_RIGHTS_FILE_ALL;
65 1 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
66 1 : io.in.create_disposition = NTCREATEX_DISP_CREATE;
67 1 : io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
68 1 : io.in.fname = MAXIMUM_ALLOWED_FILE;
69 1 : io.in.sec_desc = sd;
70 :
71 1 : status = smb2_create(tree, mem_ctx, &io);
72 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
73 : talloc_asprintf(tctx, "Incorrect status %s - should be %s\n",
74 : nt_errstr(status), nt_errstr(NT_STATUS_OK)));
75 1 : fnum = io.out.file.handle;
76 :
77 : /* the correct answers for this test depends on whether the
78 : user has restore privileges. To find that out we first need
79 : to know our SID - get it from the owner_sid of the file we
80 : just created */
81 1 : q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
82 1 : q.query_secdesc.in.file.handle = fnum;
83 1 : q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
84 1 : status = smb2_getinfo_file(tree, tctx, &q);
85 1 : torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
86 : talloc_asprintf(tctx, "Incorrect status %s - should be %s\n",
87 : nt_errstr(status), nt_errstr(NT_STATUS_OK)));
88 1 : sd_orig = q.query_secdesc.out.sd;
89 :
90 1 : owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
91 :
92 1 : status = torture_smb2_check_privilege(tree,
93 : owner_sid,
94 : sec_privilege_name(SEC_PRIV_RESTORE));
95 1 : has_restore_privilege = NT_STATUS_IS_OK(status);
96 1 : torture_comment(tctx, "Checked SEC_PRIV_RESTORE for %s - %s\n",
97 : owner_sid,
98 : has_restore_privilege?"Yes":"No");
99 :
100 1 : status = torture_smb2_check_privilege(tree,
101 : owner_sid,
102 : sec_privilege_name(SEC_PRIV_BACKUP));
103 1 : has_backup_privilege = NT_STATUS_IS_OK(status);
104 1 : torture_comment(tctx, "Checked SEC_PRIV_BACKUP for %s - %s\n",
105 : owner_sid,
106 : has_backup_privilege?"Yes":"No");
107 :
108 1 : status = torture_smb2_check_privilege(tree,
109 : owner_sid,
110 : sec_privilege_name(SEC_PRIV_SECURITY));
111 1 : has_system_security_privilege = NT_STATUS_IS_OK(status);
112 1 : torture_comment(tctx, "Checked SEC_PRIV_SECURITY for %s - %s\n",
113 : owner_sid,
114 : has_system_security_privilege?"Yes":"No");
115 :
116 1 : smb2_util_close(tree, fnum);
117 :
118 2 : for (i = 0; i < 32; i++) {
119 2 : uint32_t mask = SEC_FLAG_MAXIMUM_ALLOWED | (1u << i);
120 : /*
121 : * SEC_GENERIC_EXECUTE is a complete subset of
122 : * SEC_GENERIC_READ when mapped to specific bits,
123 : * so we need to include it in the basic OK mask.
124 : */
125 2 : uint32_t ok_mask = SEC_RIGHTS_FILE_READ | SEC_GENERIC_READ | SEC_GENERIC_EXECUTE |
126 : SEC_STD_DELETE | SEC_STD_WRITE_DAC;
127 :
128 : /*
129 : * Now SEC_RIGHTS_PRIV_RESTORE and SEC_RIGHTS_PRIV_BACKUP
130 : * don't include any generic bits (they're used directly
131 : * in the fileserver where the generic bits have already
132 : * been mapped into file specific bits) we need to add the
133 : * generic bits to the ok_mask when we have these privileges.
134 : */
135 2 : if (has_restore_privilege) {
136 2 : ok_mask |= SEC_RIGHTS_PRIV_RESTORE|SEC_GENERIC_WRITE;
137 : }
138 2 : if (has_backup_privilege) {
139 2 : ok_mask |= SEC_RIGHTS_PRIV_BACKUP|SEC_GENERIC_READ;
140 : }
141 2 : if (has_system_security_privilege) {
142 2 : ok_mask |= SEC_FLAG_SYSTEM_SECURITY;
143 : }
144 :
145 : /* Skip all SACL related tests. */
146 2 : if ((!torture_setting_bool(tctx, "sacl_support", true)) &&
147 0 : (mask & SEC_FLAG_SYSTEM_SECURITY))
148 0 : continue;
149 :
150 2 : io = (struct smb2_create){0};
151 2 : io.in.desired_access = mask;
152 2 : io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
153 2 : io.in.create_disposition = NTCREATEX_DISP_OPEN;
154 2 : io.in.impersonation_level =
155 : NTCREATEX_IMPERSONATION_ANONYMOUS;
156 2 : io.in.fname = MAXIMUM_ALLOWED_FILE;
157 :
158 2 : status = smb2_create(tree, mem_ctx, &io);
159 2 : if (mask & ok_mask ||
160 : mask == SEC_FLAG_MAXIMUM_ALLOWED) {
161 2 : torture_assert_ntstatus_ok_goto(tctx, status, ret,
162 : done, talloc_asprintf(tctx,
163 : "Incorrect status %s - should be %s\n",
164 : nt_errstr(status), nt_errstr(NT_STATUS_OK)));
165 : } else {
166 0 : if (mask & SEC_FLAG_SYSTEM_SECURITY) {
167 0 : torture_assert_ntstatus_equal_goto(tctx,
168 : status, NT_STATUS_PRIVILEGE_NOT_HELD,
169 : ret, done, talloc_asprintf(tctx,
170 : "Incorrect status %s - should be %s\n",
171 : nt_errstr(status),
172 : nt_errstr(NT_STATUS_PRIVILEGE_NOT_HELD)));
173 : } else {
174 0 : torture_assert_ntstatus_equal_goto(tctx,
175 : status, NT_STATUS_ACCESS_DENIED,
176 : ret, done, talloc_asprintf(tctx,
177 : "Incorrect status %s - should be %s\n",
178 : nt_errstr(status),
179 : nt_errstr(NT_STATUS_ACCESS_DENIED)));
180 : }
181 : }
182 :
183 1 : fnum = io.out.file.handle;
184 :
185 1 : smb2_util_close(tree, fnum);
186 : }
187 :
188 0 : done:
189 1 : smb2_util_unlink(tree, MAXIMUM_ALLOWED_FILE);
190 1 : talloc_free(mem_ctx);
191 1 : return ret;
192 : }
|