xref: /reactos/ntoskrnl/se/accesschk.c (revision d7202564)
1 /*
2  * PROJECT:     ReactOS Kernel
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Security access check control implementation
5  * COPYRIGHT:   Copyright 2014 Timo Kreuzer <timo.kreuzer@reactos.org>
6  *              Copyright 2014 Eric Kohl
7  *              Copyright 2022-2023 George Bișoc <george.bisoc@reactos.org>
8  */
9 
10 /* INCLUDES *******************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* PRIVATE FUNCTIONS **********************************************************/
17 
18 /**
19  * @brief
20  * Denies access of a target object and the children objects
21  * in an object type list.
22  *
23  * @param[in,out] ObjectTypeList
24  * A pointer to an object type list where access is to be
25  * denied for the target object and its children in the
26  * hierarchy list.
27  *
28  * @param[in] ObjectTypeListLength
29  * The length of the object type list. This length represents
30  * the number of object elements in the list.
31  *
32  * @param[in] AccessMask
33  * The access mask right that is to be denied for the object.
34  *
35  * @param[in] ObjectTypeGuid
36  * A pointer to a object type GUID, that identifies the object.
37  * This GUID is used to search for the target object in the list.
38  * If this parameter is set to NULL, the function will deny access
39  * starting from the object itself in the list (aka the root).
40  */
41 static
42 VOID
SepDenyAccessObjectTypeResultList(_Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,_In_ ULONG ObjectTypeListLength,_In_ ACCESS_MASK AccessMask,_In_opt_ PGUID ObjectTypeGuid)43 SepDenyAccessObjectTypeResultList(
44     _Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,
45     _In_ ULONG ObjectTypeListLength,
46     _In_ ACCESS_MASK AccessMask,
47     _In_opt_ PGUID ObjectTypeGuid)
48 {
49     ULONG ObjectTypeIndex;
50     ULONG ReturnedObjectIndex;
51     USHORT Level;
52 
53     PAGED_CODE();
54 
55     DPRINT("Access rights 0x%08lx\n", AccessMask);
56 
57     /*
58      * The object type of interest is the one that was supplied
59      * by the creator who made the ACE. If the object type was
60      * not supplied then we have no clear indication from where
61      * shall we start updating the access rights of objects on
62      * this list, so we have to begin from the root (aka the
63      * object itself).
64      */
65     if (!ObjectTypeGuid)
66     {
67         DPRINT("No object type provided, updating access rights from root\n");
68         ReturnedObjectIndex = 0;
69         goto LoopAndUpdateRightsObjects;
70     }
71 
72     /* Check if that object exists in the list */
73     if (SepObjectTypeGuidInList(ObjectTypeList,
74                                 ObjectTypeListLength,
75                                 ObjectTypeGuid,
76                                 &ReturnedObjectIndex))
77     {
78 LoopAndUpdateRightsObjects:
79         /* Update the access rights of the target object */
80         ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights |=
81             (AccessMask & ~ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights);
82         DPRINT("Denied rights 0x%08lx of target object at index %lu\n",
83             ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights, ReturnedObjectIndex);
84 
85         /* And update the children of the target object */
86         for (ObjectTypeIndex = ReturnedObjectIndex + 1;
87              ObjectTypeIndex < ObjectTypeListLength;
88              ObjectTypeIndex++)
89         {
90             /*
91              * Stop looking for children objects if we hit an object that has
92              * the same level as the target object or less.
93              */
94             Level = ObjectTypeList[ObjectTypeIndex].Level;
95             if (Level <= ObjectTypeList[ReturnedObjectIndex].Level)
96             {
97                 DPRINT("We looked for all children objects, stop looking\n");
98                 break;
99             }
100 
101             /* Update the access right of the child */
102             ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.DeniedAccessRights |=
103                 (AccessMask & ~ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights);
104             DPRINT("Denied rights 0x%08lx of child object at index %lu\n",
105                 ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.DeniedAccessRights, ObjectTypeIndex);
106         }
107     }
108 }
109 
110 /**
111  * @brief
112  * Allows access of a target object and the children objects
113  * in an object type list.
114  *
115  * @param[in,out] ObjectTypeList
116  * A pointer to an object type list where access is to be
117  * allowed for the target object and its children in the
118  * hierarchy list.
119  *
120  * @param[in] ObjectTypeListLength
121  * The length of the object type list. This length represents
122  * the number of object elements in the list.
123  *
124  * @param[in] AccessMask
125  * The access mask right that is to be allowed for the object.
126  *
127  * @param[in] ObjectTypeGuid
128  * A pointer to a object type GUID, that identifies the object.
129  * This GUID is used to search for the target object in the list.
130  * If this parameter is set to NULL, the function will allow access
131  * starting from the object itself in the list (aka the root).
132  */
133 static
134 VOID
SepAllowAccessObjectTypeResultList(_Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,_In_ ULONG ObjectTypeListLength,_In_ ACCESS_MASK AccessMask,_In_opt_ PGUID ObjectTypeGuid)135 SepAllowAccessObjectTypeResultList(
136     _Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,
137     _In_ ULONG ObjectTypeListLength,
138     _In_ ACCESS_MASK AccessMask,
139     _In_opt_ PGUID ObjectTypeGuid)
140 {
141     ULONG ObjectTypeIndex;
142     ULONG ReturnedObjectIndex;
143     USHORT Level;
144 
145     PAGED_CODE();
146 
147     DPRINT("Access rights 0x%08lx\n", AccessMask);
148 
149     /*
150      * Begin updating the access rights from the root object
151      * (see comment in SepDenyAccessObjectTypeListMaximum).
152      */
153     if (!ObjectTypeGuid)
154     {
155         DPRINT("No object type provided, updating access rights from root\n");
156         ReturnedObjectIndex = 0;
157         goto LoopAndUpdateRightsObjects;
158     }
159 
160     /* Check if that object exists in the list */
161     if (SepObjectTypeGuidInList(ObjectTypeList,
162                                 ObjectTypeListLength,
163                                 ObjectTypeGuid,
164                                 &ReturnedObjectIndex))
165     {
166 LoopAndUpdateRightsObjects:
167         /* Update the access rights of the target object */
168         ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights |=
169             (AccessMask & ~ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights);
170         DPRINT("Granted rights 0x%08lx of target object at index %lu\n",
171             ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights, ReturnedObjectIndex);
172 
173         /* And update the children of the target object */
174         for (ObjectTypeIndex = ReturnedObjectIndex + 1;
175              ObjectTypeIndex < ObjectTypeListLength;
176              ObjectTypeIndex++)
177         {
178             /*
179              * Stop looking for children objects if we hit an object that has
180              * the same level as the target object or less.
181              */
182             Level = ObjectTypeList[ObjectTypeIndex].Level;
183             if (Level <= ObjectTypeList[ReturnedObjectIndex].Level)
184             {
185                 break;
186             }
187 
188             /* Update the access right of the child */
189             ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights |=
190                 (AccessMask & ~ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.DeniedAccessRights);
191             DPRINT("Granted rights 0x%08lx of child object at index %lu\n",
192                 ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights, ObjectTypeIndex);
193         }
194     }
195 }
196 
197 /**
198  * @brief
199  * Denies access of a target object in the object type
200  * list. This access is denied for the whole hierarchy
201  * in the list.
202  *
203  * @param[in,out] ObjectTypeList
204  * A pointer to an object type list where access is to be
205  * denied for the target object. This operation applies
206  * for the entire hierarchy of the object type list.
207  *
208  * @param[in] ObjectTypeListLength
209  * The length of the object type list. This length represents
210  * the number of object elements in the list.
211  *
212  * @param[in] AccessMask
213  * The access mask right that is to be denied for the object.
214  *
215  * @param[in] ObjectTypeGuid
216  * A pointer to a object type GUID, that identifies the object.
217  * This GUID is used to search for the target object in the list.
218  * If this parameter is set to NULL, the function will deny access
219  * to the object itself in the list (aka the root).
220  *
221  * @param[out] BreakOnDeny
222  * A pointer returned boolean value to the caller. The function
223  * will return TRUE if the requested remaining right is denied
224  * by the ACE, otherwise it returns FALSE.
225  */
226 static
227 VOID
SepDenyAccessObjectTypeList(_Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,_In_ ULONG ObjectTypeListLength,_In_ ACCESS_MASK AccessMask,_In_opt_ PGUID ObjectTypeGuid,_Out_opt_ PBOOLEAN BreakOnDeny)228 SepDenyAccessObjectTypeList(
229     _Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,
230     _In_ ULONG ObjectTypeListLength,
231     _In_ ACCESS_MASK AccessMask,
232     _In_opt_ PGUID ObjectTypeGuid,
233     _Out_opt_ PBOOLEAN BreakOnDeny)
234 {
235     ULONG ReturnedObjectIndex;
236     BOOLEAN MustBreak;
237 
238     PAGED_CODE();
239 
240     DPRINT("Access rights 0x%08lx\n", AccessMask);
241 
242     /* Assume we do not want to break at first */
243     MustBreak = FALSE;
244 
245     /*
246      * If no object type was supplied then tell the caller it has to break on
247      * searching for other ACEs if the requested remaining access right is
248      * denied by the deny ACE itself. Track down that denied right too.
249      */
250     if (!ObjectTypeGuid)
251     {
252         if (ObjectTypeList[0].ObjectAccessRights.RemainingAccessRights & AccessMask)
253         {
254             DPRINT("Root object requests remaining access right that is denied 0x%08lx\n", AccessMask);
255             MustBreak = TRUE;
256         }
257 
258         ObjectTypeList[0].ObjectAccessRights.DeniedAccessRights |=
259             (AccessMask & ~ObjectTypeList[0].ObjectAccessRights.GrantedAccessRights);
260         DPRINT("Denied rights of root object 0x%08lx\n", ObjectTypeList[0].ObjectAccessRights.DeniedAccessRights);
261         goto Quit;
262     }
263 
264     /*
265      * If the object exists tell the caller it has to break down if the requested
266      * remaining access right is denied by the ACE. Track down the denied right too.
267      */
268     if (SepObjectTypeGuidInList(ObjectTypeList,
269                                 ObjectTypeListLength,
270                                 ObjectTypeGuid,
271                                 &ReturnedObjectIndex))
272     {
273         if (ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.RemainingAccessRights & AccessMask)
274         {
275             DPRINT("Object at index %lu requests remaining access right that is denied 0x%08lx\n", ReturnedObjectIndex, AccessMask);
276             MustBreak = TRUE;
277         }
278 
279         ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights |=
280             (AccessMask & ~ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights);
281         DPRINT("Denied rights 0x%08lx of object at index %lu\n",
282             ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights, ReturnedObjectIndex);
283     }
284 
285 Quit:
286     /* Signal the caller he has to break if he wants to */
287     if (BreakOnDeny)
288     {
289         *BreakOnDeny = MustBreak;
290     }
291 }
292 
293 /**
294  * @brief
295  * Allows access of a target object in the object type
296  * list. This access is allowed for the whole hierarchy
297  * in the list.
298  *
299  * @param[in,out] ObjectTypeList
300  * A pointer to an object type list where access is to be
301  * allowed for the target object. This operation applies
302  * for the entire hierarchy of the object type list.
303  *
304  * @param[in] ObjectTypeListLength
305  * The length of the object type list. This length represents
306  * the number of object elements in the list.
307  *
308  * @param[in] AccessMask
309  * The access mask right that is to be allowed for the object.
310  *
311  * @param[in] RemoveRemainingRights
312  * If set to TRUE, the function will remove the remaining rights
313  * of a target object. It will also grant access of the said object.
314  * Otherwise if set to FALSE, the function will only grant access.
315  *
316  * @param[in] ObjectTypeGuid
317  * A pointer to a object type GUID, that identifies the object.
318  * This GUID is used to search for the target object in the list.
319  * If this parameter is set to NULL, the function will allow access
320  * to the object itself in the list (aka the root).
321  */
322 static
323 VOID
SepAllowAccessObjectTypeList(_Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,_In_ ULONG ObjectTypeListLength,_In_ ACCESS_MASK AccessMask,_In_ BOOLEAN RemoveRemainingRights,_In_opt_ PGUID ObjectTypeGuid)324 SepAllowAccessObjectTypeList(
325     _Inout_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,
326     _In_ ULONG ObjectTypeListLength,
327     _In_ ACCESS_MASK AccessMask,
328     _In_ BOOLEAN RemoveRemainingRights,
329     _In_opt_ PGUID ObjectTypeGuid)
330 {
331     ULONG ReturnedObjectIndex;
332 
333     PAGED_CODE();
334 
335     DPRINT("Access rights 0x%08lx\n", AccessMask);
336 
337     /*
338      * If no object type was supplied then remove the remaining rights
339      * of the object itself, the root. Track down that right to the
340      * granted rights as well.
341      */
342     if (!ObjectTypeGuid)
343     {
344         if (RemoveRemainingRights)
345         {
346             ObjectTypeList[0].ObjectAccessRights.RemainingAccessRights &= ~AccessMask;
347             DPRINT("Remaining rights of root object 0x%08lx\n", ObjectTypeList[0].ObjectAccessRights.RemainingAccessRights);
348         }
349 
350         ObjectTypeList[0].ObjectAccessRights.GrantedAccessRights |=
351             (AccessMask & ~ObjectTypeList[0].ObjectAccessRights.DeniedAccessRights);
352         DPRINT("Granted rights of root object 0x%08lx\n", ObjectTypeList[0].ObjectAccessRights.GrantedAccessRights);
353         return;
354     }
355 
356     /*
357      * Grant access to the object if it exists by removing the remaining
358      * rights. Unlike the NtAccessCheckByTypeResultList variant we do not
359      * care about the children of the target object beccause NtAccessCheckByType
360      * will either grant or deny access to the entire hierarchy of the list.
361      */
362     if (SepObjectTypeGuidInList(ObjectTypeList,
363                                 ObjectTypeListLength,
364                                 ObjectTypeGuid,
365                                 &ReturnedObjectIndex))
366     {
367         /* Remove the remaining rights of that object */
368         if (RemoveRemainingRights)
369         {
370             ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.RemainingAccessRights &= ~AccessMask;
371             DPRINT("Remaining rights of object 0x%08lx at index %lu\n",
372                 ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.RemainingAccessRights, ReturnedObjectIndex);
373         }
374 
375         /* And track it down to the granted access rights */
376         ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights |=
377             (AccessMask & ~ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.DeniedAccessRights);
378         DPRINT("Granted rights of object 0x%08lx at index %lu\n",
379             ObjectTypeList[ReturnedObjectIndex].ObjectAccessRights.GrantedAccessRights, ReturnedObjectIndex);
380     }
381 }
382 
383 /**
384  * @brief
385  * Analyzes an access control entry that is present in a discretionary
386  * access control list (DACL) for access right masks of each entry with
387  * the purpose to judge whether the calling thread can be warranted
388  * access check to a certain object or not.
389  *
390  * @param[in] ActionType
391  * The type of analysis to be done against an access entry. This type
392  * influences how access rights are gathered. This can either be AccessCheckMaximum
393  * which means the algorithm will perform analysis against ACEs on behalf of the
394  * requestor that gave us the acknowledgement that he desires MAXIMUM_ALLOWED access
395  * right or AccessCheckRegular if the requestor wants a subset of access rights.
396  *
397  * @param[in] RemainingAccess
398  * The remaining access rights that have yet to be granted to the calling thread
399  * whomst requests access to a certain object. This parameter mustn't be 0 as
400  * the remaining rights are left to be addressed. This is the case if we have
401  * to address the remaining rights on a regular subset basis (the requestor
402  * didn't ask for MAXIMUM_ALLOWED). Otherwise this parameter can be 0.
403  *
404  * @param[in] Dacl
405  * The discretionary access control list to be given to this function. This DACL
406  * must have at least one ACE currently present in the list.
407  *
408  * @param[in] AccessToken
409  * A pointer to an access token, where an equality comparison check is performed if
410  * the security identifier (SID) from a ACE of a certain object is present in this
411  * token. This token represents the effective (calling thread) token of the caller.
412  *
413  * @param[in] PrimaryAccessToken
414  * A pointer to an access token, represented as an access token associated with the
415  * primary calling process. This token describes the primary security context of the
416  * main process.
417  *
418  * @param[in] IsTokenRestricted
419  * If this parameter is set to TRUE, the function considers the token pointed by
420  * AccessToken parameter argument as restricted. That is, the token has restricted
421  * SIDs therefore the function will act accordingly against that token by checking
422  * for restricted SIDs only when doing an equaility comparison check between the
423  * two identifiers.
424  *
425  * @param[in] PrincipalSelfSid
426  * A pointer to a security identifier that represents a principal. A principal
427  * identifies a user object which is associated with its own security descriptor.
428  *
429  * @param[in] GenericMapping
430  * A pointer to a generic mapping that is associated with the object in question
431  * being checked for access. If certain set of desired access rights have
432  * a generic access right, this parameter is needed to map generic rights.
433  *
434  * @param[in] ObjectTypeList
435  * A pointer to a list array of object types. If such array is provided to the
436  * function, the algorithm will perform a different approach by doing analysis
437  * against ACEs each sub-object of an object of primary level (level 0) or sub-objects
438  * of a sub-object of an object. If this parameter is NULL, the function will normally
439  * analyze the ACEs of a DACL of the target object itself.
440  *
441  * @param[in] ObjectTypeListLength
442  * The length of the object type list array, pointed by ObjectTypeList. This length in
443  * question represents the number of elements in such array. This parameter must be 0
444  * if no array list is provided.
445  *
446  * @param[in] UseResultList
447  * This parameter is to used to determine how to perform an object type access check.
448  * If set to TRUE, the function will either grant or deny access to the object and sub-objects
449  * in the hierarchy list. If set to FALSE, the function will either grant or deny access to
450  * the target that will affect the entire hierarchy of the list. This parameter is used
451  * if the access action type is AccessCheckMaximum.
452  *
453  * @param[in,out] AccessCheckRights
454  * A pointer to a structure that contains the access check rights. This function fills
455  * up this structure with remaining, granted and denied rights to the caller for
456  * access check. Henceforth, this parameter must not be NULL!
457  */
458 static
459 VOID
SepAnalyzeAcesFromDacl(_In_ ACCESS_CHECK_RIGHT_TYPE ActionType,_In_ ACCESS_MASK RemainingAccess,_In_ PACL Dacl,_In_ PACCESS_TOKEN AccessToken,_In_ PACCESS_TOKEN PrimaryAccessToken,_In_ BOOLEAN IsTokenRestricted,_In_opt_ PSID PrincipalSelfSid,_In_ PGENERIC_MAPPING GenericMapping,_In_opt_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,_In_ ULONG ObjectTypeListLength,_In_ BOOLEAN UseResultList,_Inout_ PACCESS_CHECK_RIGHTS AccessCheckRights)460 SepAnalyzeAcesFromDacl(
461     _In_ ACCESS_CHECK_RIGHT_TYPE ActionType,
462     _In_ ACCESS_MASK RemainingAccess,
463     _In_ PACL Dacl,
464     _In_ PACCESS_TOKEN AccessToken,
465     _In_ PACCESS_TOKEN PrimaryAccessToken,
466     _In_ BOOLEAN IsTokenRestricted,
467     _In_opt_ PSID PrincipalSelfSid,
468     _In_ PGENERIC_MAPPING GenericMapping,
469     _In_opt_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,
470     _In_ ULONG ObjectTypeListLength,
471     _In_ BOOLEAN UseResultList,
472     _Inout_ PACCESS_CHECK_RIGHTS AccessCheckRights)
473 {
474     NTSTATUS Status;
475     PACE CurrentAce;
476     ULONG AceIndex;
477     ULONG ObjectTypeIndex;
478     PSID Sid;
479     PGUID ObjectTypeGuid;
480     ACCESS_MASK Access;
481     BOOLEAN BreakOnDeny;
482 
483     PAGED_CODE();
484 
485     /* These parameters are really needed */
486     ASSERT(Dacl);
487     ASSERT(AccessToken);
488 
489     /* TODO: To be removed once we support compound ACEs handling in Se */
490     DBG_UNREFERENCED_PARAMETER(PrimaryAccessToken);
491 
492     /* Determine how we should analyze the ACEs */
493     switch (ActionType)
494     {
495         /*
496          * We got the acknowledgement the calling thread desires
497          * maximum rights (as according to MAXIMUM_ALLOWED access
498          * mask). Analyze the ACE of the given DACL.
499          */
500         case AccessCheckMaximum:
501         {
502             /* Loop over the DACL to retrieve ACEs */
503             for (AceIndex = 0; AceIndex < Dacl->AceCount; AceIndex++)
504             {
505                 /* Obtain a ACE now */
506                 Status = RtlGetAce(Dacl, AceIndex, (PVOID*)&CurrentAce);
507 
508                 /* Getting this ACE is important, otherwise something is seriously wrong */
509                 ASSERT(NT_SUCCESS(Status));
510 
511                 /*
512                  * Now it's time to analyze it based upon the
513                  * type of this ACE we're being given.
514                  */
515                 if (!(CurrentAce->Header.AceFlags & INHERIT_ONLY_ACE))
516                 {
517                     if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE)
518                     {
519                         /* Get the SID from this ACE */
520                         Sid = SepGetSidFromAce(CurrentAce);
521                         ASSERT(Sid);
522 
523                         if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, TRUE, IsTokenRestricted))
524                         {
525                             /* Get this access right from the ACE */
526                             Access = CurrentAce->AccessMask;
527 
528                             /* Map this access right if it has a generic mask right */
529                             if ((Access & GENERIC_ACCESS) && GenericMapping)
530                             {
531                                 RtlMapGenericMask(&Access, GenericMapping);
532                             }
533 
534                             /* Deny access rights that have not been granted yet */
535                             AccessCheckRights->DeniedAccessRights |= (Access & ~AccessCheckRights->GrantedAccessRights);
536                             DPRINT("DeniedAccessRights 0x%08lx\n", AccessCheckRights->DeniedAccessRights);
537                         }
538                     }
539                     else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
540                     {
541                         /* Get the SID from this ACE */
542                         Sid = SepGetSidFromAce(CurrentAce);
543                         ASSERT(Sid);
544 
545                         if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, FALSE, IsTokenRestricted))
546                         {
547                             /* Get this access right from the ACE */
548                             Access = CurrentAce->AccessMask;
549 
550                             /* Map this access right if it has a generic mask right */
551                             if ((Access & GENERIC_ACCESS) && GenericMapping)
552                             {
553                                 RtlMapGenericMask(&Access, GenericMapping);
554                             }
555 
556                             /* Grant access rights that have not been denied yet */
557                             AccessCheckRights->GrantedAccessRights |= (Access & ~AccessCheckRights->DeniedAccessRights);
558                             DPRINT("GrantedAccessRights 0x%08lx\n", AccessCheckRights->GrantedAccessRights);
559                         }
560                     }
561                     else if (CurrentAce->Header.AceType == ACCESS_DENIED_OBJECT_ACE_TYPE)
562                     {
563                         /* Get the SID and object type from this ACE */
564                         Sid = SepGetSidFromAce(CurrentAce);
565                         ObjectTypeGuid = SepGetObjectTypeGuidFromAce(CurrentAce, TRUE);
566                         ASSERT(Sid);
567 
568                         if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, TRUE, IsTokenRestricted))
569                         {
570                             /* Get this access right from the ACE */
571                             Access = CurrentAce->AccessMask;
572 
573                             /* Map this access right if it has a generic mask right */
574                             if ((Access & GENERIC_ACCESS) && GenericMapping)
575                             {
576                                 RtlMapGenericMask(&Access, GenericMapping);
577                             }
578 
579                             /* If no list was passed treat this is as ACCESS_DENIED_ACE_TYPE */
580                             if (!ObjectTypeList && !ObjectTypeListLength)
581                             {
582                                 AccessCheckRights->DeniedAccessRights |= (Access & ~AccessCheckRights->GrantedAccessRights);
583                                 DPRINT("DeniedAccessRights 0x%08lx\n", AccessCheckRights->DeniedAccessRights);
584                             }
585                             else if (!UseResultList)
586                             {
587                                 /*
588                                  * We have an object type list but the caller wants to deny access
589                                  * to the entire hierarchy list. Evaluate the rights of the object
590                                  * for the whole list. Ignore what the function tells us if we have
591                                  * to break on deny or not because we only want to keep track of
592                                  * denied rights.
593                                  */
594                                SepDenyAccessObjectTypeList(ObjectTypeList,
595                                                            ObjectTypeListLength,
596                                                            Access,
597                                                            ObjectTypeGuid,
598                                                            NULL);
599                             }
600                             else
601                             {
602                                 /* Otherwise evaluate the access rights for each sub-object */
603                                 SepDenyAccessObjectTypeResultList(ObjectTypeList,
604                                                                   ObjectTypeListLength,
605                                                                   Access,
606                                                                   ObjectTypeGuid);
607                             }
608                         }
609                     }
610                     else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_OBJECT_ACE_TYPE)
611                     {
612                         /* Get the SID and object type from this ACE */
613                         Sid = SepGetSidFromAce(CurrentAce);
614                         ObjectTypeGuid = SepGetObjectTypeGuidFromAce(CurrentAce, FALSE);
615                         ASSERT(Sid);
616 
617                         if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, FALSE, IsTokenRestricted))
618                         {
619                             /* Get this access right from the ACE */
620                             Access = CurrentAce->AccessMask;
621 
622                             /* Map this access right if it has a generic mask right */
623                             if ((Access & GENERIC_ACCESS) && GenericMapping)
624                             {
625                                 RtlMapGenericMask(&Access, GenericMapping);
626                             }
627 
628                             /* If no list was passed treat this is as ACCESS_ALLOWED_ACE_TYPE */
629                             if (!ObjectTypeList && !ObjectTypeListLength)
630                             {
631                                 AccessCheckRights->GrantedAccessRights |= (Access & ~AccessCheckRights->DeniedAccessRights);
632                                 DPRINT("GrantedAccessRights 0x%08lx\n", AccessCheckRights->GrantedAccessRights);
633                             }
634                             else if (!UseResultList)
635                             {
636                                 /*
637                                  * We have an object type list but the caller wants to allow access
638                                  * to the entire hierarchy list. Evaluate the rights of the object
639                                  * for the whole list.
640                                  */
641                                 SepAllowAccessObjectTypeList(ObjectTypeList,
642                                                              ObjectTypeListLength,
643                                                              Access,
644                                                              FALSE,
645                                                              ObjectTypeGuid);
646                             }
647                             else
648                             {
649                                 /* Otherwise evaluate the access rights for each sub-object */
650                                 SepAllowAccessObjectTypeResultList(ObjectTypeList,
651                                                                    ObjectTypeListLength,
652                                                                    Access,
653                                                                    ObjectTypeGuid);
654                             }
655                         }
656                     }
657                     else
658                     {
659                         DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType);
660                     }
661                 }
662             }
663 
664             /* We're done here */
665             break;
666         }
667 
668         /*
669          * We got the acknowledgement the calling thread desires
670          * only a subset of rights therefore we have to act a little
671          * different here.
672          */
673         case AccessCheckRegular:
674         {
675             /* Cache the remaining access rights to be addressed */
676             ASSERT(RemainingAccess != 0);
677             AccessCheckRights->RemainingAccessRights = RemainingAccess;
678 
679             /* Fill the remaining rights of each object in the list if we have one */
680             if (ObjectTypeList && (ObjectTypeListLength != 0))
681             {
682                 for (ObjectTypeIndex = 0;
683                      ObjectTypeIndex < ObjectTypeListLength;
684                      ObjectTypeIndex++)
685                 {
686                     ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.RemainingAccessRights = RemainingAccess;
687                 }
688             }
689 
690             /* Loop over the DACL to retrieve ACEs */
691             for (AceIndex = 0; AceIndex < Dacl->AceCount; AceIndex++)
692             {
693                 /* Obtain a ACE now */
694                 Status = RtlGetAce(Dacl, AceIndex, (PVOID*)&CurrentAce);
695 
696                 /* Getting this ACE is important, otherwise something is seriously wrong */
697                 ASSERT(NT_SUCCESS(Status));
698 
699                 /*
700                  * Now it's time to analyze it based upon the
701                  * type of this ACE we're being given.
702                  */
703                 if (!(CurrentAce->Header.AceFlags & INHERIT_ONLY_ACE))
704                 {
705                     if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE)
706                     {
707                         /* Get the SID from this ACE */
708                         Sid = SepGetSidFromAce(CurrentAce);
709                         ASSERT(Sid);
710 
711                         if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, TRUE, IsTokenRestricted))
712                         {
713                             /* Get this access right from the ACE */
714                             Access = CurrentAce->AccessMask;
715 
716                             /* Map this access right if it has a generic mask right */
717                             if ((Access & GENERIC_ACCESS) && GenericMapping)
718                             {
719                                 RtlMapGenericMask(&Access, GenericMapping);
720                             }
721 
722                             /*
723                              * The caller requests a right that cannot be
724                              * granted. Access is implicitly denied for
725                              * the calling thread. Track this access right.
726                              */
727                             if (AccessCheckRights->RemainingAccessRights & Access)
728                             {
729                                 DPRINT("Refuted access 0x%08lx\n", Access);
730                                 AccessCheckRights->DeniedAccessRights |= Access;
731                                 break;
732                             }
733                         }
734                     }
735                     else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
736                     {
737                         /* Get the SID from this ACE */
738                         Sid = SepGetSidFromAce(CurrentAce);
739                         ASSERT(Sid);
740 
741                         if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, FALSE, IsTokenRestricted))
742                         {
743                             /* Get this access right from the ACE */
744                             Access = CurrentAce->AccessMask;
745 
746                             /* Map this access right if it has a generic mask right */
747                             if ((Access & GENERIC_ACCESS) && GenericMapping)
748                             {
749                                 RtlMapGenericMask(&Access, GenericMapping);
750                             }
751 
752                             /* Remove the remaining rights */
753                             DPRINT("RemainingAccessRights 0x%08lx  Access 0x%08lx\n", AccessCheckRights->RemainingAccessRights, Access);
754                             AccessCheckRights->RemainingAccessRights &= ~Access;
755                             DPRINT("RemainingAccessRights 0x%08lx\n", AccessCheckRights->RemainingAccessRights);
756 
757                             /* Track the granted access right */
758                             AccessCheckRights->GrantedAccessRights |= Access;
759                         }
760                     }
761                     else if (CurrentAce->Header.AceType == ACCESS_DENIED_OBJECT_ACE_TYPE)
762                     {
763                         /* Get the SID and object type from this ACE */
764                         Sid = SepGetSidFromAce(CurrentAce);
765                         ObjectTypeGuid = SepGetObjectTypeGuidFromAce(CurrentAce, TRUE);
766                         ASSERT(Sid);
767 
768                         if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, TRUE, IsTokenRestricted))
769                         {
770                             /* Get this access right from the ACE */
771                             Access = CurrentAce->AccessMask;
772 
773                             /* Map this access right if it has a generic mask right */
774                             if ((Access & GENERIC_ACCESS) && GenericMapping)
775                             {
776                                 RtlMapGenericMask(&Access, GenericMapping);
777                             }
778 
779                             /* If no list was passed treat this is as ACCESS_DENIED_ACE_TYPE */
780                             if (!ObjectTypeList && !ObjectTypeListLength)
781                             {
782                                 if (AccessCheckRights->RemainingAccessRights & Access)
783                                 {
784                                     DPRINT("Refuted access 0x%08lx\n", Access);
785                                     AccessCheckRights->DeniedAccessRights |= Access;
786                                     break;
787                                 }
788                             }
789                             else
790                             {
791                                 /*
792                                  * Otherwise evaluate the rights of the object for the entire list.
793                                  * The function will signal us if the caller requested a right that is
794                                  * denied by the ACE of an object in the list.
795                                  */
796                                 SepDenyAccessObjectTypeList(ObjectTypeList,
797                                                             ObjectTypeListLength,
798                                                             Access,
799                                                             ObjectTypeGuid,
800                                                             &BreakOnDeny);
801 
802                                 /* We are acknowledged the caller requested a denied right */
803                                 if (BreakOnDeny)
804                                 {
805                                     DPRINT("Refuted access 0x%08lx\n", Access);
806                                     break;
807                                 }
808                             }
809                         }
810                     }
811                     else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_OBJECT_ACE_TYPE)
812                     {
813                         /* Get the SID and object type from this ACE */
814                         Sid = SepGetSidFromAce(CurrentAce);
815                         ObjectTypeGuid = SepGetObjectTypeGuidFromAce(CurrentAce, FALSE);
816                         ASSERT(Sid);
817 
818                         if (SepSidInTokenEx(AccessToken, PrincipalSelfSid, Sid, FALSE, IsTokenRestricted))
819                         {
820                             /* Get this access right from the ACE */
821                             Access = CurrentAce->AccessMask;
822 
823                             /* Map this access right if it has a generic mask right */
824                             if ((Access & GENERIC_ACCESS) && GenericMapping)
825                             {
826                                 RtlMapGenericMask(&Access, GenericMapping);
827                             }
828 
829                             /* If no list was passed treat this is as ACCESS_ALLOWED_ACE_TYPE */
830                             if (!ObjectTypeList && !ObjectTypeListLength)
831                             {
832                                 /* Remove the remaining rights */
833                                 DPRINT("RemainingAccessRights 0x%08lx  Access 0x%08lx\n", AccessCheckRights->RemainingAccessRights, Access);
834                                 AccessCheckRights->RemainingAccessRights &= ~Access;
835                                 DPRINT("RemainingAccessRights 0x%08lx\n", AccessCheckRights->RemainingAccessRights);
836 
837                                 /* Track the granted access right */
838                                 AccessCheckRights->GrantedAccessRights |= Access;
839                             }
840                             else
841                             {
842                                 /* Otherwise evaluate the rights of the object for the entire list */
843                                 SepAllowAccessObjectTypeList(ObjectTypeList,
844                                                              ObjectTypeListLength,
845                                                              Access,
846                                                              TRUE,
847                                                              ObjectTypeGuid);
848                             }
849                         }
850                     }
851                     else
852                     {
853                         DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType);
854                     }
855                 }
856             }
857 
858             /* We're done here */
859             break;
860         }
861 
862         /* We shouldn't reach here */
863         DEFAULT_UNREACHABLE;
864     }
865 }
866 
867 /**
868  * @brief
869  * Private worker function that determines whether security access rights can be
870  * givento the calling thread in order to access an object depending on the
871  * security descriptor and other security context entities, such as an owner. This
872  * function is the heart and brain of the whole access check algorithm in the kernel.
873  *
874  * @param[in] ClientAccessToken
875  * A pointer to a client (thread) access token that requests access rights
876  * of an object or subset of multiple objects.
877  *
878  * @param[in] PrimaryAccessToken
879  * A pointer to a primary access token that describes the primary security
880  * context of the main calling process.
881  *
882  * @param[in] PrincipalSelfSid
883  * A pointer to a security identifier that represents a security principal,
884  * that is, a user object associated with its security descriptor.
885  *
886  * @param[in] DesiredAccess
887  * The access rights desired by the calling thread to acquire in order to
888  * access an object.
889  *
890  * @param[in] ObjectTypeList
891  * An array list of object types to be checked against for access. The function
892  * will act accordingly in this case by checking each sub-object of an object
893  * of primary level and such. If this parameter is NULL, the function will
894  * perform a normal access check against the target object itself.
895  *
896  * @param[in] ObjectTypeListLength
897  * The length of a object type list. Such length represents the number of
898  * elements in this list.
899  *
900  * @param[in] PreviouslyGrantedAccess
901  * The access rights previously acquired in the past. If this parameter is 0,
902  * it is deemed that the calling thread hasn't acquired any rights. Access checks
903  * are more tighten in this case.
904  *
905  * @param[in] GenericMapping
906  * A pointer to a generic mapping of access rights of the target object.
907  *
908  * @param[in] AccessMode
909  * The processor request level mode.
910  *
911  * @param[in] UseResultList
912  * If set to TRUE, the function will return a list of granted access rights
913  * of each sub-object as well as status code for each. If this parameter is
914  * set to FALSE, then the function will just return only the granted access
915  * rights and status code for single object that's been target for access
916  * checks.
917  *
918  * @param[out] Privileges
919  * A pointer to a definite set of privileges that have been audited
920  * whilst doing access check procedures. Such set of privileges are
921  * optionally returned to the caller. This can be set to NULL if
922  * the caller doesn't want to obtain a set of privileges.
923  *
924  * @param[out] GrantedAccessList
925  * A list of granted access rights returned to the caller. This list
926  * can comprehend multiple elements which represent the sub-objects
927  * that have been checked or a single element which is the target
928  * object itself.
929  *
930  * @param[out] AccessStatusList
931  * A list of access status codes returned to the caller. This list
932  * can comprehend multiple elements which represent the sub-objects
933  * that have been checked or a single element which is the target
934  * object itself.
935  *
936  * @return
937  * Returns TRUE if access onto the specific object is allowed, FALSE
938  * otherwise.
939  */
940 static
941 BOOLEAN
SepAccessCheckWorker(_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,_In_opt_ PACCESS_TOKEN ClientAccessToken,_In_ PACCESS_TOKEN PrimaryAccessToken,_In_opt_ PSID PrincipalSelfSid,_In_ ACCESS_MASK DesiredAccess,_In_opt_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,_In_ ULONG ObjectTypeListLength,_In_ ACCESS_MASK PreviouslyGrantedAccess,_In_ PGENERIC_MAPPING GenericMapping,_In_ KPROCESSOR_MODE AccessMode,_In_ BOOLEAN UseResultList,_Out_opt_ PPRIVILEGE_SET * Privileges,_Out_ PACCESS_MASK GrantedAccessList,_Out_ PNTSTATUS AccessStatusList)942 SepAccessCheckWorker(
943     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
944     _In_opt_ PACCESS_TOKEN ClientAccessToken,
945     _In_ PACCESS_TOKEN PrimaryAccessToken,
946     _In_opt_ PSID PrincipalSelfSid,
947     _In_ ACCESS_MASK DesiredAccess,
948     _In_opt_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList,
949     _In_ ULONG ObjectTypeListLength,
950     _In_ ACCESS_MASK PreviouslyGrantedAccess,
951     _In_ PGENERIC_MAPPING GenericMapping,
952     _In_ KPROCESSOR_MODE AccessMode,
953     _In_ BOOLEAN UseResultList,
954     _Out_opt_ PPRIVILEGE_SET* Privileges,
955     _Out_ PACCESS_MASK GrantedAccessList,
956     _Out_ PNTSTATUS AccessStatusList)
957 {
958     ACCESS_MASK RemainingAccess;
959     ACCESS_MASK WantedRights;
960     ACCESS_MASK MaskDesired;
961     ACCESS_MASK GrantedRights = 0;
962     ULONG ResultListIndex;
963     ULONG ObjectTypeIndex;
964     PACL Dacl;
965     BOOLEAN Present;
966     BOOLEAN Defaulted;
967     NTSTATUS Status;
968     BOOLEAN AccessIsGranted = FALSE;
969     PACCESS_TOKEN Token = NULL;
970     ACCESS_CHECK_RIGHTS AccessCheckRights = {0};
971 
972     PAGED_CODE();
973 
974     /* A security descriptor must be expected for access checks */
975     ASSERT(SecurityDescriptor);
976 
977     /* Check for no access desired */
978     if (!DesiredAccess)
979     {
980         /* Check if we had no previous access */
981         if (!PreviouslyGrantedAccess)
982         {
983             /* Then there's nothing to give */
984             DPRINT1("The caller has no previously granted access gained!\n");
985             Status = STATUS_ACCESS_DENIED;
986             goto ReturnCommonStatus;
987         }
988 
989         /* Return the previous access only */
990         Status = STATUS_SUCCESS;
991         *Privileges = NULL;
992         goto ReturnCommonStatus;
993     }
994 
995     /* Map given accesses */
996     RtlMapGenericMask(&DesiredAccess, GenericMapping);
997     if (PreviouslyGrantedAccess)
998         RtlMapGenericMask(&PreviouslyGrantedAccess, GenericMapping);
999 
1000     /* Initialize remaining access rights */
1001     RemainingAccess = DesiredAccess;
1002 
1003     /*
1004      * Initialize the required rights if the caller wants to know access
1005      * for the object and each sub-object in the list.
1006      */
1007     if (UseResultList)
1008     {
1009         if (DesiredAccess & MAXIMUM_ALLOWED)
1010         {
1011             WantedRights = (DesiredAccess | PreviouslyGrantedAccess) & ~MAXIMUM_ALLOWED;
1012             MaskDesired = ~MAXIMUM_ALLOWED;
1013         }
1014         else
1015         {
1016             WantedRights = MaskDesired = DesiredAccess | PreviouslyGrantedAccess;
1017         }
1018     }
1019 
1020     /*
1021      * Obtain the token provided by the caller. Client (or also
1022      * called impersonation or thread) token takes precedence over
1023      * the primary token which is the token associated with the security
1024      * context of the main calling process. This is because it is the
1025      * client itself that requests access of an object or subset of
1026      * multiple objects. Otherwise obtain the security context of the
1027      * main process (the actual primary token).
1028      */
1029     Token = ClientAccessToken ? ClientAccessToken : PrimaryAccessToken;
1030 
1031     /*
1032      * We should at least expect a primary token
1033      * to be present if client token is not
1034      * available.
1035      */
1036     ASSERT(Token);
1037 
1038     /*
1039      * Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access.
1040      * Write down a set of privileges that have been checked
1041      * if the caller wants it.
1042      */
1043     Status = SePrivilegePolicyCheck(&RemainingAccess,
1044                                     &PreviouslyGrantedAccess,
1045                                     NULL,
1046                                     Token,
1047                                     Privileges,
1048                                     AccessMode);
1049     if (!NT_SUCCESS(Status))
1050     {
1051         goto ReturnCommonStatus;
1052     }
1053 
1054     /* Succeed if there are no more rights to grant */
1055     if (RemainingAccess == 0)
1056     {
1057         Status = STATUS_SUCCESS;
1058         goto ReturnCommonStatus;
1059     }
1060 
1061     /*
1062      * HACK: Temporary hack that checks if the caller passed an empty
1063      * generic mapping. In such cases we cannot mask out the remaining
1064      * access rights without a proper mapping so the only option we
1065      * can do is to check if the client is an administrator,
1066      * since they are powerful users.
1067      *
1068      * See CORE-18576 for information.
1069      */
1070     if (GenericMapping->GenericRead == 0 &&
1071         GenericMapping->GenericWrite == 0 &&
1072         GenericMapping->GenericExecute == 0 &&
1073         GenericMapping->GenericAll == 0)
1074     {
1075         if (SeTokenIsAdmin(Token))
1076         {
1077             /* Grant him access */
1078             PreviouslyGrantedAccess |= RemainingAccess;
1079             Status = STATUS_SUCCESS;
1080             goto ReturnCommonStatus;
1081         }
1082 
1083         /* It's not an admin so bail out */
1084         PreviouslyGrantedAccess = 0;
1085         Status = STATUS_ACCESS_DENIED;
1086         goto ReturnCommonStatus;
1087     }
1088 
1089     /* Get the DACL */
1090     Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
1091                                           &Present,
1092                                           &Dacl,
1093                                           &Defaulted);
1094     if (!NT_SUCCESS(Status))
1095     {
1096         goto ReturnCommonStatus;
1097     }
1098 
1099     /* Grant desired access if the object is unprotected */
1100     if (Present == FALSE || Dacl == NULL)
1101     {
1102         PreviouslyGrantedAccess |= RemainingAccess;
1103         if (RemainingAccess & MAXIMUM_ALLOWED)
1104         {
1105             PreviouslyGrantedAccess &= ~MAXIMUM_ALLOWED;
1106             PreviouslyGrantedAccess |= GenericMapping->GenericAll;
1107         }
1108 
1109         Status = STATUS_SUCCESS;
1110         goto ReturnCommonStatus;
1111     }
1112 
1113     /* Deny access if the DACL is empty */
1114     if (Dacl->AceCount == 0)
1115     {
1116         if (RemainingAccess == MAXIMUM_ALLOWED && PreviouslyGrantedAccess != 0)
1117         {
1118             Status = STATUS_SUCCESS;
1119         }
1120         else
1121         {
1122             DPRINT1("The DACL has no ACEs and the caller has no previously granted access!\n");
1123             PreviouslyGrantedAccess = 0;
1124             Status = STATUS_ACCESS_DENIED;
1125         }
1126         goto ReturnCommonStatus;
1127     }
1128 
1129     /*
1130      * Determine the MAXIMUM_ALLOWED access rights according to the DACL.
1131      * Or if the caller is supplying a list of object types then determine
1132      * the rights of each object on that list.
1133      */
1134     if ((DesiredAccess & MAXIMUM_ALLOWED) || UseResultList)
1135     {
1136         /* Perform access checks against ACEs from this DACL */
1137         SepAnalyzeAcesFromDacl(AccessCheckMaximum,
1138                                0,
1139                                Dacl,
1140                                Token,
1141                                PrimaryAccessToken,
1142                                FALSE,
1143                                PrincipalSelfSid,
1144                                GenericMapping,
1145                                ObjectTypeList,
1146                                ObjectTypeListLength,
1147                                UseResultList,
1148                                &AccessCheckRights);
1149 
1150         /*
1151          * Perform further access checks if this token
1152          * has restricted SIDs.
1153          */
1154         if (SeTokenIsRestricted(Token))
1155         {
1156             SepAnalyzeAcesFromDacl(AccessCheckMaximum,
1157                                    0,
1158                                    Dacl,
1159                                    Token,
1160                                    PrimaryAccessToken,
1161                                    TRUE,
1162                                    PrincipalSelfSid,
1163                                    GenericMapping,
1164                                    ObjectTypeList,
1165                                    ObjectTypeListLength,
1166                                    UseResultList,
1167                                    &AccessCheckRights);
1168         }
1169 
1170         /* The caller did not provide an object type list, check access only for that object */
1171         if (!ObjectTypeList && !ObjectTypeListLength)
1172         {
1173             /* Fail if some rights have not been granted */
1174             RemainingAccess &= ~(MAXIMUM_ALLOWED | AccessCheckRights.GrantedAccessRights);
1175             if (RemainingAccess != 0)
1176             {
1177                 DPRINT("Failed to grant access rights, access denied. RemainingAccess = 0x%08lx  DesiredAccess = 0x%08lx\n", RemainingAccess, DesiredAccess);
1178                 PreviouslyGrantedAccess = 0;
1179                 Status = STATUS_ACCESS_DENIED;
1180                 goto ReturnCommonStatus;
1181             }
1182 
1183             /* Set granted access right and access status */
1184             PreviouslyGrantedAccess |= AccessCheckRights.GrantedAccessRights;
1185             if (PreviouslyGrantedAccess != 0)
1186             {
1187                 Status = STATUS_SUCCESS;
1188             }
1189             else
1190             {
1191                 DPRINT("Failed to grant access rights, access denied. PreviouslyGrantedAccess == 0  DesiredAccess = %08lx\n", DesiredAccess);
1192                 Status = STATUS_ACCESS_DENIED;
1193             }
1194 
1195             /* We are done here */
1196             goto ReturnCommonStatus;
1197         }
1198         else if (!UseResultList)
1199         {
1200             /*
1201              * We have a list but the caller wants to know if access can be granted
1202              * to an object in the list. Access will either be granted or denied
1203              * to the whole hierarchy of the list. Look for every object in the list
1204              * that has granted access rights and collect them.
1205              */
1206             for (ObjectTypeIndex = 0;
1207                  ObjectTypeIndex < ObjectTypeListLength;
1208                  ObjectTypeIndex++)
1209             {
1210                 if (ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights != 0)
1211                 {
1212                     GrantedRights |= ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights;
1213                 }
1214             }
1215 
1216             /* Now check if acccess can be granted */
1217             RemainingAccess &= ~(MAXIMUM_ALLOWED | GrantedRights);
1218             if (RemainingAccess != 0)
1219             {
1220                 DPRINT("Failed to grant access rights to the whole object hierarchy list, access denied. RemainingAccess = 0x%08lx  DesiredAccess = 0x%08lx\n",
1221                     RemainingAccess, DesiredAccess);
1222                 PreviouslyGrantedAccess = 0;
1223                 Status = STATUS_ACCESS_DENIED;
1224                 goto ReturnCommonStatus;
1225             }
1226 
1227             /* Set granted access right and access status */
1228             PreviouslyGrantedAccess |= GrantedRights;
1229             if (PreviouslyGrantedAccess != 0)
1230             {
1231                 Status = STATUS_SUCCESS;
1232             }
1233             else
1234             {
1235                 DPRINT("Failed to grant access rights to the whole object hierarchy list, access denied. PreviouslyGrantedAccess == 0  DesiredAccess = %08lx\n",
1236                     DesiredAccess);
1237                 Status = STATUS_ACCESS_DENIED;
1238             }
1239 
1240             /* We are done here */
1241             goto ReturnCommonStatus;
1242         }
1243         else
1244         {
1245             /*
1246              * We have a list and the caller wants to know access for each
1247              * sub-object in the list. Report the access status and granted
1248              * rights for the object and each sub-object in the list.
1249              */
1250             for (ObjectTypeIndex = 0;
1251                  ObjectTypeIndex < ObjectTypeListLength;
1252                  ObjectTypeIndex++)
1253             {
1254                 /* Check if we have some rights */
1255                 GrantedRights = (ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights | PreviouslyGrantedAccess) & MaskDesired;
1256                 if (GrantedRights != 0)
1257                 {
1258                     /*
1259                      * If we still have some remaining rights to grant the ultimate
1260                      * conclusion is that the caller has no access to the object itself.
1261                      */
1262                     RemainingAccess = (~GrantedRights & WantedRights);
1263                     if (RemainingAccess != 0)
1264                     {
1265                         DPRINT("Failed to grant access rights at specific object at index %lu, access denied. RemainingAccess = 0x%08lx  DesiredAccess = 0x%08lx\n",
1266                             ObjectTypeIndex, RemainingAccess, DesiredAccess);
1267                         AccessStatusList[ObjectTypeIndex] = STATUS_ACCESS_DENIED;
1268                     }
1269                     else
1270                     {
1271                         AccessStatusList[ObjectTypeIndex] = STATUS_SUCCESS;
1272                     }
1273                 }
1274                 else
1275                 {
1276                     /* No access is given */
1277                     DPRINT("Failed to grant access rights at specific object at index %lu. No access is given\n", ObjectTypeIndex);
1278                     AccessStatusList[ObjectTypeIndex] = STATUS_ACCESS_DENIED;
1279                 }
1280 
1281                 /* Return the access rights to the caller */
1282                 GrantedAccessList[ObjectTypeIndex] = GrantedRights;
1283             }
1284 
1285             /*
1286              * We have built a list of access statuses for each object but
1287              * we still need to figure out the common status for the
1288              * function. The same status code will be used to check if
1289              * we should report any security debug stuff once we are done.
1290              */
1291             Status = STATUS_SUCCESS;
1292             for (ResultListIndex = 0; ResultListIndex < ObjectTypeListLength; ResultListIndex++)
1293             {
1294                 /* There is at least one sub-object of which access cannot be granted */
1295                 if (AccessStatusList[ResultListIndex] == STATUS_ACCESS_DENIED)
1296                 {
1297                     Status = AccessStatusList[ResultListIndex];
1298                     break;
1299                 }
1300             }
1301 
1302             /* We are done here */
1303             goto ReturnCommonStatus;
1304         }
1305     }
1306 
1307     /* Grant rights according to the DACL */
1308     SepAnalyzeAcesFromDacl(AccessCheckRegular,
1309                            RemainingAccess,
1310                            Dacl,
1311                            Token,
1312                            PrimaryAccessToken,
1313                            FALSE,
1314                            PrincipalSelfSid,
1315                            GenericMapping,
1316                            ObjectTypeList,
1317                            ObjectTypeListLength,
1318                            UseResultList,
1319                            &AccessCheckRights);
1320 
1321     /* The caller did not provide an object type list, check access only for that object */
1322     if (!ObjectTypeList && !ObjectTypeListLength)
1323     {
1324         /* Fail if some rights have not been granted */
1325         if (AccessCheckRights.RemainingAccessRights != 0)
1326         {
1327             DPRINT("Failed to grant access rights, access denied. RemainingAccess = 0x%08lx  DesiredAccess = 0x%08lx\n", AccessCheckRights.RemainingAccessRights, DesiredAccess);
1328             PreviouslyGrantedAccess = 0;
1329             Status = STATUS_ACCESS_DENIED;
1330             goto ReturnCommonStatus;
1331         }
1332     }
1333     else
1334     {
1335         /*
1336          * We have an object type list, look for the object of which
1337          * remaining rights are all granted.
1338          */
1339         for (ObjectTypeIndex = 0;
1340              ObjectTypeIndex < ObjectTypeListLength;
1341              ObjectTypeIndex++)
1342         {
1343             if (ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.RemainingAccessRights == 0)
1344             {
1345                 AccessIsGranted = TRUE;
1346                 break;
1347             }
1348         }
1349 
1350         if (!AccessIsGranted)
1351         {
1352             DPRINT("Failed to grant access rights to the whole object hierarchy list, access denied. DesiredAccess = 0x%08lx\n", DesiredAccess);
1353             PreviouslyGrantedAccess = 0;
1354             Status = STATUS_ACCESS_DENIED;
1355             goto ReturnCommonStatus;
1356         }
1357     }
1358 
1359     /*
1360      * Perform further access checks if this token
1361      * has restricted SIDs.
1362      */
1363     if (SeTokenIsRestricted(Token))
1364     {
1365         SepAnalyzeAcesFromDacl(AccessCheckRegular,
1366                                RemainingAccess,
1367                                Dacl,
1368                                Token,
1369                                PrimaryAccessToken,
1370                                TRUE,
1371                                PrincipalSelfSid,
1372                                GenericMapping,
1373                                ObjectTypeList,
1374                                ObjectTypeListLength,
1375                                UseResultList,
1376                                &AccessCheckRights);
1377 
1378         /* The caller did not provide an object type list, check access only for that object */
1379         if (!ObjectTypeList && !ObjectTypeListLength)
1380         {
1381             /* Fail if some rights have not been granted */
1382             if (AccessCheckRights.RemainingAccessRights != 0)
1383             {
1384                 DPRINT("Failed to grant access rights, access denied. RemainingAccess = 0x%08lx  DesiredAccess = 0x%08lx\n", AccessCheckRights.RemainingAccessRights, DesiredAccess);
1385                 PreviouslyGrantedAccess = 0;
1386                 Status = STATUS_ACCESS_DENIED;
1387                 goto ReturnCommonStatus;
1388             }
1389         }
1390         else
1391         {
1392             /*
1393              * We have an object type list, look for the object of which remaining
1394              * rights are all granted. The user may have access to the requested
1395              * object but on a restricted token case the user is only granted partial
1396              * access. If access is denied to restricted SIDs, the bottom line is that
1397              * access is denied to the user.
1398              */
1399             AccessIsGranted = FALSE;
1400             for (ObjectTypeIndex = 0;
1401                  ObjectTypeIndex < ObjectTypeListLength;
1402                  ObjectTypeIndex++)
1403             {
1404                 if (ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.RemainingAccessRights == 0)
1405                 {
1406                     AccessIsGranted = TRUE;
1407                     break;
1408                 }
1409             }
1410 
1411             if (!AccessIsGranted)
1412             {
1413                 DPRINT("Failed to grant access rights to the whole object hierarchy list, access denied. DesiredAccess = 0x%08lx\n", DesiredAccess);
1414                 PreviouslyGrantedAccess = 0;
1415                 Status = STATUS_ACCESS_DENIED;
1416                 goto ReturnCommonStatus;
1417             }
1418         }
1419     }
1420 
1421     /* Set granted access rights */
1422     PreviouslyGrantedAccess |= DesiredAccess;
1423 
1424     /* Fail if no rights have been granted */
1425     if (PreviouslyGrantedAccess == 0)
1426     {
1427         DPRINT("Failed to grant access rights, access denied. PreviouslyGrantedAccess == 0  DesiredAccess = %08lx\n", DesiredAccess);
1428         Status = STATUS_ACCESS_DENIED;
1429         goto ReturnCommonStatus;
1430     }
1431 
1432     /*
1433      * If we're here then we granted all the desired
1434      * access rights the caller wanted.
1435      */
1436     Status = STATUS_SUCCESS;
1437 
1438 ReturnCommonStatus:
1439     if (!UseResultList)
1440     {
1441         *GrantedAccessList = PreviouslyGrantedAccess;
1442         *AccessStatusList = Status;
1443     }
1444 
1445 #if DBG
1446     /* Dump security debug info on access denied case */
1447     if (Status == STATUS_ACCESS_DENIED)
1448     {
1449         SepDumpSdDebugInfo(SecurityDescriptor);
1450         SepDumpTokenDebugInfo(Token);
1451 
1452         if (ObjectTypeList && (ObjectTypeListLength != 0))
1453         {
1454             SepDumpAccessAndStatusList(GrantedAccessList,
1455                                        AccessStatusList,
1456                                        UseResultList,
1457                                        ObjectTypeList,
1458                                        ObjectTypeListLength);
1459         }
1460         else
1461         {
1462             SepDumpAccessRightsStats(&AccessCheckRights);
1463         }
1464     }
1465 #endif
1466 
1467     return NT_SUCCESS(Status);
1468 }
1469 
1470 /**
1471  * @brief
1472  * Retrieves the length size of a set list of privileges structure.
1473  *
1474  * @param[in] PrivilegeSet
1475  * A valid set of privileges.
1476  *
1477  * @return
1478  * Returns the total length of a set of privileges.
1479  */
1480 static
1481 ULONG
SepGetPrivilegeSetLength(_In_ PPRIVILEGE_SET PrivilegeSet)1482 SepGetPrivilegeSetLength(
1483     _In_ PPRIVILEGE_SET PrivilegeSet)
1484 {
1485     if (PrivilegeSet == NULL)
1486         return 0;
1487 
1488     if (PrivilegeSet->PrivilegeCount == 0)
1489         return (ULONG)(sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES));
1490 
1491     return (ULONG)(sizeof(PRIVILEGE_SET) +
1492                    (PrivilegeSet->PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES));
1493 }
1494 
1495 /**
1496  * @brief
1497  * Internal function that performs a security check against the
1498  * client who requests access on a resource object. This function
1499  * is used by access check NT system calls.
1500  *
1501  * @param[in] SecurityDescriptor
1502  * A pointer to a security descriptor that identifies the security
1503  * information of an object being accessed. This function walks
1504  * through this descriptor for any ACLs and respective access
1505  * rights if access can be granted.
1506  *
1507  * @param[in] ClientToken
1508  * A handle to an access token, that identifies the client of which
1509  * requests access to the target object.
1510  *
1511  * @param[in] PrincipalSelfSid
1512  * A pointer to a principal self SID. This parameter can be NULL if
1513  * the associated object being checked for access does not represent
1514  * a principal.
1515  *
1516  * @param[in] DesiredAccess
1517  * The access right bitmask where the client wants to acquire. This
1518  * can be an OR'ed set of multiple access rights or MAXIMUM_ALLOWED
1519  * to request all of possible access rights the target object allows.
1520  * If only some rights were granted but not all the access is deemed
1521  * as denied.
1522  *
1523  * @param[in] GenericMapping
1524  * The generic mapping of access rights of an object type.
1525  *
1526  * @param[out] PrivilegeSet
1527  * A pointer to a set of privileges that were used to perform the
1528  * access check, returned to caller. This function will return no
1529  * privileges (privilege count set to 0) if no privileges were used
1530  * to accomplish the access check. This parameter must not be NULL!
1531  *
1532  * @param[in,out] PrivilegeSetLength
1533  * The total length size of a set of privileges. This length represents
1534  * the count of elements in the privilege set array.
1535  *
1536  * @param[in] ObjectTypeList
1537  * A pointer to a given object type list. If this parameter is not NULL
1538  * the function will perform an access check against the main object
1539  * and sub-objects of this list. If this parameter is NULL and
1540  * ObjectTypeListLength is 0, the function will perform a normal
1541  * access check instead.
1542  *
1543  * @param[in] ObjectTypeListLength
1544  * The length of the object type list array, pointed by ObjectTypeList.
1545  * This length in question represents the number of elements in such array.
1546  * This parameter must be 0 if no array list is provided.
1547  *
1548  * @param[in] UseResultList
1549  * If this parameter is set to TRUE, the function will return the GrantedAccess
1550  * and AccessStatus parameter as arrays of granted rights and status value for
1551  * each individual object element pointed by ObjectTypeList.
1552  *
1553  * @param[out] GrantedAccess
1554  * A pointer to granted access rights, returned to the caller. If ObjectTypeList
1555  * is not NULL this paramater is an array of granted access rights for the object
1556  * and each individual sub-object of the list.
1557  *
1558  * @param[out] AccessStatus
1559  * A pointer to a status code, returned to the caller. This status code
1560  * represents whether access is granted or denied to the client on the
1561  * target object. The difference between the status code of the function
1562  * is that code indicates whether the function has successfully completed
1563  * the access check operation. If ObjectTypeList is not NULL, this
1564  * parameter is an array of access status for the object and each individual
1565  * sub-object of the list.
1566  *
1567  * @return
1568  * Returns STATUS_SUCCESS if access check has been done without problems
1569  * and that the object can be accessed. STATUS_GENERIC_NOT_MAPPED is returned
1570  * if no generic access right is mapped. STATUS_NO_IMPERSONATION_TOKEN is returned
1571  * if the token from the handle is not an impersonation token.
1572  * STATUS_BAD_IMPERSONATION_LEVEL is returned if the token cannot be impersonated
1573  * because the current security impersonation level doesn't permit so.
1574  * STATUS_INVALID_SECURITY_DESCR is returned if the security descriptor given
1575  * to the call is not a valid one. STATUS_BUFFER_TOO_SMALL is returned if
1576  * the buffer to the captured privileges has a length that is less than the required
1577  * size of the set of privileges. STATUS_INVALID_PARAMETER is returned if the caller
1578  * did not provide an object type list but the caller wanted to invoke an object type
1579  * result list access check, or if the list is out of order or the list is invalid.
1580  * A failure NTSTATUS code is returned otherwise.
1581  *
1582  * @remarks
1583  * The function performs an access check against the object type list,
1584  * if provided, depending on the UseResultList parameter. That is, if that
1585  * parameter was set to TRUE the function will either grant or deny access
1586  * to each individual sub-object and return an array of access status and
1587  * granted rights for the corresponding object type list. Otherwise the function
1588  * will grant or deny access to the object type list hierarchy as a whole.
1589  */
1590 static
1591 NTSTATUS
SepAccessCheck(_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,_In_ HANDLE ClientToken,_In_opt_ PSID PrincipalSelfSid,_In_ ACCESS_MASK DesiredAccess,_In_ PGENERIC_MAPPING GenericMapping,_Out_writes_bytes_ (* PrivilegeSetLength)PPRIVILEGE_SET PrivilegeSet,_Inout_ PULONG PrivilegeSetLength,_In_reads_opt_ (ObjectTypeListLength)POBJECT_TYPE_LIST ObjectTypeList,_In_ ULONG ObjectTypeListLength,_In_ BOOLEAN UseResultList,_Out_ PACCESS_MASK GrantedAccess,_Out_ PNTSTATUS AccessStatus)1592 SepAccessCheck(
1593     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1594     _In_ HANDLE ClientToken,
1595     _In_opt_ PSID PrincipalSelfSid,
1596     _In_ ACCESS_MASK DesiredAccess,
1597     _In_ PGENERIC_MAPPING GenericMapping,
1598     _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,
1599     _Inout_ PULONG PrivilegeSetLength,
1600     _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
1601     _In_ ULONG ObjectTypeListLength,
1602     _In_ BOOLEAN UseResultList,
1603     _Out_ PACCESS_MASK GrantedAccess,
1604     _Out_ PNTSTATUS AccessStatus)
1605 {
1606     PSECURITY_DESCRIPTOR CapturedSecurityDescriptor = NULL;
1607     POBJECT_TYPE_LIST_INTERNAL CapturedObjectTypeList = NULL;
1608     PSID CapturedPrincipalSelfSid = NULL;
1609     SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
1610     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1611     ACCESS_MASK PreviouslyGrantedAccess = 0;
1612     PPRIVILEGE_SET Privileges = NULL;
1613     ULONG CapturedPrivilegeSetLength, RequiredPrivilegeSetLength;
1614     ULONG ResultListIndex;
1615     PTOKEN Token;
1616     NTSTATUS Status;
1617 
1618     PAGED_CODE();
1619 
1620     /* Check if this is kernel mode */
1621     if (PreviousMode == KernelMode)
1622     {
1623         /* Check if kernel wants everything */
1624         if (DesiredAccess & MAXIMUM_ALLOWED)
1625         {
1626             /* Give it */
1627             *GrantedAccess = GenericMapping->GenericAll;
1628             *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED);
1629         }
1630         else
1631         {
1632             /* Just give the desired access */
1633             *GrantedAccess = DesiredAccess;
1634         }
1635 
1636         /* Success */
1637         *AccessStatus = STATUS_SUCCESS;
1638         return STATUS_SUCCESS;
1639     }
1640 
1641     /* Protect probe in SEH */
1642     _SEH2_TRY
1643     {
1644         /* Probe all pointers */
1645         ProbeForRead(GenericMapping, sizeof(GENERIC_MAPPING), sizeof(ULONG));
1646         ProbeForRead(PrivilegeSetLength, sizeof(ULONG), sizeof(ULONG));
1647         ProbeForWrite(PrivilegeSet, *PrivilegeSetLength, sizeof(ULONG));
1648 
1649         /*
1650          * Probe the access and status list based on the way
1651          * we are going to fill data in.
1652          */
1653         if (UseResultList)
1654         {
1655             /* Bail out on an empty list */
1656             if (!ObjectTypeListLength)
1657             {
1658                 DPRINT1("The object type list is empty\n");
1659                 _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
1660             }
1661 
1662             ProbeForWrite(GrantedAccess, sizeof(ACCESS_MASK) * ObjectTypeListLength, sizeof(ULONG));
1663             ProbeForWrite(AccessStatus, sizeof(NTSTATUS) * ObjectTypeListLength, sizeof(ULONG));
1664         }
1665         else
1666         {
1667             ProbeForWrite(GrantedAccess, sizeof(ACCESS_MASK), sizeof(ULONG));
1668             ProbeForWrite(AccessStatus, sizeof(NTSTATUS), sizeof(ULONG));
1669         }
1670 
1671         /* Capture the privilege set length and the mapping */
1672         CapturedPrivilegeSetLength = *PrivilegeSetLength;
1673     }
1674     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1675     {
1676         /* Return the exception code */
1677         _SEH2_YIELD(return _SEH2_GetExceptionCode());
1678     }
1679     _SEH2_END;
1680 
1681     /* Check for unmapped access rights */
1682     if (DesiredAccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL))
1683     {
1684         DPRINT1("Some generic rights are not mapped\n");
1685         return STATUS_GENERIC_NOT_MAPPED;
1686     }
1687 
1688     /* Reference the token */
1689     Status = ObReferenceObjectByHandle(ClientToken,
1690                                        TOKEN_QUERY,
1691                                        SeTokenObjectType,
1692                                        PreviousMode,
1693                                        (PVOID*)&Token,
1694                                        NULL);
1695     if (!NT_SUCCESS(Status))
1696     {
1697         DPRINT1("Failed to reference token (Status 0x%08lx)\n", Status);
1698         return Status;
1699     }
1700 
1701     /* Check token type */
1702     if (Token->TokenType != TokenImpersonation)
1703     {
1704         DPRINT("No impersonation token\n");
1705         ObDereferenceObject(Token);
1706         return STATUS_NO_IMPERSONATION_TOKEN;
1707     }
1708 
1709     /* Check the impersonation level */
1710     if (Token->ImpersonationLevel < SecurityIdentification)
1711     {
1712         DPRINT1("Impersonation level < SecurityIdentification\n");
1713         ObDereferenceObject(Token);
1714         return STATUS_BAD_IMPERSONATION_LEVEL;
1715     }
1716 
1717     /* Capture the object type list, the list is probed by the function itself */
1718     Status = SeCaptureObjectTypeList(ObjectTypeList,
1719                                      ObjectTypeListLength,
1720                                      PreviousMode,
1721                                      &CapturedObjectTypeList);
1722     if (!NT_SUCCESS(Status))
1723     {
1724         DPRINT1("Failed to capture the object type list (Status 0x%08lx)\n", Status);
1725         ObDereferenceObject(Token);
1726         return Status;
1727     }
1728 
1729     /* Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access */
1730     Status = SePrivilegePolicyCheck(&DesiredAccess,
1731                                     &PreviouslyGrantedAccess,
1732                                     NULL,
1733                                     Token,
1734                                     &Privileges,
1735                                     PreviousMode);
1736     if (!NT_SUCCESS(Status))
1737     {
1738         DPRINT1("SePrivilegePolicyCheck failed (Status 0x%08lx)\n", Status);
1739         SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
1740         ObDereferenceObject(Token);
1741 
1742         /*
1743          * The caller does not have the required access to do an access check.
1744          * Propagate the access and status for the whole hierarchy of the list
1745          * or just to single target object.
1746          */
1747         if (UseResultList)
1748         {
1749             for (ResultListIndex = 0; ResultListIndex < ObjectTypeListLength; ResultListIndex++)
1750             {
1751                 AccessStatus[ResultListIndex] = Status;
1752                 GrantedAccess[ResultListIndex] = 0;
1753             }
1754         }
1755         else
1756         {
1757             *AccessStatus = Status;
1758             *GrantedAccess = 0;
1759         }
1760 
1761         return STATUS_SUCCESS;
1762     }
1763 
1764     /* Check the size of the privilege set and return the privileges */
1765     if (Privileges != NULL)
1766     {
1767         DPRINT("Privileges != NULL\n");
1768 
1769         /* Calculate the required privilege set buffer size */
1770         RequiredPrivilegeSetLength = SepGetPrivilegeSetLength(Privileges);
1771 
1772         /* Fail if the privilege set buffer is too small */
1773         if (CapturedPrivilegeSetLength < RequiredPrivilegeSetLength)
1774         {
1775             SeFreePrivileges(Privileges);
1776             SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
1777             ObDereferenceObject(Token);
1778             *PrivilegeSetLength = RequiredPrivilegeSetLength;
1779             return STATUS_BUFFER_TOO_SMALL;
1780         }
1781 
1782         /* Copy the privilege set to the caller */
1783         RtlCopyMemory(PrivilegeSet,
1784                       Privileges,
1785                       RequiredPrivilegeSetLength);
1786 
1787         /* Free the local privilege set */
1788         SeFreePrivileges(Privileges);
1789     }
1790     else
1791     {
1792         DPRINT("Privileges == NULL\n");
1793 
1794         /* Fail if the privilege set buffer is too small */
1795         if (CapturedPrivilegeSetLength < sizeof(PRIVILEGE_SET))
1796         {
1797             SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
1798             ObDereferenceObject(Token);
1799             *PrivilegeSetLength = sizeof(PRIVILEGE_SET);
1800             return STATUS_BUFFER_TOO_SMALL;
1801         }
1802 
1803         /* Initialize the privilege set */
1804         PrivilegeSet->PrivilegeCount = 0;
1805         PrivilegeSet->Control = 0;
1806     }
1807 
1808     /* Capture the security descriptor */
1809     Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
1810                                          PreviousMode,
1811                                          PagedPool,
1812                                          FALSE,
1813                                          &CapturedSecurityDescriptor);
1814     if (!NT_SUCCESS(Status))
1815     {
1816         DPRINT1("Failed to capture the Security Descriptor\n");
1817         SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
1818         ObDereferenceObject(Token);
1819         return Status;
1820     }
1821 
1822     /* Check the captured security descriptor */
1823     if (CapturedSecurityDescriptor == NULL)
1824     {
1825         DPRINT1("Security Descriptor is NULL\n");
1826         SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
1827         ObDereferenceObject(Token);
1828         return STATUS_INVALID_SECURITY_DESCR;
1829     }
1830 
1831     /* Check security descriptor for valid owner and group */
1832     if (SepGetOwnerFromDescriptor(CapturedSecurityDescriptor) == NULL ||
1833         SepGetGroupFromDescriptor(CapturedSecurityDescriptor) == NULL)
1834     {
1835         DPRINT1("Security Descriptor does not have a valid group or owner\n");
1836         SeReleaseSecurityDescriptor(CapturedSecurityDescriptor,
1837                                     PreviousMode,
1838                                     FALSE);
1839         SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
1840         ObDereferenceObject(Token);
1841         return STATUS_INVALID_SECURITY_DESCR;
1842     }
1843 
1844     /* Capture the principal self SID if we have one */
1845     if (PrincipalSelfSid)
1846     {
1847         Status = SepCaptureSid(PrincipalSelfSid,
1848                                PreviousMode,
1849                                PagedPool,
1850                                TRUE,
1851                                &CapturedPrincipalSelfSid);
1852         if (!NT_SUCCESS(Status))
1853         {
1854             DPRINT1("Failed to capture the principal self SID (Status 0x%08lx)\n", Status);
1855             SeReleaseSecurityDescriptor(CapturedSecurityDescriptor,
1856                                         PreviousMode,
1857                                         FALSE);
1858             SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
1859             ObDereferenceObject(Token);
1860             return Status;
1861         }
1862     }
1863 
1864     /* Set up the subject context, and lock it */
1865     SeCaptureSubjectContext(&SubjectSecurityContext);
1866 
1867     /* Lock the token */
1868     SepAcquireTokenLockShared(Token);
1869 
1870     /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
1871     if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED))
1872     {
1873         if (SepTokenIsOwner(Token, CapturedSecurityDescriptor, FALSE))
1874         {
1875             if (DesiredAccess & MAXIMUM_ALLOWED)
1876                 PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL);
1877             else
1878                 PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL));
1879 
1880             DesiredAccess &= ~(WRITE_DAC | READ_CONTROL);
1881         }
1882     }
1883 
1884     if (DesiredAccess == 0)
1885     {
1886         /*
1887          * Propagate the access and status for the whole hierarchy
1888          * of the list or just to single target object.
1889          */
1890         if (UseResultList)
1891         {
1892             for (ResultListIndex = 0; ResultListIndex < ObjectTypeListLength; ResultListIndex++)
1893             {
1894                 AccessStatus[ResultListIndex] = STATUS_SUCCESS;
1895                 GrantedAccess[ResultListIndex] = PreviouslyGrantedAccess;
1896             }
1897         }
1898         else
1899         {
1900             *GrantedAccess = PreviouslyGrantedAccess;
1901             *AccessStatus = STATUS_SUCCESS;
1902         }
1903     }
1904     else
1905     {
1906         /* Now perform the access check */
1907         SepAccessCheckWorker(CapturedSecurityDescriptor,
1908                              Token,
1909                              &SubjectSecurityContext.PrimaryToken,
1910                              CapturedPrincipalSelfSid,
1911                              DesiredAccess,
1912                              CapturedObjectTypeList,
1913                              ObjectTypeListLength,
1914                              PreviouslyGrantedAccess,
1915                              GenericMapping,
1916                              PreviousMode,
1917                              UseResultList,
1918                              NULL,
1919                              GrantedAccess,
1920                              AccessStatus);
1921     }
1922 
1923     /* Release subject context and unlock the token */
1924     SeReleaseSubjectContext(&SubjectSecurityContext);
1925     SepReleaseTokenLock(Token);
1926 
1927     /* Release the caputed principal self SID */
1928     SepReleaseSid(CapturedPrincipalSelfSid,
1929                   PreviousMode,
1930                   TRUE);
1931 
1932     /* Release the captured security descriptor */
1933     SeReleaseSecurityDescriptor(CapturedSecurityDescriptor,
1934                                 PreviousMode,
1935                                 FALSE);
1936 
1937     /* Release the object type list */
1938     SeReleaseObjectTypeList(CapturedObjectTypeList, PreviousMode);
1939 
1940     /* Dereference the token */
1941     ObDereferenceObject(Token);
1942 
1943     /* Check succeeded */
1944     return STATUS_SUCCESS;
1945 }
1946 
1947 /* PUBLIC FUNCTIONS ***********************************************************/
1948 
1949 /**
1950  * @brief
1951  * Determines whether security access rights can be given to an object
1952  * depending on the security descriptor and other security context
1953  * entities, such as an owner.
1954  *
1955  * @param[in] SecurityDescriptor
1956  * Security descriptor of the object that is being accessed.
1957  *
1958  * @param[in] SubjectSecurityContext
1959  * The captured subject security context.
1960  *
1961  * @param[in] SubjectContextLocked
1962  * If set to TRUE, the caller acknowledges that the subject context
1963  * has already been locked by the caller himself. If set to FALSE,
1964  * the function locks the subject context.
1965  *
1966  * @param[in] DesiredAccess
1967  * Access right bitmask that the calling thread wants to acquire.
1968  *
1969  * @param[in] PreviouslyGrantedAccess
1970  * The access rights previously acquired in the past.
1971  *
1972  * @param[out] Privileges
1973  * The returned set of privileges.
1974  *
1975  * @param[in] GenericMapping
1976  * The generic mapping of access rights of an object type.
1977  *
1978  * @param[in] AccessMode
1979  * The processor request level mode.
1980  *
1981  * @param[out] GrantedAccess
1982  * A list of granted access rights.
1983  *
1984  * @param[out] AccessStatus
1985  * The returned status code specifying why access cannot be made
1986  * onto an object (if said access is denied in the first place).
1987  *
1988  * @return
1989  * Returns TRUE if access onto the specific object is allowed, FALSE
1990  * otherwise.
1991  */
1992 BOOLEAN
1993 NTAPI
SeAccessCheck(_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,_In_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,_In_ BOOLEAN SubjectContextLocked,_In_ ACCESS_MASK DesiredAccess,_In_ ACCESS_MASK PreviouslyGrantedAccess,_Out_ PPRIVILEGE_SET * Privileges,_In_ PGENERIC_MAPPING GenericMapping,_In_ KPROCESSOR_MODE AccessMode,_Out_ PACCESS_MASK GrantedAccess,_Out_ PNTSTATUS AccessStatus)1994 SeAccessCheck(
1995     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1996     _In_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
1997     _In_ BOOLEAN SubjectContextLocked,
1998     _In_ ACCESS_MASK DesiredAccess,
1999     _In_ ACCESS_MASK PreviouslyGrantedAccess,
2000     _Out_ PPRIVILEGE_SET* Privileges,
2001     _In_ PGENERIC_MAPPING GenericMapping,
2002     _In_ KPROCESSOR_MODE AccessMode,
2003     _Out_ PACCESS_MASK GrantedAccess,
2004     _Out_ PNTSTATUS AccessStatus)
2005 {
2006     BOOLEAN ret;
2007 
2008     PAGED_CODE();
2009 
2010     /* Check if this is kernel mode */
2011     if (AccessMode == KernelMode)
2012     {
2013         /* Check if kernel wants everything */
2014         if (DesiredAccess & MAXIMUM_ALLOWED)
2015         {
2016             /* Give it */
2017             *GrantedAccess = GenericMapping->GenericAll;
2018             *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED);
2019             *GrantedAccess |= PreviouslyGrantedAccess;
2020         }
2021         else
2022         {
2023             /* Give the desired and previous access */
2024             *GrantedAccess = DesiredAccess | PreviouslyGrantedAccess;
2025         }
2026 
2027         /* Success */
2028         *AccessStatus = STATUS_SUCCESS;
2029         return TRUE;
2030     }
2031 
2032     /* Check if we didn't get an SD */
2033     if (!SecurityDescriptor)
2034     {
2035         /* Automatic failure */
2036         *AccessStatus = STATUS_ACCESS_DENIED;
2037         return FALSE;
2038     }
2039 
2040     /* Check for invalid impersonation */
2041     if ((SubjectSecurityContext->ClientToken) &&
2042         (SubjectSecurityContext->ImpersonationLevel < SecurityImpersonation))
2043     {
2044         *AccessStatus = STATUS_BAD_IMPERSONATION_LEVEL;
2045         return FALSE;
2046     }
2047 
2048     /* Acquire the lock if needed */
2049     if (!SubjectContextLocked)
2050         SeLockSubjectContext(SubjectSecurityContext);
2051 
2052     /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
2053     if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED))
2054     {
2055          PACCESS_TOKEN Token = SubjectSecurityContext->ClientToken ?
2056              SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken;
2057 
2058         if (SepTokenIsOwner(Token,
2059                             SecurityDescriptor,
2060                             FALSE))
2061         {
2062             if (DesiredAccess & MAXIMUM_ALLOWED)
2063                 PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL);
2064             else
2065                 PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL));
2066 
2067             DesiredAccess &= ~(WRITE_DAC | READ_CONTROL);
2068         }
2069     }
2070 
2071     if (DesiredAccess == 0)
2072     {
2073         *GrantedAccess = PreviouslyGrantedAccess;
2074         if (PreviouslyGrantedAccess == 0)
2075         {
2076             DPRINT1("Request for zero access to an object. Denying.\n");
2077             *AccessStatus = STATUS_ACCESS_DENIED;
2078             ret = FALSE;
2079         }
2080         else
2081         {
2082             *AccessStatus = STATUS_SUCCESS;
2083             ret = TRUE;
2084         }
2085     }
2086     else
2087     {
2088         /* Call the internal function */
2089         ret = SepAccessCheckWorker(SecurityDescriptor,
2090                                    SubjectSecurityContext->ClientToken,
2091                                    SubjectSecurityContext->PrimaryToken,
2092                                    NULL,
2093                                    DesiredAccess,
2094                                    NULL,
2095                                    0,
2096                                    PreviouslyGrantedAccess,
2097                                    GenericMapping,
2098                                    AccessMode,
2099                                    FALSE,
2100                                    Privileges,
2101                                    GrantedAccess,
2102                                    AccessStatus);
2103     }
2104 
2105     /* Release the lock if needed */
2106     if (!SubjectContextLocked)
2107         SeUnlockSubjectContext(SubjectSecurityContext);
2108 
2109     return ret;
2110 }
2111 
2112 /**
2113  * @brief
2114  * Determines whether security access rights can be given to an object
2115  * depending on the security descriptor. Unlike the regular access check
2116  * procedure in the NT kernel, the fast traverse check is a faster way
2117  * to quickly check if access can be made into an object.
2118  *
2119  * @param[in] SecurityDescriptor
2120  * Security descriptor of the object that is being accessed.
2121  *
2122  * @param[in] AccessState
2123  * An access state to determine if the access token in the current
2124  * security context of the object is an restricted token.
2125  *
2126  * @param[in] DesiredAccess
2127  * The access right bitmask where the calling thread wants to acquire.
2128  *
2129  * @param[in] AccessMode
2130  * Process level request mode.
2131  *
2132  * @return
2133  * Returns TRUE if access onto the specific object is allowed, FALSE
2134  * otherwise.
2135  */
2136 BOOLEAN
2137 NTAPI
SeFastTraverseCheck(_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,_In_ PACCESS_STATE AccessState,_In_ ACCESS_MASK DesiredAccess,_In_ KPROCESSOR_MODE AccessMode)2138 SeFastTraverseCheck(
2139     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
2140     _In_ PACCESS_STATE AccessState,
2141     _In_ ACCESS_MASK DesiredAccess,
2142     _In_ KPROCESSOR_MODE AccessMode)
2143 {
2144     PACL Dacl;
2145     ULONG AceIndex;
2146     PKNOWN_ACE Ace;
2147 
2148     PAGED_CODE();
2149 
2150     ASSERT(AccessMode != KernelMode);
2151 
2152     if (SecurityDescriptor == NULL)
2153         return FALSE;
2154 
2155     /* Get DACL */
2156     Dacl = SepGetDaclFromDescriptor(SecurityDescriptor);
2157     /* If no DACL, grant access */
2158     if (Dacl == NULL)
2159         return TRUE;
2160 
2161     /* No ACE -> Deny */
2162     if (!Dacl->AceCount)
2163         return FALSE;
2164 
2165     /* Can't perform the check on restricted token */
2166     if (AccessState->Flags & TOKEN_IS_RESTRICTED)
2167         return FALSE;
2168 
2169     /* Browse the ACEs */
2170     for (AceIndex = 0, Ace = (PKNOWN_ACE)((ULONG_PTR)Dacl + sizeof(ACL));
2171          AceIndex < Dacl->AceCount;
2172          AceIndex++, Ace = (PKNOWN_ACE)((ULONG_PTR)Ace + Ace->Header.AceSize))
2173     {
2174         if (Ace->Header.AceFlags & INHERIT_ONLY_ACE)
2175             continue;
2176 
2177         /* If access-allowed ACE */
2178         if (Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
2179         {
2180             /* Check if all accesses are granted */
2181             if (!(Ace->Mask & DesiredAccess))
2182                 continue;
2183 
2184             /* Check SID and grant access if matching */
2185             if (RtlEqualSid(SeWorldSid, &(Ace->SidStart)))
2186                 return TRUE;
2187         }
2188         /* If access-denied ACE */
2189         else if (Ace->Header.AceType == ACCESS_DENIED_ACE_TYPE)
2190         {
2191             /* Here, only check if it denies any access wanted and deny if so */
2192             if (Ace->Mask & DesiredAccess)
2193                 return FALSE;
2194         }
2195     }
2196 
2197     /* Faulty, deny */
2198     return FALSE;
2199 }
2200 
2201 /* SYSTEM CALLS ***************************************************************/
2202 
2203 /**
2204  * @brief
2205  * Determines whether security access can be granted to a client
2206  * that requests such access on an object.
2207  *
2208  * @remarks
2209  * For more documentation details about the parameters and
2210  * overall function behavior, see SepAccessCheck.
2211  */
2212 NTSTATUS
2213 NTAPI
NtAccessCheck(_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,_In_ HANDLE ClientToken,_In_ ACCESS_MASK DesiredAccess,_In_ PGENERIC_MAPPING GenericMapping,_Out_writes_bytes_ (* PrivilegeSetLength)PPRIVILEGE_SET PrivilegeSet,_Inout_ PULONG PrivilegeSetLength,_Out_ PACCESS_MASK GrantedAccess,_Out_ PNTSTATUS AccessStatus)2214 NtAccessCheck(
2215     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
2216     _In_ HANDLE ClientToken,
2217     _In_ ACCESS_MASK DesiredAccess,
2218     _In_ PGENERIC_MAPPING GenericMapping,
2219     _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,
2220     _Inout_ PULONG PrivilegeSetLength,
2221     _Out_ PACCESS_MASK GrantedAccess,
2222     _Out_ PNTSTATUS AccessStatus)
2223 {
2224     PAGED_CODE();
2225 
2226     /* Invoke the internal function to do the job */
2227     return SepAccessCheck(SecurityDescriptor,
2228                           ClientToken,
2229                           NULL,
2230                           DesiredAccess,
2231                           GenericMapping,
2232                           PrivilegeSet,
2233                           PrivilegeSetLength,
2234                           NULL,
2235                           0,
2236                           FALSE,
2237                           GrantedAccess,
2238                           AccessStatus);
2239 }
2240 
2241 /**
2242  * @brief
2243  * Determines whether security access can be granted to a client
2244  * that requests such access on the object type list. The access
2245  * is either granted or denied for the whole object hierarchy
2246  * in the list.
2247  *
2248  * @remarks
2249  * For more documentation details about the parameters and
2250  * overall function behavior, see SepAccessCheck.
2251  */
2252 NTSTATUS
2253 NTAPI
NtAccessCheckByType(_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,_In_opt_ PSID PrincipalSelfSid,_In_ HANDLE ClientToken,_In_ ACCESS_MASK DesiredAccess,_In_reads_opt_ (ObjectTypeListLength)POBJECT_TYPE_LIST ObjectTypeList,_In_ ULONG ObjectTypeListLength,_In_ PGENERIC_MAPPING GenericMapping,_Out_writes_bytes_ (* PrivilegeSetLength)PPRIVILEGE_SET PrivilegeSet,_Inout_ PULONG PrivilegeSetLength,_Out_ PACCESS_MASK GrantedAccess,_Out_ PNTSTATUS AccessStatus)2254 NtAccessCheckByType(
2255     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
2256     _In_opt_ PSID PrincipalSelfSid,
2257     _In_ HANDLE ClientToken,
2258     _In_ ACCESS_MASK DesiredAccess,
2259     _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
2260     _In_ ULONG ObjectTypeListLength,
2261     _In_ PGENERIC_MAPPING GenericMapping,
2262     _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,
2263     _Inout_ PULONG PrivilegeSetLength,
2264     _Out_ PACCESS_MASK GrantedAccess,
2265     _Out_ PNTSTATUS AccessStatus)
2266 {
2267     PAGED_CODE();
2268 
2269     /* Invoke the internal function to do the job */
2270     return SepAccessCheck(SecurityDescriptor,
2271                           ClientToken,
2272                           PrincipalSelfSid,
2273                           DesiredAccess,
2274                           GenericMapping,
2275                           PrivilegeSet,
2276                           PrivilegeSetLength,
2277                           ObjectTypeList,
2278                           ObjectTypeListLength,
2279                           FALSE,
2280                           GrantedAccess,
2281                           AccessStatus);
2282 }
2283 
2284 /**
2285  * @brief
2286  * Determines whether security access can be granted to a client
2287  * that requests such access on the object type list. Unlike the
2288  * NtAccessCheckByType variant, this function will grant or deny
2289  * access to each individual object and sub-object in the list.
2290  *
2291  * @remarks
2292  * For more documentation details about the parameters and
2293  * overall function behavior, see SepAccessCheck.
2294  */
2295 NTSTATUS
2296 NTAPI
NtAccessCheckByTypeResultList(_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,_In_opt_ PSID PrincipalSelfSid,_In_ HANDLE ClientToken,_In_ ACCESS_MASK DesiredAccess,_In_reads_ (ObjectTypeListLength)POBJECT_TYPE_LIST ObjectTypeList,_In_ ULONG ObjectTypeListLength,_In_ PGENERIC_MAPPING GenericMapping,_Out_writes_bytes_ (* PrivilegeSetLength)PPRIVILEGE_SET PrivilegeSet,_Inout_ PULONG PrivilegeSetLength,_Out_writes_ (ObjectTypeListLength)PACCESS_MASK GrantedAccess,_Out_writes_ (ObjectTypeListLength)PNTSTATUS AccessStatus)2297 NtAccessCheckByTypeResultList(
2298     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
2299     _In_opt_ PSID PrincipalSelfSid,
2300     _In_ HANDLE ClientToken,
2301     _In_ ACCESS_MASK DesiredAccess,
2302     _In_reads_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
2303     _In_ ULONG ObjectTypeListLength,
2304     _In_ PGENERIC_MAPPING GenericMapping,
2305     _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet,
2306     _Inout_ PULONG PrivilegeSetLength,
2307     _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccess,
2308     _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatus)
2309 {
2310     PAGED_CODE();
2311 
2312     /* Invoke the internal function to do the job */
2313     return SepAccessCheck(SecurityDescriptor,
2314                           ClientToken,
2315                           PrincipalSelfSid,
2316                           DesiredAccess,
2317                           GenericMapping,
2318                           PrivilegeSet,
2319                           PrivilegeSetLength,
2320                           ObjectTypeList,
2321                           ObjectTypeListLength,
2322                           TRUE,
2323                           GrantedAccess,
2324                           AccessStatus);
2325 }
2326 
2327 /* EOF */
2328