xref: /reactos/ntoskrnl/config/cmse.c (revision 565bf9e3)
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
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
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
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
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
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