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
FreeInitializedSids(VOID)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
SepInitSecurityIDs(VOID)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
SepCaptureSid(_In_ PSID InputSid,_In_ KPROCESSOR_MODE AccessMode,_In_ POOL_TYPE PoolType,_In_ BOOLEAN CaptureIfKernel,_Out_ PSID * CapturedSid)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
SepReleaseSid(_In_ PSID CapturedSid,_In_ KPROCESSOR_MODE AccessMode,_In_ BOOLEAN CaptureIfKernel)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
SepSidInTokenEx(_In_ PACCESS_TOKEN _Token,_In_ PSID PrincipalSelfSid,_In_ PSID _Sid,_In_ BOOLEAN Deny,_In_ BOOLEAN Restricted)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
SepSidInToken(_In_ PACCESS_TOKEN _Token,_In_ PSID Sid)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
SepGetSidFromAce(_In_ PACE Ace)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
SeCaptureSidAndAttributesArray(_In_ PSID_AND_ATTRIBUTES SrcSidAndAttributes,_In_ ULONG AttributeCount,_In_ KPROCESSOR_MODE PreviousMode,_In_opt_ PVOID AllocatedMem,_In_ ULONG AllocatedLength,_In_ POOL_TYPE PoolType,_In_ BOOLEAN CaptureIfKernel,_Out_ PSID_AND_ATTRIBUTES * CapturedSidAndAttributes,_Out_ PULONG ResultLength)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
SeReleaseSidAndAttributesArray(_In_ _Post_invalid_ PSID_AND_ATTRIBUTES CapturedSidAndAttributes,_In_ KPROCESSOR_MODE AccessMode,_In_ BOOLEAN CaptureIfKernel)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