1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Security Identifier (SID) implementation support and handling 5 * COPYRIGHT: Copyright David Welch <welch@cwcom.net> 6 */ 7 8 /* INCLUDES *******************************************************************/ 9 10 #include <ntoskrnl.h> 11 #define NDEBUG 12 #include <debug.h> 13 14 /* GLOBALS ********************************************************************/ 15 16 #define SE_MAXIMUM_GROUP_LIMIT 0x1000 17 18 SID_IDENTIFIER_AUTHORITY SeNullSidAuthority = {SECURITY_NULL_SID_AUTHORITY}; 19 SID_IDENTIFIER_AUTHORITY SeWorldSidAuthority = {SECURITY_WORLD_SID_AUTHORITY}; 20 SID_IDENTIFIER_AUTHORITY SeLocalSidAuthority = {SECURITY_LOCAL_SID_AUTHORITY}; 21 SID_IDENTIFIER_AUTHORITY SeCreatorSidAuthority = {SECURITY_CREATOR_SID_AUTHORITY}; 22 SID_IDENTIFIER_AUTHORITY SeNtSidAuthority = {SECURITY_NT_AUTHORITY}; 23 24 PSID SeNullSid = NULL; 25 PSID SeWorldSid = NULL; 26 PSID SeLocalSid = NULL; 27 PSID SeCreatorOwnerSid = NULL; 28 PSID SeCreatorGroupSid = NULL; 29 PSID SeCreatorOwnerServerSid = NULL; 30 PSID SeCreatorGroupServerSid = NULL; 31 PSID SeNtAuthoritySid = NULL; 32 PSID SeDialupSid = NULL; 33 PSID SeNetworkSid = NULL; 34 PSID SeBatchSid = NULL; 35 PSID SeInteractiveSid = NULL; 36 PSID SeServiceSid = NULL; 37 PSID SePrincipalSelfSid = NULL; 38 PSID SeLocalSystemSid = NULL; 39 PSID SeAuthenticatedUserSid = NULL; 40 PSID SeRestrictedCodeSid = NULL; 41 PSID SeAliasAdminsSid = NULL; 42 PSID SeAliasUsersSid = NULL; 43 PSID SeAliasGuestsSid = NULL; 44 PSID SeAliasPowerUsersSid = NULL; 45 PSID SeAliasAccountOpsSid = NULL; 46 PSID SeAliasSystemOpsSid = NULL; 47 PSID SeAliasPrintOpsSid = NULL; 48 PSID SeAliasBackupOpsSid = NULL; 49 PSID SeAuthenticatedUsersSid = NULL; 50 PSID SeRestrictedSid = NULL; 51 PSID SeAnonymousLogonSid = NULL; 52 PSID SeLocalServiceSid = NULL; 53 PSID SeNetworkServiceSid = NULL; 54 55 typedef struct _SID_VALIDATE 56 { 57 UCHAR SubAuthorityCount; 58 PISID ProbeSid; 59 } SID_VALIDATE, *PSID_VALIDATE; 60 61 /* FUNCTIONS ******************************************************************/ 62 63 /** 64 * @brief 65 * Frees all the known initialized SIDs in the system from the memory. 66 * 67 * @return 68 * Nothing. 69 */ 70 VOID 71 NTAPI 72 FreeInitializedSids(VOID) 73 { 74 if (SeNullSid) ExFreePoolWithTag(SeNullSid, TAG_SID); 75 if (SeWorldSid) ExFreePoolWithTag(SeWorldSid, TAG_SID); 76 if (SeLocalSid) ExFreePoolWithTag(SeLocalSid, TAG_SID); 77 if (SeCreatorOwnerSid) ExFreePoolWithTag(SeCreatorOwnerSid, TAG_SID); 78 if (SeCreatorGroupSid) ExFreePoolWithTag(SeCreatorGroupSid, TAG_SID); 79 if (SeCreatorOwnerServerSid) ExFreePoolWithTag(SeCreatorOwnerServerSid, TAG_SID); 80 if (SeCreatorGroupServerSid) ExFreePoolWithTag(SeCreatorGroupServerSid, TAG_SID); 81 if (SeNtAuthoritySid) ExFreePoolWithTag(SeNtAuthoritySid, TAG_SID); 82 if (SeDialupSid) ExFreePoolWithTag(SeDialupSid, TAG_SID); 83 if (SeNetworkSid) ExFreePoolWithTag(SeNetworkSid, TAG_SID); 84 if (SeBatchSid) ExFreePoolWithTag(SeBatchSid, TAG_SID); 85 if (SeInteractiveSid) ExFreePoolWithTag(SeInteractiveSid, TAG_SID); 86 if (SeServiceSid) ExFreePoolWithTag(SeServiceSid, TAG_SID); 87 if (SePrincipalSelfSid) ExFreePoolWithTag(SePrincipalSelfSid, TAG_SID); 88 if (SeLocalSystemSid) ExFreePoolWithTag(SeLocalSystemSid, TAG_SID); 89 if (SeAuthenticatedUserSid) ExFreePoolWithTag(SeAuthenticatedUserSid, TAG_SID); 90 if (SeRestrictedCodeSid) ExFreePoolWithTag(SeRestrictedCodeSid, TAG_SID); 91 if (SeAliasAdminsSid) ExFreePoolWithTag(SeAliasAdminsSid, TAG_SID); 92 if (SeAliasUsersSid) ExFreePoolWithTag(SeAliasUsersSid, TAG_SID); 93 if (SeAliasGuestsSid) ExFreePoolWithTag(SeAliasGuestsSid, TAG_SID); 94 if (SeAliasPowerUsersSid) ExFreePoolWithTag(SeAliasPowerUsersSid, TAG_SID); 95 if (SeAliasAccountOpsSid) ExFreePoolWithTag(SeAliasAccountOpsSid, TAG_SID); 96 if (SeAliasSystemOpsSid) ExFreePoolWithTag(SeAliasSystemOpsSid, TAG_SID); 97 if (SeAliasPrintOpsSid) ExFreePoolWithTag(SeAliasPrintOpsSid, TAG_SID); 98 if (SeAliasBackupOpsSid) ExFreePoolWithTag(SeAliasBackupOpsSid, TAG_SID); 99 if (SeAuthenticatedUsersSid) ExFreePoolWithTag(SeAuthenticatedUsersSid, TAG_SID); 100 if (SeRestrictedSid) ExFreePoolWithTag(SeRestrictedSid, TAG_SID); 101 if (SeAnonymousLogonSid) ExFreePoolWithTag(SeAnonymousLogonSid, TAG_SID); 102 } 103 104 /** 105 * @brief 106 * Initializes all the SIDs known in the system. 107 * 108 * @return 109 * Returns TRUE if all the SIDs have been initialized, 110 * FALSE otherwise. 111 */ 112 CODE_SEG("INIT") 113 BOOLEAN 114 NTAPI 115 SepInitSecurityIDs(VOID) 116 { 117 ULONG SidLength0; 118 ULONG SidLength1; 119 ULONG SidLength2; 120 PULONG SubAuthority; 121 122 SidLength0 = RtlLengthRequiredSid(0); 123 SidLength1 = RtlLengthRequiredSid(1); 124 SidLength2 = RtlLengthRequiredSid(2); 125 126 /* create NullSid */ 127 SeNullSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 128 SeWorldSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 129 SeLocalSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 130 SeCreatorOwnerSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 131 SeCreatorGroupSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 132 SeCreatorOwnerServerSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 133 SeCreatorGroupServerSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 134 SeNtAuthoritySid = ExAllocatePoolWithTag(PagedPool, SidLength0, TAG_SID); 135 SeDialupSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 136 SeNetworkSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 137 SeBatchSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 138 SeInteractiveSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 139 SeServiceSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 140 SePrincipalSelfSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 141 SeLocalSystemSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 142 SeAuthenticatedUserSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 143 SeRestrictedCodeSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 144 SeAliasAdminsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID); 145 SeAliasUsersSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID); 146 SeAliasGuestsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID); 147 SeAliasPowerUsersSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID); 148 SeAliasAccountOpsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID); 149 SeAliasSystemOpsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID); 150 SeAliasPrintOpsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID); 151 SeAliasBackupOpsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID); 152 SeAuthenticatedUsersSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 153 SeRestrictedSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 154 SeAnonymousLogonSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 155 SeLocalServiceSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 156 SeNetworkServiceSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); 157 158 if (SeNullSid == NULL || SeWorldSid == NULL || 159 SeLocalSid == NULL || SeCreatorOwnerSid == NULL || 160 SeCreatorGroupSid == NULL || SeCreatorOwnerServerSid == NULL || 161 SeCreatorGroupServerSid == NULL || SeNtAuthoritySid == NULL || 162 SeDialupSid == NULL || SeNetworkSid == NULL || SeBatchSid == NULL || 163 SeInteractiveSid == NULL || SeServiceSid == NULL || 164 SePrincipalSelfSid == NULL || SeLocalSystemSid == NULL || 165 SeAuthenticatedUserSid == NULL || SeRestrictedCodeSid == NULL || 166 SeAliasAdminsSid == NULL || SeAliasUsersSid == NULL || 167 SeAliasGuestsSid == NULL || SeAliasPowerUsersSid == NULL || 168 SeAliasAccountOpsSid == NULL || SeAliasSystemOpsSid == NULL || 169 SeAliasPrintOpsSid == NULL || SeAliasBackupOpsSid == NULL || 170 SeAuthenticatedUsersSid == NULL || SeRestrictedSid == NULL || 171 SeAnonymousLogonSid == NULL || SeLocalServiceSid == NULL || 172 SeNetworkServiceSid == NULL) 173 { 174 FreeInitializedSids(); 175 return FALSE; 176 } 177 178 RtlInitializeSid(SeNullSid, &SeNullSidAuthority, 1); 179 RtlInitializeSid(SeWorldSid, &SeWorldSidAuthority, 1); 180 RtlInitializeSid(SeLocalSid, &SeLocalSidAuthority, 1); 181 RtlInitializeSid(SeCreatorOwnerSid, &SeCreatorSidAuthority, 1); 182 RtlInitializeSid(SeCreatorGroupSid, &SeCreatorSidAuthority, 1); 183 RtlInitializeSid(SeCreatorOwnerServerSid, &SeCreatorSidAuthority, 1); 184 RtlInitializeSid(SeCreatorGroupServerSid, &SeCreatorSidAuthority, 1); 185 RtlInitializeSid(SeNtAuthoritySid, &SeNtSidAuthority, 0); 186 RtlInitializeSid(SeDialupSid, &SeNtSidAuthority, 1); 187 RtlInitializeSid(SeNetworkSid, &SeNtSidAuthority, 1); 188 RtlInitializeSid(SeBatchSid, &SeNtSidAuthority, 1); 189 RtlInitializeSid(SeInteractiveSid, &SeNtSidAuthority, 1); 190 RtlInitializeSid(SeServiceSid, &SeNtSidAuthority, 1); 191 RtlInitializeSid(SePrincipalSelfSid, &SeNtSidAuthority, 1); 192 RtlInitializeSid(SeLocalSystemSid, &SeNtSidAuthority, 1); 193 RtlInitializeSid(SeAuthenticatedUserSid, &SeNtSidAuthority, 1); 194 RtlInitializeSid(SeRestrictedCodeSid, &SeNtSidAuthority, 1); 195 RtlInitializeSid(SeAliasAdminsSid, &SeNtSidAuthority, 2); 196 RtlInitializeSid(SeAliasUsersSid, &SeNtSidAuthority, 2); 197 RtlInitializeSid(SeAliasGuestsSid, &SeNtSidAuthority, 2); 198 RtlInitializeSid(SeAliasPowerUsersSid, &SeNtSidAuthority, 2); 199 RtlInitializeSid(SeAliasAccountOpsSid, &SeNtSidAuthority, 2); 200 RtlInitializeSid(SeAliasSystemOpsSid, &SeNtSidAuthority, 2); 201 RtlInitializeSid(SeAliasPrintOpsSid, &SeNtSidAuthority, 2); 202 RtlInitializeSid(SeAliasBackupOpsSid, &SeNtSidAuthority, 2); 203 RtlInitializeSid(SeAuthenticatedUsersSid, &SeNtSidAuthority, 1); 204 RtlInitializeSid(SeRestrictedSid, &SeNtSidAuthority, 1); 205 RtlInitializeSid(SeAnonymousLogonSid, &SeNtSidAuthority, 1); 206 RtlInitializeSid(SeLocalServiceSid, &SeNtSidAuthority, 1); 207 RtlInitializeSid(SeNetworkServiceSid, &SeNtSidAuthority, 1); 208 209 SubAuthority = RtlSubAuthoritySid(SeNullSid, 0); 210 *SubAuthority = SECURITY_NULL_RID; 211 SubAuthority = RtlSubAuthoritySid(SeWorldSid, 0); 212 *SubAuthority = SECURITY_WORLD_RID; 213 SubAuthority = RtlSubAuthoritySid(SeLocalSid, 0); 214 *SubAuthority = SECURITY_LOCAL_RID; 215 SubAuthority = RtlSubAuthoritySid(SeCreatorOwnerSid, 0); 216 *SubAuthority = SECURITY_CREATOR_OWNER_RID; 217 SubAuthority = RtlSubAuthoritySid(SeCreatorGroupSid, 0); 218 *SubAuthority = SECURITY_CREATOR_GROUP_RID; 219 SubAuthority = RtlSubAuthoritySid(SeCreatorOwnerServerSid, 0); 220 *SubAuthority = SECURITY_CREATOR_OWNER_SERVER_RID; 221 SubAuthority = RtlSubAuthoritySid(SeCreatorGroupServerSid, 0); 222 *SubAuthority = SECURITY_CREATOR_GROUP_SERVER_RID; 223 SubAuthority = RtlSubAuthoritySid(SeDialupSid, 0); 224 *SubAuthority = SECURITY_DIALUP_RID; 225 SubAuthority = RtlSubAuthoritySid(SeNetworkSid, 0); 226 *SubAuthority = SECURITY_NETWORK_RID; 227 SubAuthority = RtlSubAuthoritySid(SeBatchSid, 0); 228 *SubAuthority = SECURITY_BATCH_RID; 229 SubAuthority = RtlSubAuthoritySid(SeInteractiveSid, 0); 230 *SubAuthority = SECURITY_INTERACTIVE_RID; 231 SubAuthority = RtlSubAuthoritySid(SeServiceSid, 0); 232 *SubAuthority = SECURITY_SERVICE_RID; 233 SubAuthority = RtlSubAuthoritySid(SePrincipalSelfSid, 0); 234 *SubAuthority = SECURITY_PRINCIPAL_SELF_RID; 235 SubAuthority = RtlSubAuthoritySid(SeLocalSystemSid, 0); 236 *SubAuthority = SECURITY_LOCAL_SYSTEM_RID; 237 SubAuthority = RtlSubAuthoritySid(SeAuthenticatedUserSid, 0); 238 *SubAuthority = SECURITY_AUTHENTICATED_USER_RID; 239 SubAuthority = RtlSubAuthoritySid(SeRestrictedCodeSid, 0); 240 *SubAuthority = SECURITY_RESTRICTED_CODE_RID; 241 SubAuthority = RtlSubAuthoritySid(SeAliasAdminsSid, 0); 242 *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID; 243 SubAuthority = RtlSubAuthoritySid(SeAliasAdminsSid, 1); 244 *SubAuthority = DOMAIN_ALIAS_RID_ADMINS; 245 SubAuthority = RtlSubAuthoritySid(SeAliasUsersSid, 0); 246 *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID; 247 SubAuthority = RtlSubAuthoritySid(SeAliasUsersSid, 1); 248 *SubAuthority = DOMAIN_ALIAS_RID_USERS; 249 SubAuthority = RtlSubAuthoritySid(SeAliasGuestsSid, 0); 250 *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID; 251 SubAuthority = RtlSubAuthoritySid(SeAliasGuestsSid, 1); 252 *SubAuthority = DOMAIN_ALIAS_RID_GUESTS; 253 SubAuthority = RtlSubAuthoritySid(SeAliasPowerUsersSid, 0); 254 *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID; 255 SubAuthority = RtlSubAuthoritySid(SeAliasPowerUsersSid, 1); 256 *SubAuthority = DOMAIN_ALIAS_RID_POWER_USERS; 257 SubAuthority = RtlSubAuthoritySid(SeAliasAccountOpsSid, 0); 258 *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID; 259 SubAuthority = RtlSubAuthoritySid(SeAliasAccountOpsSid, 1); 260 *SubAuthority = DOMAIN_ALIAS_RID_ACCOUNT_OPS; 261 SubAuthority = RtlSubAuthoritySid(SeAliasSystemOpsSid, 0); 262 *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID; 263 SubAuthority = RtlSubAuthoritySid(SeAliasSystemOpsSid, 1); 264 *SubAuthority = DOMAIN_ALIAS_RID_SYSTEM_OPS; 265 SubAuthority = RtlSubAuthoritySid(SeAliasPrintOpsSid, 0); 266 *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID; 267 SubAuthority = RtlSubAuthoritySid(SeAliasPrintOpsSid, 1); 268 *SubAuthority = DOMAIN_ALIAS_RID_PRINT_OPS; 269 SubAuthority = RtlSubAuthoritySid(SeAliasBackupOpsSid, 0); 270 *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID; 271 SubAuthority = RtlSubAuthoritySid(SeAliasBackupOpsSid, 1); 272 *SubAuthority = DOMAIN_ALIAS_RID_BACKUP_OPS; 273 SubAuthority = RtlSubAuthoritySid(SeAuthenticatedUsersSid, 0); 274 *SubAuthority = SECURITY_AUTHENTICATED_USER_RID; 275 SubAuthority = RtlSubAuthoritySid(SeRestrictedSid, 0); 276 *SubAuthority = SECURITY_RESTRICTED_CODE_RID; 277 SubAuthority = RtlSubAuthoritySid(SeAnonymousLogonSid, 0); 278 *SubAuthority = SECURITY_ANONYMOUS_LOGON_RID; 279 SubAuthority = RtlSubAuthoritySid(SeLocalServiceSid, 0); 280 *SubAuthority = SECURITY_LOCAL_SERVICE_RID; 281 SubAuthority = RtlSubAuthoritySid(SeNetworkServiceSid, 0); 282 *SubAuthority = SECURITY_NETWORK_SERVICE_RID; 283 284 return TRUE; 285 } 286 287 /** 288 * @brief 289 * Captures a SID. 290 * 291 * @param[in] InputSid 292 * A valid security identifier to be captured. 293 * 294 * @param[in] AccessMode 295 * Processor level access mode. 296 * 297 * @param[in] PoolType 298 * Pool memory type for the captured SID to assign upon 299 * allocation. 300 * 301 * @param[in] CaptureIfKernel 302 * If set to TRUE, the capturing is done within the kernel. 303 * Otherwise the capturing is done in a kernel mode driver. 304 * 305 * @param[out] CapturedSid 306 * The captured security identifier, returned to the caller. 307 * 308 * @return 309 * Returns STATUS_SUCCESS if the SID was captured. STATUS_INSUFFICIENT_RESOURCES 310 * is returned if memory pool allocation for the captured SID has failed. 311 */ 312 NTSTATUS 313 NTAPI 314 SepCaptureSid( 315 _In_ PSID InputSid, 316 _In_ KPROCESSOR_MODE AccessMode, 317 _In_ POOL_TYPE PoolType, 318 _In_ BOOLEAN CaptureIfKernel, 319 _Out_ PSID *CapturedSid) 320 { 321 ULONG SidSize = 0; 322 PISID NewSid, Sid = (PISID)InputSid; 323 324 PAGED_CODE(); 325 326 if (AccessMode != KernelMode) 327 { 328 _SEH2_TRY 329 { 330 ProbeForRead(Sid, FIELD_OFFSET(SID, SubAuthority), sizeof(UCHAR)); 331 SidSize = RtlLengthRequiredSid(Sid->SubAuthorityCount); 332 ProbeForRead(Sid, SidSize, sizeof(UCHAR)); 333 } 334 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 335 { 336 /* Return the exception code */ 337 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 338 } 339 _SEH2_END; 340 341 /* Allocate a SID and copy it */ 342 NewSid = ExAllocatePoolWithTag(PoolType, SidSize, TAG_SID); 343 if (!NewSid) 344 return STATUS_INSUFFICIENT_RESOURCES; 345 346 _SEH2_TRY 347 { 348 RtlCopyMemory(NewSid, Sid, SidSize); 349 350 *CapturedSid = NewSid; 351 } 352 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 353 { 354 /* Free the SID and return the exception code */ 355 ExFreePoolWithTag(NewSid, TAG_SID); 356 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 357 } 358 _SEH2_END; 359 } 360 else if (!CaptureIfKernel) 361 { 362 *CapturedSid = InputSid; 363 } 364 else 365 { 366 SidSize = RtlLengthRequiredSid(Sid->SubAuthorityCount); 367 368 /* Allocate a SID and copy it */ 369 NewSid = ExAllocatePoolWithTag(PoolType, SidSize, TAG_SID); 370 if (NewSid == NULL) 371 return STATUS_INSUFFICIENT_RESOURCES; 372 373 RtlCopyMemory(NewSid, Sid, SidSize); 374 375 *CapturedSid = NewSid; 376 } 377 378 return STATUS_SUCCESS; 379 } 380 381 /** 382 * @brief 383 * Releases a captured SID. 384 * 385 * @param[in] CapturedSid 386 * The captured SID to be released. 387 * 388 * @param[in] AccessMode 389 * Processor level access mode. 390 * 391 * @param[in] CaptureIfKernel 392 * If set to TRUE, the releasing is done within the kernel. 393 * Otherwise the releasing is done in a kernel mode driver. 394 * 395 * @return 396 * Nothing. 397 */ 398 VOID 399 NTAPI 400 SepReleaseSid( 401 _In_ PSID CapturedSid, 402 _In_ KPROCESSOR_MODE AccessMode, 403 _In_ BOOLEAN CaptureIfKernel) 404 { 405 PAGED_CODE(); 406 407 if (CapturedSid != NULL && 408 (AccessMode != KernelMode || 409 (AccessMode == KernelMode && CaptureIfKernel))) 410 { 411 ExFreePoolWithTag(CapturedSid, TAG_SID); 412 } 413 } 414 415 /** 416 * @brief 417 * Checks if a SID is present in a token. 418 * 419 * @param[in] _Token 420 * A valid token object. 421 * 422 * @param[in] PrincipalSelfSid 423 * A principal self SID. 424 * 425 * @param[in] _Sid 426 * A regular SID. 427 * 428 * @param[in] Deny 429 * If set to TRUE, the caller expected that a SID in a token 430 * must be a deny-only SID, that is, access checks are performed 431 * only for deny-only ACEs of the said SID. 432 * 433 * @param[in] Restricted 434 * If set to TRUE, the caller expects that a SID in a token is 435 * restricted (by the general definition, a token is restricted). 436 * 437 * @return 438 * Returns TRUE if the specified SID in the call is present in the token, 439 * FALSE otherwise. 440 */ 441 BOOLEAN 442 NTAPI 443 SepSidInTokenEx( 444 _In_ PACCESS_TOKEN _Token, 445 _In_ PSID PrincipalSelfSid, 446 _In_ PSID _Sid, 447 _In_ BOOLEAN Deny, 448 _In_ BOOLEAN Restricted) 449 { 450 ULONG SidIndex; 451 PTOKEN Token = (PTOKEN)_Token; 452 PISID TokenSid, Sid = (PISID)_Sid; 453 PSID_AND_ATTRIBUTES SidAndAttributes; 454 ULONG SidCount, SidLength; 455 USHORT SidMetadata; 456 PAGED_CODE(); 457 458 /* Check if a principal SID was given, and this is our current SID already */ 459 if ((PrincipalSelfSid) && (RtlEqualSid(SePrincipalSelfSid, Sid))) 460 { 461 /* Just use the principal SID in this case */ 462 Sid = PrincipalSelfSid; 463 } 464 465 /* Check if this is a restricted token or not */ 466 if (Restricted) 467 { 468 /* Use the restricted SIDs and count */ 469 SidAndAttributes = Token->RestrictedSids; 470 SidCount = Token->RestrictedSidCount; 471 } 472 else 473 { 474 /* Use the normal SIDs and count */ 475 SidAndAttributes = Token->UserAndGroups; 476 SidCount = Token->UserAndGroupCount; 477 } 478 479 /* Do checks here by hand instead of the usual 4 function calls */ 480 SidLength = FIELD_OFFSET(SID, 481 SubAuthority[Sid->SubAuthorityCount]); 482 SidMetadata = *(PUSHORT)&Sid->Revision; 483 484 /* Loop every SID */ 485 for (SidIndex = 0; SidIndex < SidCount; SidIndex++) 486 { 487 TokenSid = (PISID)SidAndAttributes->Sid; 488 #if SE_SID_DEBUG 489 UNICODE_STRING sidString; 490 RtlConvertSidToUnicodeString(&sidString, TokenSid, TRUE); 491 DPRINT1("SID in Token: %wZ\n", &sidString); 492 RtlFreeUnicodeString(&sidString); 493 #endif 494 /* Check if the SID metadata matches */ 495 if (*(PUSHORT)&TokenSid->Revision == SidMetadata) 496 { 497 /* Check if the SID data matches */ 498 if (RtlEqualMemory(Sid, TokenSid, SidLength)) 499 { 500 /* 501 * Check if the group is enabled, or used for deny only. 502 * Otherwise we have to check if this is the first user. 503 * We understand that by looking if this SID is not 504 * restricted, this is the first element we are iterating 505 * and that it doesn't have SE_GROUP_USE_FOR_DENY_ONLY 506 * attribute. 507 */ 508 if ((!Restricted && (SidIndex == 0) && !(SidAndAttributes->Attributes & SE_GROUP_USE_FOR_DENY_ONLY)) || 509 (SidAndAttributes->Attributes & SE_GROUP_ENABLED) || 510 ((Deny) && (SidAndAttributes->Attributes & SE_GROUP_USE_FOR_DENY_ONLY))) 511 { 512 /* SID is present */ 513 return TRUE; 514 } 515 else 516 { 517 /* SID is not present */ 518 return FALSE; 519 } 520 } 521 } 522 523 /* Move to the next SID */ 524 SidAndAttributes++; 525 } 526 527 /* SID is not present */ 528 return FALSE; 529 } 530 531 /** 532 * @brief 533 * Checks if a SID is present in a token. 534 * 535 * @param[in] _Token 536 * A valid token object. 537 * 538 * @param[in] _Sid 539 * A regular SID. 540 * 541 * @return 542 * Returns TRUE if the specified SID in the call is present in the token, 543 * FALSE otherwise. 544 */ 545 BOOLEAN 546 NTAPI 547 SepSidInToken( 548 _In_ PACCESS_TOKEN _Token, 549 _In_ PSID Sid) 550 { 551 /* Call extended API */ 552 return SepSidInTokenEx(_Token, NULL, Sid, FALSE, FALSE); 553 } 554 555 /** 556 * @brief 557 * Captures a security identifier from a 558 * given access control entry. This identifier 559 * is valid for the whole of its lifetime. 560 * 561 * @param[in] Ace 562 * A pointer to an access control entry, which 563 * can be obtained from a DACL. 564 * 565 * @return 566 * Returns a pointer to a security identifier (SID), 567 * otherwise NULL is returned if an unsupported ACE 568 * type was given to the function. 569 */ 570 PSID 571 NTAPI 572 SepGetSidFromAce( 573 _In_ PACE Ace) 574 { 575 PULONG Flags; 576 ULONG GuidSize = 0; 577 PSID Sid = NULL; 578 PAGED_CODE(); 579 580 /* Sanity check */ 581 ASSERT(Ace); 582 583 /* Obtain the SID based upon ACE type */ 584 switch (Ace->Header.AceType) 585 { 586 case ACCESS_DENIED_ACE_TYPE: 587 case ACCESS_ALLOWED_ACE_TYPE: 588 case SYSTEM_AUDIT_ACE_TYPE: 589 case SYSTEM_ALARM_ACE_TYPE: 590 { 591 Sid = (PSID)&((PKNOWN_ACE)Ace)->SidStart; 592 break; 593 } 594 595 case ACCESS_DENIED_OBJECT_ACE_TYPE: 596 case ACCESS_ALLOWED_OBJECT_ACE_TYPE: 597 { 598 Flags = (PULONG)&((PKNOWN_OBJECT_ACE)Ace)->Flags; 599 if (*Flags & ACE_OBJECT_TYPE_PRESENT) 600 { 601 GuidSize += sizeof(GUID); 602 } 603 604 if (*Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT) 605 { 606 GuidSize += sizeof(GUID); 607 } 608 609 Sid = (PSID)((ULONG_PTR)&((PKNOWN_OBJECT_ACE)Ace)->SidStart + GuidSize); 610 break; 611 } 612 613 default: 614 { 615 DPRINT1("SepGetSidFromAce(): Unknown ACE type (Ace 0x%p, Type %u)\n", Ace, Ace->Header.AceType); 616 break; 617 } 618 } 619 620 return Sid; 621 } 622 623 /** 624 * @brief 625 * Captures a SID with attributes. 626 * 627 * @param[in] SrcSidAndAttributes 628 * Source of the SID with attributes to be captured. 629 * 630 * @param[in] AttributeCount 631 * The number count of attributes, in total. 632 * 633 * @param[in] PreviousMode 634 * Processor access level mode. 635 * 636 * @param[in] AllocatedMem 637 * The allocated memory buffer for the captured SID. If the caller 638 * supplies no allocated block of memory then the function will 639 * allocate some buffer block of memory for the captured SID 640 * automatically. 641 * 642 * @param[in] AllocatedLength 643 * The length of the buffer that points to the allocated memory, 644 * in bytes. 645 * 646 * @param[in] PoolType 647 * The pool type for the captured SID and attributes to assign. 648 * 649 * @param[in] CaptureIfKernel 650 * If set to TRUE, the capturing is done within the kernel. 651 * Otherwise the capturing is done in a kernel mode driver. 652 * 653 * @param[out] CapturedSidAndAttributes 654 * The captured SID and attributes. 655 * 656 * @param[out] ResultLength 657 * The length of the captured SID and attributes, in bytes. 658 * 659 * @return 660 * Returns STATUS_SUCCESS if SID and attributes capturing 661 * has been completed successfully. STATUS_INVALID_PARAMETER 662 * is returned if the count of attributes exceeds the maximum 663 * threshold that the kernel can permit, with the purpose of 664 * avoiding integer overflows. STATUS_INSUFFICIENT_RESOURCES 665 * is returned if memory pool allocation for the captured SID has failed. 666 * STATUS_BUFFER_TOO_SMALL is returned if the length of the allocated 667 * buffer is less than the required size. STATUS_INVALID_SID is returned 668 * if a SID doesn't meet certain requirements to be considered a valid 669 * SID by the security manager. A failure NTSTATUS code is returned 670 * otherwise. 671 * 672 * @remarks 673 * A security identifier (SID) is a variable-length data structure that 674 * can change in size over time, depending on the factors that influence 675 * this effect in question. An attacker can take advantage of this fact 676 * and can potentially modify certain properties of a SID making it 677 * different in size than it was originally before. This is what we'd 678 * call, a TOCTOU vulnerability. 679 * 680 * For this reason, the logic of copying the SIDs and their attributes 681 * into a new buffer goes like this: first, allocate a buffer array 682 * that just holds the lengths and subauthority count of each SID. 683 * Such information is copied in the first loop. Then in a second loop, 684 * iterate over the array with SID provided and copy them into the final 685 * array. The moment we're doing this, validate the lengths of each SID 686 * basing upon the captured lengths we've got before. In this way we 687 * ensure that the SIDs have remained intact. The validation checks are 688 * done in user mode as a general rule that we just cannot trust UM and 689 * whatever data is coming from it. 690 */ 691 NTSTATUS 692 NTAPI 693 SeCaptureSidAndAttributesArray( 694 _In_ PSID_AND_ATTRIBUTES SrcSidAndAttributes, 695 _In_ ULONG AttributeCount, 696 _In_ KPROCESSOR_MODE PreviousMode, 697 _In_opt_ PVOID AllocatedMem, 698 _In_ ULONG AllocatedLength, 699 _In_ POOL_TYPE PoolType, 700 _In_ BOOLEAN CaptureIfKernel, 701 _Out_ PSID_AND_ATTRIBUTES *CapturedSidAndAttributes, 702 _Out_ PULONG ResultLength) 703 { 704 ULONG ArraySize, RequiredLength, SidLength, i; 705 ULONG TempArrayValidate, TempLengthValidate; 706 PSID_AND_ATTRIBUTES SidAndAttributes; 707 _SEH2_VOLATILE PSID_VALIDATE ValidateArray; 708 PUCHAR CurrentDest; 709 PISID Sid; 710 NTSTATUS Status; 711 PAGED_CODE(); 712 713 ValidateArray = NULL; 714 SidAndAttributes = NULL; 715 *CapturedSidAndAttributes = NULL; 716 *ResultLength = 0; 717 718 if (AttributeCount == 0) 719 { 720 return STATUS_SUCCESS; 721 } 722 723 if (AttributeCount > SE_MAXIMUM_GROUP_LIMIT) 724 { 725 DPRINT1("SeCaptureSidAndAttributesArray(): Maximum group limit exceeded!\n"); 726 return STATUS_INVALID_PARAMETER; 727 } 728 729 if ((PreviousMode == KernelMode) && !CaptureIfKernel) 730 { 731 *CapturedSidAndAttributes = SrcSidAndAttributes; 732 return STATUS_SUCCESS; 733 } 734 735 ArraySize = AttributeCount * sizeof(SID_AND_ATTRIBUTES); 736 RequiredLength = ALIGN_UP_BY(ArraySize, sizeof(ULONG)); 737 738 if (PreviousMode != KernelMode) 739 { 740 /* Check for user mode data */ 741 _SEH2_TRY 742 { 743 /* First probe the whole array */ 744 ProbeForRead(SrcSidAndAttributes, ArraySize, sizeof(ULONG)); 745 746 /* We're in user mode, set up the size for the temporary array */ 747 TempArrayValidate = AttributeCount * sizeof(SID_VALIDATE); 748 TempLengthValidate = ALIGN_UP_BY(TempArrayValidate, sizeof(ULONG)); 749 750 /* 751 * Allocate a buffer for the array that we're going to 752 * temporarily hold the subauthority count and the SID 753 * elements. We'll be going to use this array to perform 754 * validation checks later. 755 */ 756 ValidateArray = ExAllocatePoolWithTag(PoolType | POOL_RAISE_IF_ALLOCATION_FAILURE, 757 TempLengthValidate, 758 TAG_SID_VALIDATE); 759 760 /* Loop the array elements */ 761 for (i = 0; i < AttributeCount; i++) 762 { 763 /* Get the SID and probe the minimal structure */ 764 Sid = SrcSidAndAttributes[i].Sid; 765 ProbeForRead(Sid, sizeof(*Sid), sizeof(ULONG)); 766 767 /* 768 * Capture the subauthority count and hold it 769 * into the temporary array for later validation. 770 * This way we ensure that the said count of each 771 * SID has remained the same. 772 */ 773 ValidateArray[i].SubAuthorityCount = Sid->SubAuthorityCount; 774 775 /* Capture the SID */ 776 ValidateArray[i].ProbeSid = Sid; 777 778 /* Calculate the SID length and probe the full SID */ 779 SidLength = RtlLengthRequiredSid(ValidateArray[i].SubAuthorityCount); 780 ProbeForRead(ValidateArray[i].ProbeSid, SidLength, sizeof(ULONG)); 781 782 /* Add the aligned length to the required length */ 783 RequiredLength += ALIGN_UP_BY(SidLength, sizeof(ULONG)); 784 } 785 } 786 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 787 { 788 Status = _SEH2_GetExceptionCode(); 789 _SEH2_YIELD(goto Cleanup); 790 } 791 _SEH2_END; 792 } 793 else 794 { 795 /* Loop the array elements */ 796 for (i = 0; i < AttributeCount; i++) 797 { 798 /* Get the SID and it's length */ 799 Sid = SrcSidAndAttributes[i].Sid; 800 SidLength = RtlLengthRequiredSid(Sid->SubAuthorityCount); 801 802 /* Add the aligned length to the required length */ 803 RequiredLength += ALIGN_UP_BY(SidLength, sizeof(ULONG)); 804 } 805 } 806 807 /* Assume success */ 808 Status = STATUS_SUCCESS; 809 *ResultLength = RequiredLength; 810 811 /* Check if we have no buffer */ 812 if (AllocatedMem == NULL) 813 { 814 /* Allocate a new buffer */ 815 SidAndAttributes = ExAllocatePoolWithTag(PoolType, 816 RequiredLength, 817 TAG_SID_AND_ATTRIBUTES); 818 if (SidAndAttributes == NULL) 819 { 820 DPRINT1("SeCaptureSidAndAttributesArray(): Failed to allocate memory for SID and attributes array (requested size -> %lu)!\n", RequiredLength); 821 Status = STATUS_INSUFFICIENT_RESOURCES; 822 goto Cleanup; 823 } 824 } 825 /* Otherwise check if the buffer is large enough */ 826 else if (AllocatedLength >= RequiredLength) 827 { 828 /* Buffer is large enough, use it */ 829 SidAndAttributes = AllocatedMem; 830 } 831 else 832 { 833 /* Buffer is too small, fail */ 834 DPRINT1("SeCaptureSidAndAttributesArray(): The provided buffer is small (expected size -> %lu || current size -> %lu)!\n", RequiredLength, AllocatedLength); 835 Status = STATUS_BUFFER_TOO_SMALL; 836 goto Cleanup; 837 } 838 839 *CapturedSidAndAttributes = SidAndAttributes; 840 841 /* Check again for user mode */ 842 if (PreviousMode != KernelMode) 843 { 844 _SEH2_TRY 845 { 846 /* The rest of the data starts after the array */ 847 CurrentDest = (PUCHAR)SidAndAttributes; 848 CurrentDest += ALIGN_UP_BY(ArraySize, sizeof(ULONG)); 849 850 /* Loop the array elements */ 851 for (i = 0; i < AttributeCount; i++) 852 { 853 /* 854 * Get the SID length from the subauthority 855 * count we've captured before. 856 */ 857 SidLength = RtlLengthRequiredSid(ValidateArray[i].SubAuthorityCount); 858 859 /* Copy attributes */ 860 SidAndAttributes[i].Attributes = SrcSidAndAttributes[i].Attributes; 861 862 /* Copy the SID to the current destination address */ 863 SidAndAttributes[i].Sid = (PSID)CurrentDest; 864 RtlCopyMemory(CurrentDest, ValidateArray[i].ProbeSid, SidLength); 865 866 /* Obtain the SID we've captured before for validation */ 867 Sid = SidAndAttributes[i].Sid; 868 869 /* Validate that the subauthority count hasn't changed */ 870 if (ValidateArray[i].SubAuthorityCount != 871 Sid->SubAuthorityCount) 872 { 873 /* It's changed, bail out */ 874 DPRINT1("SeCaptureSidAndAttributesArray(): The subauthority counts have changed (captured count -> %u || current count -> %u)\n", 875 ValidateArray[i].SubAuthorityCount, Sid->SubAuthorityCount); 876 Status = STATUS_INVALID_SID; 877 goto Cleanup; 878 } 879 880 /* Validate that the SID length is the same */ 881 if (SidLength != RtlLengthSid(Sid)) 882 { 883 /* They're no longer the same, bail out */ 884 DPRINT1("SeCaptureSidAndAttributesArray(): The SID lengths have changed (captured length -> %lu || current length -> %lu)\n", 885 SidLength, RtlLengthSid(Sid)); 886 Status = STATUS_INVALID_SID; 887 goto Cleanup; 888 } 889 890 /* Check that the SID is valid */ 891 if (!RtlValidSid(Sid)) 892 { 893 DPRINT1("SeCaptureSidAndAttributesArray(): The SID is not valid!\n"); 894 Status = STATUS_INVALID_SID; 895 goto Cleanup; 896 } 897 898 /* Update the current destination address */ 899 CurrentDest += ALIGN_UP_BY(SidLength, sizeof(ULONG)); 900 } 901 } 902 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 903 { 904 Status = _SEH2_GetExceptionCode(); 905 } 906 _SEH2_END; 907 } 908 else 909 { 910 /* The rest of the data starts after the array */ 911 CurrentDest = (PUCHAR)SidAndAttributes; 912 CurrentDest += ALIGN_UP_BY(ArraySize, sizeof(ULONG)); 913 914 /* Loop the array elements */ 915 for (i = 0; i < AttributeCount; i++) 916 { 917 /* Get the SID and it's length */ 918 Sid = SrcSidAndAttributes[i].Sid; 919 SidLength = RtlLengthRequiredSid(Sid->SubAuthorityCount); 920 921 /* Copy attributes */ 922 SidAndAttributes[i].Attributes = SrcSidAndAttributes[i].Attributes; 923 924 /* Copy the SID to the current destination address */ 925 SidAndAttributes[i].Sid = (PSID)CurrentDest; 926 RtlCopyMemory(CurrentDest, SrcSidAndAttributes[i].Sid, SidLength); 927 928 /* Update the current destination address */ 929 CurrentDest += ALIGN_UP_BY(SidLength, sizeof(ULONG)); 930 } 931 } 932 933 Cleanup: 934 /* Check for failure */ 935 if (!NT_SUCCESS(Status)) 936 { 937 /* Check if we allocated a new array */ 938 if ((SidAndAttributes != AllocatedMem) && (SidAndAttributes != NULL)) 939 { 940 /* Free the array */ 941 ExFreePoolWithTag(SidAndAttributes, TAG_SID_AND_ATTRIBUTES); 942 } 943 944 /* Set returned address to NULL */ 945 *CapturedSidAndAttributes = NULL; 946 } 947 948 /* Free the temporary validation array */ 949 if ((PreviousMode != KernelMode) && (ValidateArray != NULL)) 950 { 951 ExFreePoolWithTag(ValidateArray, TAG_SID_VALIDATE); 952 } 953 954 return Status; 955 } 956 957 /** 958 * @brief 959 * Releases a captured SID with attributes. 960 * 961 * @param[in] CapturedSidAndAttributes 962 * The captured SID with attributes to be released. 963 * 964 * @param[in] AccessMode 965 * Processor access level mode. 966 * 967 * @param[in] CaptureIfKernel 968 * If set to TRUE, the releasing is done within the kernel. 969 * Otherwise the releasing is done in a kernel mode driver. 970 * 971 * @return 972 * Nothing. 973 */ 974 VOID 975 NTAPI 976 SeReleaseSidAndAttributesArray( 977 _In_ _Post_invalid_ PSID_AND_ATTRIBUTES CapturedSidAndAttributes, 978 _In_ KPROCESSOR_MODE AccessMode, 979 _In_ BOOLEAN CaptureIfKernel) 980 { 981 PAGED_CODE(); 982 983 if ((CapturedSidAndAttributes != NULL) && 984 ((AccessMode != KernelMode) || CaptureIfKernel)) 985 { 986 ExFreePoolWithTag(CapturedSidAndAttributes, TAG_SID_AND_ATTRIBUTES); 987 } 988 } 989 990 /* EOF */ 991