xref: /reactos/ntoskrnl/se/sid.c (revision ede7a20a)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            ntoskrnl/se/sid.c
5  * PURPOSE:         Security manager
6  *
7  * PROGRAMMERS:     David Welch <welch@cwcom.net>
8  */
9 
10 /* INCLUDES *******************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 #define TAG_SID_AND_ATTRIBUTES 'aSeS'
17 
18 #if defined (ALLOC_PRAGMA)
19 #pragma alloc_text(INIT, SepInitSecurityIDs)
20 #endif
21 
22 /* GLOBALS ********************************************************************/
23 
24 SID_IDENTIFIER_AUTHORITY SeNullSidAuthority = {SECURITY_NULL_SID_AUTHORITY};
25 SID_IDENTIFIER_AUTHORITY SeWorldSidAuthority = {SECURITY_WORLD_SID_AUTHORITY};
26 SID_IDENTIFIER_AUTHORITY SeLocalSidAuthority = {SECURITY_LOCAL_SID_AUTHORITY};
27 SID_IDENTIFIER_AUTHORITY SeCreatorSidAuthority = {SECURITY_CREATOR_SID_AUTHORITY};
28 SID_IDENTIFIER_AUTHORITY SeNtSidAuthority = {SECURITY_NT_AUTHORITY};
29 
30 PSID SeNullSid = NULL;
31 PSID SeWorldSid = NULL;
32 PSID SeLocalSid = NULL;
33 PSID SeCreatorOwnerSid = NULL;
34 PSID SeCreatorGroupSid = NULL;
35 PSID SeCreatorOwnerServerSid = NULL;
36 PSID SeCreatorGroupServerSid = NULL;
37 PSID SeNtAuthoritySid = NULL;
38 PSID SeDialupSid = NULL;
39 PSID SeNetworkSid = NULL;
40 PSID SeBatchSid = NULL;
41 PSID SeInteractiveSid = NULL;
42 PSID SeServiceSid = NULL;
43 PSID SePrincipalSelfSid = NULL;
44 PSID SeLocalSystemSid = NULL;
45 PSID SeAuthenticatedUserSid = NULL;
46 PSID SeRestrictedCodeSid = NULL;
47 PSID SeAliasAdminsSid = NULL;
48 PSID SeAliasUsersSid = NULL;
49 PSID SeAliasGuestsSid = NULL;
50 PSID SeAliasPowerUsersSid = NULL;
51 PSID SeAliasAccountOpsSid = NULL;
52 PSID SeAliasSystemOpsSid = NULL;
53 PSID SeAliasPrintOpsSid = NULL;
54 PSID SeAliasBackupOpsSid = NULL;
55 PSID SeAuthenticatedUsersSid = NULL;
56 PSID SeRestrictedSid = NULL;
57 PSID SeAnonymousLogonSid = NULL;
58 PSID SeLocalServiceSid = NULL;
59 PSID SeNetworkServiceSid = NULL;
60 
61 /* FUNCTIONS ******************************************************************/
62 
63 VOID
64 NTAPI
65 FreeInitializedSids(VOID)
66 {
67     if (SeNullSid) ExFreePoolWithTag(SeNullSid, TAG_SID);
68     if (SeWorldSid) ExFreePoolWithTag(SeWorldSid, TAG_SID);
69     if (SeLocalSid) ExFreePoolWithTag(SeLocalSid, TAG_SID);
70     if (SeCreatorOwnerSid) ExFreePoolWithTag(SeCreatorOwnerSid, TAG_SID);
71     if (SeCreatorGroupSid) ExFreePoolWithTag(SeCreatorGroupSid, TAG_SID);
72     if (SeCreatorOwnerServerSid) ExFreePoolWithTag(SeCreatorOwnerServerSid, TAG_SID);
73     if (SeCreatorGroupServerSid) ExFreePoolWithTag(SeCreatorGroupServerSid, TAG_SID);
74     if (SeNtAuthoritySid) ExFreePoolWithTag(SeNtAuthoritySid, TAG_SID);
75     if (SeDialupSid) ExFreePoolWithTag(SeDialupSid, TAG_SID);
76     if (SeNetworkSid) ExFreePoolWithTag(SeNetworkSid, TAG_SID);
77     if (SeBatchSid) ExFreePoolWithTag(SeBatchSid, TAG_SID);
78     if (SeInteractiveSid) ExFreePoolWithTag(SeInteractiveSid, TAG_SID);
79     if (SeServiceSid) ExFreePoolWithTag(SeServiceSid, TAG_SID);
80     if (SePrincipalSelfSid) ExFreePoolWithTag(SePrincipalSelfSid, TAG_SID);
81     if (SeLocalSystemSid) ExFreePoolWithTag(SeLocalSystemSid, TAG_SID);
82     if (SeAuthenticatedUserSid) ExFreePoolWithTag(SeAuthenticatedUserSid, TAG_SID);
83     if (SeRestrictedCodeSid) ExFreePoolWithTag(SeRestrictedCodeSid, TAG_SID);
84     if (SeAliasAdminsSid) ExFreePoolWithTag(SeAliasAdminsSid, TAG_SID);
85     if (SeAliasUsersSid) ExFreePoolWithTag(SeAliasUsersSid, TAG_SID);
86     if (SeAliasGuestsSid) ExFreePoolWithTag(SeAliasGuestsSid, TAG_SID);
87     if (SeAliasPowerUsersSid) ExFreePoolWithTag(SeAliasPowerUsersSid, TAG_SID);
88     if (SeAliasAccountOpsSid) ExFreePoolWithTag(SeAliasAccountOpsSid, TAG_SID);
89     if (SeAliasSystemOpsSid) ExFreePoolWithTag(SeAliasSystemOpsSid, TAG_SID);
90     if (SeAliasPrintOpsSid) ExFreePoolWithTag(SeAliasPrintOpsSid, TAG_SID);
91     if (SeAliasBackupOpsSid) ExFreePoolWithTag(SeAliasBackupOpsSid, TAG_SID);
92     if (SeAuthenticatedUsersSid) ExFreePoolWithTag(SeAuthenticatedUsersSid, TAG_SID);
93     if (SeRestrictedSid) ExFreePoolWithTag(SeRestrictedSid, TAG_SID);
94     if (SeAnonymousLogonSid) ExFreePoolWithTag(SeAnonymousLogonSid, TAG_SID);
95 }
96 
97 INIT_FUNCTION
98 BOOLEAN
99 NTAPI
100 SepInitSecurityIDs(VOID)
101 {
102     ULONG SidLength0;
103     ULONG SidLength1;
104     ULONG SidLength2;
105     PULONG SubAuthority;
106 
107     SidLength0 = RtlLengthRequiredSid(0);
108     SidLength1 = RtlLengthRequiredSid(1);
109     SidLength2 = RtlLengthRequiredSid(2);
110 
111     /* create NullSid */
112     SeNullSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
113     SeWorldSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
114     SeLocalSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
115     SeCreatorOwnerSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
116     SeCreatorGroupSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
117     SeCreatorOwnerServerSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
118     SeCreatorGroupServerSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
119     SeNtAuthoritySid = ExAllocatePoolWithTag(PagedPool, SidLength0, TAG_SID);
120     SeDialupSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
121     SeNetworkSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
122     SeBatchSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
123     SeInteractiveSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
124     SeServiceSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
125     SePrincipalSelfSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
126     SeLocalSystemSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
127     SeAuthenticatedUserSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
128     SeRestrictedCodeSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
129     SeAliasAdminsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID);
130     SeAliasUsersSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID);
131     SeAliasGuestsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID);
132     SeAliasPowerUsersSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID);
133     SeAliasAccountOpsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID);
134     SeAliasSystemOpsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID);
135     SeAliasPrintOpsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID);
136     SeAliasBackupOpsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID);
137     SeAuthenticatedUsersSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
138     SeRestrictedSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
139     SeAnonymousLogonSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
140     SeLocalServiceSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
141     SeNetworkServiceSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
142 
143     if (SeNullSid == NULL || SeWorldSid == NULL ||
144         SeLocalSid == NULL || SeCreatorOwnerSid == NULL ||
145         SeCreatorGroupSid == NULL || SeCreatorOwnerServerSid == NULL ||
146         SeCreatorGroupServerSid == NULL || SeNtAuthoritySid == NULL ||
147         SeDialupSid == NULL || SeNetworkSid == NULL || SeBatchSid == NULL ||
148         SeInteractiveSid == NULL || SeServiceSid == NULL ||
149         SePrincipalSelfSid == NULL || SeLocalSystemSid == NULL ||
150         SeAuthenticatedUserSid == NULL || SeRestrictedCodeSid == NULL ||
151         SeAliasAdminsSid == NULL || SeAliasUsersSid == NULL ||
152         SeAliasGuestsSid == NULL || SeAliasPowerUsersSid == NULL ||
153         SeAliasAccountOpsSid == NULL || SeAliasSystemOpsSid == NULL ||
154         SeAliasPrintOpsSid == NULL || SeAliasBackupOpsSid == NULL ||
155         SeAuthenticatedUsersSid == NULL || SeRestrictedSid == NULL ||
156         SeAnonymousLogonSid == NULL || SeLocalServiceSid == NULL ||
157         SeNetworkServiceSid == NULL)
158     {
159         FreeInitializedSids();
160         return FALSE;
161     }
162 
163     RtlInitializeSid(SeNullSid, &SeNullSidAuthority, 1);
164     RtlInitializeSid(SeWorldSid, &SeWorldSidAuthority, 1);
165     RtlInitializeSid(SeLocalSid, &SeLocalSidAuthority, 1);
166     RtlInitializeSid(SeCreatorOwnerSid, &SeCreatorSidAuthority, 1);
167     RtlInitializeSid(SeCreatorGroupSid, &SeCreatorSidAuthority, 1);
168     RtlInitializeSid(SeCreatorOwnerServerSid, &SeCreatorSidAuthority, 1);
169     RtlInitializeSid(SeCreatorGroupServerSid, &SeCreatorSidAuthority, 1);
170     RtlInitializeSid(SeNtAuthoritySid, &SeNtSidAuthority, 0);
171     RtlInitializeSid(SeDialupSid, &SeNtSidAuthority, 1);
172     RtlInitializeSid(SeNetworkSid, &SeNtSidAuthority, 1);
173     RtlInitializeSid(SeBatchSid, &SeNtSidAuthority, 1);
174     RtlInitializeSid(SeInteractiveSid, &SeNtSidAuthority, 1);
175     RtlInitializeSid(SeServiceSid, &SeNtSidAuthority, 1);
176     RtlInitializeSid(SePrincipalSelfSid, &SeNtSidAuthority, 1);
177     RtlInitializeSid(SeLocalSystemSid, &SeNtSidAuthority, 1);
178     RtlInitializeSid(SeAuthenticatedUserSid, &SeNtSidAuthority, 1);
179     RtlInitializeSid(SeRestrictedCodeSid, &SeNtSidAuthority, 1);
180     RtlInitializeSid(SeAliasAdminsSid, &SeNtSidAuthority, 2);
181     RtlInitializeSid(SeAliasUsersSid, &SeNtSidAuthority, 2);
182     RtlInitializeSid(SeAliasGuestsSid, &SeNtSidAuthority, 2);
183     RtlInitializeSid(SeAliasPowerUsersSid, &SeNtSidAuthority, 2);
184     RtlInitializeSid(SeAliasAccountOpsSid, &SeNtSidAuthority, 2);
185     RtlInitializeSid(SeAliasSystemOpsSid, &SeNtSidAuthority, 2);
186     RtlInitializeSid(SeAliasPrintOpsSid, &SeNtSidAuthority, 2);
187     RtlInitializeSid(SeAliasBackupOpsSid, &SeNtSidAuthority, 2);
188     RtlInitializeSid(SeAuthenticatedUsersSid, &SeNtSidAuthority, 1);
189     RtlInitializeSid(SeRestrictedSid, &SeNtSidAuthority, 1);
190     RtlInitializeSid(SeAnonymousLogonSid, &SeNtSidAuthority, 1);
191     RtlInitializeSid(SeLocalServiceSid, &SeNtSidAuthority, 1);
192     RtlInitializeSid(SeNetworkServiceSid, &SeNtSidAuthority, 1);
193 
194     SubAuthority = RtlSubAuthoritySid(SeNullSid, 0);
195     *SubAuthority = SECURITY_NULL_RID;
196     SubAuthority = RtlSubAuthoritySid(SeWorldSid, 0);
197     *SubAuthority = SECURITY_WORLD_RID;
198     SubAuthority = RtlSubAuthoritySid(SeLocalSid, 0);
199     *SubAuthority = SECURITY_LOCAL_RID;
200     SubAuthority = RtlSubAuthoritySid(SeCreatorOwnerSid, 0);
201     *SubAuthority = SECURITY_CREATOR_OWNER_RID;
202     SubAuthority = RtlSubAuthoritySid(SeCreatorGroupSid, 0);
203     *SubAuthority = SECURITY_CREATOR_GROUP_RID;
204     SubAuthority = RtlSubAuthoritySid(SeCreatorOwnerServerSid, 0);
205     *SubAuthority = SECURITY_CREATOR_OWNER_SERVER_RID;
206     SubAuthority = RtlSubAuthoritySid(SeCreatorGroupServerSid, 0);
207     *SubAuthority = SECURITY_CREATOR_GROUP_SERVER_RID;
208     SubAuthority = RtlSubAuthoritySid(SeDialupSid, 0);
209     *SubAuthority = SECURITY_DIALUP_RID;
210     SubAuthority = RtlSubAuthoritySid(SeNetworkSid, 0);
211     *SubAuthority = SECURITY_NETWORK_RID;
212     SubAuthority = RtlSubAuthoritySid(SeBatchSid, 0);
213     *SubAuthority = SECURITY_BATCH_RID;
214     SubAuthority = RtlSubAuthoritySid(SeInteractiveSid, 0);
215     *SubAuthority = SECURITY_INTERACTIVE_RID;
216     SubAuthority = RtlSubAuthoritySid(SeServiceSid, 0);
217     *SubAuthority = SECURITY_SERVICE_RID;
218     SubAuthority = RtlSubAuthoritySid(SePrincipalSelfSid, 0);
219     *SubAuthority = SECURITY_PRINCIPAL_SELF_RID;
220     SubAuthority = RtlSubAuthoritySid(SeLocalSystemSid, 0);
221     *SubAuthority = SECURITY_LOCAL_SYSTEM_RID;
222     SubAuthority = RtlSubAuthoritySid(SeAuthenticatedUserSid, 0);
223     *SubAuthority = SECURITY_AUTHENTICATED_USER_RID;
224     SubAuthority = RtlSubAuthoritySid(SeRestrictedCodeSid, 0);
225     *SubAuthority = SECURITY_RESTRICTED_CODE_RID;
226     SubAuthority = RtlSubAuthoritySid(SeAliasAdminsSid, 0);
227     *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID;
228     SubAuthority = RtlSubAuthoritySid(SeAliasAdminsSid, 1);
229     *SubAuthority = DOMAIN_ALIAS_RID_ADMINS;
230     SubAuthority = RtlSubAuthoritySid(SeAliasUsersSid, 0);
231     *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID;
232     SubAuthority = RtlSubAuthoritySid(SeAliasUsersSid, 1);
233     *SubAuthority = DOMAIN_ALIAS_RID_USERS;
234     SubAuthority = RtlSubAuthoritySid(SeAliasGuestsSid, 0);
235     *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID;
236     SubAuthority = RtlSubAuthoritySid(SeAliasGuestsSid, 1);
237     *SubAuthority = DOMAIN_ALIAS_RID_GUESTS;
238     SubAuthority = RtlSubAuthoritySid(SeAliasPowerUsersSid, 0);
239     *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID;
240     SubAuthority = RtlSubAuthoritySid(SeAliasPowerUsersSid, 1);
241     *SubAuthority = DOMAIN_ALIAS_RID_POWER_USERS;
242     SubAuthority = RtlSubAuthoritySid(SeAliasAccountOpsSid, 0);
243     *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID;
244     SubAuthority = RtlSubAuthoritySid(SeAliasAccountOpsSid, 1);
245     *SubAuthority = DOMAIN_ALIAS_RID_ACCOUNT_OPS;
246     SubAuthority = RtlSubAuthoritySid(SeAliasSystemOpsSid, 0);
247     *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID;
248     SubAuthority = RtlSubAuthoritySid(SeAliasSystemOpsSid, 1);
249     *SubAuthority = DOMAIN_ALIAS_RID_SYSTEM_OPS;
250     SubAuthority = RtlSubAuthoritySid(SeAliasPrintOpsSid, 0);
251     *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID;
252     SubAuthority = RtlSubAuthoritySid(SeAliasPrintOpsSid, 1);
253     *SubAuthority = DOMAIN_ALIAS_RID_PRINT_OPS;
254     SubAuthority = RtlSubAuthoritySid(SeAliasBackupOpsSid, 0);
255     *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID;
256     SubAuthority = RtlSubAuthoritySid(SeAliasBackupOpsSid, 1);
257     *SubAuthority = DOMAIN_ALIAS_RID_BACKUP_OPS;
258     SubAuthority = RtlSubAuthoritySid(SeAuthenticatedUsersSid, 0);
259     *SubAuthority = SECURITY_AUTHENTICATED_USER_RID;
260     SubAuthority = RtlSubAuthoritySid(SeRestrictedSid, 0);
261     *SubAuthority = SECURITY_RESTRICTED_CODE_RID;
262     SubAuthority = RtlSubAuthoritySid(SeAnonymousLogonSid, 0);
263     *SubAuthority = SECURITY_ANONYMOUS_LOGON_RID;
264     SubAuthority = RtlSubAuthoritySid(SeLocalServiceSid, 0);
265     *SubAuthority = SECURITY_LOCAL_SERVICE_RID;
266     SubAuthority = RtlSubAuthoritySid(SeNetworkServiceSid, 0);
267     *SubAuthority = SECURITY_NETWORK_SERVICE_RID;
268 
269     return TRUE;
270 }
271 
272 NTSTATUS
273 NTAPI
274 SepCaptureSid(IN PSID InputSid,
275               IN KPROCESSOR_MODE AccessMode,
276               IN POOL_TYPE PoolType,
277               IN BOOLEAN CaptureIfKernel,
278               OUT PSID *CapturedSid)
279 {
280     ULONG SidSize = 0;
281     PISID NewSid, Sid = (PISID)InputSid;
282 
283     PAGED_CODE();
284 
285     if (AccessMode != KernelMode)
286     {
287         _SEH2_TRY
288         {
289             ProbeForRead(Sid, FIELD_OFFSET(SID, SubAuthority), sizeof(UCHAR));
290             SidSize = RtlLengthRequiredSid(Sid->SubAuthorityCount);
291             ProbeForRead(Sid, SidSize, sizeof(UCHAR));
292         }
293         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
294         {
295             /* Return the exception code */
296             _SEH2_YIELD(return _SEH2_GetExceptionCode());
297         }
298         _SEH2_END;
299 
300         /* Allocate a SID and copy it */
301         NewSid = ExAllocatePoolWithTag(PoolType, SidSize, TAG_SID);
302         if (!NewSid)
303             return STATUS_INSUFFICIENT_RESOURCES;
304 
305         _SEH2_TRY
306         {
307             RtlCopyMemory(NewSid, Sid, SidSize);
308 
309             *CapturedSid = NewSid;
310         }
311         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
312         {
313             /* Free the SID and return the exception code */
314             ExFreePoolWithTag(NewSid, TAG_SID);
315             _SEH2_YIELD(return _SEH2_GetExceptionCode());
316         }
317         _SEH2_END;
318     }
319     else if (!CaptureIfKernel)
320     {
321         *CapturedSid = InputSid;
322     }
323     else
324     {
325         SidSize = RtlLengthRequiredSid(Sid->SubAuthorityCount);
326 
327         /* Allocate a SID and copy it */
328         NewSid = ExAllocatePoolWithTag(PoolType, SidSize, TAG_SID);
329         if (NewSid == NULL)
330             return STATUS_INSUFFICIENT_RESOURCES;
331 
332         RtlCopyMemory(NewSid, Sid, SidSize);
333 
334         *CapturedSid = NewSid;
335     }
336 
337     return STATUS_SUCCESS;
338 }
339 
340 VOID
341 NTAPI
342 SepReleaseSid(IN PSID CapturedSid,
343               IN KPROCESSOR_MODE AccessMode,
344               IN BOOLEAN CaptureIfKernel)
345 {
346     PAGED_CODE();
347 
348     if (CapturedSid != NULL &&
349         (AccessMode != KernelMode ||
350          (AccessMode == KernelMode && CaptureIfKernel)))
351     {
352         ExFreePoolWithTag(CapturedSid, TAG_SID);
353     }
354 }
355 
356 NTSTATUS
357 NTAPI
358 SeCaptureSidAndAttributesArray(
359     _In_ PSID_AND_ATTRIBUTES SrcSidAndAttributes,
360     _In_ ULONG AttributeCount,
361     _In_ KPROCESSOR_MODE PreviousMode,
362     _In_opt_ PVOID AllocatedMem,
363     _In_ ULONG AllocatedLength,
364     _In_ POOL_TYPE PoolType,
365     _In_ BOOLEAN CaptureIfKernel,
366     _Out_ PSID_AND_ATTRIBUTES *CapturedSidAndAttributes,
367     _Out_ PULONG ResultLength)
368 {
369     ULONG ArraySize, RequiredLength, SidLength, i;
370     PSID_AND_ATTRIBUTES SidAndAttributes;
371     PUCHAR CurrentDest;
372     PISID Sid;
373     NTSTATUS Status;
374     PAGED_CODE();
375 
376     *CapturedSidAndAttributes = NULL;
377     *ResultLength = 0;
378 
379     if (AttributeCount == 0)
380     {
381         return STATUS_SUCCESS;
382     }
383 
384     if (AttributeCount > 0x1000)
385     {
386         return STATUS_INVALID_PARAMETER;
387     }
388 
389     if ((PreviousMode == KernelMode) && !CaptureIfKernel)
390     {
391         *CapturedSidAndAttributes = SrcSidAndAttributes;
392         return STATUS_SUCCESS;
393     }
394 
395     ArraySize = AttributeCount * sizeof(SID_AND_ATTRIBUTES);
396     RequiredLength = ALIGN_UP_BY(ArraySize, sizeof(ULONG));
397 
398     /* Check for user mode data */
399     if (PreviousMode != KernelMode)
400     {
401         _SEH2_TRY
402         {
403             /* First probe the whole array */
404             ProbeForRead(SrcSidAndAttributes, ArraySize, sizeof(ULONG));
405 
406             /* Loop the array elements */
407             for (i = 0; i < AttributeCount; i++)
408             {
409                 /* Get the SID and probe the minimal structure */
410                 Sid = SrcSidAndAttributes[i].Sid;
411                 ProbeForRead(Sid, sizeof(*Sid), sizeof(ULONG));
412 
413                 /* Verify that the SID is valid */
414                 if (((Sid->Revision & 0xF) != SID_REVISION) ||
415                     (Sid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES))
416                 {
417                     _SEH2_YIELD(return STATUS_INVALID_SID);
418                 }
419 
420                 /* Calculate the SID length and probe the full SID */
421                 SidLength = RtlLengthRequiredSid(Sid->SubAuthorityCount);
422                 ProbeForRead(Sid, SidLength, sizeof(ULONG));
423 
424                 /* Add the aligned length to the required length */
425                 RequiredLength += ALIGN_UP_BY(SidLength, sizeof(ULONG));
426             }
427         }
428         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
429         {
430             _SEH2_YIELD(return _SEH2_GetExceptionCode());
431         }
432         _SEH2_END;
433     }
434     else
435     {
436         /* Loop the array elements */
437         for (i = 0; i < AttributeCount; i++)
438         {
439             /* Get the SID and it's length */
440             Sid = SrcSidAndAttributes[i].Sid;
441             SidLength = RtlLengthRequiredSid(Sid->SubAuthorityCount);
442 
443             /* Add the aligned length to the required length */
444             RequiredLength += ALIGN_UP_BY(SidLength, sizeof(ULONG));
445         }
446     }
447 
448     /* Assume success */
449     Status = STATUS_SUCCESS;
450     *ResultLength = RequiredLength;
451 
452     /* Check if we have no buffer */
453     if (AllocatedMem == NULL)
454     {
455         /* Allocate a new buffer */
456         SidAndAttributes = ExAllocatePoolWithTag(PoolType,
457                                                  RequiredLength,
458                                                  TAG_SID_AND_ATTRIBUTES);
459         if (SidAndAttributes == NULL)
460         {
461             return STATUS_INSUFFICIENT_RESOURCES;
462         }
463     }
464     /* Otherwise check if the buffer is large enough */
465     else if (AllocatedLength >= RequiredLength)
466     {
467         /* Buffer is large enough, use it */
468         SidAndAttributes = AllocatedMem;
469     }
470     else
471     {
472         /* Buffer is too small, fail */
473         return STATUS_BUFFER_TOO_SMALL;
474     }
475 
476     *CapturedSidAndAttributes = SidAndAttributes;
477 
478     /* Check again for user mode */
479     if (PreviousMode != KernelMode)
480     {
481         _SEH2_TRY
482         {
483             /* The rest of the data starts after the array */
484             CurrentDest = (PUCHAR)SidAndAttributes;
485             CurrentDest += ALIGN_UP_BY(ArraySize, sizeof(ULONG));
486 
487             /* Loop the array elements */
488             for (i = 0; i < AttributeCount; i++)
489             {
490                 /* Get the SID and it's length */
491                 Sid = SrcSidAndAttributes[i].Sid;
492                 SidLength = RtlLengthRequiredSid(Sid->SubAuthorityCount);
493 
494                 /* Copy attributes */
495                 SidAndAttributes[i].Attributes = SrcSidAndAttributes[i].Attributes;
496 
497                 /* Copy the SID to the current destination address */
498                 SidAndAttributes[i].Sid = (PSID)CurrentDest;
499                 RtlCopyMemory(CurrentDest, SrcSidAndAttributes[i].Sid, SidLength);
500 
501                 /* Sanity checks */
502                 ASSERT(RtlLengthSid(SidAndAttributes[i].Sid) == SidLength);
503                 ASSERT(RtlValidSid(SidAndAttributes[i].Sid));
504 
505                 /* Update the current destination address */
506                 CurrentDest += ALIGN_UP_BY(SidLength, sizeof(ULONG));
507             }
508         }
509         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
510         {
511             Status = _SEH2_GetExceptionCode();
512         }
513         _SEH2_END;
514     }
515     else
516     {
517         /* The rest of the data starts after the array */
518         CurrentDest = (PUCHAR)SidAndAttributes;
519         CurrentDest += ALIGN_UP_BY(ArraySize, sizeof(ULONG));
520 
521         /* Loop the array elements */
522         for (i = 0; i < AttributeCount; i++)
523         {
524             /* Get the SID and it's length */
525             Sid = SrcSidAndAttributes[i].Sid;
526             SidLength = RtlLengthRequiredSid(Sid->SubAuthorityCount);
527 
528             /* Copy attributes */
529             SidAndAttributes[i].Attributes = SrcSidAndAttributes[i].Attributes;
530 
531             /* Copy the SID to the current destination address */
532             SidAndAttributes[i].Sid = (PSID)CurrentDest;
533             RtlCopyMemory(CurrentDest, SrcSidAndAttributes[i].Sid, SidLength);
534 
535             /* Update the current destination address */
536             CurrentDest += ALIGN_UP_BY(SidLength, sizeof(ULONG));
537         }
538     }
539 
540     /* Check for failure */
541     if (!NT_SUCCESS(Status))
542     {
543         /* Check if we allocated a new array */
544         if (SidAndAttributes != AllocatedMem)
545         {
546             /* Free the array */
547             ExFreePoolWithTag(SidAndAttributes, TAG_SID_AND_ATTRIBUTES);
548         }
549 
550         /* Set returned address to NULL */
551         *CapturedSidAndAttributes = NULL ;
552     }
553 
554     return Status;
555 }
556 
557 VOID
558 NTAPI
559 SeReleaseSidAndAttributesArray(
560     _In_ _Post_invalid_ PSID_AND_ATTRIBUTES CapturedSidAndAttributes,
561     _In_ KPROCESSOR_MODE AccessMode,
562     _In_ BOOLEAN CaptureIfKernel)
563 {
564     PAGED_CODE();
565 
566     if ((CapturedSidAndAttributes != NULL) &&
567         ((AccessMode != KernelMode) || CaptureIfKernel))
568     {
569         ExFreePoolWithTag(CapturedSidAndAttributes, TAG_SID_AND_ATTRIBUTES);
570     }
571 }
572 
573 
574 /* EOF */
575