[NTOS:INBV] Implement rotation bar for boot screen
[reactos.git] / ntoskrnl / se / accesschk.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/se/accesschk.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 /* GLOBALS ********************************************************************/
17
18
19 /* PRIVATE FUNCTIONS **********************************************************/
20
21 /*
22 * FIXME: Incomplete!
23 */
24 BOOLEAN NTAPI
25 SepAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
26 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
27 IN ACCESS_MASK DesiredAccess,
28 IN POBJECT_TYPE_LIST ObjectTypeList,
29 IN ULONG ObjectTypeListLength,
30 IN ACCESS_MASK PreviouslyGrantedAccess,
31 OUT PPRIVILEGE_SET* Privileges,
32 IN PGENERIC_MAPPING GenericMapping,
33 IN KPROCESSOR_MODE AccessMode,
34 OUT PACCESS_MASK GrantedAccessList,
35 OUT PNTSTATUS AccessStatusList,
36 IN BOOLEAN UseResultList)
37 {
38 ACCESS_MASK RemainingAccess;
39 ACCESS_MASK TempAccess;
40 ACCESS_MASK TempGrantedAccess = 0;
41 ACCESS_MASK TempDeniedAccess = 0;
42 PACCESS_TOKEN Token;
43 ULONG i, ResultListLength;
44 PACL Dacl;
45 BOOLEAN Present;
46 BOOLEAN Defaulted;
47 PACE CurrentAce;
48 PSID Sid;
49 NTSTATUS Status;
50 PAGED_CODE();
51
52 DPRINT("SepAccessCheck()\n");
53
54 /* Check for no access desired */
55 if (!DesiredAccess)
56 {
57 /* Check if we had no previous access */
58 if (!PreviouslyGrantedAccess)
59 {
60 /* Then there's nothing to give */
61 Status = STATUS_ACCESS_DENIED;
62 goto ReturnCommonStatus;
63 }
64
65 /* Return the previous access only */
66 Status = STATUS_SUCCESS;
67 *Privileges = NULL;
68 goto ReturnCommonStatus;
69 }
70
71 /* Map given accesses */
72 RtlMapGenericMask(&DesiredAccess, GenericMapping);
73 if (PreviouslyGrantedAccess)
74 RtlMapGenericMask(&PreviouslyGrantedAccess, GenericMapping);
75
76 /* Initialize remaining access rights */
77 RemainingAccess = DesiredAccess;
78
79 Token = SubjectSecurityContext->ClientToken ?
80 SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken;
81
82 /* Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access */
83 Status = SePrivilegePolicyCheck(&RemainingAccess,
84 &PreviouslyGrantedAccess,
85 NULL,
86 Token,
87 NULL,
88 UserMode);
89 if (!NT_SUCCESS(Status))
90 {
91 goto ReturnCommonStatus;
92 }
93
94 /* Succeed if there are no more rights to grant */
95 if (RemainingAccess == 0)
96 {
97 Status = STATUS_SUCCESS;
98 goto ReturnCommonStatus;
99 }
100
101 /* Get the DACL */
102 Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
103 &Present,
104 &Dacl,
105 &Defaulted);
106 if (!NT_SUCCESS(Status))
107 {
108 goto ReturnCommonStatus;
109 }
110
111 /* RULE 1: Grant desired access if the object is unprotected */
112 if (Present == FALSE || Dacl == NULL)
113 {
114 PreviouslyGrantedAccess |= RemainingAccess;
115 if (RemainingAccess & MAXIMUM_ALLOWED)
116 {
117 PreviouslyGrantedAccess &= ~MAXIMUM_ALLOWED;
118 PreviouslyGrantedAccess |= GenericMapping->GenericAll;
119 }
120
121 Status = STATUS_SUCCESS;
122 goto ReturnCommonStatus;
123 }
124
125 /* Deny access if the DACL is empty */
126 if (Dacl->AceCount == 0)
127 {
128 if (RemainingAccess == MAXIMUM_ALLOWED && PreviouslyGrantedAccess != 0)
129 {
130 Status = STATUS_SUCCESS;
131 }
132 else
133 {
134 PreviouslyGrantedAccess = 0;
135 Status = STATUS_ACCESS_DENIED;
136 }
137 goto ReturnCommonStatus;
138 }
139
140 /* Determine the MAXIMUM_ALLOWED access rights according to the DACL */
141 if (DesiredAccess & MAXIMUM_ALLOWED)
142 {
143 CurrentAce = (PACE)(Dacl + 1);
144 for (i = 0; i < Dacl->AceCount; i++)
145 {
146 if (!(CurrentAce->Header.AceFlags & INHERIT_ONLY_ACE))
147 {
148 Sid = (PSID)(CurrentAce + 1);
149 if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE)
150 {
151 if (SepSidInToken(Token, Sid))
152 {
153 /* Map access rights from the ACE */
154 TempAccess = CurrentAce->AccessMask;
155 RtlMapGenericMask(&TempAccess, GenericMapping);
156
157 /* Deny access rights that have not been granted yet */
158 TempDeniedAccess |= (TempAccess & ~TempGrantedAccess);
159 }
160 }
161 else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
162 {
163 if (SepSidInToken(Token, Sid))
164 {
165 /* Map access rights from the ACE */
166 TempAccess = CurrentAce->AccessMask;
167 RtlMapGenericMask(&TempAccess, GenericMapping);
168
169 /* Grant access rights that have not been denied yet */
170 TempGrantedAccess |= (TempAccess & ~TempDeniedAccess);
171 }
172 }
173 else
174 {
175 DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType);
176 }
177 }
178
179 /* Get the next ACE */
180 CurrentAce = (PACE)((ULONG_PTR)CurrentAce + CurrentAce->Header.AceSize);
181 }
182
183 /* Fail if some rights have not been granted */
184 RemainingAccess &= ~(MAXIMUM_ALLOWED | TempGrantedAccess);
185 if (RemainingAccess != 0)
186 {
187 PreviouslyGrantedAccess = 0;
188 Status = STATUS_ACCESS_DENIED;
189 goto ReturnCommonStatus;
190 }
191
192 /* Set granted access right and access status */
193 PreviouslyGrantedAccess |= TempGrantedAccess;
194 if (PreviouslyGrantedAccess != 0)
195 {
196 Status = STATUS_SUCCESS;
197 }
198 else
199 {
200 Status = STATUS_ACCESS_DENIED;
201 }
202 goto ReturnCommonStatus;
203 }
204
205 /* RULE 4: Grant rights according to the DACL */
206 CurrentAce = (PACE)(Dacl + 1);
207 for (i = 0; i < Dacl->AceCount; i++)
208 {
209 if (!(CurrentAce->Header.AceFlags & INHERIT_ONLY_ACE))
210 {
211 Sid = (PSID)(CurrentAce + 1);
212 if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE)
213 {
214 if (SepSidInToken(Token, Sid))
215 {
216 /* Map access rights from the ACE */
217 TempAccess = CurrentAce->AccessMask;
218 RtlMapGenericMask(&TempAccess, GenericMapping);
219
220 /* Leave if a remaining right must be denied */
221 if (RemainingAccess & TempAccess)
222 break;
223 }
224 }
225 else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
226 {
227 if (SepSidInToken(Token, Sid))
228 {
229 /* Map access rights from the ACE */
230 TempAccess = CurrentAce->AccessMask;
231 DPRINT("TempAccess 0x%08lx\n", TempAccess);
232 RtlMapGenericMask(&TempAccess, GenericMapping);
233
234 /* Remove granted rights */
235 DPRINT("RemainingAccess 0x%08lx TempAccess 0x%08lx\n", RemainingAccess, TempAccess);
236 RemainingAccess &= ~TempAccess;
237 DPRINT("RemainingAccess 0x%08lx\n", RemainingAccess);
238 }
239 }
240 else
241 {
242 DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType);
243 }
244 }
245
246 /* Get the next ACE */
247 CurrentAce = (PACE)((ULONG_PTR)CurrentAce + CurrentAce->Header.AceSize);
248 }
249
250 DPRINT("DesiredAccess %08lx\nPreviouslyGrantedAccess %08lx\nRemainingAccess %08lx\n",
251 DesiredAccess, PreviouslyGrantedAccess, RemainingAccess);
252
253 /* Fail if some rights have not been granted */
254 if (RemainingAccess != 0)
255 {
256 DPRINT("HACK: RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", RemainingAccess, DesiredAccess);
257 #if 0
258 /* HACK HACK HACK */
259 Status = STATUS_ACCESS_DENIED;
260 goto ReturnCommonStatus;
261 #endif
262 }
263
264 /* Set granted access rights */
265 PreviouslyGrantedAccess |= DesiredAccess;
266
267 /* Fail if no rights have been granted */
268 if (PreviouslyGrantedAccess == 0)
269 {
270 DPRINT1("PreviouslyGrantedAccess == 0 DesiredAccess = %08lx\n", DesiredAccess);
271 Status = STATUS_ACCESS_DENIED;
272 goto ReturnCommonStatus;
273 }
274
275 Status = STATUS_SUCCESS;
276 goto ReturnCommonStatus;
277
278 ReturnCommonStatus:
279 ResultListLength = UseResultList ? ObjectTypeListLength : 1;
280 for (i = 0; i < ResultListLength; i++)
281 {
282 GrantedAccessList[i] = PreviouslyGrantedAccess;
283 AccessStatusList[i] = Status;
284 }
285
286 return NT_SUCCESS(Status);
287 }
288
289 static PSID
290 SepGetSDOwner(IN PSECURITY_DESCRIPTOR _SecurityDescriptor)
291 {
292 PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor;
293 PSID Owner;
294
295 if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
296 Owner = (PSID)((ULONG_PTR)SecurityDescriptor->Owner +
297 (ULONG_PTR)SecurityDescriptor);
298 else
299 Owner = (PSID)SecurityDescriptor->Owner;
300
301 return Owner;
302 }
303
304 static PSID
305 SepGetSDGroup(IN PSECURITY_DESCRIPTOR _SecurityDescriptor)
306 {
307 PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor;
308 PSID Group;
309
310 if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
311 Group = (PSID)((ULONG_PTR)SecurityDescriptor->Group +
312 (ULONG_PTR)SecurityDescriptor);
313 else
314 Group = (PSID)SecurityDescriptor->Group;
315
316 return Group;
317 }
318
319 static
320 ULONG
321 SepGetPrivilegeSetLength(IN PPRIVILEGE_SET PrivilegeSet)
322 {
323 if (PrivilegeSet == NULL)
324 return 0;
325
326 if (PrivilegeSet->PrivilegeCount == 0)
327 return (ULONG)(sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES));
328
329 return (ULONG)(sizeof(PRIVILEGE_SET) +
330 (PrivilegeSet->PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES));
331 }
332
333 /* PUBLIC FUNCTIONS ***********************************************************/
334
335 /*
336 * @implemented
337 */
338 BOOLEAN
339 NTAPI
340 SeAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
341 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
342 IN BOOLEAN SubjectContextLocked,
343 IN ACCESS_MASK DesiredAccess,
344 IN ACCESS_MASK PreviouslyGrantedAccess,
345 OUT PPRIVILEGE_SET* Privileges,
346 IN PGENERIC_MAPPING GenericMapping,
347 IN KPROCESSOR_MODE AccessMode,
348 OUT PACCESS_MASK GrantedAccess,
349 OUT PNTSTATUS AccessStatus)
350 {
351 BOOLEAN ret;
352
353 PAGED_CODE();
354
355 /* Check if this is kernel mode */
356 if (AccessMode == KernelMode)
357 {
358 /* Check if kernel wants everything */
359 if (DesiredAccess & MAXIMUM_ALLOWED)
360 {
361 /* Give it */
362 *GrantedAccess = GenericMapping->GenericAll;
363 *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED);
364 *GrantedAccess |= PreviouslyGrantedAccess;
365 }
366 else
367 {
368 /* Give the desired and previous access */
369 *GrantedAccess = DesiredAccess | PreviouslyGrantedAccess;
370 }
371
372 /* Success */
373 *AccessStatus = STATUS_SUCCESS;
374 return TRUE;
375 }
376
377 /* Check if we didn't get an SD */
378 if (!SecurityDescriptor)
379 {
380 /* Automatic failure */
381 *AccessStatus = STATUS_ACCESS_DENIED;
382 return FALSE;
383 }
384
385 /* Check for invalid impersonation */
386 if ((SubjectSecurityContext->ClientToken) &&
387 (SubjectSecurityContext->ImpersonationLevel < SecurityImpersonation))
388 {
389 *AccessStatus = STATUS_BAD_IMPERSONATION_LEVEL;
390 return FALSE;
391 }
392
393 /* Acquire the lock if needed */
394 if (!SubjectContextLocked)
395 SeLockSubjectContext(SubjectSecurityContext);
396
397 /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
398 if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED))
399 {
400 PACCESS_TOKEN Token = SubjectSecurityContext->ClientToken ?
401 SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken;
402
403 if (SepTokenIsOwner(Token,
404 SecurityDescriptor,
405 FALSE))
406 {
407 if (DesiredAccess & MAXIMUM_ALLOWED)
408 PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL);
409 else
410 PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL));
411
412 DesiredAccess &= ~(WRITE_DAC | READ_CONTROL);
413 }
414 }
415
416 if (DesiredAccess == 0)
417 {
418 *GrantedAccess = PreviouslyGrantedAccess;
419 if (PreviouslyGrantedAccess == 0)
420 {
421 DPRINT1("Request for zero access to an object. Denying.\n");
422 *AccessStatus = STATUS_ACCESS_DENIED;
423 ret = FALSE;
424 }
425 else
426 {
427 *AccessStatus = STATUS_SUCCESS;
428 ret = TRUE;
429 }
430 }
431 else
432 {
433 /* Call the internal function */
434 ret = SepAccessCheck(SecurityDescriptor,
435 SubjectSecurityContext,
436 DesiredAccess,
437 NULL,
438 0,
439 PreviouslyGrantedAccess,
440 Privileges,
441 GenericMapping,
442 AccessMode,
443 GrantedAccess,
444 AccessStatus,
445 FALSE);
446 }
447
448 /* Release the lock if needed */
449 if (!SubjectContextLocked)
450 SeUnlockSubjectContext(SubjectSecurityContext);
451
452 return ret;
453 }
454
455 /*
456 * @implemented
457 */
458 BOOLEAN
459 NTAPI
460 SeFastTraverseCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
461 IN PACCESS_STATE AccessState,
462 IN ACCESS_MASK DesiredAccess,
463 IN KPROCESSOR_MODE AccessMode)
464 {
465 PACL Dacl;
466 ULONG AceIndex;
467 PKNOWN_ACE Ace;
468
469 PAGED_CODE();
470
471 ASSERT(AccessMode != KernelMode);
472
473 if (SecurityDescriptor == NULL)
474 return FALSE;
475
476 /* Get DACL */
477 Dacl = SepGetDaclFromDescriptor(SecurityDescriptor);
478 /* If no DACL, grant access */
479 if (Dacl == NULL)
480 return TRUE;
481
482 /* No ACE -> Deny */
483 if (!Dacl->AceCount)
484 return FALSE;
485
486 /* Can't perform the check on restricted token */
487 if (AccessState->Flags & TOKEN_IS_RESTRICTED)
488 return FALSE;
489
490 /* Browse the ACEs */
491 for (AceIndex = 0, Ace = (PKNOWN_ACE)((ULONG_PTR)Dacl + sizeof(ACL));
492 AceIndex < Dacl->AceCount;
493 AceIndex++, Ace = (PKNOWN_ACE)((ULONG_PTR)Ace + Ace->Header.AceSize))
494 {
495 if (Ace->Header.AceFlags & INHERIT_ONLY_ACE)
496 continue;
497
498 /* If access-allowed ACE */
499 if (Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
500 {
501 /* Check if all accesses are granted */
502 if (!(Ace->Mask & DesiredAccess))
503 continue;
504
505 /* Check SID and grant access if matching */
506 if (RtlEqualSid(SeWorldSid, &(Ace->SidStart)))
507 return TRUE;
508 }
509 /* If access-denied ACE */
510 else if (Ace->Header.AceType == ACCESS_DENIED_ACE_TYPE)
511 {
512 /* Here, only check if it denies any access wanted and deny if so */
513 if (Ace->Mask & DesiredAccess)
514 return FALSE;
515 }
516 }
517
518 /* Faulty, deny */
519 return FALSE;
520 }
521
522 /* SYSTEM CALLS ***************************************************************/
523
524 /*
525 * @implemented
526 */
527 NTSTATUS
528 NTAPI
529 NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
530 IN HANDLE TokenHandle,
531 IN ACCESS_MASK DesiredAccess,
532 IN PGENERIC_MAPPING GenericMapping,
533 OUT PPRIVILEGE_SET PrivilegeSet OPTIONAL,
534 IN OUT PULONG PrivilegeSetLength,
535 OUT PACCESS_MASK GrantedAccess,
536 OUT PNTSTATUS AccessStatus)
537 {
538 PSECURITY_DESCRIPTOR CapturedSecurityDescriptor = NULL;
539 SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
540 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
541 ACCESS_MASK PreviouslyGrantedAccess = 0;
542 PPRIVILEGE_SET Privileges = NULL;
543 ULONG CapturedPrivilegeSetLength, RequiredPrivilegeSetLength;
544 PTOKEN Token;
545 NTSTATUS Status;
546 PAGED_CODE();
547
548 /* Check if this is kernel mode */
549 if (PreviousMode == KernelMode)
550 {
551 /* Check if kernel wants everything */
552 if (DesiredAccess & MAXIMUM_ALLOWED)
553 {
554 /* Give it */
555 *GrantedAccess = GenericMapping->GenericAll;
556 *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED);
557 }
558 else
559 {
560 /* Just give the desired access */
561 *GrantedAccess = DesiredAccess;
562 }
563
564 /* Success */
565 *AccessStatus = STATUS_SUCCESS;
566 return STATUS_SUCCESS;
567 }
568
569 /* Protect probe in SEH */
570 _SEH2_TRY
571 {
572 /* Probe all pointers */
573 ProbeForRead(GenericMapping, sizeof(GENERIC_MAPPING), sizeof(ULONG));
574 ProbeForRead(PrivilegeSetLength, sizeof(ULONG), sizeof(ULONG));
575 ProbeForWrite(PrivilegeSet, *PrivilegeSetLength, sizeof(ULONG));
576 ProbeForWrite(GrantedAccess, sizeof(ACCESS_MASK), sizeof(ULONG));
577 ProbeForWrite(AccessStatus, sizeof(NTSTATUS), sizeof(ULONG));
578
579 /* Capture the privilege set length and the mapping */
580 CapturedPrivilegeSetLength = *PrivilegeSetLength;
581 }
582 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
583 {
584 /* Return the exception code */
585 _SEH2_YIELD(return _SEH2_GetExceptionCode());
586 }
587 _SEH2_END;
588
589 /* Check for unmapped access rights */
590 if (DesiredAccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL))
591 return STATUS_GENERIC_NOT_MAPPED;
592
593 /* Reference the token */
594 Status = ObReferenceObjectByHandle(TokenHandle,
595 TOKEN_QUERY,
596 SeTokenObjectType,
597 PreviousMode,
598 (PVOID*)&Token,
599 NULL);
600 if (!NT_SUCCESS(Status))
601 {
602 DPRINT("Failed to reference token (Status %lx)\n", Status);
603 return Status;
604 }
605
606 /* Check token type */
607 if (Token->TokenType != TokenImpersonation)
608 {
609 DPRINT("No impersonation token\n");
610 ObDereferenceObject(Token);
611 return STATUS_NO_IMPERSONATION_TOKEN;
612 }
613
614 /* Check the impersonation level */
615 if (Token->ImpersonationLevel < SecurityIdentification)
616 {
617 DPRINT("Impersonation level < SecurityIdentification\n");
618 ObDereferenceObject(Token);
619 return STATUS_BAD_IMPERSONATION_LEVEL;
620 }
621
622 /* Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access */
623 Status = SePrivilegePolicyCheck(&DesiredAccess,
624 &PreviouslyGrantedAccess,
625 NULL,
626 Token,
627 &Privileges,
628 PreviousMode);
629 if (!NT_SUCCESS(Status))
630 {
631 DPRINT("SePrivilegePolicyCheck failed (Status 0x%08lx)\n", Status);
632 ObDereferenceObject(Token);
633 *AccessStatus = Status;
634 *GrantedAccess = 0;
635 return STATUS_SUCCESS;
636 }
637
638 /* Check the size of the privilege set and return the privileges */
639 if (Privileges != NULL)
640 {
641 DPRINT("Privileges != NULL\n");
642
643 /* Calculate the required privilege set buffer size */
644 RequiredPrivilegeSetLength = SepGetPrivilegeSetLength(Privileges);
645
646 /* Fail if the privilege set buffer is too small */
647 if (CapturedPrivilegeSetLength < RequiredPrivilegeSetLength)
648 {
649 ObDereferenceObject(Token);
650 SeFreePrivileges(Privileges);
651 *PrivilegeSetLength = RequiredPrivilegeSetLength;
652 return STATUS_BUFFER_TOO_SMALL;
653 }
654
655 /* Copy the privilege set to the caller */
656 RtlCopyMemory(PrivilegeSet,
657 Privileges,
658 RequiredPrivilegeSetLength);
659
660 /* Free the local privilege set */
661 SeFreePrivileges(Privileges);
662 }
663 else
664 {
665 DPRINT("Privileges == NULL\n");
666
667 /* Fail if the privilege set buffer is too small */
668 if (CapturedPrivilegeSetLength < sizeof(PRIVILEGE_SET))
669 {
670 ObDereferenceObject(Token);
671 *PrivilegeSetLength = sizeof(PRIVILEGE_SET);
672 return STATUS_BUFFER_TOO_SMALL;
673 }
674
675 /* Initialize the privilege set */
676 PrivilegeSet->PrivilegeCount = 0;
677 PrivilegeSet->Control = 0;
678 }
679
680 /* Capture the security descriptor */
681 Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
682 PreviousMode,
683 PagedPool,
684 FALSE,
685 &CapturedSecurityDescriptor);
686 if (!NT_SUCCESS(Status))
687 {
688 DPRINT("Failed to capture the Security Descriptor\n");
689 ObDereferenceObject(Token);
690 return Status;
691 }
692
693 /* Check the captured security descriptor */
694 if (CapturedSecurityDescriptor == NULL)
695 {
696 DPRINT("Security Descriptor is NULL\n");
697 ObDereferenceObject(Token);
698 return STATUS_INVALID_SECURITY_DESCR;
699 }
700
701 /* Check security descriptor for valid owner and group */
702 if (SepGetSDOwner(SecurityDescriptor) == NULL || // FIXME: use CapturedSecurityDescriptor
703 SepGetSDGroup(SecurityDescriptor) == NULL) // FIXME: use CapturedSecurityDescriptor
704 {
705 DPRINT("Security Descriptor does not have a valid group or owner\n");
706 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor,
707 PreviousMode,
708 FALSE);
709 ObDereferenceObject(Token);
710 return STATUS_INVALID_SECURITY_DESCR;
711 }
712
713 /* Set up the subject context, and lock it */
714 SeCaptureSubjectContext(&SubjectSecurityContext);
715
716 /* Lock the token */
717 SepAcquireTokenLockShared(Token);
718
719 /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
720 if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED))
721 {
722 if (SepTokenIsOwner(Token, SecurityDescriptor, FALSE)) // FIXME: use CapturedSecurityDescriptor
723 {
724 if (DesiredAccess & MAXIMUM_ALLOWED)
725 PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL);
726 else
727 PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL));
728
729 DesiredAccess &= ~(WRITE_DAC | READ_CONTROL);
730 }
731 }
732
733 if (DesiredAccess == 0)
734 {
735 *GrantedAccess = PreviouslyGrantedAccess;
736 *AccessStatus = STATUS_SUCCESS;
737 }
738 else
739 {
740 /* Now perform the access check */
741 SepAccessCheck(SecurityDescriptor, // FIXME: use CapturedSecurityDescriptor
742 &SubjectSecurityContext,
743 DesiredAccess,
744 NULL,
745 0,
746 PreviouslyGrantedAccess,
747 &PrivilegeSet, //FIXME
748 GenericMapping,
749 PreviousMode,
750 GrantedAccess,
751 AccessStatus,
752 FALSE);
753 }
754
755 /* Release subject context and unlock the token */
756 SeReleaseSubjectContext(&SubjectSecurityContext);
757 SepReleaseTokenLock(Token);
758
759 /* Release the captured security descriptor */
760 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor,
761 PreviousMode,
762 FALSE);
763
764 /* Dereference the token */
765 ObDereferenceObject(Token);
766
767 /* Check succeeded */
768 return STATUS_SUCCESS;
769 }
770
771
772 NTSTATUS
773 NTAPI
774 NtAccessCheckByType(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
775 IN PSID PrincipalSelfSid,
776 IN HANDLE ClientToken,
777 IN ACCESS_MASK DesiredAccess,
778 IN POBJECT_TYPE_LIST ObjectTypeList,
779 IN ULONG ObjectTypeLength,
780 IN PGENERIC_MAPPING GenericMapping,
781 IN PPRIVILEGE_SET PrivilegeSet,
782 IN OUT PULONG PrivilegeSetLength,
783 OUT PACCESS_MASK GrantedAccess,
784 OUT PNTSTATUS AccessStatus)
785 {
786 UNIMPLEMENTED;
787 return STATUS_NOT_IMPLEMENTED;
788 }
789
790 NTSTATUS
791 NTAPI
792 NtAccessCheckByTypeResultList(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
793 IN PSID PrincipalSelfSid,
794 IN HANDLE ClientToken,
795 IN ACCESS_MASK DesiredAccess,
796 IN POBJECT_TYPE_LIST ObjectTypeList,
797 IN ULONG ObjectTypeLength,
798 IN PGENERIC_MAPPING GenericMapping,
799 IN PPRIVILEGE_SET PrivilegeSet,
800 IN OUT PULONG PrivilegeSetLength,
801 OUT PACCESS_MASK GrantedAccess,
802 OUT PNTSTATUS AccessStatus)
803 {
804 UNIMPLEMENTED;
805 return STATUS_NOT_IMPLEMENTED;
806 }
807
808 /* EOF */