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