1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cmse.c
5 * PURPOSE: Configuration Manager - Security Subsystem Interface
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "ntoskrnl.h"
12 #define NDEBUG
13 #include "debug.h"
14
15 /* GLOBALS *******************************************************************/
16
17 /* FUNCTIONS *****************************************************************/
18
19 PSECURITY_DESCRIPTOR
20 NTAPI
CmpHiveRootSecurityDescriptor(VOID)21 CmpHiveRootSecurityDescriptor(VOID)
22 {
23 NTSTATUS Status;
24 PSECURITY_DESCRIPTOR SecurityDescriptor;
25 PACL Acl, AclCopy;
26 PSID Sid[4];
27 SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
28 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
29 ULONG AceLength, AclLength, SidLength;
30 PACE_HEADER AceHeader;
31 ULONG i;
32 PAGED_CODE();
33
34 /* Phase 1: Allocate SIDs */
35 SidLength = RtlLengthRequiredSid(1);
36 Sid[0] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CMSD);
37 Sid[1] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CMSD);
38 Sid[2] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CMSD);
39 SidLength = RtlLengthRequiredSid(2);
40 Sid[3] = ExAllocatePoolWithTag(PagedPool, SidLength, TAG_CMSD);
41
42 /* Make sure all SIDs were allocated */
43 if (!Sid[0] || !Sid[1] || !Sid[2] || !Sid[3])
44 {
45 /* Bugcheck */
46 KeBugCheckEx(REGISTRY_ERROR, 11, 1, 0, 0);
47 }
48
49 /* Phase 2: Initialize all SIDs */
50 Status = RtlInitializeSid(Sid[0], &WorldAuthority, 1);
51 Status |= RtlInitializeSid(Sid[1], &NtAuthority, 1);
52 Status |= RtlInitializeSid(Sid[2], &NtAuthority, 1);
53 Status |= RtlInitializeSid(Sid[3], &NtAuthority, 2);
54 if (!NT_SUCCESS(Status)) KeBugCheckEx(REGISTRY_ERROR, 11, 2, 0, 0);
55
56 /* Phase 2: Setup SID Sub Authorities */
57 *RtlSubAuthoritySid(Sid[0], 0) = SECURITY_WORLD_RID;
58 *RtlSubAuthoritySid(Sid[1], 0) = SECURITY_RESTRICTED_CODE_RID;
59 *RtlSubAuthoritySid(Sid[2], 0) = SECURITY_LOCAL_SYSTEM_RID;
60 *RtlSubAuthoritySid(Sid[3], 0) = SECURITY_BUILTIN_DOMAIN_RID;
61 *RtlSubAuthoritySid(Sid[3], 1) = DOMAIN_ALIAS_RID_ADMINS;
62
63 /* Make sure all SIDs are valid */
64 ASSERT(RtlValidSid(Sid[0]));
65 ASSERT(RtlValidSid(Sid[1]));
66 ASSERT(RtlValidSid(Sid[2]));
67 ASSERT(RtlValidSid(Sid[3]));
68
69 /* Phase 3: Calculate ACL Length */
70 AclLength = sizeof(ACL);
71 for (i = 0; i < 4; i++)
72 {
73 /* This is what MSDN says to do */
74 AceLength = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart);
75 AceLength += SeLengthSid(Sid[i]);
76 AclLength += AceLength;
77 }
78
79 /* Phase 3: Allocate the ACL */
80 Acl = ExAllocatePoolWithTag(PagedPool, AclLength, TAG_CMSD);
81 if (!Acl) KeBugCheckEx(REGISTRY_ERROR, 11, 3, 0, 0);
82
83 /* Phase 4: Create the ACL */
84 Status = RtlCreateAcl(Acl, AclLength, ACL_REVISION);
85 if (!NT_SUCCESS(Status)) KeBugCheckEx(REGISTRY_ERROR, 11, 4, Status, 0);
86
87 /* Phase 5: Build the ACL */
88 Status = RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_ALL_ACCESS, Sid[2]);
89 Status |= RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_ALL_ACCESS, Sid[3]);
90 Status |= RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_READ, Sid[0]);
91 Status |= RtlAddAccessAllowedAce(Acl, ACL_REVISION, KEY_READ, Sid[1]);
92 if (!NT_SUCCESS(Status)) KeBugCheckEx(REGISTRY_ERROR, 11, 5, Status, 0);
93
94 /* Phase 5: Make the ACEs inheritable */
95 Status = RtlGetAce(Acl, 0, (PVOID*)&AceHeader);
96 ASSERT(NT_SUCCESS(Status));
97 AceHeader->AceFlags |= CONTAINER_INHERIT_ACE;
98 Status = RtlGetAce(Acl, 1, (PVOID*)&AceHeader);
99 ASSERT(NT_SUCCESS(Status));
100 AceHeader->AceFlags |= CONTAINER_INHERIT_ACE;
101 Status = RtlGetAce(Acl, 2, (PVOID*)&AceHeader);
102 ASSERT(NT_SUCCESS(Status));
103 AceHeader->AceFlags |= CONTAINER_INHERIT_ACE;
104 Status = RtlGetAce(Acl, 3, (PVOID*)&AceHeader);
105 ASSERT(NT_SUCCESS(Status));
106 AceHeader->AceFlags |= CONTAINER_INHERIT_ACE;
107
108 /* Phase 6: Allocate the security descriptor and make space for the ACL */
109 SecurityDescriptor = ExAllocatePoolWithTag(PagedPool,
110 sizeof(SECURITY_DESCRIPTOR) +
111 AclLength,
112 TAG_CMSD);
113 if (!SecurityDescriptor) KeBugCheckEx(REGISTRY_ERROR, 11, 6, 0, 0);
114
115 /* Phase 6: Make a copy of the ACL */
116 AclCopy = (PACL)((PISECURITY_DESCRIPTOR)SecurityDescriptor + 1);
117 RtlCopyMemory(AclCopy, Acl, AclLength);
118
119 /* Phase 7: Create the security descriptor */
120 Status = RtlCreateSecurityDescriptor(SecurityDescriptor,
121 SECURITY_DESCRIPTOR_REVISION);
122 if (!NT_SUCCESS(Status)) KeBugCheckEx(REGISTRY_ERROR, 11, 7, Status, 0);
123
124 /* Phase 8: Set the ACL as a DACL */
125 Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor,
126 TRUE,
127 AclCopy,
128 FALSE);
129 if (!NT_SUCCESS(Status)) KeBugCheckEx(REGISTRY_ERROR, 11, 8, Status, 0);
130
131 /* Free the SIDs and original ACL */
132 for (i = 0; i < 4; i++) ExFreePoolWithTag(Sid[i], TAG_CMSD);
133 ExFreePoolWithTag(Acl, TAG_CMSD);
134
135 /* Return the security descriptor */
136 return SecurityDescriptor;
137 }
138
139 NTSTATUS
CmpQuerySecurityDescriptor(IN PCM_KEY_CONTROL_BLOCK Kcb,IN SECURITY_INFORMATION SecurityInformation,OUT PSECURITY_DESCRIPTOR SecurityDescriptor,IN OUT PULONG BufferLength)140 CmpQuerySecurityDescriptor(IN PCM_KEY_CONTROL_BLOCK Kcb,
141 IN SECURITY_INFORMATION SecurityInformation,
142 OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
143 IN OUT PULONG BufferLength)
144 {
145 PISECURITY_DESCRIPTOR_RELATIVE RelSd;
146 ULONG SidSize;
147 ULONG AclSize;
148 ULONG SdSize;
149 NTSTATUS Status;
150 SECURITY_DESCRIPTOR_CONTROL Control = 0;
151 ULONG Owner = 0;
152 ULONG Group = 0;
153 ULONG Dacl = 0;
154
155 DBG_UNREFERENCED_PARAMETER(Kcb);
156
157 DPRINT("CmpQuerySecurityDescriptor()\n");
158
159 if (SecurityInformation == 0)
160 {
161 return STATUS_ACCESS_DENIED;
162 }
163
164 SidSize = RtlLengthSid(SeWorldSid);
165 RelSd = SecurityDescriptor;
166 SdSize = sizeof(*RelSd);
167
168 if (SecurityInformation & OWNER_SECURITY_INFORMATION)
169 {
170 Owner = SdSize;
171 SdSize += SidSize;
172 }
173
174 if (SecurityInformation & GROUP_SECURITY_INFORMATION)
175 {
176 Group = SdSize;
177 SdSize += SidSize;
178 }
179
180 if (SecurityInformation & DACL_SECURITY_INFORMATION)
181 {
182 Control |= SE_DACL_PRESENT;
183 Dacl = SdSize;
184 AclSize = sizeof(ACL) + sizeof(ACE) + SidSize;
185 SdSize += AclSize;
186 }
187
188 if (SecurityInformation & SACL_SECURITY_INFORMATION)
189 {
190 Control |= SE_SACL_PRESENT;
191 }
192
193 if (*BufferLength < SdSize)
194 {
195 *BufferLength = SdSize;
196 return STATUS_BUFFER_TOO_SMALL;
197 }
198
199 *BufferLength = SdSize;
200
201 Status = RtlCreateSecurityDescriptorRelative(RelSd,
202 SECURITY_DESCRIPTOR_REVISION);
203 if (!NT_SUCCESS(Status))
204 return Status;
205
206 RelSd->Control |= Control;
207 RelSd->Owner = Owner;
208 RelSd->Group = Group;
209 RelSd->Dacl = Dacl;
210
211 if (Owner)
212 RtlCopyMemory((PUCHAR)RelSd + Owner,
213 SeWorldSid,
214 SidSize);
215
216 if (Group)
217 RtlCopyMemory((PUCHAR)RelSd + Group,
218 SeWorldSid,
219 SidSize);
220
221 if (Dacl)
222 {
223 Status = RtlCreateAcl((PACL)((PUCHAR)RelSd + Dacl),
224 AclSize,
225 ACL_REVISION);
226 if (NT_SUCCESS(Status))
227 {
228 Status = RtlAddAccessAllowedAce((PACL)((PUCHAR)RelSd + Dacl),
229 ACL_REVISION,
230 GENERIC_ALL,
231 SeWorldSid);
232 }
233 }
234
235 ASSERT(Status == STATUS_SUCCESS);
236 return Status;
237 }
238
239 NTSTATUS
CmpSetSecurityDescriptor(IN PCM_KEY_CONTROL_BLOCK Kcb,IN PSECURITY_INFORMATION SecurityInformation,IN PSECURITY_DESCRIPTOR SecurityDescriptor,IN POOL_TYPE PoolType,IN PGENERIC_MAPPING GenericMapping)240 CmpSetSecurityDescriptor(IN PCM_KEY_CONTROL_BLOCK Kcb,
241 IN PSECURITY_INFORMATION SecurityInformation,
242 IN PSECURITY_DESCRIPTOR SecurityDescriptor,
243 IN POOL_TYPE PoolType,
244 IN PGENERIC_MAPPING GenericMapping)
245 {
246 DPRINT("CmpSetSecurityDescriptor()\n");
247 return STATUS_SUCCESS;
248 }
249
250 NTSTATUS
CmpAssignSecurityDescriptor(IN PCM_KEY_CONTROL_BLOCK Kcb,IN PSECURITY_DESCRIPTOR SecurityDescriptor)251 CmpAssignSecurityDescriptor(IN PCM_KEY_CONTROL_BLOCK Kcb,
252 IN PSECURITY_DESCRIPTOR SecurityDescriptor)
253 {
254 DPRINT("CmpAssignSecurityDescriptor(%p %p)\n",
255 Kcb, SecurityDescriptor);
256 return STATUS_SUCCESS;
257 }
258
259 NTSTATUS
260 NTAPI
CmpSecurityMethod(IN PVOID ObjectBody,IN SECURITY_OPERATION_CODE OperationCode,IN PSECURITY_INFORMATION SecurityInformation,IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,IN OUT PULONG BufferLength,IN OUT PSECURITY_DESCRIPTOR * OldSecurityDescriptor,IN POOL_TYPE PoolType,IN PGENERIC_MAPPING GenericMapping)261 CmpSecurityMethod(IN PVOID ObjectBody,
262 IN SECURITY_OPERATION_CODE OperationCode,
263 IN PSECURITY_INFORMATION SecurityInformation,
264 IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
265 IN OUT PULONG BufferLength,
266 IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
267 IN POOL_TYPE PoolType,
268 IN PGENERIC_MAPPING GenericMapping)
269 {
270 PCM_KEY_CONTROL_BLOCK Kcb;
271 NTSTATUS Status = STATUS_SUCCESS;
272
273 DBG_UNREFERENCED_PARAMETER(OldSecurityDescriptor);
274 DBG_UNREFERENCED_PARAMETER(GenericMapping);
275
276 Kcb = ((PCM_KEY_BODY)ObjectBody)->KeyControlBlock;
277
278 /* Acquire the hive lock */
279 CmpLockRegistry();
280
281 /* Acquire the KCB lock */
282 if (OperationCode == QuerySecurityDescriptor)
283 {
284 /* Avoid recursive locking if somebody already holds it */
285 if (!((PCM_KEY_BODY)ObjectBody)->KcbLocked)
286 {
287 CmpAcquireKcbLockShared(Kcb);
288 }
289 }
290 else
291 {
292 ASSERT(!((PCM_KEY_BODY)ObjectBody)->KcbLocked);
293 CmpAcquireKcbLockExclusive(Kcb);
294 }
295
296 /* Don't touch deleted keys */
297 if (Kcb->Delete)
298 {
299 /* Release the KCB lock */
300 CmpReleaseKcbLock(Kcb);
301
302 /* Release the hive lock */
303 CmpUnlockRegistry();
304 return STATUS_KEY_DELETED;
305 }
306
307 switch (OperationCode)
308 {
309 case SetSecurityDescriptor:
310 DPRINT("Set security descriptor\n");
311 ASSERT((PoolType == PagedPool) || (PoolType == NonPagedPool));
312 Status = CmpSetSecurityDescriptor(Kcb,
313 SecurityInformation,
314 SecurityDescriptor,
315 PoolType,
316 GenericMapping);
317 break;
318
319 case QuerySecurityDescriptor:
320 DPRINT("Query security descriptor\n");
321 Status = CmpQuerySecurityDescriptor(Kcb,
322 *SecurityInformation,
323 SecurityDescriptor,
324 BufferLength);
325 break;
326
327 case DeleteSecurityDescriptor:
328 DPRINT("Delete security descriptor\n");
329 /* HACK */
330 break;
331
332 case AssignSecurityDescriptor:
333 DPRINT("Assign security descriptor\n");
334 Status = CmpAssignSecurityDescriptor(Kcb,
335 SecurityDescriptor);
336 break;
337
338 default:
339 KeBugCheckEx(SECURITY_SYSTEM, 0, STATUS_INVALID_PARAMETER, 0, 0);
340 }
341
342 /*
343 * Release the KCB lock, but only if we locked it ourselves and
344 * nobody else was locking it by themselves.
345 */
346 if (!((PCM_KEY_BODY)ObjectBody)->KcbLocked)
347 {
348 CmpReleaseKcbLock(Kcb);
349 }
350
351 /* Release the hive lock */
352 CmpUnlockRegistry();
353
354 return Status;
355 }
356