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