xref: /reactos/ntoskrnl/se/priv.c (revision 018d4d39)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            ntoskrnl/se/priv.c
5  * PURPOSE:         Security manager
6  *
7  * PROGRAMMERS:     No programmer listed.
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 #if defined (ALLOC_PRAGMA)
17 #pragma alloc_text(INIT, SepInitPrivileges)
18 #endif
19 
20 /* GLOBALS ********************************************************************/
21 
22 #define CONST_LUID(x1, x2) {x1, x2}
23 const LUID SeCreateTokenPrivilege = CONST_LUID(SE_CREATE_TOKEN_PRIVILEGE, 0);
24 const LUID SeAssignPrimaryTokenPrivilege = CONST_LUID(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, 0);
25 const LUID SeLockMemoryPrivilege = CONST_LUID(SE_LOCK_MEMORY_PRIVILEGE, 0);
26 const LUID SeIncreaseQuotaPrivilege = CONST_LUID(SE_INCREASE_QUOTA_PRIVILEGE, 0);
27 const LUID SeUnsolicitedInputPrivilege = CONST_LUID(6, 0);
28 const LUID SeTcbPrivilege = CONST_LUID(SE_TCB_PRIVILEGE, 0);
29 const LUID SeSecurityPrivilege = CONST_LUID(SE_SECURITY_PRIVILEGE, 0);
30 const LUID SeTakeOwnershipPrivilege = CONST_LUID(SE_TAKE_OWNERSHIP_PRIVILEGE, 0);
31 const LUID SeLoadDriverPrivilege = CONST_LUID(SE_LOAD_DRIVER_PRIVILEGE, 0);
32 const LUID SeSystemProfilePrivilege = CONST_LUID(SE_SYSTEM_PROFILE_PRIVILEGE, 0);
33 const LUID SeSystemtimePrivilege = CONST_LUID(SE_SYSTEMTIME_PRIVILEGE, 0);
34 const LUID SeProfileSingleProcessPrivilege = CONST_LUID(SE_PROF_SINGLE_PROCESS_PRIVILEGE, 0);
35 const LUID SeIncreaseBasePriorityPrivilege = CONST_LUID(SE_INC_BASE_PRIORITY_PRIVILEGE, 0);
36 const LUID SeCreatePagefilePrivilege = CONST_LUID(SE_CREATE_PAGEFILE_PRIVILEGE, 0);
37 const LUID SeCreatePermanentPrivilege = CONST_LUID(SE_CREATE_PERMANENT_PRIVILEGE, 0);
38 const LUID SeBackupPrivilege = CONST_LUID(SE_BACKUP_PRIVILEGE, 0);
39 const LUID SeRestorePrivilege = CONST_LUID(SE_RESTORE_PRIVILEGE, 0);
40 const LUID SeShutdownPrivilege = CONST_LUID(SE_SHUTDOWN_PRIVILEGE, 0);
41 const LUID SeDebugPrivilege = CONST_LUID(SE_DEBUG_PRIVILEGE, 0);
42 const LUID SeAuditPrivilege = CONST_LUID(SE_AUDIT_PRIVILEGE, 0);
43 const LUID SeSystemEnvironmentPrivilege = CONST_LUID(SE_SYSTEM_ENVIRONMENT_PRIVILEGE, 0);
44 const LUID SeChangeNotifyPrivilege = CONST_LUID(SE_CHANGE_NOTIFY_PRIVILEGE, 0);
45 const LUID SeRemoteShutdownPrivilege = CONST_LUID(SE_REMOTE_SHUTDOWN_PRIVILEGE, 0);
46 const LUID SeUndockPrivilege = CONST_LUID(SE_UNDOCK_PRIVILEGE, 0);
47 const LUID SeSyncAgentPrivilege = CONST_LUID(SE_SYNC_AGENT_PRIVILEGE, 0);
48 const LUID SeEnableDelegationPrivilege = CONST_LUID(SE_ENABLE_DELEGATION_PRIVILEGE, 0);
49 const LUID SeManageVolumePrivilege = CONST_LUID(SE_MANAGE_VOLUME_PRIVILEGE, 0);
50 const LUID SeImpersonatePrivilege = CONST_LUID(SE_IMPERSONATE_PRIVILEGE, 0);
51 const LUID SeCreateGlobalPrivilege = CONST_LUID(SE_CREATE_GLOBAL_PRIVILEGE, 0);
52 const LUID SeTrustedCredmanPrivilege = CONST_LUID(SE_TRUSTED_CREDMAN_ACCESS_PRIVILEGE, 0);
53 const LUID SeRelabelPrivilege = CONST_LUID(SE_RELABEL_PRIVILEGE, 0);
54 const LUID SeIncreaseWorkingSetPrivilege = CONST_LUID(SE_INC_WORKING_SET_PRIVILEGE, 0);
55 const LUID SeTimeZonePrivilege = CONST_LUID(SE_TIME_ZONE_PRIVILEGE, 0);
56 const LUID SeCreateSymbolicLinkPrivilege = CONST_LUID(SE_CREATE_SYMBOLIC_LINK_PRIVILEGE, 0);
57 
58 
59 /* PRIVATE FUNCTIONS **********************************************************/
60 
61 INIT_FUNCTION
62 VOID
63 NTAPI
64 SepInitPrivileges(VOID)
65 {
66 
67 }
68 
69 
70 BOOLEAN
71 NTAPI
72 SepPrivilegeCheck(PTOKEN Token,
73                   PLUID_AND_ATTRIBUTES Privileges,
74                   ULONG PrivilegeCount,
75                   ULONG PrivilegeControl,
76                   KPROCESSOR_MODE PreviousMode)
77 {
78     ULONG i;
79     ULONG j;
80     ULONG Required;
81 
82     DPRINT("SepPrivilegeCheck() called\n");
83 
84     PAGED_CODE();
85 
86     if (PreviousMode == KernelMode)
87         return TRUE;
88 
89     /* Get the number of privileges that are required to match */
90     Required = (PrivilegeControl & PRIVILEGE_SET_ALL_NECESSARY) ? PrivilegeCount : 1;
91 
92     /* Acquire a shared token lock */
93     SepAcquireTokenLockShared(Token);
94 
95     /* Loop all requested privileges until we found the required ones */
96     for (i = 0; i < PrivilegeCount; i++)
97     {
98         /* Loop the privileges of the token */
99         for (j = 0; j < Token->PrivilegeCount; j++)
100         {
101             /* Check if the LUIDs match */
102             if (RtlEqualLuid(&Token->Privileges[j].Luid, &Privileges[i].Luid))
103             {
104                 DPRINT("Found privilege. Attributes: %lx\n",
105                        Token->Privileges[j].Attributes);
106 
107                 /* Check if the privilege is enabled */
108                 if (Token->Privileges[j].Attributes & SE_PRIVILEGE_ENABLED)
109                 {
110                     Privileges[i].Attributes |= SE_PRIVILEGE_USED_FOR_ACCESS;
111                     Required--;
112 
113                     /* Check if we have found all privileges */
114                     if (Required == 0)
115                     {
116                         /* We're done! */
117                         SepReleaseTokenLock(Token);
118                         return TRUE;
119                     }
120                 }
121 
122                 /* Leave the inner loop */
123                 break;
124             }
125         }
126     }
127 
128     /* Release the token lock */
129     SepReleaseTokenLock(Token);
130 
131     /* When we reached this point, we did not find all privileges */
132     ASSERT(Required > 0);
133     return FALSE;
134 }
135 
136 NTSTATUS
137 NTAPI
138 SepSinglePrivilegeCheck(
139     LUID PrivilegeValue,
140     PTOKEN Token,
141     KPROCESSOR_MODE PreviousMode)
142 {
143     LUID_AND_ATTRIBUTES Privilege;
144     PAGED_CODE();
145     ASSERT(!RtlEqualLuid(&PrivilegeValue, &SeTcbPrivilege));
146 
147     Privilege.Luid = PrivilegeValue;
148     Privilege.Attributes = SE_PRIVILEGE_ENABLED;
149     return SepPrivilegeCheck(Token,
150                              &Privilege,
151                              1,
152                              PRIVILEGE_SET_ALL_NECESSARY,
153                              PreviousMode);
154 }
155 
156 NTSTATUS
157 NTAPI
158 SePrivilegePolicyCheck(
159     _Inout_ PACCESS_MASK DesiredAccess,
160     _Inout_ PACCESS_MASK GrantedAccess,
161     _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
162     _In_ PTOKEN Token,
163     _Out_opt_ PPRIVILEGE_SET *OutPrivilegeSet,
164     _In_ KPROCESSOR_MODE PreviousMode)
165 {
166     SIZE_T PrivilegeSize;
167     PPRIVILEGE_SET PrivilegeSet;
168     ULONG PrivilegeCount = 0, Index = 0;
169     ACCESS_MASK AccessMask = 0;
170     PAGED_CODE();
171 
172     /* Check if we have a security subject context */
173     if (SubjectContext != NULL)
174     {
175         /* Check if there is a client impersonation token */
176         if (SubjectContext->ClientToken != NULL)
177             Token = SubjectContext->ClientToken;
178         else
179             Token = SubjectContext->PrimaryToken;
180     }
181 
182     /* Check if the caller wants ACCESS_SYSTEM_SECURITY access */
183     if (*DesiredAccess & ACCESS_SYSTEM_SECURITY)
184     {
185         /* Do the privilege check */
186         if (SepSinglePrivilegeCheck(SeSecurityPrivilege, Token, PreviousMode))
187         {
188             /* Remember this access flag */
189             AccessMask |= ACCESS_SYSTEM_SECURITY;
190             PrivilegeCount++;
191         }
192         else
193         {
194             return STATUS_PRIVILEGE_NOT_HELD;
195         }
196     }
197 
198     /* Check if the caller wants WRITE_OWNER access */
199     if (*DesiredAccess & WRITE_OWNER)
200     {
201         /* Do the privilege check */
202         if (SepSinglePrivilegeCheck(SeTakeOwnershipPrivilege, Token, PreviousMode))
203         {
204             /* Remember this access flag */
205             AccessMask |= WRITE_OWNER;
206             PrivilegeCount++;
207         }
208     }
209 
210     /* Update the access masks */
211     *GrantedAccess |= AccessMask;
212     *DesiredAccess &= ~AccessMask;
213 
214     /* Does the caller want a privilege set? */
215     if (OutPrivilegeSet != NULL)
216     {
217         /* Do we have any privileges to report? */
218         if (PrivilegeCount > 0)
219         {
220             /* Calculate size and allocate the structure */
221             PrivilegeSize = FIELD_OFFSET(PRIVILEGE_SET, Privilege[PrivilegeCount]);
222             PrivilegeSet = ExAllocatePoolWithTag(PagedPool, PrivilegeSize, TAG_PRIVILEGE_SET);
223             *OutPrivilegeSet = PrivilegeSet;
224             if (PrivilegeSet == NULL)
225             {
226                 return STATUS_INSUFFICIENT_RESOURCES;
227             }
228 
229             PrivilegeSet->PrivilegeCount = PrivilegeCount;
230             PrivilegeSet->Control = 0;
231 
232             if (AccessMask & WRITE_OWNER)
233             {
234                 PrivilegeSet->Privilege[Index].Luid = SeTakeOwnershipPrivilege;
235                 PrivilegeSet->Privilege[Index].Attributes = SE_PRIVILEGE_USED_FOR_ACCESS;
236                 Index++;
237             }
238 
239             if (AccessMask & ACCESS_SYSTEM_SECURITY)
240             {
241                 PrivilegeSet->Privilege[Index].Luid = SeSecurityPrivilege;
242                 PrivilegeSet->Privilege[Index].Attributes = SE_PRIVILEGE_USED_FOR_ACCESS;
243             }
244         }
245         else
246         {
247             /* No privileges, no structure */
248             *OutPrivilegeSet = NULL;
249         }
250     }
251 
252     return STATUS_SUCCESS;
253 }
254 
255 BOOLEAN
256 NTAPI
257 SeCheckAuditPrivilege(
258     _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
259     _In_ KPROCESSOR_MODE PreviousMode)
260 {
261     PRIVILEGE_SET PrivilegeSet;
262     BOOLEAN Result;
263     PAGED_CODE();
264 
265     /* Initialize the privilege set with the single privilege */
266     PrivilegeSet.PrivilegeCount = 1;
267     PrivilegeSet.Control = PRIVILEGE_SET_ALL_NECESSARY;
268     PrivilegeSet.Privilege[0].Luid = SeAuditPrivilege;
269     PrivilegeSet.Privilege[0].Attributes = 0;
270 
271     /* Check against the primary token! */
272     Result = SepPrivilegeCheck(SubjectContext->PrimaryToken,
273                                &PrivilegeSet.Privilege[0],
274                                1,
275                                PRIVILEGE_SET_ALL_NECESSARY,
276                                PreviousMode);
277 
278     if (PreviousMode != KernelMode)
279     {
280         SePrivilegedServiceAuditAlarm(NULL,
281                                       SubjectContext,
282                                       &PrivilegeSet,
283                                       Result);
284     }
285 
286     return Result;
287 }
288 
289 NTSTATUS
290 NTAPI
291 SeCaptureLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Src,
292                                 ULONG PrivilegeCount,
293                                 KPROCESSOR_MODE PreviousMode,
294                                 PLUID_AND_ATTRIBUTES AllocatedMem,
295                                 ULONG AllocatedLength,
296                                 POOL_TYPE PoolType,
297                                 BOOLEAN CaptureIfKernel,
298                                 PLUID_AND_ATTRIBUTES *Dest,
299                                 PULONG Length)
300 {
301     ULONG BufferSize;
302     NTSTATUS Status = STATUS_SUCCESS;
303 
304     PAGED_CODE();
305 
306     if (PrivilegeCount == 0)
307     {
308         *Dest = 0;
309         *Length = 0;
310         return STATUS_SUCCESS;
311     }
312 
313     if (PreviousMode == KernelMode && !CaptureIfKernel)
314     {
315         *Dest = Src;
316         return STATUS_SUCCESS;
317     }
318 
319     /* FIXME - check PrivilegeCount for a valid number so we don't
320      cause an integer overflow or exhaust system resources! */
321 
322     BufferSize = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
323     *Length = ROUND_UP(BufferSize, 4); /* round up to a 4 byte alignment */
324 
325     /* probe the buffer */
326     if (PreviousMode != KernelMode)
327     {
328         _SEH2_TRY
329         {
330             ProbeForRead(Src,
331                          BufferSize,
332                          sizeof(ULONG));
333         }
334         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
335         {
336             /* Return the exception code */
337             _SEH2_YIELD(return _SEH2_GetExceptionCode());
338         }
339         _SEH2_END;
340     }
341 
342     /* allocate enough memory or check if the provided buffer is
343      large enough to hold the array */
344     if (AllocatedMem != NULL)
345     {
346         if (AllocatedLength < BufferSize)
347         {
348             return STATUS_BUFFER_TOO_SMALL;
349         }
350 
351         *Dest = AllocatedMem;
352     }
353     else
354     {
355         *Dest = ExAllocatePoolWithTag(PoolType,
356                                       BufferSize,
357                                       TAG_LUID);
358         if (*Dest == NULL)
359         {
360             return STATUS_INSUFFICIENT_RESOURCES;
361         }
362     }
363 
364     /* copy the array to the buffer */
365     _SEH2_TRY
366     {
367         RtlCopyMemory(*Dest,
368                       Src,
369                       BufferSize);
370     }
371     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
372     {
373         Status = _SEH2_GetExceptionCode();
374     }
375     _SEH2_END;
376 
377     if (!NT_SUCCESS(Status) && AllocatedMem == NULL)
378     {
379         ExFreePoolWithTag(*Dest, TAG_LUID);
380     }
381 
382     return Status;
383 }
384 
385 VOID
386 NTAPI
387 SeReleaseLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Privilege,
388                                 KPROCESSOR_MODE PreviousMode,
389                                 BOOLEAN CaptureIfKernel)
390 {
391     PAGED_CODE();
392 
393     if (Privilege != NULL &&
394         (PreviousMode != KernelMode || CaptureIfKernel))
395     {
396         ExFreePoolWithTag(Privilege, TAG_LUID);
397     }
398 }
399 
400 /* PUBLIC FUNCTIONS ***********************************************************/
401 
402 /*
403  * @implemented
404  */
405 NTSTATUS
406 NTAPI
407 SeAppendPrivileges(IN OUT PACCESS_STATE AccessState,
408                    IN PPRIVILEGE_SET Privileges)
409 {
410     PAUX_ACCESS_DATA AuxData;
411     ULONG OldPrivilegeSetSize;
412     ULONG NewPrivilegeSetSize;
413     PPRIVILEGE_SET PrivilegeSet;
414 
415     PAGED_CODE();
416 
417     /* Get the Auxiliary Data */
418     AuxData = AccessState->AuxData;
419 
420     /* Calculate the size of the old privilege set */
421     OldPrivilegeSetSize = sizeof(PRIVILEGE_SET) +
422                           (AuxData->PrivilegeSet->PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES);
423 
424     if (AuxData->PrivilegeSet->PrivilegeCount +
425         Privileges->PrivilegeCount > INITIAL_PRIVILEGE_COUNT)
426     {
427         /* Calculate the size of the new privilege set */
428         NewPrivilegeSetSize = OldPrivilegeSetSize +
429                               Privileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
430 
431         /* Allocate a new privilege set */
432         PrivilegeSet = ExAllocatePoolWithTag(PagedPool,
433                                              NewPrivilegeSetSize,
434                                              TAG_PRIVILEGE_SET);
435         if (PrivilegeSet == NULL)
436             return STATUS_INSUFFICIENT_RESOURCES;
437 
438         /* Copy original privileges from the acess state */
439         RtlCopyMemory(PrivilegeSet,
440                       AuxData->PrivilegeSet,
441                       OldPrivilegeSetSize);
442 
443         /* Append privileges from the privilege set*/
444         RtlCopyMemory((PVOID)((ULONG_PTR)PrivilegeSet + OldPrivilegeSetSize),
445                       (PVOID)((ULONG_PTR)Privileges + sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES)),
446                       Privileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
447 
448         /* Adjust the number of privileges in the new privilege set */
449         PrivilegeSet->PrivilegeCount += Privileges->PrivilegeCount;
450 
451         /* Free the old privilege set if it was allocated */
452         if (AccessState->PrivilegesAllocated != FALSE)
453             ExFreePoolWithTag(AuxData->PrivilegeSet, TAG_PRIVILEGE_SET);
454 
455         /* Now we are using an allocated privilege set */
456         AccessState->PrivilegesAllocated = TRUE;
457 
458         /* Assign the new privileges to the access state */
459         AuxData->PrivilegeSet = PrivilegeSet;
460     }
461     else
462     {
463         /* Append privileges */
464         RtlCopyMemory((PVOID)((ULONG_PTR)AuxData->PrivilegeSet + OldPrivilegeSetSize),
465                       (PVOID)((ULONG_PTR)Privileges + sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES)),
466                       Privileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
467 
468         /* Adjust the number of privileges in the target privilege set */
469         AuxData->PrivilegeSet->PrivilegeCount += Privileges->PrivilegeCount;
470     }
471 
472     return STATUS_SUCCESS;
473 }
474 
475 /*
476  * @implemented
477  */
478 VOID
479 NTAPI
480 SeFreePrivileges(IN PPRIVILEGE_SET Privileges)
481 {
482     PAGED_CODE();
483     ExFreePoolWithTag(Privileges, TAG_PRIVILEGE_SET);
484 }
485 
486 /*
487  * @implemented
488  */
489 BOOLEAN
490 NTAPI
491 SePrivilegeCheck(PPRIVILEGE_SET Privileges,
492                  PSECURITY_SUBJECT_CONTEXT SubjectContext,
493                  KPROCESSOR_MODE PreviousMode)
494 {
495     PACCESS_TOKEN Token = NULL;
496 
497     PAGED_CODE();
498 
499     if (SubjectContext->ClientToken == NULL)
500     {
501         Token = SubjectContext->PrimaryToken;
502     }
503     else
504     {
505         Token = SubjectContext->ClientToken;
506         if (SubjectContext->ImpersonationLevel < 2)
507         {
508             return FALSE;
509         }
510     }
511 
512     return SepPrivilegeCheck(Token,
513                              Privileges->Privilege,
514                              Privileges->PrivilegeCount,
515                              Privileges->Control,
516                              PreviousMode);
517 }
518 
519 /*
520  * @implemented
521  */
522 BOOLEAN
523 NTAPI
524 SeSinglePrivilegeCheck(IN LUID PrivilegeValue,
525                        IN KPROCESSOR_MODE PreviousMode)
526 {
527     SECURITY_SUBJECT_CONTEXT SubjectContext;
528     PRIVILEGE_SET Priv;
529     BOOLEAN Result;
530 
531     PAGED_CODE();
532 
533     SeCaptureSubjectContext(&SubjectContext);
534 
535     Priv.PrivilegeCount = 1;
536     Priv.Control = PRIVILEGE_SET_ALL_NECESSARY;
537     Priv.Privilege[0].Luid = PrivilegeValue;
538     Priv.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
539 
540     Result = SePrivilegeCheck(&Priv,
541                               &SubjectContext,
542                               PreviousMode);
543 
544     if (PreviousMode != KernelMode)
545     {
546         SePrivilegedServiceAuditAlarm(NULL,
547                                       &SubjectContext,
548                                       &Priv,
549                                       Result);
550 
551     }
552 
553     SeReleaseSubjectContext(&SubjectContext);
554 
555     return Result;
556 }
557 
558 BOOLEAN
559 NTAPI
560 SeCheckPrivilegedObject(IN LUID PrivilegeValue,
561                         IN HANDLE ObjectHandle,
562                         IN ACCESS_MASK DesiredAccess,
563                         IN KPROCESSOR_MODE PreviousMode)
564 {
565     SECURITY_SUBJECT_CONTEXT SubjectContext;
566     PRIVILEGE_SET Priv;
567     BOOLEAN Result;
568 
569     PAGED_CODE();
570 
571     SeCaptureSubjectContext(&SubjectContext);
572 
573     Priv.PrivilegeCount = 1;
574     Priv.Control = PRIVILEGE_SET_ALL_NECESSARY;
575     Priv.Privilege[0].Luid = PrivilegeValue;
576     Priv.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
577 
578     Result = SePrivilegeCheck(&Priv, &SubjectContext, PreviousMode);
579     if (PreviousMode != KernelMode)
580     {
581 #if 0
582         SePrivilegeObjectAuditAlarm(ObjectHandle,
583                                     &SubjectContext,
584                                     DesiredAccess,
585                                     &PrivilegeValue,
586                                     Result,
587                                     PreviousMode);
588 #endif
589     }
590 
591     SeReleaseSubjectContext(&SubjectContext);
592 
593     return Result;
594 }
595 
596 /* SYSTEM CALLS ***************************************************************/
597 
598 NTSTATUS
599 NTAPI
600 NtPrivilegeCheck(IN HANDLE ClientToken,
601                  IN PPRIVILEGE_SET RequiredPrivileges,
602                  OUT PBOOLEAN Result)
603 {
604     PLUID_AND_ATTRIBUTES Privileges;
605     PTOKEN Token;
606     ULONG PrivilegeCount = 0;
607     ULONG PrivilegeControl = 0;
608     ULONG Length;
609     BOOLEAN CheckResult;
610     KPROCESSOR_MODE PreviousMode;
611     NTSTATUS Status;
612 
613     PAGED_CODE();
614 
615     PreviousMode = KeGetPreviousMode();
616 
617     /* probe the buffers */
618     if (PreviousMode != KernelMode)
619     {
620         _SEH2_TRY
621         {
622             ProbeForWrite(RequiredPrivileges,
623                           FIELD_OFFSET(PRIVILEGE_SET,
624                                        Privilege),
625                           sizeof(ULONG));
626 
627             PrivilegeCount = RequiredPrivileges->PrivilegeCount;
628             PrivilegeControl = RequiredPrivileges->Control;
629 
630             /* Check PrivilegeCount to avoid an integer overflow! */
631             if (FIELD_OFFSET(PRIVILEGE_SET,
632                              Privilege[PrivilegeCount]) /
633                 sizeof(RequiredPrivileges->Privilege[0]) != PrivilegeCount)
634             {
635                 _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
636             }
637 
638             /* probe all of the array */
639             ProbeForWrite(RequiredPrivileges,
640                           FIELD_OFFSET(PRIVILEGE_SET,
641                                        Privilege[PrivilegeCount]),
642                           sizeof(ULONG));
643 
644             ProbeForWriteBoolean(Result);
645         }
646         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
647         {
648             /* Return the exception code */
649             _SEH2_YIELD(return _SEH2_GetExceptionCode());
650         }
651         _SEH2_END;
652     }
653     else
654     {
655         PrivilegeCount = RequiredPrivileges->PrivilegeCount;
656         PrivilegeControl = RequiredPrivileges->Control;
657     }
658 
659     /* reference the token and make sure we're
660      not doing an anonymous impersonation */
661     Status = ObReferenceObjectByHandle(ClientToken,
662                                        TOKEN_QUERY,
663                                        SeTokenObjectType,
664                                        PreviousMode,
665                                        (PVOID*)&Token,
666                                        NULL);
667     if (!NT_SUCCESS(Status))
668     {
669         return Status;
670     }
671 
672     if (Token->TokenType == TokenImpersonation &&
673         Token->ImpersonationLevel < SecurityIdentification)
674     {
675         ObDereferenceObject(Token);
676         return STATUS_BAD_IMPERSONATION_LEVEL;
677     }
678 
679     /* capture the privileges */
680     Status = SeCaptureLuidAndAttributesArray(RequiredPrivileges->Privilege,
681                                              PrivilegeCount,
682                                              PreviousMode,
683                                              NULL,
684                                              0,
685                                              PagedPool,
686                                              TRUE,
687                                              &Privileges,
688                                              &Length);
689     if (!NT_SUCCESS(Status))
690     {
691         ObDereferenceObject (Token);
692         return Status;
693     }
694 
695     CheckResult = SepPrivilegeCheck(Token,
696                                     Privileges,
697                                     PrivilegeCount,
698                                     PrivilegeControl,
699                                     PreviousMode);
700 
701     ObDereferenceObject(Token);
702 
703     /* return the array */
704     _SEH2_TRY
705     {
706         RtlCopyMemory(RequiredPrivileges->Privilege,
707                       Privileges,
708                       PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
709         *Result = CheckResult;
710         Status = STATUS_SUCCESS;
711     }
712     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
713     {
714         Status = _SEH2_GetExceptionCode();
715     }
716     _SEH2_END;
717 
718     SeReleaseLuidAndAttributesArray(Privileges,
719                                     PreviousMode,
720                                     TRUE);
721 
722     return Status;
723 }
724 
725 /* EOF */
726