xref: /reactos/ntoskrnl/se/accesschk.c (revision ea6e7740)
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 Timo Kreuzer <timo.kreuzer@reactos.org>
6  *                  Copyright Eric Kohl
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* GLOBALS ********************************************************************/
16 
17 
18 /* PRIVATE FUNCTIONS **********************************************************/
19 
20 /**
21  * @brief
22  * Private function that determines whether security access rights can be given
23  * to an object depending on the security descriptor and other security context
24  * entities, such as an owner.
25  *
26  * @param[in] SecurityDescriptor
27  * Security descriptor of the object that is being accessed.
28  *
29  * @param[in] SubjectSecurityContext
30  * The captured subject security context.
31  *
32  * @param[in] DesiredAccess
33  * Access right bitmask that the calling thread wants to acquire.
34  *
35  * @param[in] ObjectTypeListLength
36  * The length of a object type list.
37  *
38  * @param[in] PreviouslyGrantedAccess
39  * The access rights previously acquired in the past.
40  *
41  * @param[out] Privileges
42  * The returned set of privileges.
43  *
44  * @param[in] GenericMapping
45  * The generic mapping of access rights of an object type.
46  *
47  * @param[in] AccessMode
48  * The processor request level mode.
49  *
50  * @param[out] GrantedAccessList
51  * A list of granted access rights.
52  *
53  * @param[out] AccessStatusList
54  * The returned status code specifying why access cannot be made
55  * onto an object (if said access is denied in the first place).
56  *
57  * @param[in] UseResultList
58  * If set to TRUE, the function will return complete lists of
59  * access status codes and granted access rights.
60  *
61  * @return
62  * Returns TRUE if access onto the specific object is allowed, FALSE
63  * otherwise.
64  *
65  * @remarks
66  * The function is currently incomplete!
67  */
68 BOOLEAN NTAPI
69 SepAccessCheck(
70     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
71     _In_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
72     _In_ ACCESS_MASK DesiredAccess,
73     _In_ POBJECT_TYPE_LIST ObjectTypeList,
74     _In_ ULONG ObjectTypeListLength,
75     _In_ ACCESS_MASK PreviouslyGrantedAccess,
76     _Out_ PPRIVILEGE_SET* Privileges,
77     _In_ PGENERIC_MAPPING GenericMapping,
78     _In_ KPROCESSOR_MODE AccessMode,
79     _Out_ PACCESS_MASK GrantedAccessList,
80     _Out_ PNTSTATUS AccessStatusList,
81     _In_ BOOLEAN UseResultList)
82 {
83     ACCESS_MASK RemainingAccess;
84     ACCESS_MASK TempAccess;
85     ACCESS_MASK TempGrantedAccess = 0;
86     ACCESS_MASK TempDeniedAccess = 0;
87     PACCESS_TOKEN Token;
88     ULONG i, ResultListLength;
89     PACL Dacl;
90     BOOLEAN Present;
91     BOOLEAN Defaulted;
92     PACE CurrentAce;
93     PSID Sid;
94     NTSTATUS Status;
95     PAGED_CODE();
96 
97     DPRINT("SepAccessCheck()\n");
98 
99     /* Check for no access desired */
100     if (!DesiredAccess)
101     {
102         /* Check if we had no previous access */
103         if (!PreviouslyGrantedAccess)
104         {
105             /* Then there's nothing to give */
106             Status = STATUS_ACCESS_DENIED;
107             goto ReturnCommonStatus;
108         }
109 
110         /* Return the previous access only */
111         Status = STATUS_SUCCESS;
112         *Privileges = NULL;
113         goto ReturnCommonStatus;
114     }
115 
116     /* Map given accesses */
117     RtlMapGenericMask(&DesiredAccess, GenericMapping);
118     if (PreviouslyGrantedAccess)
119         RtlMapGenericMask(&PreviouslyGrantedAccess, GenericMapping);
120 
121     /* Initialize remaining access rights */
122     RemainingAccess = DesiredAccess;
123 
124     Token = SubjectSecurityContext->ClientToken ?
125         SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken;
126 
127     /* Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access */
128     Status = SePrivilegePolicyCheck(&RemainingAccess,
129                                     &PreviouslyGrantedAccess,
130                                     NULL,
131                                     Token,
132                                     NULL,
133                                     UserMode);
134     if (!NT_SUCCESS(Status))
135     {
136         goto ReturnCommonStatus;
137     }
138 
139     /* Succeed if there are no more rights to grant */
140     if (RemainingAccess == 0)
141     {
142         Status = STATUS_SUCCESS;
143         goto ReturnCommonStatus;
144     }
145 
146     /* Get the DACL */
147     Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
148                                           &Present,
149                                           &Dacl,
150                                           &Defaulted);
151     if (!NT_SUCCESS(Status))
152     {
153         goto ReturnCommonStatus;
154     }
155 
156     /* RULE 1: Grant desired access if the object is unprotected */
157     if (Present == FALSE || Dacl == NULL)
158     {
159         PreviouslyGrantedAccess |= RemainingAccess;
160         if (RemainingAccess & MAXIMUM_ALLOWED)
161         {
162             PreviouslyGrantedAccess &= ~MAXIMUM_ALLOWED;
163             PreviouslyGrantedAccess |= GenericMapping->GenericAll;
164         }
165 
166         Status = STATUS_SUCCESS;
167         goto ReturnCommonStatus;
168     }
169 
170     /* Deny access if the DACL is empty */
171     if (Dacl->AceCount == 0)
172     {
173         if (RemainingAccess == MAXIMUM_ALLOWED && PreviouslyGrantedAccess != 0)
174         {
175             Status = STATUS_SUCCESS;
176         }
177         else
178         {
179             PreviouslyGrantedAccess = 0;
180             Status = STATUS_ACCESS_DENIED;
181         }
182         goto ReturnCommonStatus;
183     }
184 
185     /* Determine the MAXIMUM_ALLOWED access rights according to the DACL */
186     if (DesiredAccess & MAXIMUM_ALLOWED)
187     {
188         CurrentAce = (PACE)(Dacl + 1);
189         for (i = 0; i < Dacl->AceCount; i++)
190         {
191             if (!(CurrentAce->Header.AceFlags & INHERIT_ONLY_ACE))
192             {
193                 Sid = (PSID)(CurrentAce + 1);
194                 if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE)
195                 {
196                     if (SepSidInToken(Token, Sid))
197                     {
198                         /* Map access rights from the ACE */
199                         TempAccess = CurrentAce->AccessMask;
200                         RtlMapGenericMask(&TempAccess, GenericMapping);
201 
202                         /* Deny access rights that have not been granted yet */
203                         TempDeniedAccess |= (TempAccess & ~TempGrantedAccess);
204                     }
205                 }
206                 else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
207                 {
208                     if (SepSidInToken(Token, Sid))
209                     {
210                         /* Map access rights from the ACE */
211                         TempAccess = CurrentAce->AccessMask;
212                         RtlMapGenericMask(&TempAccess, GenericMapping);
213 
214                         /* Grant access rights that have not been denied yet */
215                         TempGrantedAccess |= (TempAccess & ~TempDeniedAccess);
216                     }
217                 }
218                 else
219                 {
220                     DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType);
221                 }
222             }
223 
224             /* Get the next ACE */
225             CurrentAce = (PACE)((ULONG_PTR)CurrentAce + CurrentAce->Header.AceSize);
226         }
227 
228         /* Fail if some rights have not been granted */
229         RemainingAccess &= ~(MAXIMUM_ALLOWED | TempGrantedAccess);
230         if (RemainingAccess != 0)
231         {
232             PreviouslyGrantedAccess = 0;
233             Status = STATUS_ACCESS_DENIED;
234             goto ReturnCommonStatus;
235         }
236 
237         /* Set granted access right and access status */
238         PreviouslyGrantedAccess |= TempGrantedAccess;
239         if (PreviouslyGrantedAccess != 0)
240         {
241             Status = STATUS_SUCCESS;
242         }
243         else
244         {
245             Status = STATUS_ACCESS_DENIED;
246         }
247         goto ReturnCommonStatus;
248     }
249 
250     /* RULE 4: Grant rights according to the DACL */
251     CurrentAce = (PACE)(Dacl + 1);
252     for (i = 0; i < Dacl->AceCount; i++)
253     {
254         if (!(CurrentAce->Header.AceFlags & INHERIT_ONLY_ACE))
255         {
256             Sid = (PSID)(CurrentAce + 1);
257             if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE)
258             {
259                 if (SepSidInToken(Token, Sid))
260                 {
261                     /* Map access rights from the ACE */
262                     TempAccess = CurrentAce->AccessMask;
263                     RtlMapGenericMask(&TempAccess, GenericMapping);
264 
265                     /* Leave if a remaining right must be denied */
266                     if (RemainingAccess & TempAccess)
267                         break;
268                 }
269             }
270             else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
271             {
272                 if (SepSidInToken(Token, Sid))
273                 {
274                     /* Map access rights from the ACE */
275                     TempAccess = CurrentAce->AccessMask;
276                     DPRINT("TempAccess 0x%08lx\n", TempAccess);
277                     RtlMapGenericMask(&TempAccess, GenericMapping);
278 
279                     /* Remove granted rights */
280                     DPRINT("RemainingAccess 0x%08lx  TempAccess 0x%08lx\n", RemainingAccess, TempAccess);
281                     RemainingAccess &= ~TempAccess;
282                     DPRINT("RemainingAccess 0x%08lx\n", RemainingAccess);
283                 }
284             }
285             else
286             {
287                 DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType);
288             }
289         }
290 
291         /* Get the next ACE */
292         CurrentAce = (PACE)((ULONG_PTR)CurrentAce + CurrentAce->Header.AceSize);
293     }
294 
295     DPRINT("DesiredAccess %08lx\nPreviouslyGrantedAccess %08lx\nRemainingAccess %08lx\n",
296            DesiredAccess, PreviouslyGrantedAccess, RemainingAccess);
297 
298     /* Fail if some rights have not been granted */
299     if (RemainingAccess != 0)
300     {
301         DPRINT("HACK: RemainingAccess = 0x%08lx  DesiredAccess = 0x%08lx\n", RemainingAccess, DesiredAccess);
302 #if 0
303         /* HACK HACK HACK */
304         Status = STATUS_ACCESS_DENIED;
305         goto ReturnCommonStatus;
306 #endif
307     }
308 
309     /* Set granted access rights */
310     PreviouslyGrantedAccess |= DesiredAccess;
311 
312     /* Fail if no rights have been granted */
313     if (PreviouslyGrantedAccess == 0)
314     {
315         DPRINT1("PreviouslyGrantedAccess == 0  DesiredAccess = %08lx\n", DesiredAccess);
316         Status = STATUS_ACCESS_DENIED;
317         goto ReturnCommonStatus;
318     }
319 
320     Status = STATUS_SUCCESS;
321     goto ReturnCommonStatus;
322 
323 ReturnCommonStatus:
324     ResultListLength = UseResultList ? ObjectTypeListLength : 1;
325     for (i = 0; i < ResultListLength; i++)
326     {
327         GrantedAccessList[i] = PreviouslyGrantedAccess;
328         AccessStatusList[i] = Status;
329     }
330 
331     return NT_SUCCESS(Status);
332 }
333 
334 /**
335  * @brief
336  * Retrieves the main user from a security descriptor.
337  *
338  * @param[in] SecurityDescriptor
339  * A valid allocated security descriptor structure where the owner
340  * is to be retrieved.
341  *
342  * @return
343  * Returns a SID that represents the main user (owner).
344  */
345 static PSID
346 SepGetSDOwner(
347     _In_ PSECURITY_DESCRIPTOR _SecurityDescriptor)
348 {
349     PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor;
350     PSID Owner;
351 
352     if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
353         Owner = (PSID)((ULONG_PTR)SecurityDescriptor->Owner +
354                        (ULONG_PTR)SecurityDescriptor);
355     else
356         Owner = (PSID)SecurityDescriptor->Owner;
357 
358     return Owner;
359 }
360 
361 /**
362  * @brief
363  * Retrieves the group from a security descriptor.
364  *
365  * @param[in] SecurityDescriptor
366  * A valid allocated security descriptor structure where the group
367  * is to be retrieved.
368  *
369  * @return
370  * Returns a SID that represents a group.
371  */
372 static PSID
373 SepGetSDGroup(
374     _In_ PSECURITY_DESCRIPTOR _SecurityDescriptor)
375 {
376     PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor;
377     PSID Group;
378 
379     if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
380         Group = (PSID)((ULONG_PTR)SecurityDescriptor->Group +
381                        (ULONG_PTR)SecurityDescriptor);
382     else
383         Group = (PSID)SecurityDescriptor->Group;
384 
385     return Group;
386 }
387 
388 /**
389  * @brief
390  * Retrieves the length size of a set list of privileges structure.
391  *
392  * @param[in] PrivilegeSet
393  * A valid set of privileges.
394  *
395  * @return
396  * Returns the total length of a set of privileges.
397  */
398 static
399 ULONG
400 SepGetPrivilegeSetLength(
401     _In_ PPRIVILEGE_SET PrivilegeSet)
402 {
403     if (PrivilegeSet == NULL)
404         return 0;
405 
406     if (PrivilegeSet->PrivilegeCount == 0)
407         return (ULONG)(sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES));
408 
409     return (ULONG)(sizeof(PRIVILEGE_SET) +
410                    (PrivilegeSet->PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES));
411 }
412 
413 /* PUBLIC FUNCTIONS ***********************************************************/
414 
415 /**
416  * @brief
417  * Determines whether security access rights can be given to an object
418  * depending on the security descriptor and other security context
419  * entities, such as an owner.
420  *
421  * @param[in] SecurityDescriptor
422  * Security descriptor of the object that is being accessed.
423  *
424  * @param[in] SubjectSecurityContext
425  * The captured subject security context.
426  *
427  * @param[in] SubjectContextLocked
428  * If set to TRUE, a lock must be acquired for the security subject
429  * context.
430  *
431  * @param[in] DesiredAccess
432  * Access right bitmask that the calling thread wants to acquire.
433  *
434  * @param[in] PreviouslyGrantedAccess
435  * The access rights previously acquired in the past.
436  *
437  * @param[out] Privileges
438  * The returned set of privileges.
439  *
440  * @param[in] GenericMapping
441  * The generic mapping of access rights of an object type.
442  *
443  * @param[in] AccessMode
444  * The processor request level mode.
445  *
446  * @param[out] GrantedAccess
447  * A list of granted access rights.
448  *
449  * @param[out] AccessStatus
450  * The returned status code specifying why access cannot be made
451  * onto an object (if said access is denied in the first place).
452  *
453  * @return
454  * Returns TRUE if access onto the specific object is allowed, FALSE
455  * otherwise.
456  */
457 BOOLEAN
458 NTAPI
459 SeAccessCheck(
460     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
461     _In_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
462     _In_ BOOLEAN SubjectContextLocked,
463     _In_ ACCESS_MASK DesiredAccess,
464     _In_ ACCESS_MASK PreviouslyGrantedAccess,
465     _Out_ PPRIVILEGE_SET* Privileges,
466     _In_ PGENERIC_MAPPING GenericMapping,
467     _In_ KPROCESSOR_MODE AccessMode,
468     _Out_ PACCESS_MASK GrantedAccess,
469     _Out_ PNTSTATUS AccessStatus)
470 {
471     BOOLEAN ret;
472 
473     PAGED_CODE();
474 
475     /* Check if this is kernel mode */
476     if (AccessMode == KernelMode)
477     {
478         /* Check if kernel wants everything */
479         if (DesiredAccess & MAXIMUM_ALLOWED)
480         {
481             /* Give it */
482             *GrantedAccess = GenericMapping->GenericAll;
483             *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED);
484             *GrantedAccess |= PreviouslyGrantedAccess;
485         }
486         else
487         {
488             /* Give the desired and previous access */
489             *GrantedAccess = DesiredAccess | PreviouslyGrantedAccess;
490         }
491 
492         /* Success */
493         *AccessStatus = STATUS_SUCCESS;
494         return TRUE;
495     }
496 
497     /* Check if we didn't get an SD */
498     if (!SecurityDescriptor)
499     {
500         /* Automatic failure */
501         *AccessStatus = STATUS_ACCESS_DENIED;
502         return FALSE;
503     }
504 
505     /* Check for invalid impersonation */
506     if ((SubjectSecurityContext->ClientToken) &&
507         (SubjectSecurityContext->ImpersonationLevel < SecurityImpersonation))
508     {
509         *AccessStatus = STATUS_BAD_IMPERSONATION_LEVEL;
510         return FALSE;
511     }
512 
513     /* Acquire the lock if needed */
514     if (!SubjectContextLocked)
515         SeLockSubjectContext(SubjectSecurityContext);
516 
517     /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
518     if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED))
519     {
520          PACCESS_TOKEN Token = SubjectSecurityContext->ClientToken ?
521              SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken;
522 
523         if (SepTokenIsOwner(Token,
524                             SecurityDescriptor,
525                             FALSE))
526         {
527             if (DesiredAccess & MAXIMUM_ALLOWED)
528                 PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL);
529             else
530                 PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL));
531 
532             DesiredAccess &= ~(WRITE_DAC | READ_CONTROL);
533         }
534     }
535 
536     if (DesiredAccess == 0)
537     {
538         *GrantedAccess = PreviouslyGrantedAccess;
539         if (PreviouslyGrantedAccess == 0)
540         {
541             DPRINT1("Request for zero access to an object. Denying.\n");
542             *AccessStatus = STATUS_ACCESS_DENIED;
543             ret = FALSE;
544         }
545         else
546         {
547             *AccessStatus = STATUS_SUCCESS;
548             ret = TRUE;
549         }
550     }
551     else
552     {
553         /* Call the internal function */
554         ret = SepAccessCheck(SecurityDescriptor,
555                              SubjectSecurityContext,
556                              DesiredAccess,
557                              NULL,
558                              0,
559                              PreviouslyGrantedAccess,
560                              Privileges,
561                              GenericMapping,
562                              AccessMode,
563                              GrantedAccess,
564                              AccessStatus,
565                              FALSE);
566     }
567 
568     /* Release the lock if needed */
569     if (!SubjectContextLocked)
570         SeUnlockSubjectContext(SubjectSecurityContext);
571 
572     return ret;
573 }
574 
575 /**
576  * @brief
577  * Determines whether security access rights can be given to an object
578  * depending on the security descriptor. Unlike the regular access check
579  * procedure in the NT kernel, the fast traverse check is a faster way
580  * to quickly check if access can be made into an object.
581  *
582  * @param[in] SecurityDescriptor
583  * Security descriptor of the object that is being accessed.
584  *
585  * @param[in] AccessState
586  * An access state to determine if the access token in the current
587  * security context of the object is an restricted token.
588  *
589  * @param[in] DesiredAccess
590  * The access right bitmask where the calling thread wants to acquire.
591  *
592  * @param[in] AccessMode
593  * Process level request mode.
594  *
595  * @return
596  * Returns TRUE if access onto the specific object is allowed, FALSE
597  * otherwise.
598  */
599 BOOLEAN
600 NTAPI
601 SeFastTraverseCheck(
602     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
603     _In_ PACCESS_STATE AccessState,
604     _In_ ACCESS_MASK DesiredAccess,
605     _In_ KPROCESSOR_MODE AccessMode)
606 {
607     PACL Dacl;
608     ULONG AceIndex;
609     PKNOWN_ACE Ace;
610 
611     PAGED_CODE();
612 
613     ASSERT(AccessMode != KernelMode);
614 
615     if (SecurityDescriptor == NULL)
616         return FALSE;
617 
618     /* Get DACL */
619     Dacl = SepGetDaclFromDescriptor(SecurityDescriptor);
620     /* If no DACL, grant access */
621     if (Dacl == NULL)
622         return TRUE;
623 
624     /* No ACE -> Deny */
625     if (!Dacl->AceCount)
626         return FALSE;
627 
628     /* Can't perform the check on restricted token */
629     if (AccessState->Flags & TOKEN_IS_RESTRICTED)
630         return FALSE;
631 
632     /* Browse the ACEs */
633     for (AceIndex = 0, Ace = (PKNOWN_ACE)((ULONG_PTR)Dacl + sizeof(ACL));
634          AceIndex < Dacl->AceCount;
635          AceIndex++, Ace = (PKNOWN_ACE)((ULONG_PTR)Ace + Ace->Header.AceSize))
636     {
637         if (Ace->Header.AceFlags & INHERIT_ONLY_ACE)
638             continue;
639 
640         /* If access-allowed ACE */
641         if (Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
642         {
643             /* Check if all accesses are granted */
644             if (!(Ace->Mask & DesiredAccess))
645                 continue;
646 
647             /* Check SID and grant access if matching */
648             if (RtlEqualSid(SeWorldSid, &(Ace->SidStart)))
649                 return TRUE;
650         }
651         /* If access-denied ACE */
652         else if (Ace->Header.AceType == ACCESS_DENIED_ACE_TYPE)
653         {
654             /* Here, only check if it denies any access wanted and deny if so */
655             if (Ace->Mask & DesiredAccess)
656                 return FALSE;
657         }
658     }
659 
660     /* Faulty, deny */
661     return FALSE;
662 }
663 
664 /* SYSTEM CALLS ***************************************************************/
665 
666 /**
667  * @brief
668  * Determines whether security access rights can be given to an object
669  * depending on the security descriptor and a valid handle to an access
670  * token.
671  *
672  * @param[in] SecurityDescriptor
673  * Security descriptor of the object that is being accessed.
674  *
675  * @param[in] TokenHandle
676  * A handle to a token.
677  *
678  * @param[in] DesiredAccess
679  * The access right bitmask where the calling thread wants to acquire.
680  *
681  * @param[in] GenericMapping
682  * The generic mapping of access rights of an object type.
683  *
684  * @param[out] PrivilegeSet
685  * The returned set of privileges.
686  *
687  * @param[in,out] PrivilegeSetLength
688  * The total length size of a set of privileges.
689  *
690  * @param[out] GrantedAccess
691  * A list of granted access rights.
692  *
693  * @param[out] AccessStatus
694  * The returned status code specifying why access cannot be made
695  * onto an object (if said access is denied in the first place).
696  *
697  * @return
698  * Returns STATUS_SUCCESS if access check has been done without problems
699  * and that the object can be accessed. STATUS_GENERIC_NOT_MAPPED is returned
700  * if no generic access right is mapped. STATUS_NO_IMPERSONATION_TOKEN is returned
701  * if the token from the handle is not an impersonation token.
702  * STATUS_BAD_IMPERSONATION_LEVEL is returned if the token cannot be impersonated
703  * because the current security impersonation level doesn't permit so.
704  * STATUS_INVALID_SECURITY_DESCR is returned if the security descriptor given
705  * to the call is not a valid one. STATUS_BUFFER_TOO_SMALL is returned if
706  * the buffer to the captured privileges has a length that is less than the required
707  * size of the set of privileges. A failure NTSTATUS code is returned otherwise.
708  */
709 NTSTATUS
710 NTAPI
711 NtAccessCheck(
712     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
713     _In_ HANDLE TokenHandle,
714     _In_ ACCESS_MASK DesiredAccess,
715     _In_ PGENERIC_MAPPING GenericMapping,
716     _Out_opt_ PPRIVILEGE_SET PrivilegeSet,
717     _Inout_ PULONG PrivilegeSetLength,
718     _Out_ PACCESS_MASK GrantedAccess,
719     _Out_ PNTSTATUS AccessStatus)
720 {
721     PSECURITY_DESCRIPTOR CapturedSecurityDescriptor = NULL;
722     SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
723     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
724     ACCESS_MASK PreviouslyGrantedAccess = 0;
725     PPRIVILEGE_SET Privileges = NULL;
726     ULONG CapturedPrivilegeSetLength, RequiredPrivilegeSetLength;
727     PTOKEN Token;
728     NTSTATUS Status;
729     PAGED_CODE();
730 
731     /* Check if this is kernel mode */
732     if (PreviousMode == KernelMode)
733     {
734         /* Check if kernel wants everything */
735         if (DesiredAccess & MAXIMUM_ALLOWED)
736         {
737             /* Give it */
738             *GrantedAccess = GenericMapping->GenericAll;
739             *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED);
740         }
741         else
742         {
743             /* Just give the desired access */
744             *GrantedAccess = DesiredAccess;
745         }
746 
747         /* Success */
748         *AccessStatus = STATUS_SUCCESS;
749         return STATUS_SUCCESS;
750     }
751 
752     /* Protect probe in SEH */
753     _SEH2_TRY
754     {
755         /* Probe all pointers */
756         ProbeForRead(GenericMapping, sizeof(GENERIC_MAPPING), sizeof(ULONG));
757         ProbeForRead(PrivilegeSetLength, sizeof(ULONG), sizeof(ULONG));
758         ProbeForWrite(PrivilegeSet, *PrivilegeSetLength, sizeof(ULONG));
759         ProbeForWrite(GrantedAccess, sizeof(ACCESS_MASK), sizeof(ULONG));
760         ProbeForWrite(AccessStatus, sizeof(NTSTATUS), sizeof(ULONG));
761 
762         /* Capture the privilege set length and the mapping */
763         CapturedPrivilegeSetLength = *PrivilegeSetLength;
764     }
765     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
766     {
767         /* Return the exception code */
768         _SEH2_YIELD(return _SEH2_GetExceptionCode());
769     }
770     _SEH2_END;
771 
772     /* Check for unmapped access rights */
773     if (DesiredAccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL))
774         return STATUS_GENERIC_NOT_MAPPED;
775 
776     /* Reference the token */
777     Status = ObReferenceObjectByHandle(TokenHandle,
778                                        TOKEN_QUERY,
779                                        SeTokenObjectType,
780                                        PreviousMode,
781                                        (PVOID*)&Token,
782                                        NULL);
783     if (!NT_SUCCESS(Status))
784     {
785         DPRINT("Failed to reference token (Status %lx)\n", Status);
786         return Status;
787     }
788 
789     /* Check token type */
790     if (Token->TokenType != TokenImpersonation)
791     {
792         DPRINT("No impersonation token\n");
793         ObDereferenceObject(Token);
794         return STATUS_NO_IMPERSONATION_TOKEN;
795     }
796 
797     /* Check the impersonation level */
798     if (Token->ImpersonationLevel < SecurityIdentification)
799     {
800         DPRINT("Impersonation level < SecurityIdentification\n");
801         ObDereferenceObject(Token);
802         return STATUS_BAD_IMPERSONATION_LEVEL;
803     }
804 
805     /* Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access */
806     Status = SePrivilegePolicyCheck(&DesiredAccess,
807                                     &PreviouslyGrantedAccess,
808                                     NULL,
809                                     Token,
810                                     &Privileges,
811                                     PreviousMode);
812     if (!NT_SUCCESS(Status))
813     {
814         DPRINT("SePrivilegePolicyCheck failed (Status 0x%08lx)\n", Status);
815         ObDereferenceObject(Token);
816         *AccessStatus = Status;
817         *GrantedAccess = 0;
818         return STATUS_SUCCESS;
819     }
820 
821     /* Check the size of the privilege set and return the privileges */
822     if (Privileges != NULL)
823     {
824         DPRINT("Privileges != NULL\n");
825 
826         /* Calculate the required privilege set buffer size */
827         RequiredPrivilegeSetLength = SepGetPrivilegeSetLength(Privileges);
828 
829         /* Fail if the privilege set buffer is too small */
830         if (CapturedPrivilegeSetLength < RequiredPrivilegeSetLength)
831         {
832             ObDereferenceObject(Token);
833             SeFreePrivileges(Privileges);
834             *PrivilegeSetLength = RequiredPrivilegeSetLength;
835             return STATUS_BUFFER_TOO_SMALL;
836         }
837 
838         /* Copy the privilege set to the caller */
839         RtlCopyMemory(PrivilegeSet,
840                       Privileges,
841                       RequiredPrivilegeSetLength);
842 
843         /* Free the local privilege set */
844         SeFreePrivileges(Privileges);
845     }
846     else
847     {
848         DPRINT("Privileges == NULL\n");
849 
850         /* Fail if the privilege set buffer is too small */
851         if (CapturedPrivilegeSetLength < sizeof(PRIVILEGE_SET))
852         {
853             ObDereferenceObject(Token);
854             *PrivilegeSetLength = sizeof(PRIVILEGE_SET);
855             return STATUS_BUFFER_TOO_SMALL;
856         }
857 
858         /* Initialize the privilege set */
859         PrivilegeSet->PrivilegeCount = 0;
860         PrivilegeSet->Control = 0;
861     }
862 
863     /* Capture the security descriptor */
864     Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
865                                          PreviousMode,
866                                          PagedPool,
867                                          FALSE,
868                                          &CapturedSecurityDescriptor);
869     if (!NT_SUCCESS(Status))
870     {
871         DPRINT("Failed to capture the Security Descriptor\n");
872         ObDereferenceObject(Token);
873         return Status;
874     }
875 
876     /* Check the captured security descriptor */
877     if (CapturedSecurityDescriptor == NULL)
878     {
879         DPRINT("Security Descriptor is NULL\n");
880         ObDereferenceObject(Token);
881         return STATUS_INVALID_SECURITY_DESCR;
882     }
883 
884     /* Check security descriptor for valid owner and group */
885     if (SepGetSDOwner(SecurityDescriptor) == NULL ||  // FIXME: use CapturedSecurityDescriptor
886         SepGetSDGroup(SecurityDescriptor) == NULL)    // FIXME: use CapturedSecurityDescriptor
887     {
888         DPRINT("Security Descriptor does not have a valid group or owner\n");
889         SeReleaseSecurityDescriptor(CapturedSecurityDescriptor,
890                                     PreviousMode,
891                                     FALSE);
892         ObDereferenceObject(Token);
893         return STATUS_INVALID_SECURITY_DESCR;
894     }
895 
896     /* Set up the subject context, and lock it */
897     SeCaptureSubjectContext(&SubjectSecurityContext);
898 
899     /* Lock the token */
900     SepAcquireTokenLockShared(Token);
901 
902     /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
903     if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED))
904     {
905         if (SepTokenIsOwner(Token, SecurityDescriptor, FALSE)) // FIXME: use CapturedSecurityDescriptor
906         {
907             if (DesiredAccess & MAXIMUM_ALLOWED)
908                 PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL);
909             else
910                 PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL));
911 
912             DesiredAccess &= ~(WRITE_DAC | READ_CONTROL);
913         }
914     }
915 
916     if (DesiredAccess == 0)
917     {
918         *GrantedAccess = PreviouslyGrantedAccess;
919         *AccessStatus = STATUS_SUCCESS;
920     }
921     else
922     {
923         /* Now perform the access check */
924         SepAccessCheck(SecurityDescriptor, // FIXME: use CapturedSecurityDescriptor
925                        &SubjectSecurityContext,
926                        DesiredAccess,
927                        NULL,
928                        0,
929                        PreviouslyGrantedAccess,
930                        &PrivilegeSet, //FIXME
931                        GenericMapping,
932                        PreviousMode,
933                        GrantedAccess,
934                        AccessStatus,
935                        FALSE);
936     }
937 
938     /* Release subject context and unlock the token */
939     SeReleaseSubjectContext(&SubjectSecurityContext);
940     SepReleaseTokenLock(Token);
941 
942     /* Release the captured security descriptor */
943     SeReleaseSecurityDescriptor(CapturedSecurityDescriptor,
944                                 PreviousMode,
945                                 FALSE);
946 
947     /* Dereference the token */
948     ObDereferenceObject(Token);
949 
950     /* Check succeeded */
951     return STATUS_SUCCESS;
952 }
953 
954 /**
955  * @brief
956  * Determines whether security access could be granted or not on
957  * an object by the requestor who wants such access through type.
958  *
959  * @param[in] SecurityDescriptor
960  * A security descriptor with information data for auditing.
961  *
962  * @param[in] PrincipalSelfSid
963  * A principal self user SID.
964  *
965  * @param[in] ClientToken
966  * A client access token.
967  *
968  * @param[in] DesiredAccess
969  * The desired access masks rights requested by the caller.
970  *
971  * @param[in] ObjectTypeList
972  * A list of object types.
973  *
974  * @param[in] ObjectTypeLength
975  * The length size of the list.
976  *
977  * @param[in] GenericMapping
978  * The generic mapping list of access masks rights.
979  *
980  * @param[in] PrivilegeSet
981  * An array set of privileges.
982  *
983  * @param[in,out] PrivilegeSetLength
984  * The length size of the array set of privileges.
985  *
986  * @param[out] GrantedAccess
987  * The returned granted access rights.
988  *
989  * @param[out] AccessStatus
990  * The returned NTSTATUS code indicating the final results
991  * of auditing.
992  *
993  * @return
994  * To be added...
995  */
996 NTSTATUS
997 NTAPI
998 NtAccessCheckByType(
999     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1000     _In_ PSID PrincipalSelfSid,
1001     _In_ HANDLE ClientToken,
1002     _In_ ACCESS_MASK DesiredAccess,
1003     _In_ POBJECT_TYPE_LIST ObjectTypeList,
1004     _In_ ULONG ObjectTypeLength,
1005     _In_ PGENERIC_MAPPING GenericMapping,
1006     _In_ PPRIVILEGE_SET PrivilegeSet,
1007     _Inout_ PULONG PrivilegeSetLength,
1008     _Out_ PACCESS_MASK GrantedAccess,
1009     _Out_ PNTSTATUS AccessStatus)
1010 {
1011     UNIMPLEMENTED;
1012     return STATUS_NOT_IMPLEMENTED;
1013 }
1014 
1015 /**
1016  * @brief
1017  * Determines whether security access could be granted or not on
1018  * an object by the requestor who wants such access through
1019  * type list.
1020  *
1021  * @param[in] SecurityDescriptor
1022  * A security descriptor with information data for auditing.
1023  *
1024  * @param[in] PrincipalSelfSid
1025  * A principal self user SID.
1026  *
1027  * @param[in] ClientToken
1028  * A client access token.
1029  *
1030  * @param[in] DesiredAccess
1031  * The desired access masks rights requested by the caller.
1032  *
1033  * @param[in] ObjectTypeList
1034  * A list of object types.
1035  *
1036  * @param[in] ObjectTypeLength
1037  * The length size of the list.
1038  *
1039  * @param[in] GenericMapping
1040  * The generic mapping list of access masks rights.
1041  *
1042  * @param[in] PrivilegeSet
1043  * An array set of privileges.
1044  *
1045  * @param[in,out] PrivilegeSetLength
1046  * The length size of the array set of privileges.
1047  *
1048  * @param[out] GrantedAccess
1049  * The returned granted access rights.
1050  *
1051  * @param[out] AccessStatus
1052  * The returned NTSTATUS code indicating the final results
1053  * of auditing.
1054  *
1055  * @return
1056  * To be added...
1057  */
1058 NTSTATUS
1059 NTAPI
1060 NtAccessCheckByTypeResultList(
1061     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1062     _In_ PSID PrincipalSelfSid,
1063     _In_ HANDLE ClientToken,
1064     _In_ ACCESS_MASK DesiredAccess,
1065     _In_ POBJECT_TYPE_LIST ObjectTypeList,
1066     _In_ ULONG ObjectTypeLength,
1067     _In_ PGENERIC_MAPPING GenericMapping,
1068     _In_ PPRIVILEGE_SET PrivilegeSet,
1069     _Inout_ PULONG PrivilegeSetLength,
1070     _Out_ PACCESS_MASK GrantedAccess,
1071     _Out_ PNTSTATUS AccessStatus)
1072 {
1073     UNIMPLEMENTED;
1074     return STATUS_NOT_IMPLEMENTED;
1075 }
1076 
1077 /* EOF */
1078