xref: /reactos/ntoskrnl/se/sid.c (revision 8f9ef68e)
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