* Sync up to trunk head (r65183).
[reactos.git] / ntoskrnl / se / priv.c
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 VOID
62 INIT_FUNCTION
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 NT_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, 'rPeS');
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 = ExAllocatePool(PoolType,
356 BufferSize);
357 if (*Dest == NULL)
358 {
359 return STATUS_INSUFFICIENT_RESOURCES;
360 }
361 }
362
363 /* copy the array to the buffer */
364 _SEH2_TRY
365 {
366 RtlCopyMemory(*Dest,
367 Src,
368 BufferSize);
369 }
370 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
371 {
372 Status = _SEH2_GetExceptionCode();
373 }
374 _SEH2_END;
375
376 if (!NT_SUCCESS(Status) && AllocatedMem == NULL)
377 {
378 ExFreePool(*Dest);
379 }
380
381 return Status;
382 }
383
384 VOID
385 NTAPI
386 SeReleaseLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Privilege,
387 KPROCESSOR_MODE PreviousMode,
388 BOOLEAN CaptureIfKernel)
389 {
390 PAGED_CODE();
391
392 if (Privilege != NULL &&
393 (PreviousMode != KernelMode || CaptureIfKernel))
394 {
395 ExFreePool(Privilege);
396 }
397 }
398
399 /* PUBLIC FUNCTIONS ***********************************************************/
400
401 /*
402 * @implemented
403 */
404 NTSTATUS
405 NTAPI
406 SeAppendPrivileges(IN OUT PACCESS_STATE AccessState,
407 IN PPRIVILEGE_SET Privileges)
408 {
409 PAUX_ACCESS_DATA AuxData;
410 ULONG OldPrivilegeSetSize;
411 ULONG NewPrivilegeSetSize;
412 PPRIVILEGE_SET PrivilegeSet;
413
414 PAGED_CODE();
415
416 /* Get the Auxiliary Data */
417 AuxData = AccessState->AuxData;
418
419 /* Calculate the size of the old privilege set */
420 OldPrivilegeSetSize = sizeof(PRIVILEGE_SET) +
421 (AuxData->PrivilegeSet->PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES);
422
423 if (AuxData->PrivilegeSet->PrivilegeCount +
424 Privileges->PrivilegeCount > INITIAL_PRIVILEGE_COUNT)
425 {
426 /* Calculate the size of the new privilege set */
427 NewPrivilegeSetSize = OldPrivilegeSetSize +
428 Privileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
429
430 /* Allocate a new privilege set */
431 PrivilegeSet = ExAllocatePool(PagedPool, NewPrivilegeSetSize);
432 if (PrivilegeSet == NULL)
433 return STATUS_INSUFFICIENT_RESOURCES;
434
435 /* Copy original privileges from the acess state */
436 RtlCopyMemory(PrivilegeSet,
437 AuxData->PrivilegeSet,
438 OldPrivilegeSetSize);
439
440 /* Append privileges from the privilege set*/
441 RtlCopyMemory((PVOID)((ULONG_PTR)PrivilegeSet + OldPrivilegeSetSize),
442 (PVOID)((ULONG_PTR)Privileges + sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES)),
443 Privileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
444
445 /* Adjust the number of privileges in the new privilege set */
446 PrivilegeSet->PrivilegeCount += Privileges->PrivilegeCount;
447
448 /* Free the old privilege set if it was allocated */
449 if (AccessState->PrivilegesAllocated == TRUE)
450 ExFreePool(AuxData->PrivilegeSet);
451
452 /* Now we are using an allocated privilege set */
453 AccessState->PrivilegesAllocated = TRUE;
454
455 /* Assign the new privileges to the access state */
456 AuxData->PrivilegeSet = PrivilegeSet;
457 }
458 else
459 {
460 /* Append privileges */
461 RtlCopyMemory((PVOID)((ULONG_PTR)AuxData->PrivilegeSet + OldPrivilegeSetSize),
462 (PVOID)((ULONG_PTR)Privileges + sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES)),
463 Privileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
464
465 /* Adjust the number of privileges in the target privilege set */
466 AuxData->PrivilegeSet->PrivilegeCount += Privileges->PrivilegeCount;
467 }
468
469 return STATUS_SUCCESS;
470 }
471
472 /*
473 * @implemented
474 */
475 VOID
476 NTAPI
477 SeFreePrivileges(IN PPRIVILEGE_SET Privileges)
478 {
479 PAGED_CODE();
480 ExFreePool(Privileges);
481 }
482
483 /*
484 * @implemented
485 */
486 BOOLEAN
487 NTAPI
488 SePrivilegeCheck(PPRIVILEGE_SET Privileges,
489 PSECURITY_SUBJECT_CONTEXT SubjectContext,
490 KPROCESSOR_MODE PreviousMode)
491 {
492 PACCESS_TOKEN Token = NULL;
493
494 PAGED_CODE();
495
496 if (SubjectContext->ClientToken == NULL)
497 {
498 Token = SubjectContext->PrimaryToken;
499 }
500 else
501 {
502 Token = SubjectContext->ClientToken;
503 if (SubjectContext->ImpersonationLevel < 2)
504 {
505 return FALSE;
506 }
507 }
508
509 return SepPrivilegeCheck(Token,
510 Privileges->Privilege,
511 Privileges->PrivilegeCount,
512 Privileges->Control,
513 PreviousMode);
514 }
515
516 /*
517 * @implemented
518 */
519 BOOLEAN
520 NTAPI
521 SeSinglePrivilegeCheck(IN LUID PrivilegeValue,
522 IN KPROCESSOR_MODE PreviousMode)
523 {
524 SECURITY_SUBJECT_CONTEXT SubjectContext;
525 PRIVILEGE_SET Priv;
526 BOOLEAN Result;
527
528 PAGED_CODE();
529
530 SeCaptureSubjectContext(&SubjectContext);
531
532 Priv.PrivilegeCount = 1;
533 Priv.Control = PRIVILEGE_SET_ALL_NECESSARY;
534 Priv.Privilege[0].Luid = PrivilegeValue;
535 Priv.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
536
537 Result = SePrivilegeCheck(&Priv,
538 &SubjectContext,
539 PreviousMode);
540
541 if (PreviousMode != KernelMode)
542 {
543 SePrivilegedServiceAuditAlarm(NULL,
544 &SubjectContext,
545 &Priv,
546 Result);
547
548 }
549
550 SeReleaseSubjectContext(&SubjectContext);
551
552 return Result;
553 }
554
555 BOOLEAN
556 NTAPI
557 SeCheckPrivilegedObject(IN LUID PrivilegeValue,
558 IN HANDLE ObjectHandle,
559 IN ACCESS_MASK DesiredAccess,
560 IN KPROCESSOR_MODE PreviousMode)
561 {
562 SECURITY_SUBJECT_CONTEXT SubjectContext;
563 PRIVILEGE_SET Priv;
564 BOOLEAN Result;
565
566 PAGED_CODE();
567
568 SeCaptureSubjectContext(&SubjectContext);
569
570 Priv.PrivilegeCount = 1;
571 Priv.Control = PRIVILEGE_SET_ALL_NECESSARY;
572 Priv.Privilege[0].Luid = PrivilegeValue;
573 Priv.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
574
575 Result = SePrivilegeCheck(&Priv, &SubjectContext, PreviousMode);
576 if (PreviousMode != KernelMode)
577 {
578 #if 0
579 SePrivilegeObjectAuditAlarm(ObjectHandle,
580 &SubjectContext,
581 DesiredAccess,
582 &PrivilegeValue,
583 Result,
584 PreviousMode);
585 #endif
586 }
587
588 SeReleaseSubjectContext(&SubjectContext);
589
590 return Result;
591 }
592
593 /* SYSTEM CALLS ***************************************************************/
594
595 NTSTATUS
596 NTAPI
597 NtPrivilegeCheck(IN HANDLE ClientToken,
598 IN PPRIVILEGE_SET RequiredPrivileges,
599 OUT PBOOLEAN Result)
600 {
601 PLUID_AND_ATTRIBUTES Privileges;
602 PTOKEN Token;
603 ULONG PrivilegeCount = 0;
604 ULONG PrivilegeControl = 0;
605 ULONG Length;
606 BOOLEAN CheckResult;
607 KPROCESSOR_MODE PreviousMode;
608 NTSTATUS Status;
609
610 PAGED_CODE();
611
612 PreviousMode = KeGetPreviousMode();
613
614 /* probe the buffers */
615 if (PreviousMode != KernelMode)
616 {
617 _SEH2_TRY
618 {
619 ProbeForWrite(RequiredPrivileges,
620 FIELD_OFFSET(PRIVILEGE_SET,
621 Privilege),
622 sizeof(ULONG));
623
624 PrivilegeCount = RequiredPrivileges->PrivilegeCount;
625 PrivilegeControl = RequiredPrivileges->Control;
626
627 /* Check PrivilegeCount to avoid an integer overflow! */
628 if (FIELD_OFFSET(PRIVILEGE_SET,
629 Privilege[PrivilegeCount]) /
630 sizeof(RequiredPrivileges->Privilege[0]) != PrivilegeCount)
631 {
632 _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
633 }
634
635 /* probe all of the array */
636 ProbeForWrite(RequiredPrivileges,
637 FIELD_OFFSET(PRIVILEGE_SET,
638 Privilege[PrivilegeCount]),
639 sizeof(ULONG));
640
641 ProbeForWriteBoolean(Result);
642 }
643 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
644 {
645 /* Return the exception code */
646 _SEH2_YIELD(return _SEH2_GetExceptionCode());
647 }
648 _SEH2_END;
649 }
650 else
651 {
652 PrivilegeCount = RequiredPrivileges->PrivilegeCount;
653 PrivilegeControl = RequiredPrivileges->Control;
654 }
655
656 /* reference the token and make sure we're
657 not doing an anonymous impersonation */
658 Status = ObReferenceObjectByHandle(ClientToken,
659 TOKEN_QUERY,
660 SeTokenObjectType,
661 PreviousMode,
662 (PVOID*)&Token,
663 NULL);
664 if (!NT_SUCCESS(Status))
665 {
666 return Status;
667 }
668
669 if (Token->TokenType == TokenImpersonation &&
670 Token->ImpersonationLevel < SecurityIdentification)
671 {
672 ObDereferenceObject(Token);
673 return STATUS_BAD_IMPERSONATION_LEVEL;
674 }
675
676 /* capture the privileges */
677 Status = SeCaptureLuidAndAttributesArray(RequiredPrivileges->Privilege,
678 PrivilegeCount,
679 PreviousMode,
680 NULL,
681 0,
682 PagedPool,
683 TRUE,
684 &Privileges,
685 &Length);
686 if (!NT_SUCCESS(Status))
687 {
688 ObDereferenceObject (Token);
689 return Status;
690 }
691
692 CheckResult = SepPrivilegeCheck(Token,
693 Privileges,
694 PrivilegeCount,
695 PrivilegeControl,
696 PreviousMode);
697
698 ObDereferenceObject(Token);
699
700 /* return the array */
701 _SEH2_TRY
702 {
703 RtlCopyMemory(RequiredPrivileges->Privilege,
704 Privileges,
705 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
706 *Result = CheckResult;
707 Status = STATUS_SUCCESS;
708 }
709 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
710 {
711 Status = _SEH2_GetExceptionCode();
712 }
713 _SEH2_END;
714
715 SeReleaseLuidAndAttributesArray(Privileges,
716 PreviousMode,
717 TRUE);
718
719 return Status;
720 }
721
722 /* EOF */