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] AceType 562 * The type of an access control entry. This 563 * type that is given by the calling thread 564 * must coincide with the actual ACE that is 565 * given in the second parameter otherwise this 566 * can potentially lead to UNDEFINED behavior! 567 * 568 * @param[in] Ace 569 * A pointer to an access control entry, which 570 * can be obtained from a DACL. 571 * 572 * @return 573 * Returns a pointer to a security identifier (SID), 574 * otherwise NULL is returned if an unsupported ACE 575 * type was given to the function. 576 */ 577 PSID 578 NTAPI 579 SepGetSidFromAce( 580 _In_ UCHAR AceType, 581 _In_ PACE Ace) 582 { 583 PSID Sid; 584 PAGED_CODE(); 585 586 /* Sanity check */ 587 ASSERT(Ace); 588 589 /* Initialize the SID */ 590 Sid = NULL; 591 592 /* Obtain the SID based upon ACE type */ 593 switch (AceType) 594 { 595 case ACCESS_DENIED_ACE_TYPE: 596 { 597 Sid = (PSID)&((PACCESS_DENIED_ACE)Ace)->SidStart; 598 break; 599 } 600 601 case ACCESS_ALLOWED_ACE_TYPE: 602 { 603 Sid = (PSID)&((PACCESS_ALLOWED_ACE)Ace)->SidStart; 604 break; 605 } 606 607 case ACCESS_DENIED_OBJECT_ACE_TYPE: 608 { 609 Sid = (PSID)&((PACCESS_DENIED_OBJECT_ACE)Ace)->SidStart; 610 break; 611 } 612 613 case ACCESS_ALLOWED_OBJECT_ACE_TYPE: 614 { 615 Sid = (PSID)&((PACCESS_ALLOWED_OBJECT_ACE)Ace)->SidStart; 616 break; 617 } 618 619 case SYSTEM_AUDIT_ACE_TYPE: 620 { 621 Sid = (PSID)&((PSYSTEM_AUDIT_ACE)Ace)->SidStart; 622 break; 623 } 624 625 case SYSTEM_ALARM_ACE_TYPE: 626 { 627 Sid = (PSID)&((PSYSTEM_ALARM_ACE)Ace)->SidStart; 628 break; 629 } 630 631 default: 632 { 633 DPRINT1("SepGetSidFromAce(): Unknown ACE type (Ace 0x%p, Type %u)\n", Ace, AceType); 634 break; 635 } 636 } 637 638 return Sid; 639 } 640 641 /** 642 * @brief 643 * Captures a SID with attributes. 644 * 645 * @param[in] SrcSidAndAttributes 646 * Source of the SID with attributes to be captured. 647 * 648 * @param[in] AttributeCount 649 * The number count of attributes, in total. 650 * 651 * @param[in] PreviousMode 652 * Processor access level mode. 653 * 654 * @param[in] AllocatedMem 655 * The allocated memory buffer for the captured SID. If the caller 656 * supplies no allocated block of memory then the function will 657 * allocate some buffer block of memory for the captured SID 658 * automatically. 659 * 660 * @param[in] AllocatedLength 661 * The length of the buffer that points to the allocated memory, 662 * in bytes. 663 * 664 * @param[in] PoolType 665 * The pool type for the captured SID and attributes to assign. 666 * 667 * @param[in] CaptureIfKernel 668 * If set to TRUE, the capturing is done within the kernel. 669 * Otherwise the capturing is done in a kernel mode driver. 670 * 671 * @param[out] CapturedSidAndAttributes 672 * The captured SID and attributes. 673 * 674 * @param[out] ResultLength 675 * The length of the captured SID and attributes, in bytes. 676 * 677 * @return 678 * Returns STATUS_SUCCESS if SID and attributes capturing 679 * has been completed successfully. STATUS_INVALID_PARAMETER 680 * is returned if the count of attributes exceeds the maximum 681 * threshold that the kernel can permit, with the purpose of 682 * avoiding integer overflows. STATUS_INSUFFICIENT_RESOURCES 683 * is returned if memory pool allocation for the captured SID has failed. 684 * STATUS_BUFFER_TOO_SMALL is returned if the length of the allocated 685 * buffer is less than the required size. STATUS_INVALID_SID is returned 686 * if a SID doesn't meet certain requirements to be considered a valid 687 * SID by the security manager. A failure NTSTATUS code is returned 688 * otherwise. 689 * 690 * @remarks 691 * A security identifier (SID) is a variable-length data structure that 692 * can change in size over time, depending on the factors that influence 693 * this effect in question. An attacker can take advantage of this fact 694 * and can potentially modify certain properties of a SID making it 695 * different in size than it was originally before. This is what we'd 696 * call, a TOCTOU vulnerability. 697 * 698 * For this reason, the logic of copying the SIDs and their attributes 699 * into a new buffer goes like this: first, allocate a buffer array 700 * that just holds the lengths and subauthority count of each SID. 701 * Such information is copied in the first loop. Then in a second loop, 702 * iterate over the array with SID provided and copy them into the final 703 * array. The moment we're doing this, validate the lengths of each SID 704 * basing upon the captured lengths we've got before. In this way we 705 * ensure that the SIDs have remained intact. The validation checks are 706 * done in user mode as a general rule that we just cannot trust UM and 707 * whatever data is coming from it. 708 */ 709 NTSTATUS 710 NTAPI 711 SeCaptureSidAndAttributesArray( 712 _In_ PSID_AND_ATTRIBUTES SrcSidAndAttributes, 713 _In_ ULONG AttributeCount, 714 _In_ KPROCESSOR_MODE PreviousMode, 715 _In_opt_ PVOID AllocatedMem, 716 _In_ ULONG AllocatedLength, 717 _In_ POOL_TYPE PoolType, 718 _In_ BOOLEAN CaptureIfKernel, 719 _Out_ PSID_AND_ATTRIBUTES *CapturedSidAndAttributes, 720 _Out_ PULONG ResultLength) 721 { 722 ULONG ArraySize, RequiredLength, SidLength, i; 723 ULONG TempArrayValidate, TempLengthValidate; 724 PSID_AND_ATTRIBUTES SidAndAttributes; 725 _SEH2_VOLATILE PSID_VALIDATE ValidateArray; 726 PUCHAR CurrentDest; 727 PISID Sid; 728 NTSTATUS Status; 729 PAGED_CODE(); 730 731 ValidateArray = NULL; 732 SidAndAttributes = NULL; 733 *CapturedSidAndAttributes = NULL; 734 *ResultLength = 0; 735 736 if (AttributeCount == 0) 737 { 738 return STATUS_SUCCESS; 739 } 740 741 if (AttributeCount > SE_MAXIMUM_GROUP_LIMIT) 742 { 743 DPRINT1("SeCaptureSidAndAttributesArray(): Maximum group limit exceeded!\n"); 744 return STATUS_INVALID_PARAMETER; 745 } 746 747 if ((PreviousMode == KernelMode) && !CaptureIfKernel) 748 { 749 *CapturedSidAndAttributes = SrcSidAndAttributes; 750 return STATUS_SUCCESS; 751 } 752 753 ArraySize = AttributeCount * sizeof(SID_AND_ATTRIBUTES); 754 RequiredLength = ALIGN_UP_BY(ArraySize, sizeof(ULONG)); 755 756 if (PreviousMode != KernelMode) 757 { 758 /* Check for user mode data */ 759 _SEH2_TRY 760 { 761 /* First probe the whole array */ 762 ProbeForRead(SrcSidAndAttributes, ArraySize, sizeof(ULONG)); 763 764 /* We're in user mode, set up the size for the temporary array */ 765 TempArrayValidate = AttributeCount * sizeof(SID_VALIDATE); 766 TempLengthValidate = ALIGN_UP_BY(TempArrayValidate, sizeof(ULONG)); 767 768 /* 769 * Allocate a buffer for the array that we're going to 770 * temporarily hold the subauthority count and the SID 771 * elements. We'll be going to use this array to perform 772 * validation checks later. 773 */ 774 ValidateArray = ExAllocatePoolWithTag(PoolType | POOL_RAISE_IF_ALLOCATION_FAILURE, 775 TempLengthValidate, 776 TAG_SID_VALIDATE); 777 778 /* Loop the array elements */ 779 for (i = 0; i < AttributeCount; i++) 780 { 781 /* Get the SID and probe the minimal structure */ 782 Sid = SrcSidAndAttributes[i].Sid; 783 ProbeForRead(Sid, sizeof(*Sid), sizeof(ULONG)); 784 785 /* 786 * Capture the subauthority count and hold it 787 * into the temporary array for later validation. 788 * This way we ensure that the said count of each 789 * SID has remained the same. 790 */ 791 ValidateArray[i].SubAuthorityCount = Sid->SubAuthorityCount; 792 793 /* Capture the SID */ 794 ValidateArray[i].ProbeSid = Sid; 795 796 /* Calculate the SID length and probe the full SID */ 797 SidLength = RtlLengthRequiredSid(ValidateArray[i].SubAuthorityCount); 798 ProbeForRead(ValidateArray[i].ProbeSid, SidLength, sizeof(ULONG)); 799 800 /* Add the aligned length to the required length */ 801 RequiredLength += ALIGN_UP_BY(SidLength, sizeof(ULONG)); 802 } 803 } 804 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 805 { 806 Status = _SEH2_GetExceptionCode(); 807 _SEH2_YIELD(goto Cleanup); 808 } 809 _SEH2_END; 810 } 811 else 812 { 813 /* Loop the array elements */ 814 for (i = 0; i < AttributeCount; i++) 815 { 816 /* Get the SID and it's length */ 817 Sid = SrcSidAndAttributes[i].Sid; 818 SidLength = RtlLengthRequiredSid(Sid->SubAuthorityCount); 819 820 /* Add the aligned length to the required length */ 821 RequiredLength += ALIGN_UP_BY(SidLength, sizeof(ULONG)); 822 } 823 } 824 825 /* Assume success */ 826 Status = STATUS_SUCCESS; 827 *ResultLength = RequiredLength; 828 829 /* Check if we have no buffer */ 830 if (AllocatedMem == NULL) 831 { 832 /* Allocate a new buffer */ 833 SidAndAttributes = ExAllocatePoolWithTag(PoolType, 834 RequiredLength, 835 TAG_SID_AND_ATTRIBUTES); 836 if (SidAndAttributes == NULL) 837 { 838 DPRINT1("SeCaptureSidAndAttributesArray(): Failed to allocate memory for SID and attributes array (requested size -> %lu)!\n", RequiredLength); 839 Status = STATUS_INSUFFICIENT_RESOURCES; 840 goto Cleanup; 841 } 842 } 843 /* Otherwise check if the buffer is large enough */ 844 else if (AllocatedLength >= RequiredLength) 845 { 846 /* Buffer is large enough, use it */ 847 SidAndAttributes = AllocatedMem; 848 } 849 else 850 { 851 /* Buffer is too small, fail */ 852 DPRINT1("SeCaptureSidAndAttributesArray(): The provided buffer is small (expected size -> %lu || current size -> %lu)!\n", RequiredLength, AllocatedLength); 853 Status = STATUS_BUFFER_TOO_SMALL; 854 goto Cleanup; 855 } 856 857 *CapturedSidAndAttributes = SidAndAttributes; 858 859 /* Check again for user mode */ 860 if (PreviousMode != KernelMode) 861 { 862 _SEH2_TRY 863 { 864 /* The rest of the data starts after the array */ 865 CurrentDest = (PUCHAR)SidAndAttributes; 866 CurrentDest += ALIGN_UP_BY(ArraySize, sizeof(ULONG)); 867 868 /* Loop the array elements */ 869 for (i = 0; i < AttributeCount; i++) 870 { 871 /* 872 * Get the SID length from the subauthority 873 * count we've captured before. 874 */ 875 SidLength = RtlLengthRequiredSid(ValidateArray[i].SubAuthorityCount); 876 877 /* Copy attributes */ 878 SidAndAttributes[i].Attributes = SrcSidAndAttributes[i].Attributes; 879 880 /* Copy the SID to the current destination address */ 881 SidAndAttributes[i].Sid = (PSID)CurrentDest; 882 RtlCopyMemory(CurrentDest, ValidateArray[i].ProbeSid, SidLength); 883 884 /* Obtain the SID we've captured before for validation */ 885 Sid = SidAndAttributes[i].Sid; 886 887 /* Validate that the subauthority count hasn't changed */ 888 if (ValidateArray[i].SubAuthorityCount != 889 Sid->SubAuthorityCount) 890 { 891 /* It's changed, bail out */ 892 DPRINT1("SeCaptureSidAndAttributesArray(): The subauthority counts have changed (captured count -> %u || current count -> %u)\n", 893 ValidateArray[i].SubAuthorityCount, Sid->SubAuthorityCount); 894 Status = STATUS_INVALID_SID; 895 goto Cleanup; 896 } 897 898 /* Validate that the SID length is the same */ 899 if (SidLength != RtlLengthSid(Sid)) 900 { 901 /* They're no longer the same, bail out */ 902 DPRINT1("SeCaptureSidAndAttributesArray(): The SID lengths have changed (captured length -> %lu || current length -> %lu)\n", 903 SidLength, RtlLengthSid(Sid)); 904 Status = STATUS_INVALID_SID; 905 goto Cleanup; 906 } 907 908 /* Check that the SID is valid */ 909 if (!RtlValidSid(Sid)) 910 { 911 DPRINT1("SeCaptureSidAndAttributesArray(): The SID is not valid!\n"); 912 Status = STATUS_INVALID_SID; 913 goto Cleanup; 914 } 915 916 /* Update the current destination address */ 917 CurrentDest += ALIGN_UP_BY(SidLength, sizeof(ULONG)); 918 } 919 } 920 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 921 { 922 Status = _SEH2_GetExceptionCode(); 923 } 924 _SEH2_END; 925 } 926 else 927 { 928 /* The rest of the data starts after the array */ 929 CurrentDest = (PUCHAR)SidAndAttributes; 930 CurrentDest += ALIGN_UP_BY(ArraySize, sizeof(ULONG)); 931 932 /* Loop the array elements */ 933 for (i = 0; i < AttributeCount; i++) 934 { 935 /* Get the SID and it's length */ 936 Sid = SrcSidAndAttributes[i].Sid; 937 SidLength = RtlLengthRequiredSid(Sid->SubAuthorityCount); 938 939 /* Copy attributes */ 940 SidAndAttributes[i].Attributes = SrcSidAndAttributes[i].Attributes; 941 942 /* Copy the SID to the current destination address */ 943 SidAndAttributes[i].Sid = (PSID)CurrentDest; 944 RtlCopyMemory(CurrentDest, SrcSidAndAttributes[i].Sid, SidLength); 945 946 /* Update the current destination address */ 947 CurrentDest += ALIGN_UP_BY(SidLength, sizeof(ULONG)); 948 } 949 } 950 951 Cleanup: 952 /* Check for failure */ 953 if (!NT_SUCCESS(Status)) 954 { 955 /* Check if we allocated a new array */ 956 if ((SidAndAttributes != AllocatedMem) && (SidAndAttributes != NULL)) 957 { 958 /* Free the array */ 959 ExFreePoolWithTag(SidAndAttributes, TAG_SID_AND_ATTRIBUTES); 960 } 961 962 /* Set returned address to NULL */ 963 *CapturedSidAndAttributes = NULL; 964 } 965 966 /* Free the temporary validation array */ 967 if ((PreviousMode != KernelMode) && (ValidateArray != NULL)) 968 { 969 ExFreePoolWithTag(ValidateArray, TAG_SID_VALIDATE); 970 } 971 972 return Status; 973 } 974 975 /** 976 * @brief 977 * Releases a captured SID with attributes. 978 * 979 * @param[in] CapturedSidAndAttributes 980 * The captured SID with attributes to be released. 981 * 982 * @param[in] AccessMode 983 * Processor access level mode. 984 * 985 * @param[in] CaptureIfKernel 986 * If set to TRUE, the releasing is done within the kernel. 987 * Otherwise the releasing is done in a kernel mode driver. 988 * 989 * @return 990 * Nothing. 991 */ 992 VOID 993 NTAPI 994 SeReleaseSidAndAttributesArray( 995 _In_ _Post_invalid_ PSID_AND_ATTRIBUTES CapturedSidAndAttributes, 996 _In_ KPROCESSOR_MODE AccessMode, 997 _In_ BOOLEAN CaptureIfKernel) 998 { 999 PAGED_CODE(); 1000 1001 if ((CapturedSidAndAttributes != NULL) && 1002 ((AccessMode != KernelMode) || CaptureIfKernel)) 1003 { 1004 ExFreePoolWithTag(CapturedSidAndAttributes, TAG_SID_AND_ATTRIBUTES); 1005 } 1006 } 1007 1008 /* EOF */ 1009