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