SepExports.SeSystemEnvironmentPrivilege = SeSystemEnvironmentPrivilege;
SepExports.SeChangeNotifyPrivilege = SeChangeNotifyPrivilege;
SepExports.SeRemoteShutdownPrivilege = SeRemoteShutdownPrivilege;
-
+
SepExports.SeNullSid = SeNullSid;
SepExports.SeWorldSid = SeWorldSid;
SepExports.SeLocalSid = SeLocalSid;
SepExports.SeAuthenticatedUsersSid = SeAuthenticatedUsersSid;
SepExports.SeRestrictedSid = SeRestrictedSid;
SepExports.SeAnonymousLogonSid = SeAnonymousLogonSid;
-
+
SepExports.SeUndockPrivilege = SeUndockPrivilege;
SepExports.SeSyncAgentPrivilege = SeSyncAgentPrivilege;
SepExports.SeEnableDelegationPrivilege = SeEnableDelegationPrivilege;
-
+
SeExports = &SepExports;
return TRUE;
}
NTAPI
SepInitializationPhase0(VOID)
{
+ PAGED_CODE();
+
ExpInitLuid();
if (!SepInitSecurityIDs()) return FALSE;
if (!SepInitDACLs()) return FALSE;
if (!SepInitSDs()) return FALSE;
SepInitPrivileges();
if (!SepInitExports()) return FALSE;
-
+
/* Initialize the subject context lock */
ExInitializeResource(&SepSubjectContextLock);
-
+
/* Initialize token objects */
SepInitializeTokenImplementation();
-
+
/* Clear impersonation info for the idle thread */
PsGetCurrentThread()->ImpersonationInfo = NULL;
PspClearCrossThreadFlag(PsGetCurrentThread(),
CT_ACTIVE_IMPERSONATION_INFO_BIT);
-
+
/* Initialize the boot token */
ObInitializeFastReference(&PsGetCurrentProcess()->Token, NULL);
ObInitializeFastReference(&PsGetCurrentProcess()->Token,
{
NTSTATUS Status;
PAGED_CODE();
-
+
/* Insert the system token into the tree */
Status = ObInsertObject((PVOID)(PsGetCurrentProcess()->Token.Value &
~MAX_FAST_REFS),
NULL,
NULL);
ASSERT(NT_SUCCESS(Status));
-
+
/* FIXME: TODO \\ Security directory */
return TRUE;
}
switch (ExpInitializationPhase)
{
case 0:
-
+
/* Do Phase 0 */
return SepInitializationPhase0();
-
+
case 1:
-
+
/* Do Phase 1 */
return SepInitializationPhase1();
-
+
default:
-
+
/* Don't know any other phase! Bugcheck! */
KeBugCheckEx(UNEXPECTED_INITIALIZATION_CALL,
0,
HANDLE DirectoryHandle;
HANDLE EventHandle;
NTSTATUS Status;
-
+
/* Create '\Security' directory */
RtlInitUnicodeString(&Name,
L"\\Security");
DPRINT1("Failed to create 'Security' directory!\n");
return FALSE;
}
-
+
/* Create 'LSA_AUTHENTICATION_INITALIZED' event */
RtlInitUnicodeString(&Name,
L"\\LSA_AUTHENTICATION_INITALIZED");
NtClose(DirectoryHandle);
return FALSE;
}
-
+
ZwClose(EventHandle);
ZwClose(DirectoryHandle);
-
+
/* FIXME: Create SRM port and listener thread */
-
+
return TRUE;
}
IN PGENERIC_MAPPING GenericMapping)
{
PAGED_CODE();
-
+
/* Select the operation type */
switch (OperationType)
{
/* Setting a new descriptor */
case SetSecurityDescriptor:
-
+
/* Sanity check */
ASSERT((PoolType == PagedPool) || (PoolType == NonPagedPool));
-
+
/* Set the information */
return ObSetSecurityDescriptorInfo(Object,
SecurityInformation,
OldSecurityDescriptor,
PoolType,
GenericMapping);
-
+
case QuerySecurityDescriptor:
-
+
/* Query the information */
return ObQuerySecurityDescriptorInfo(Object,
SecurityInformation,
SecurityDescriptor,
ReturnLength,
OldSecurityDescriptor);
-
+
case DeleteSecurityDescriptor:
-
+
/* De-assign it */
return ObDeassignSecurity(OldSecurityDescriptor);
-
+
case AssignSecurityDescriptor:
-
+
/* Assign it */
ObAssignObjectSecurityDescriptor(Object, SecurityDescriptor, PoolType);
return STATUS_SUCCESS;
-
+
default:
-
+
/* Bug check */
KeBugCheckEx(SECURITY_SYSTEM, 0, STATUS_INVALID_PARAMETER, 0, 0);
}
-
+
/* Should never reach here */
ASSERT(FALSE);
return STATUS_SUCCESS;
}
+ULONG SidInTokenCalls = 0;
static BOOLEAN
SepSidInToken(PACCESS_TOKEN _Token,
{
ULONG i;
PTOKEN Token = (PTOKEN)_Token;
-
+
PAGED_CODE();
+
+ SidInTokenCalls++;
+ if (!(SidInTokenCalls % 10000)) DPRINT1("SidInToken Calls: %d\n", SidInTokenCalls);
if (Token->UserAndGroupCount == 0)
{
return FALSE;
}
-
+
for (i=0; i<Token->UserAndGroupCount; i++)
{
if (RtlEqualSid(Sid, Token->UserAndGroups[i].Sid))
{
- if (Token->UserAndGroups[i].Attributes & SE_GROUP_ENABLED)
+ if ((i == 0)|| (Token->UserAndGroups[i].Attributes & SE_GROUP_ENABLED))
{
return TRUE;
}
-
+
return FALSE;
}
}
-
+
return FALSE;
}
+static BOOLEAN
+SepTokenIsOwner(PACCESS_TOKEN Token,
+ PSECURITY_DESCRIPTOR SecurityDescriptor)
+{
+ NTSTATUS Status;
+ PSID Sid = NULL;
+ BOOLEAN Defaulted;
+
+ Status = RtlGetOwnerSecurityDescriptor(SecurityDescriptor,
+ &Sid,
+ &Defaulted);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("RtlGetOwnerSecurityDescriptor() failed (Status %lx)\n", Status);
+ return FALSE;
+ }
+
+ if (Sid == NULL)
+ {
+ DPRINT1("Owner Sid is NULL\n");
+ return FALSE;
+ }
+
+ return SepSidInToken(Token, Sid);
+}
VOID NTAPI
SeQuerySecurityAccessMask(IN SECURITY_INFORMATION SecurityInformation,
OUT PACCESS_MASK DesiredAccess)
{
*DesiredAccess = 0;
-
+
if (SecurityInformation & (OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION))
{
OUT PACCESS_MASK DesiredAccess)
{
*DesiredAccess = 0;
-
+
if (SecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
{
*DesiredAccess |= WRITE_OWNER;
}
}
-/* PUBLIC FUNCTIONS ***********************************************************/
-
-/*
- * @implemented
- */
BOOLEAN NTAPI
-SeAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
- IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
- IN BOOLEAN SubjectContextLocked,
- IN ACCESS_MASK DesiredAccess,
- IN ACCESS_MASK PreviouslyGrantedAccess,
- OUT PPRIVILEGE_SET* Privileges,
- IN PGENERIC_MAPPING GenericMapping,
- IN KPROCESSOR_MODE AccessMode,
- OUT PACCESS_MASK GrantedAccess,
- OUT PNTSTATUS AccessStatus)
+SepAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
+ IN ACCESS_MASK DesiredAccess,
+ IN ACCESS_MASK PreviouslyGrantedAccess,
+ OUT PPRIVILEGE_SET* Privileges,
+ IN PGENERIC_MAPPING GenericMapping,
+ IN KPROCESSOR_MODE AccessMode,
+ OUT PACCESS_MASK GrantedAccess,
+ OUT PNTSTATUS AccessStatus)
{
LUID_AND_ATTRIBUTES Privilege;
ACCESS_MASK CurrentAccess, AccessMask;
+ ACCESS_MASK RemainingAccess;
PACCESS_TOKEN Token;
ULONG i;
PACL Dacl;
PSID Sid;
NTSTATUS Status;
PAGED_CODE();
-
- /* Check if this is kernel mode */
- if (AccessMode == KernelMode)
- {
- /* Check if kernel wants everything */
- if (DesiredAccess & MAXIMUM_ALLOWED)
- {
- /* Give it */
- *GrantedAccess = GenericMapping->GenericAll;
- *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED);
- *GrantedAccess |= PreviouslyGrantedAccess;
- }
- else
- {
- /* Give the desired and previous access */
- *GrantedAccess = DesiredAccess | PreviouslyGrantedAccess;
- }
-
- /* Success */
- *AccessStatus = STATUS_SUCCESS;
- return TRUE;
- }
-
- /* Check if we didn't get an SD */
- if (!SecurityDescriptor)
- {
- /* Automatic failure */
- *AccessStatus = STATUS_ACCESS_DENIED;
- return FALSE;
- }
-
- /* Check for invalid impersonation */
- if ((SubjectSecurityContext->ClientToken) &&
- (SubjectSecurityContext->ImpersonationLevel < SecurityImpersonation))
- {
- *AccessStatus = STATUS_BAD_IMPERSONATION_LEVEL;
- return FALSE;
- }
-
+
/* Check for no access desired */
if (!DesiredAccess)
{
*AccessStatus = STATUS_ACCESS_DENIED;
return FALSE;
}
-
+
/* Return the previous access only */
*GrantedAccess = PreviouslyGrantedAccess;
*AccessStatus = STATUS_SUCCESS;
*Privileges = NULL;
return TRUE;
}
-
- /* Acquire the lock if needed */
- if (!SubjectContextLocked) SeLockSubjectContext(SubjectSecurityContext);
-
+
/* Map given accesses */
RtlMapGenericMask(&DesiredAccess, GenericMapping);
if (PreviouslyGrantedAccess)
RtlMapGenericMask(&PreviouslyGrantedAccess, GenericMapping);
-
-
-
+
+
CurrentAccess = PreviouslyGrantedAccess;
-
-
-
+ RemainingAccess = DesiredAccess;
+
+
Token = SubjectSecurityContext->ClientToken ?
SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken;
-
+
+ /* Check for system security access */
+ if (RemainingAccess & ACCESS_SYSTEM_SECURITY)
+ {
+ Privilege.Luid = SeSecurityPrivilege;
+ Privilege.Attributes = SE_PRIVILEGE_ENABLED;
+
+ /* Fail if we do not the SeSecurityPrivilege */
+ if (!SepPrivilegeCheck(Token,
+ &Privilege,
+ 1,
+ PRIVILEGE_SET_ALL_NECESSARY,
+ AccessMode))
+ {
+ *AccessStatus = STATUS_PRIVILEGE_NOT_HELD;
+ return FALSE;
+ }
+
+ /* Adjust access rights */
+ RemainingAccess &= ~ACCESS_SYSTEM_SECURITY;
+ PreviouslyGrantedAccess |= ACCESS_SYSTEM_SECURITY;
+
+ /* Succeed if there are no more rights to grant */
+ if (RemainingAccess == 0)
+ {
+ *GrantedAccess = PreviouslyGrantedAccess;
+ *AccessStatus = STATUS_SUCCESS;
+ return TRUE;
+ }
+ }
+
/* Get the DACL */
Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
&Present,
&Defaulted);
if (!NT_SUCCESS(Status))
{
- if (SubjectContextLocked == FALSE)
- {
- SeUnlockSubjectContext(SubjectSecurityContext);
- }
-
*AccessStatus = Status;
return FALSE;
}
-
+
/* RULE 1: Grant desired access if the object is unprotected */
- if (Present == TRUE && Dacl == NULL)
+ if (Present == FALSE || Dacl == NULL)
{
- if (SubjectContextLocked == FALSE)
+ if (DesiredAccess & MAXIMUM_ALLOWED)
{
- SeUnlockSubjectContext(SubjectSecurityContext);
+ *GrantedAccess = GenericMapping->GenericAll;
+ *GrantedAccess |= (DesiredAccess & ~MAXIMUM_ALLOWED);
+ }
+ else
+ {
+ *GrantedAccess = DesiredAccess | PreviouslyGrantedAccess;
}
- *GrantedAccess = DesiredAccess;
*AccessStatus = STATUS_SUCCESS;
return TRUE;
}
-
+
CurrentAccess = PreviouslyGrantedAccess;
-
+
/* RULE 2: Check token for 'take ownership' privilege */
- Privilege.Luid = SeTakeOwnershipPrivilege;
- Privilege.Attributes = SE_PRIVILEGE_ENABLED;
-
- if (SepPrivilegeCheck(Token,
- &Privilege,
- 1,
- PRIVILEGE_SET_ALL_NECESSARY,
- AccessMode))
- {
- CurrentAccess |= WRITE_OWNER;
- if ((DesiredAccess & ~VALID_INHERIT_FLAGS) ==
- (CurrentAccess & ~VALID_INHERIT_FLAGS))
+ if (DesiredAccess & WRITE_OWNER)
+ {
+ Privilege.Luid = SeTakeOwnershipPrivilege;
+ Privilege.Attributes = SE_PRIVILEGE_ENABLED;
+
+ if (SepPrivilegeCheck(Token,
+ &Privilege,
+ 1,
+ PRIVILEGE_SET_ALL_NECESSARY,
+ AccessMode))
{
- if (SubjectContextLocked == FALSE)
+ /* Adjust access rights */
+ RemainingAccess &= ~WRITE_OWNER;
+ PreviouslyGrantedAccess |= WRITE_OWNER;
+ CurrentAccess |= WRITE_OWNER;
+
+ /* Succeed if there are no more rights to grant */
+ if (RemainingAccess == 0)
{
- SeUnlockSubjectContext(SubjectSecurityContext);
+ *GrantedAccess = PreviouslyGrantedAccess;
+ *AccessStatus = STATUS_SUCCESS;
+ return TRUE;
}
-
- *GrantedAccess = CurrentAccess;
- *AccessStatus = STATUS_SUCCESS;
- return TRUE;
}
}
-
- /* RULE 3: Check whether the token is the owner */
- Status = RtlGetOwnerSecurityDescriptor(SecurityDescriptor,
- &Sid,
- &Defaulted);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("RtlGetOwnerSecurityDescriptor() failed (Status %lx)\n", Status);
- if (SubjectContextLocked == FALSE)
- {
- SeUnlockSubjectContext(SubjectSecurityContext);
- }
-
- *AccessStatus = Status;
- return FALSE;
- }
-
- if (Sid && SepSidInToken(Token, Sid))
+
+ /* Deny access if the DACL is empty */
+ if (Dacl->AceCount == 0)
{
- CurrentAccess |= (READ_CONTROL | WRITE_DAC);
- if ((DesiredAccess & ~VALID_INHERIT_FLAGS) ==
- (CurrentAccess & ~VALID_INHERIT_FLAGS))
+ if (RemainingAccess == MAXIMUM_ALLOWED && PreviouslyGrantedAccess != 0)
{
- if (SubjectContextLocked == FALSE)
- {
- SeUnlockSubjectContext(SubjectSecurityContext);
- }
-
- *GrantedAccess = CurrentAccess;
+ *GrantedAccess = PreviouslyGrantedAccess;
*AccessStatus = STATUS_SUCCESS;
return TRUE;
}
+ else
+ {
+ *GrantedAccess = 0;
+ *AccessStatus = STATUS_ACCESS_DENIED;
+ return FALSE;
+ }
}
-
+
/* Fail if DACL is absent */
if (Present == FALSE)
{
- if (SubjectContextLocked == FALSE)
- {
- SeUnlockSubjectContext(SubjectSecurityContext);
- }
-
*GrantedAccess = 0;
*AccessStatus = STATUS_ACCESS_DENIED;
return FALSE;
}
-
+
/* RULE 4: Grant rights according to the DACL */
CurrentAce = (PACE)(Dacl + 1);
for (i = 0; i < Dacl->AceCount; i++)
{
if (SepSidInToken(Token, Sid))
{
- if (SubjectContextLocked == FALSE)
- {
- SeUnlockSubjectContext(SubjectSecurityContext);
- }
-
*GrantedAccess = 0;
*AccessStatus = STATUS_ACCESS_DENIED;
return FALSE;
}
}
-
+
else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
{
if (SepSidInToken(Token, Sid))
}
CurrentAce = (PACE)((ULONG_PTR)CurrentAce + CurrentAce->Header.AceSize);
}
-
- if (SubjectContextLocked == FALSE)
- {
- SeUnlockSubjectContext(SubjectSecurityContext);
- }
-
+
DPRINT("CurrentAccess %08lx\n DesiredAccess %08lx\n",
CurrentAccess, DesiredAccess);
-
+
*GrantedAccess = CurrentAccess & DesiredAccess;
-
+
if (DesiredAccess & MAXIMUM_ALLOWED)
{
*GrantedAccess = CurrentAccess;
}
else
{
- DPRINT1("Denying access for caller: granted 0x%lx, desired 0x%lx (generic mapping %p)\n",
+ DPRINT1("HACK: Should deny access for caller: granted 0x%lx, desired 0x%lx (generic mapping %p).\n",
*GrantedAccess, DesiredAccess, GenericMapping);
+ //*AccessStatus = STATUS_ACCESS_DENIED;
+ //return FALSE;
+ *AccessStatus = STATUS_SUCCESS;
+ return TRUE;
+ }
+}
+
+static PSID
+SepGetSDOwner(IN PSECURITY_DESCRIPTOR _SecurityDescriptor)
+{
+ PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor;
+ PSID Owner;
+
+ if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
+ Owner = (PSID)((ULONG_PTR)SecurityDescriptor->Owner +
+ (ULONG_PTR)SecurityDescriptor);
+ else
+ Owner = (PSID)SecurityDescriptor->Owner;
+
+ return Owner;
+}
+
+static PSID
+SepGetSDGroup(IN PSECURITY_DESCRIPTOR _SecurityDescriptor)
+{
+ PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor;
+ PSID Group;
+
+ if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
+ Group = (PSID)((ULONG_PTR)SecurityDescriptor->Group +
+ (ULONG_PTR)SecurityDescriptor);
+ else
+ Group = (PSID)SecurityDescriptor->Group;
+
+ return Group;
+}
+
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+/*
+ * @implemented
+ */
+BOOLEAN NTAPI
+SeAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
+ IN BOOLEAN SubjectContextLocked,
+ IN ACCESS_MASK DesiredAccess,
+ IN ACCESS_MASK PreviouslyGrantedAccess,
+ OUT PPRIVILEGE_SET* Privileges,
+ IN PGENERIC_MAPPING GenericMapping,
+ IN KPROCESSOR_MODE AccessMode,
+ OUT PACCESS_MASK GrantedAccess,
+ OUT PNTSTATUS AccessStatus)
+{
+ BOOLEAN ret;
+
+ PAGED_CODE();
+
+ /* Check if this is kernel mode */
+ if (AccessMode == KernelMode)
+ {
+ /* Check if kernel wants everything */
+ if (DesiredAccess & MAXIMUM_ALLOWED)
+ {
+ /* Give it */
+ *GrantedAccess = GenericMapping->GenericAll;
+ *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED);
+ *GrantedAccess |= PreviouslyGrantedAccess;
+ }
+ else
+ {
+ /* Give the desired and previous access */
+ *GrantedAccess = DesiredAccess | PreviouslyGrantedAccess;
+ }
+
+ /* Success */
+ *AccessStatus = STATUS_SUCCESS;
+ return TRUE;
+ }
+
+ /* Check if we didn't get an SD */
+ if (!SecurityDescriptor)
+ {
+ /* Automatic failure */
*AccessStatus = STATUS_ACCESS_DENIED;
return FALSE;
}
+
+ /* Check for invalid impersonation */
+ if ((SubjectSecurityContext->ClientToken) &&
+ (SubjectSecurityContext->ImpersonationLevel < SecurityImpersonation))
+ {
+ *AccessStatus = STATUS_BAD_IMPERSONATION_LEVEL;
+ return FALSE;
+ }
+
+ /* Acquire the lock if needed */
+ if (!SubjectContextLocked)
+ SeLockSubjectContext(SubjectSecurityContext);
+
+ /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
+ if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED))
+ {
+ PACCESS_TOKEN Token = SubjectSecurityContext->ClientToken ?
+ SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken;
+
+ if (SepTokenIsOwner(Token,
+ SecurityDescriptor))
+ {
+ if (DesiredAccess & MAXIMUM_ALLOWED)
+ PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL);
+ else
+ PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL));
+
+ DesiredAccess &= ~(WRITE_DAC | READ_CONTROL);
+ }
+ }
+
+ if (DesiredAccess == 0)
+ {
+ *GrantedAccess = PreviouslyGrantedAccess;
+ *AccessStatus = STATUS_SUCCESS;
+ ret = TRUE;
+ }
+ else
+ {
+ /* Call the internal function */
+ ret = SepAccessCheck(SecurityDescriptor,
+ SubjectSecurityContext,
+ DesiredAccess,
+ PreviouslyGrantedAccess,
+ Privileges,
+ GenericMapping,
+ AccessMode,
+ GrantedAccess,
+ AccessStatus);
+ }
+
+ /* Release the lock if needed */
+ if (!SubjectContextLocked)
+ SeUnlockSubjectContext(SubjectSecurityContext);
+
+ return ret;
}
/* SYSTEM CALLS ***************************************************************/
OUT PACCESS_MASK GrantedAccess,
OUT PNTSTATUS AccessStatus)
{
+ PSECURITY_DESCRIPTOR CapturedSecurityDescriptor = NULL;
SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+ ACCESS_MASK PreviouslyGrantedAccess = 0;
PTOKEN Token;
NTSTATUS Status;
PAGED_CODE();
-
+
/* Check if this is kernel mode */
if (PreviousMode == KernelMode)
{
/* Just give the desired access */
*GrantedAccess = DesiredAccess;
}
-
+
/* Success */
*AccessStatus = STATUS_SUCCESS;
return STATUS_SUCCESS;
}
+ /* Protect probe in SEH */
+ _SEH2_TRY
+ {
+ /* Probe all pointers */
+ ProbeForRead(GenericMapping, sizeof(GENERIC_MAPPING), sizeof(ULONG));
+ ProbeForRead(PrivilegeSetLength, sizeof(ULONG), sizeof(ULONG));
+ ProbeForWrite(PrivilegeSet, *PrivilegeSetLength, sizeof(ULONG));
+ ProbeForWrite(GrantedAccess, sizeof(ACCESS_MASK), sizeof(ULONG));
+ ProbeForWrite(AccessStatus, sizeof(NTSTATUS), sizeof(ULONG));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Return the exception code */
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+
+ /* Check for unmapped access rights */
+ if (DesiredAccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL))
+ return STATUS_GENERIC_NOT_MAPPED;
+
/* Reference the token */
Status = ObReferenceObjectByHandle(TokenHandle,
TOKEN_QUERY,
NULL);
if (!NT_SUCCESS(Status))
{
- DPRINT1("Failed to reference token (Status %lx)\n", Status);
+ DPRINT("Failed to reference token (Status %lx)\n", Status);
return Status;
}
/* Check token type */
if (Token->TokenType != TokenImpersonation)
{
- DPRINT1("No impersonation token\n");
+ DPRINT("No impersonation token\n");
ObDereferenceObject(Token);
- return STATUS_ACCESS_DENIED;
+ return STATUS_NO_IMPERSONATION_TOKEN;
+ }
+
+ /* Check the impersonation level */
+ if (Token->ImpersonationLevel < SecurityIdentification)
+ {
+ DPRINT("Impersonation level < SecurityIdentification\n");
+ ObDereferenceObject(Token);
+ return STATUS_BAD_IMPERSONATION_LEVEL;
+ }
+
+ /* Capture the security descriptor */
+ Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
+ PreviousMode,
+ PagedPool,
+ FALSE,
+ &CapturedSecurityDescriptor);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Failed to capture the Security Descriptor\n");
+ ObDereferenceObject(Token);
+ return Status;
+ }
+
+ /* Check the captured security descriptor */
+ if (CapturedSecurityDescriptor == NULL)
+ {
+ DPRINT("Security Descriptor is NULL\n");
+ ObDereferenceObject(Token);
+ return STATUS_INVALID_SECURITY_DESCR;
+ }
+
+ /* Check security descriptor for valid owner and group */
+ if (SepGetSDOwner(SecurityDescriptor) == NULL || // FIXME: use CapturedSecurityDescriptor
+ SepGetSDGroup(SecurityDescriptor) == NULL) // FIXME: use CapturedSecurityDescriptor
+ {
+ DPRINT("Security Descriptor does not have a valid group or owner\n");
+ SeReleaseSecurityDescriptor(CapturedSecurityDescriptor,
+ PreviousMode,
+ FALSE);
+ ObDereferenceObject(Token);
+ return STATUS_INVALID_SECURITY_DESCR;
}
/* Set up the subject context, and lock it */
SubjectSecurityContext.ProcessAuditId = NULL;
SeLockSubjectContext(&SubjectSecurityContext);
- /* Now perform the access check */
- SeAccessCheck(SecurityDescriptor,
- &SubjectSecurityContext,
- TRUE,
- DesiredAccess,
- 0,
- &PrivilegeSet, //FIXME
- GenericMapping,
- PreviousMode,
- GrantedAccess,
- AccessStatus);
-
- /* Unlock subject context and dereference the token */
+ /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
+ if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED))
+ {
+ if (SepTokenIsOwner(Token, SecurityDescriptor)) // FIXME: use CapturedSecurityDescriptor
+ {
+ if (DesiredAccess & MAXIMUM_ALLOWED)
+ PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL);
+ else
+ PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL));
+
+ DesiredAccess &= ~(WRITE_DAC | READ_CONTROL);
+ }
+ }
+
+ if (DesiredAccess == 0)
+ {
+ *GrantedAccess = PreviouslyGrantedAccess;
+ *AccessStatus = STATUS_SUCCESS;
+ }
+ else
+ {
+ /* Now perform the access check */
+ SepAccessCheck(SecurityDescriptor, // FIXME: use CapturedSecurityDescriptor
+ &SubjectSecurityContext,
+ DesiredAccess,
+ PreviouslyGrantedAccess,
+ &PrivilegeSet, //FIXME
+ GenericMapping,
+ PreviousMode,
+ GrantedAccess,
+ AccessStatus);
+ }
+
+ /* Unlock subject context */
SeUnlockSubjectContext(&SubjectSecurityContext);
+
+ /* Release the captured security descriptor */
+ SeReleaseSecurityDescriptor(CapturedSecurityDescriptor,
+ PreviousMode,
+ FALSE);
+
+ /* Dereference the token */
ObDereferenceObject(Token);
/* Check succeeded */