[NTOSKRNL] Minor PnP enhancements.
[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 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 */